impl mongo module

This commit is contained in:
tursom 2020-02-19 02:02:40 +08:00
parent 655e698eb2
commit fc8cd49841
11 changed files with 240 additions and 52 deletions

View File

@ -1,16 +0,0 @@
package cn.tursom.mongodb
import cn.tursom.mongodb.annotation.Collection
import com.mongodb.MongoClient
interface MongoConnection {
val client: MongoClient
fun <T> createTemplate(clazz: Class<T>): MongoTemplate<T>
companion object {
fun collectionName(clazz: Class<*>): String {
return clazz.getAnnotation(Collection::class.java)?.name ?: clazz.simpleName
}
}
}

View File

@ -0,0 +1,74 @@
package cn.tursom.mongodb
import cn.tursom.core.isTransient
import cn.tursom.mongodb.annotation.Ignore
import com.mongodb.client.MongoCollection
import com.mongodb.client.MongoDatabase
import com.mongodb.client.model.InsertManyOptions
import com.mongodb.client.model.InsertOneOptions
import com.mongodb.client.model.UpdateOptions
import com.mongodb.client.result.UpdateResult
import org.bson.Document
import org.bson.conversions.Bson
import kotlin.reflect.KProperty1
@Suppress("MemberVisibilityCanBePrivate", "CanBeParameter", "unused")
class MongoOperator<T : Any>(
val collection: MongoCollection<T>,
val clazz: Class<T>
) {
constructor(clazz: Class<T>, database: MongoDatabase) : this(database.getCollection(MongoUtil.collectionName(clazz), clazz), clazz)
private val fields = clazz.declaredFields.filter {
!it.isTransient() && it.getAnnotation(Ignore::class.java) == null
}
fun save(entity: T, options: InsertOneOptions = InsertOneOptions()) {
collection.insertOne(entity, options)
}
fun save(entities: Collection<T>, options: InsertManyOptions = InsertManyOptions()) {
collection.insertMany(when (entities) {
is List<T> -> entities
else -> entities.toList()
}, options)
}
fun update(update: Bson, where: Bson, options: UpdateOptions = UpdateOptions()): UpdateResult {
return collection.updateOne(where, update, options)
}
fun update(entity: T, where: Bson, options: UpdateOptions = UpdateOptions()): UpdateResult {
return update(convertToBson(entity), where, options)
}
@Suppress("SpellCheckingInspection")
fun upsert(entity: T, where: Bson, options: UpdateOptions = UpdateOptions()): UpdateResult {
return update(entity, where, options.upsert(true))
}
@Suppress("SpellCheckingInspection")
fun upsert(update: Bson, where: Bson, options: UpdateOptions = UpdateOptions()): UpdateResult {
return update(convertToBson(update), where, options.upsert(true))
}
fun add(field: KProperty1<T, Number>, value: Number, where: Bson, options: UpdateOptions = UpdateOptions()): UpdateResult {
return upsert(
Update { field inc value },
where, options
)
}
fun inc(field: KProperty1<T, Number>, where: Bson): UpdateResult {
return add(field, 1, where)
}
private fun convertToBson(entity: Any): Bson {
val bson = Document()
fields.forEach {
val value = it.get(entity) ?: return@forEach
bson[MongoUtil.fieldName(it)] = value
}
return bson
}
}

View File

