diff --git a/database/mongodb/src/main/kotlin/cn/tursom/mongodb/MongoOperator.kt b/database/mongodb/src/main/kotlin/cn/tursom/mongodb/MongoOperator.kt index 7e12674..7bd084e 100644 --- a/database/mongodb/src/main/kotlin/cn/tursom/mongodb/MongoOperator.kt +++ b/database/mongodb/src/main/kotlin/cn/tursom/mongodb/MongoOperator.kt @@ -1,5 +1,6 @@ package cn.tursom.mongodb +import cn.tursom.core.isStatic import cn.tursom.core.isTransient import cn.tursom.mongodb.annotation.Ignore import com.mongodb.client.MongoCollection @@ -14,25 +15,22 @@ import kotlin.reflect.KProperty1 @Suppress("MemberVisibilityCanBePrivate", "CanBeParameter", "unused") class MongoOperator<T : Any>( - val collection: MongoCollection<T>, + val collection: MongoCollection<Document>, val clazz: Class<T> ) { - constructor(clazz: Class<T>, database: MongoDatabase) : this(database.getCollection(MongoUtil.collectionName(clazz), clazz), clazz) + constructor(clazz: Class<T>, database: MongoDatabase) : this(database.getCollection(MongoUtil.collectionName(clazz)), clazz) private val fields = clazz.declaredFields.filter { it.isAccessible = true - !it.isTransient() && it.getAnnotation(Ignore::class.java) == null + !it.isStatic() && !it.isTransient() && it.getAnnotation(Ignore::class.java) == null } fun save(entity: T, options: InsertOneOptions = InsertOneOptions()) { - collection.insertOne(entity, options) + collection.insertOne(convertToBson(entity), options) } fun save(entities: Collection<T>, options: InsertManyOptions = InsertManyOptions()) { - collection.insertMany(when (entities) { - is List<T> -> entities - else -> entities.toList() - }, options) + collection.insertMany(entities.map { convertToBson(it) }, options) } fun update(update: Bson, where: Bson, options: UpdateOptions = UpdateOptions()): UpdateResult { @@ -64,11 +62,11 @@ class MongoOperator<T : Any>( return add(field, 1, where) } - private fun convertToBson(entity: Any): Bson { + private fun convertToBson(entity: Any): Document { + System.err.println(entity) val bson = Document() fields.forEach { - val value = it.get(entity) ?: return@forEach - bson[MongoUtil.fieldName(it)] = value + MongoUtil.injectValue(bson, it.get(entity) ?: return@forEach, it) } return bson } diff --git a/database/mongodb/src/main/kotlin/cn/tursom/mongodb/MongoUtil.kt b/database/mongodb/src/main/kotlin/cn/tursom/mongodb/MongoUtil.kt index 7186360..842c14f 100644 --- a/database/mongodb/src/main/kotlin/cn/tursom/mongodb/MongoUtil.kt +++ b/database/mongodb/src/main/kotlin/cn/tursom/mongodb/MongoUtil.kt @@ -1,8 +1,10 @@ package cn.tursom.mongodb +import cn.tursom.core.isStatic import cn.tursom.core.isTransient import cn.tursom.mongodb.annotation.Collection import cn.tursom.mongodb.annotation.Ignore +import org.bson.BsonValue import org.bson.Document import org.bson.conversions.Bson import java.lang.reflect.Field @@ -25,15 +27,59 @@ object MongoUtil { ?: property.name } - fun convertToBson(entity: Any): Bson { - val bson = Document() - entity.javaClass.declaredFields.filter { - it.isAccessible = true - !it.isTransient() && it.getAnnotation(Ignore::class.java) == null - }.forEach { - val value = it.get(entity) ?: return@forEach - bson[fieldName(it)] = value + fun convertToBson(entity: Any): Document { + return when (entity) { + is Map<*, *> -> entity.convert() + else -> { + val bson = Document() + entity.javaClass.declaredFields.filter { + it.isAccessible = true + !it.isStatic() && !it.isTransient() && it.getAnnotation(Ignore::class.java) == null + }.forEach { + injectValue(bson, it.get(entity) ?: return@forEach, it) + } + bson + } } - return bson + } + + fun injectValue(bson: Document, value: Any, field: Field) { + when (value) { + is Pair<*, *> -> bson[value.first?.toString() ?: return] = convertToBson(value.second ?: return) + is Map.Entry<*, *> -> bson[value.key?.toString() ?: return] = + convertToBson(value.value ?: return) + else -> bson[fieldName(field)] = value.convert() ?: return + } + } + + private fun Iterator<*>.convert(): List<*> { + val list = ArrayList<Any?>() + forEach { + list.add(it.convert() ?: return@forEach) + } + return list + } + + private fun Map<*, *>.convert(): Document { + val doc = Document() + forEach { any, u -> + any ?: return@forEach + doc[any.toString()] = u.convert() ?: return@forEach + } + return doc + } + + private fun Any?.convert() = when (this) { + null -> null + is Enum<*> -> name + is Boolean -> this + is Number -> this + is String -> this + is Bson -> this + is BsonValue -> this + is Map<*, *> -> this.convert() + is Iterator<*> -> this.convert() + is Iterable<*> -> this.iterator().convert() + else -> convertToBson(this) } } \ No newline at end of file