@@ -24,7 +24,6 @@ import org.ktorm.dsl.AliasRemover
2424import org.ktorm.entity.EntitySequence
2525import org.ktorm.expression.ColumnAssignmentExpression
2626import org.ktorm.expression.InsertExpression
27- import org.ktorm.ksp.compiler.util._type
2827import org.ktorm.ksp.spi.ColumnMetadata
2928import org.ktorm.ksp.spi.TableMetadata
3029import org.ktorm.schema.Column
@@ -34,44 +33,59 @@ internal object AddFunctionGenerator {
3433
3534 fun generate (table : TableMetadata ): FunSpec {
3635 val primaryKeys = table.columns.filter { it.isPrimaryKey }
37- val useGeneratedKey = primaryKeys.size == 1
38- && primaryKeys[0 ].entityProperty.isMutable
39- && primaryKeys[0 ].entityProperty._type .isMarkedNullable
40-
36+ val useGeneratedKey = primaryKeys.size == 1 && primaryKeys[0 ].entityProperty.isMutable
4137 val entityClass = table.entityClass.toClassName()
4238 val tableClass = ClassName (table.entityClass.packageName.asString(), table.tableClassName)
4339
4440 return FunSpec .builder(" add" )
4541 .addKdoc(kdoc(table, useGeneratedKey))
4642 .receiver(EntitySequence ::class .asClassName().parameterizedBy(entityClass, tableClass))
47- .addParameter(" entity" , entityClass)
48- .addParameter(ParameterSpec .builder(" isDynamic" , typeNameOf<Boolean >()).defaultValue(" false" ).build())
43+ .addParameters(parameters(entityClass, useGeneratedKey))
4944 .returns(Int ::class .asClassName())
5045 .addCode(checkForDml())
51- .addCode(addValFun())
52- .addCode(addAssignments(table, useGeneratedKey ))
46+ .addCode(addValFun(table, useGeneratedKey ))
47+ .addCode(addAssignments(table))
5348 .addCode(createExpression())
5449 .addCode(executeUpdate(useGeneratedKey, primaryKeys))
5550 .build()
5651 }
5752
5853 private fun kdoc (table : TableMetadata , useGeneratedKey : Boolean ): String {
59- var kdoc = " " +
60- " Insert the given entity into this sequence and return the affected record number. " +
61- " If [isDynamic] is set to true, the generated SQL will include only the non-null columns. "
62-
6354 if (useGeneratedKey) {
6455 val pk = table.columns.single { it.isPrimaryKey }
6556 val pkName = table.entityClass.simpleName.asString() + " ." + pk.entityProperty.simpleName.asString()
66-
67- kdoc + = " \n\n " +
68- " Note that this function will obtain the generated primary key from the database and fill it into " +
69- " the property [$pkName ] after the insertion completes. But this requires us not to set " +
70- " the primary key’s value beforehand, otherwise, if you do that, the given value will be " +
71- " inserted into the database, and no keys generated."
57+ return """
58+ Insert the given entity into the table that the sequence object represents.
59+
60+ @param entity the entity to be inserted.
61+ @param isDynamic whether only non-null columns should be inserted.
62+ @param useGeneratedKey whether to obtain the generated primary key value and fill it into the property [$pkName ] after insertion.
63+ @return the affected record number.
64+ """ .trimIndent()
65+ } else {
66+ return """
67+ Insert the given entity into the table that the sequence object represents.
68+
69+ @param entity the entity to be inserted.
70+ @param isDynamic whether only non-null columns should be inserted.
71+ @return the affected record number.
72+ """ .trimIndent()
7273 }
74+ }
7375
74- return kdoc
76+ private fun parameters (entityClass : ClassName , useGeneratedKey : Boolean ): List <ParameterSpec > {
77+ if (useGeneratedKey) {
78+ return listOf (
79+ ParameterSpec .builder(" entity" , entityClass).build(),
80+ ParameterSpec .builder(" isDynamic" , typeNameOf<Boolean >()).defaultValue(" false" ).build(),
81+ ParameterSpec .builder(" useGeneratedKey" , typeNameOf<Boolean >()).defaultValue(" false" ).build()
82+ )
83+ } else {
84+ return listOf (
85+ ParameterSpec .builder(" entity" , entityClass).build(),
86+ ParameterSpec .builder(" isDynamic" , typeNameOf<Boolean >()).defaultValue(" false" ).build()
87+ )
88+ }
7589 }
7690
7791 internal fun checkForDml (): CodeBlock {
@@ -83,7 +97,6 @@ internal object AddFunctionGenerator {
8397 || expression.orderBy.isNotEmpty()
8498 || expression.offset != null
8599 || expression.limit != null
86-
87100 if (isModified) {
88101 val msg = "" +
89102 "Entity manipulation functions are not supported by this sequence object. " +
@@ -97,38 +110,58 @@ internal object AddFunctionGenerator {
97110 return CodeBlock .of(code)
98111 }
99112
100- internal fun addValFun (): CodeBlock {
101- val code = """
102- fun <T : Any> MutableList<%1T<*>>.addVal(column: %2T<T>, value: T?, isDynamic: Boolean) {
103- if (!isDynamic || value != null) {
113+ private fun addValFun (table : TableMetadata , useGeneratedKey : Boolean ): CodeBlock {
114+ if (useGeneratedKey) {
115+ val pk = table.columns.single { it.isPrimaryKey }
116+ val code = """
117+ fun <T : Any> MutableList<%1T<*>>.addVal(column: %2T<T>, value: T?) {
118+ if (useGeneratedKey && column === sourceTable.%3N) {
119+ return
120+ }
121+
122+ if (isDynamic && value == null) {
123+ return
124+ }
125+
104126 this += %1T(column.asExpression(), column.wrapArgument(value))
105127 }
106- }
107-
128+
129+
130+ """ .trimIndent()
131+ return CodeBlock .of(
132+ code,
133+ ColumnAssignmentExpression ::class .asClassName(),
134+ Column ::class .asClassName(),
135+ pk.columnPropertyName
136+ )
137+ } else {
138+ val code = """
139+ fun <T : Any> MutableList<%1T<*>>.addVal(column: %2T<T>, value: T?) {
140+ if (isDynamic && value == null) {
141+ return
142+ }
108143
109- """ .trimIndent()
110-
111- return CodeBlock .of(code, ColumnAssignmentExpression ::class .asClassName(), Column ::class .asClassName())
144+ this += %1T(column.asExpression(), column.wrapArgument(value))
145+ }
146+
147+
148+ """ .trimIndent()
149+ return CodeBlock .of(code, ColumnAssignmentExpression ::class .asClassName(), Column ::class .asClassName())
150+ }
112151 }
113152
114- private fun addAssignments (table : TableMetadata , useGeneratedKey : Boolean ): CodeBlock {
153+ private fun addAssignments (table : TableMetadata ): CodeBlock {
115154 return buildCodeBlock {
116155 addStatement(" val assignments = ArrayList<%T<*>>()" , ColumnAssignmentExpression ::class .asClassName())
117156
118157 for (column in table.columns) {
119- val forceDynamic = useGeneratedKey
120- && column.isPrimaryKey && column.entityProperty._type .isMarkedNullable
121-
122158 addStatement(
123- " assignments.addVal(sourceTable.%N, entity.%N, %L )" ,
159+ " assignments.addVal(sourceTable.%N, entity.%N)" ,
124160 column.columnPropertyName,
125- column.entityProperty.simpleName.asString(),
126- if (forceDynamic) " isDynamic·=·true" else " isDynamic"
161+ column.entityProperty.simpleName.asString()
127162 )
128163 }
129164
130- add(" \n " )
131-
132165 beginControlFlow(" if (assignments.isEmpty())" )
133166 addStatement(" return 0" )
134167 endControlFlow()
@@ -138,33 +171,31 @@ internal object AddFunctionGenerator {
138171 }
139172
140173 private fun createExpression (): CodeBlock {
141- val code = """
142- val expression = database.dialect.createExpressionVisitor(%T).visit(
143- %T(sourceTable.asExpression(), assignments)
174+ return buildCodeBlock {
175+ addStatement(
176+ " val visitor = database.dialect.createExpressionVisitor(%T)" ,
177+ AliasRemover ::class .asClassName()
144178 )
145-
146-
147- """ .trimIndent ()
148-
149- return CodeBlock .of(code, AliasRemover :: class .asClassName(), InsertExpression :: class .asClassName())
179+ addStatement(
180+ " val expression = visitor.visit(%T(sourceTable.asExpression(), assignments)) " ,
181+ InsertExpression :: class .asClassName ()
182+ )
183+ }
150184 }
151185
152186 private fun executeUpdate (useGeneratedKey : Boolean , primaryKeys : List <ColumnMetadata >): CodeBlock {
153187 return buildCodeBlock {
154188 if (! useGeneratedKey) {
155189 addStatement(" return database.executeUpdate(expression)" )
156190 } else {
157- // If the primary key value is manually specified, not obtain the generated key.
158- beginControlFlow(" if (entity.%N != null)" , primaryKeys[0 ].entityProperty.simpleName.asString())
191+ beginControlFlow(" if (!useGeneratedKey)" )
159192 addStatement(" return database.executeUpdate(expression)" )
160-
161- // Else obtain the generated key value.
162193 nextControlFlow(" else" )
163194 addNamed(
164195 format = """
165196 val (effects, rowSet) = database.executeUpdateAndRetrieveKeys(expression)
166197 if (rowSet.next()) {
167- val generatedKey = rowSet.%getGeneratedKey:M(sourceTable.%columnName :N)
198+ val generatedKey = rowSet.%getGeneratedKey:M(sourceTable.%columnPropertyName :N)
168199 if (generatedKey != null) {
169200 if (database.logger.isDebugEnabled()) {
170201 database.logger.debug("Generated Key: ${' $' } generatedKey")
@@ -179,12 +210,11 @@ internal object AddFunctionGenerator {
179210 """ .trimIndent(),
180211
181212 arguments = mapOf (
182- " columnName" to primaryKeys[0 ].columnPropertyName,
183213 " propertyName" to primaryKeys[0 ].entityProperty.simpleName.asString(),
214+ " columnPropertyName" to primaryKeys[0 ].columnPropertyName,
184215 " getGeneratedKey" to MemberName (" org.ktorm.dsl" , " getGeneratedKey" , true )
185216 )
186217 )
187-
188218 endControlFlow()
189219 }
190220 }
0 commit comments