@ -1,5 +1,51 @@
package cn.tursom.mongodb
interface MongoTemplate<T> {
fun save(entity: T)
}
import cn.tursom.core.cast
import com.mongodb.MongoClient
import com.mongodb.client.MongoDatabase
import com.mongodb.client.model.InsertManyOptions
import com.mongodb.client.model.InsertOneOptions
import com.mongodb.client.model.UpdateOptions
import org.bson.conversions.Bson
import java.util.concurrent.ConcurrentHashMap
@Suppress("CanBeParameter", "MemberVisibilityCanBePrivate", "unused")
class MongoTemplate(
db: String,
val host: String = "127.0.0.1",
val port: Int = 27017
) {
val client = MongoClient(host, port)
val db: MongoDatabase = client.getDatabase(db)
private val operatorMap = ConcurrentHashMap<Class<*>, MongoOperator<*>>()
fun <T : Any> save(entity: T, options: InsertOneOptions = InsertOneOptions()) {
getCollection(entity.javaClass).save(entity, options)
}
inline fun <reified T : Any> save(entities: Collection<T>, options: InsertManyOptions = InsertManyOptions()) {
getCollection<T>().save(entities, options)
}
fun <T : Any> update(entity: T, where: Bson, options: UpdateOptions = UpdateOptions()) {
getCollection(entity.javaClass).update(entity, where, options)
}
@Suppress("SpellCheckingInspection")
fun <T : Any> upsert(entity: T, where: Bson, options: UpdateOptions = UpdateOptions()) {
getCollection(entity.javaClass).upsert(entity, where, options)
}
inline fun <reified T : Any> getCollection(): MongoOperator<T> = getCollection(T::class.java)
fun <T : Any> getCollection(clazz: Class<T>): MongoOperator<T> {
return operatorMap[clazz]?.cast() ?: run {
val operator = MongoOperator(clazz, db)
operatorMap[clazz] = operator
operator
}
}
}

View File

@ -0,0 +1,38 @@
package cn.tursom.mongodb
import cn.tursom.core.isTransient
import cn.tursom.mongodb.annotation.Collection
import cn.tursom.mongodb.annotation.Ignore
import org.bson.Document
import org.bson.conversions.Bson
import java.lang.reflect.Field
import kotlin.reflect.KProperty
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.jvm.javaField
object MongoUtil {
fun collectionName(clazz: Class<*>): String {
return clazz.getAnnotation(Collection::class.java)?.name ?: clazz.simpleName
}
fun fieldName(field: Field): String {
return field.getAnnotation(cn.tursom.mongodb.annotation.Field::class.java)?.name ?: field.name
}
fun fieldName(property: KProperty<*>): String {
return property.findAnnotation<cn.tursom.mongodb.annotation.Field>()?.name
?: property.javaField?.getAnnotation(cn.tursom.mongodb.annotation.Field::class.java)?.name
?: property.name
}
fun convertToBson(entity: Any): Bson {
val bson = Document()
entity.javaClass.declaredFields.filter {
!it.isTransient() && it.getAnnotation(Ignore::class.java) == null
}.forEach {
val value = it.get(entity) ?: return@forEach
bson[MongoUtil.fieldName(it)] = value
}
return bson
}
}

View File

@ -0,0 +1,22 @@
package cn.tursom.mongodb
import com.mongodb.client.model.Updates
import org.bson.conversions.Bson
import kotlin.reflect.KProperty
object Update {
operator fun invoke(action: Update.() -> Bson) = this.action()
infix fun KProperty<*>.set(value: Any): Bson = Updates.set(MongoUtil.fieldName(this), value)
fun KProperty<*>.unset(): Bson = Updates.unset(MongoUtil.fieldName(this))
fun setOnInsert(value: Bson): Bson = Updates.setOnInsert(value)
fun setOnInsert(value: Any): Bson = Updates.setOnInsert(MongoUtil.convertToBson(value))
infix fun KProperty<*>.setOnInsert(value: Any): Bson = Updates.setOnInsert(MongoUtil.fieldName(this), value)
infix fun KProperty<*>.rename(value: String): Bson = Updates.rename(MongoUtil.fieldName(this), value)
infix fun String.rename(value: String): Bson = Updates.rename(this, value)
infix fun KProperty<*>.inc(value: Number): Bson = Updates.inc(MongoUtil.fieldName(this), value)
infix fun KProperty<*>.mul(value: Number): Bson = Updates.mul(MongoUtil.fieldName(this), value)
infix fun KProperty<*>.min(value: Any): Bson = Updates.min(MongoUtil.fieldName(this), value)
infix fun KProperty<*>.max(value: Any): Bson = Updates.max(MongoUtil.fieldName(this), value)
}

View File

