diff --git a/couchbase-entity/src/main/java/com/kaufland/generation/EntityGeneration.kt b/couchbase-entity/src/main/java/com/kaufland/generation/EntityGeneration.kt index a551068b..c1813c98 100644 --- a/couchbase-entity/src/main/java/com/kaufland/generation/EntityGeneration.kt +++ b/couchbase-entity/src/main/java/com/kaufland/generation/EntityGeneration.kt @@ -48,10 +48,17 @@ class EntityGeneration { .addFunction(CblConstantGeneration.addConstants(holder, false)) .addProperty(PropertySpec.builder("mDoc", TypeUtil.mutableMapStringAny(), KModifier.PRIVATE).mutable().initializer("%T()", TypeUtil.hashMapStringAny()).build()) .addProperty(PropertySpec.builder("mDocChanges", TypeUtil.mutableMapStringAnyNullable(), KModifier.PRIVATE).mutable().initializer("%T()", TypeUtil.hashMapStringAnyNullable()).build()) - .addFunction(contructor(holder)).addFunction(setAll(holder)).addFunctions(TypeConversionMethodsGeneration(useSuspend).generate()).addFunction(id).superclass(holder.sourceElement!!.asType().asTypeName()) + .addFunction(contructor(holder)) + .addFunction(setAll(holder)) + .addFunctions(TypeConversionMethodsGeneration(useSuspend).generate()) + .addFunction(id).superclass(holder.sourceElement!!.asType().asTypeName()) .addFunction(toMap(holder, useSuspend)) .addFunction(BuilderClassGeneration.generateBuilderFun()) + if (holder.comment.isNotEmpty()) { + typeBuilder.addKdoc(holder.comment.joinToString(separator = "\n")) + } + for (baseModelHolder in holder.basedOn) { typeBuilder.addSuperinterface(baseModelHolder.interfaceTypeName) } diff --git a/couchbase-entity/src/main/java/com/kaufland/generation/RebindMethodGeneration.kt b/couchbase-entity/src/main/java/com/kaufland/generation/RebindMethodGeneration.kt index 48bb01a0..bbabd2be 100644 --- a/couchbase-entity/src/main/java/com/kaufland/generation/RebindMethodGeneration.kt +++ b/couchbase-entity/src/main/java/com/kaufland/generation/RebindMethodGeneration.kt @@ -8,7 +8,7 @@ class RebindMethodGeneration { fun generate(clearMDocChanges: Boolean): FunSpec { - val explicitType = if (clearMDocChanges) TypeUtil.hashMapStringAny() else TypeUtil.hashMapStringAnyNullable() + val explicitType = if (clearMDocChanges) TypeUtil.hashMapStringAny() else TypeUtil.linkedHashMapStringAnyNullable() val type = if (clearMDocChanges) TypeUtil.mapStringAny() else TypeUtil.mapStringAnyNullable() val rebind = FunSpec.builder("rebind").addParameter( "doc", type).addStatement("mDoc = %T()", explicitType).addCode(CblDefaultGeneration.addAddCall("mDoc")).addCode(CodeBlock.builder() .beginControlFlow("if(doc != null)") diff --git a/couchbase-entity/src/main/java/com/kaufland/generation/WrapperGeneration.kt b/couchbase-entity/src/main/java/com/kaufland/generation/WrapperGeneration.kt index 90ba85cf..654778cb 100644 --- a/couchbase-entity/src/main/java/com/kaufland/generation/WrapperGeneration.kt +++ b/couchbase-entity/src/main/java/com/kaufland/generation/WrapperGeneration.kt @@ -10,9 +10,9 @@ class WrapperGeneration { fun generateModel(holder: WrapperEntityHolder, useSuspend: Boolean): FileSpec { - var companionSpec = TypeSpec.companionObjectBuilder() + val companionSpec = TypeSpec.companionObjectBuilder() - var builderBuilder = BuilderClassGeneration.generateBaseBuilder(holder) + val builderBuilder = BuilderClassGeneration.generateBaseBuilder(holder) val typeBuilder = TypeSpec.classBuilder(holder.entitySimpleName) .addSuperinterface(TypeUtil.mapSupport()) @@ -22,12 +22,16 @@ class WrapperGeneration { .addFunction(CblDefaultGeneration.addDefaults(holder, true)) .addFunction(CblConstantGeneration.addConstants(holder, true)) .addFunction(MapSupportGeneration.toMap(holder)) - .addProperty(PropertySpec.builder("mDoc", TypeUtil.mutableMapStringAnyNullable()).addModifiers(KModifier.PRIVATE).mutable().initializer("%T()", TypeUtil.hashMapStringAnyNullable()).build()) + .addProperty(PropertySpec.builder("mDoc", TypeUtil.mutableMapStringAnyNullable()).addModifiers(KModifier.PRIVATE).mutable().initializer("%T()", TypeUtil.linkedHashMapStringAnyNullable()).build()) .addFunction(constructorMap()) .addFunction(constructorDefault()) .superclass(holder.sourceElement!!.asType().asTypeName()) .addFunction(BuilderClassGeneration.generateBuilderFun()) + if (holder.comment.isNotEmpty()) { + typeBuilder.addKdoc(holder.comment.joinToString(separator = "\n")) + } + for (baseModelHolder in holder.basedOn) { typeBuilder.addSuperinterface(baseModelHolder.interfaceTypeName) } diff --git a/couchbase-entity/src/main/java/com/kaufland/model/entity/BaseEntityHolder.kt b/couchbase-entity/src/main/java/com/kaufland/model/entity/BaseEntityHolder.kt index 7d46cb62..b86f101f 100644 --- a/couchbase-entity/src/main/java/com/kaufland/model/entity/BaseEntityHolder.kt +++ b/couchbase-entity/src/main/java/com/kaufland/model/entity/BaseEntityHolder.kt @@ -16,11 +16,11 @@ import javax.lang.model.element.Element abstract class BaseEntityHolder { - val fields: MutableMap = HashMap() + val fields: MutableMap = mutableMapOf() - var abstractParts: Set = HashSet() + var abstractParts: Set = mutableSetOf() - val fieldConstants: MutableMap = HashMap() + val fieldConstants: MutableMap = mutableMapOf() var sourceElement: Element? = null diff --git a/couchbase-entity/src/main/java/com/kaufland/model/field/CblConstantHolder.kt b/couchbase-entity/src/main/java/com/kaufland/model/field/CblConstantHolder.kt index a7bc3ebd..b646ed9d 100644 --- a/couchbase-entity/src/main/java/com/kaufland/model/field/CblConstantHolder.kt +++ b/couchbase-entity/src/main/java/com/kaufland/model/field/CblConstantHolder.kt @@ -33,6 +33,11 @@ class CblConstantHolder(field: Field) : CblBaseFieldHolder(field.name, field) { val builder = PropertySpec.builder(accessorSuffix(), returnType, KModifier.PUBLIC, KModifier.OVERRIDE) .getter(FunSpec.getterBuilder().addStatement("return " + TypeConversionMethodsGeneration.READ_METHOD_NAME + "(mDoc.get(%N), %T::class)!!", constantName, returnType).build()) + + if (comment.isNotEmpty()) { + builder.addKdoc(comment.joinToString(separator = "\n")) + } + return builder.build() } diff --git a/couchbase-entity/src/main/java/com/kaufland/model/field/CblFieldHolder.kt b/couchbase-entity/src/main/java/com/kaufland/model/field/CblFieldHolder.kt index 52703220..db3c9b4e 100644 --- a/couchbase-entity/src/main/java/com/kaufland/model/field/CblFieldHolder.kt +++ b/couchbase-entity/src/main/java/com/kaufland/model/field/CblFieldHolder.kt @@ -42,16 +42,15 @@ class CblFieldHolder(field: Field, allWrappers: List) : CblBaseFieldHold } override fun interfaceProperty(): PropertySpec { - var returnType = TypeUtil.parseMetaType(typeMirror, isIterable, subEntitySimpleName).copy(nullable = true) + val returnType = TypeUtil.parseMetaType(typeMirror, isIterable, subEntitySimpleName).copy(nullable = true) return PropertySpec.builder(accessorSuffix(), returnType.copy(true), KModifier.PUBLIC).mutable(true).build() } override fun property(dbName: String?, possibleOverrides: Set, useMDocChanges: Boolean): PropertySpec { - var returnType = TypeUtil.parseMetaType(typeMirror, isIterable, subEntitySimpleName).copy(nullable = true) + val returnType = TypeUtil.parseMetaType(typeMirror, isIterable, subEntitySimpleName).copy(nullable = true) val propertyBuilder = PropertySpec.builder(accessorSuffix(), returnType.copy(true), KModifier.PUBLIC, KModifier.OVERRIDE).mutable(true) - val getter = FunSpec.getterBuilder() val setter = FunSpec.setterBuilder().addParameter("value", String::class) @@ -90,6 +89,10 @@ class CblFieldHolder(field: Field, allWrappers: List) : CblBaseFieldHold } + if (comment.isNotEmpty()) { + propertyBuilder.addKdoc(comment.joinToString(separator = "\n")) + } + return propertyBuilder.setter(setter.build()).getter(getter.build()).build() } @@ -98,9 +101,16 @@ class CblFieldHolder(field: Field, allWrappers: List) : CblBaseFieldHold return CodeBlock.of("${TypeConversionMethodsGeneration.WRITE_METHOD_NAME}<%T>($format, %T::class)", resultType, *args, forTypeConversion) } - override fun builderSetter(dbName: String?, packageName: String, entitySimpleName: String, useMDocChanges: Boolean): FunSpec? { + override fun builderSetter(dbName: String?, packageName: String, entitySimpleName: String, useMDocChanges: Boolean): FunSpec { val fieldType = TypeUtil.parseMetaType(typeMirror, isIterable, subEntitySimpleName) - val builder = FunSpec.builder("set" + accessorSuffix().capitalize()).addModifiers(KModifier.PUBLIC).addParameter("value", fieldType).returns(ClassName(packageName, "${entitySimpleName}.Builder")) + val builder = FunSpec.builder("set" + accessorSuffix().capitalize()) + .addModifiers(KModifier.PUBLIC) + .addParameter("value", fieldType) + .returns(ClassName(packageName, "${entitySimpleName}.Builder")) + + if (this.comment.isNotEmpty()) { + builder.addKdoc(this.comment.joinToString(separator = "\n")) + } builder.addStatement("obj.${accessorSuffix()} = value") builder.addStatement("return this") diff --git a/couchbase-entity/src/main/java/com/kaufland/util/TypeUtil.kt b/couchbase-entity/src/main/java/com/kaufland/util/TypeUtil.kt index fbaa23bd..5a5b68ae 100644 --- a/couchbase-entity/src/main/java/com/kaufland/util/TypeUtil.kt +++ b/couchbase-entity/src/main/java/com/kaufland/util/TypeUtil.kt @@ -32,6 +32,10 @@ object TypeUtil { return ClassName("kotlin.collections", "HashMap").parameterizedBy(string(), anyNullable()) } + fun linkedHashMapStringAnyNullable(): ParameterizedTypeName { + return ClassName("kotlin.collections", "LinkedHashMap").parameterizedBy(string(), anyNullable()) + } + fun hashMapStringAny(): ParameterizedTypeName { return ClassName("kotlin.collections", "HashMap").parameterizedBy(string(), any()) } diff --git a/demo/src/main/java/kaufland/com/demo/entity/Product.kt b/demo/src/main/java/kaufland/com/demo/entity/Product.kt index 7cfb326e..9d7fb4d6 100644 --- a/demo/src/main/java/kaufland/com/demo/entity/Product.kt +++ b/demo/src/main/java/kaufland/com/demo/entity/Product.kt @@ -1,18 +1,16 @@ package kaufland.com.demo.entity import com.couchbase.lite.Blob -import kaufland.com.coachbasebinderapi.Comment -import kaufland.com.coachbasebinderapi.Entity -import kaufland.com.coachbasebinderapi.Field -import kaufland.com.coachbasebinderapi.Fields +import kaufland.com.coachbasebinderapi.* import kaufland.com.coachbasebinderapi.query.Queries import kaufland.com.coachbasebinderapi.query.Query @Entity(database = "mydb_db") +@MapWrapper @Comment(["Hey, I just met you and this is crazy", "But here's my documentation, so read it maybe"]) @Fields( - Field(name = "type", type = String::class, defaultValue = "product", readonly = true), - Field(name = "name", type = String::class, comment = ["contains the product name", "and other infos"]), + Field(name = "type", type = String::class, defaultValue = "product", readonly = true, comment = ["Document type"]), + Field(name = "name", type = String::class, comment = ["contains the product name.", "and other infos"]), Field(name = "comments", type = UserComment::class, list = true), Field(name = "image", type = Blob::class), Field(name = "identifiers", type = String::class, list = true) @@ -20,4 +18,4 @@ import kaufland.com.coachbasebinderapi.query.Query @Queries( Query(fields = ["type"]) ) -open class Product \ No newline at end of file +open class Product diff --git a/demo/src/test/java/kaufland/com/demo/entity/ProductWrapperTest.kt b/demo/src/test/java/kaufland/com/demo/entity/ProductWrapperTest.kt new file mode 100644 index 00000000..05140cab --- /dev/null +++ b/demo/src/test/java/kaufland/com/demo/entity/ProductWrapperTest.kt @@ -0,0 +1,53 @@ +package kaufland.com.demo.entity + +import kaufland.com.coachbasebinderapi.PersistenceConfig +import kaufland.com.coachbasebinderapi.TypeConversion +import org.junit.Assert.* +import org.junit.BeforeClass +import org.junit.Test +import kotlin.reflect.KClass + +class ProductWrapperTest { + companion object { + @BeforeClass + @JvmStatic + fun beforeClass() { + PersistenceConfig.configure(object : PersistenceConfig.Connector { + override val typeConversions: Map, TypeConversion> = mapOf() + + override fun getDocument(id: String, dbName: String): Map? { + TODO("Not yet implemented") + } + + override fun queryDoc(dbName: String, queryParams: Map): List> { + TODO("Not yet implemented") + } + + override fun deleteDocument(id: String, dbName: String) { + TODO("Not yet implemented") + } + + override fun upsertDocument(document: MutableMap, id: String?, dbName: String) { + TODO("Not yet implemented") + } + }) + } + } + + @Test + fun `toMap should preserve field order`() { + val product = ProductWrapper.create().builder() + .setName("name") + .setComments(emptyList()) + .setIdentifiers(listOf("1", "2")) + .exit() + + val map = product.toMap() + map.remove(ProductWrapper.TYPE) + assertEquals(mapOf( + ProductWrapper.NAME to "name", + ProductWrapper.COMMENTS to listOf(), + ProductWrapper.IDENTIFIERS to listOf("1", "2") + ), map) + } +}