@ -0,0 +1,44 @@
package cn.tursom.mongodb
import com.mongodb.client.model.Filters
import com.mongodb.client.model.TextSearchOptions
import org.bson.BsonType
import org.bson.conversions.Bson
import kotlin.reflect.KProperty
@Suppress("unused")
object Where {
operator fun invoke(action: Where.() -> Bson) = this.action()
infix fun KProperty<*>.eq(value: Any): Bson = Filters.eq(MongoUtil.fieldName(this), value)
infix fun KProperty<*>.ne(value: Any): Bson = Filters.ne(MongoUtil.fieldName(this), value)
infix fun KProperty<*>.gt(value: Any): Bson = Filters.gt(MongoUtil.fieldName(this), value)
infix fun KProperty<*>.lt(value: Any): Bson = Filters.lt(MongoUtil.fieldName(this), value)
infix fun KProperty<*>.gte(value: Any): Bson = Filters.gte(MongoUtil.fieldName(this), value)
infix fun KProperty<*>.lte(value: Any): Bson = Filters.lte(MongoUtil.fieldName(this), value)
fun KProperty<*>.`in`(vararg value: Any): Bson = Filters.`in`(MongoUtil.fieldName(this), *value)
fun KProperty<*>.nin(vararg value: Any): Bson = Filters.nin(MongoUtil.fieldName(this), *value)
fun KProperty<*>.all(vararg value: Any): Bson = Filters.all(MongoUtil.fieldName(this), *value)
fun KProperty<*>.exists(exists: Boolean = true): Bson = Filters.exists(MongoUtil.fieldName(this), exists)
infix fun KProperty<*>.type(type: String): Bson = Filters.type(MongoUtil.fieldName(this), type)
infix fun KProperty<*>.type(type: BsonType): Bson = Filters.type(MongoUtil.fieldName(this), type)
fun KProperty<*>.mod(divisor: Long, remainder: Long): Bson = Filters.mod(MongoUtil.fieldName(this), divisor, remainder)
infix fun KProperty<*>.regex(regex: String): Bson = Filters.regex(MongoUtil.fieldName(this), regex)
infix fun KProperty<*>.regex(regex: Regex): Bson = Filters.regex(MongoUtil.fieldName(this), regex.pattern)
fun KProperty<*>.regex(regex: String, option: String): Bson = Filters.regex(MongoUtil.fieldName(this), regex, option)
fun KProperty<*>.regex(regex: Regex, option: String): Bson = Filters.regex(MongoUtil.fieldName(this), regex.pattern, option)
fun text(search: String): Bson = Filters.text(search)
fun text(search: String, option: TextSearchOptions): Bson = Filters.text(search, option)
fun where(javaScriptExpression: String): Bson = Filters.where(javaScriptExpression)
fun expr(expression: Any): Bson = Filters.expr(expression)
fun and(vararg bson: Bson): Bson = Filters.and(*bson)
infix fun Bson.and(bson: Bson): Bson = Filters.and(this, bson)
fun or(vararg bson: Bson): Bson = Filters.or(*bson)
infix fun Bson.or(bson: Bson): Bson = Filters.or(this, bson)
fun nor(vararg bson: Bson): Bson = Filters.or(*bson)
infix fun Bson.nor(bson: Bson): Bson = Filters.nor(this, bson)
operator fun Bson.not(): Bson = Filters.not(this)
}

View File

@ -2,4 +2,5 @@ package cn.tursom.mongodb.annotation
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
annotation class Collection(val name: String)
annotation class Collection(val name: String)

View File

@ -0,0 +1,6 @@
package cn.tursom.mongodb.annotation
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
annotation class Field(val name: String)

View File

@ -0,0 +1,5 @@
package cn.tursom.mongodb.annotation
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
annotation class Ignore(val name: String)

View File

@ -1,21 +0,0 @@
package cn.tursom.mongodb.impl
import cn.tursom.mongodb.MongoConnection
import cn.tursom.mongodb.MongoTemplate
import com.mongodb.MongoClient
class MongoConnectionImpl(
db: String,
val host: String = "127.0.0.1",
val port: Int = 27017
) : MongoConnection {
override val client: MongoClient = MongoClient(host, port)
val db = client.getDatabase(db)
override fun <T> createTemplate(clazz: Class<T>): MongoTemplate<T> {
db.createCollection(MongoConnection.collectionName(clazz))
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}

View File

@ -1,11 +0,0 @@
package cn.tursom.mongodb.impl
import cn.tursom.mongodb.MongoTemplate
class MongoTemplateImpl<T>(
) : MongoTemplate<T> {
override fun save(entity: T) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}