From 6e3ebd43c95b2f79ccff86320126faad769afc36 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Sun, 13 Feb 2022 19:52:17 -0500 Subject: [PATCH 1/9] [Kotlin] Rework insert methods --- .../util/kotlin/KotlinBatchInsertBuilder.kt | 78 ++++++++++++++ ...lpers.kt => KotlinGeneralInsertBuilder.kt} | 11 -- .../sql/util/kotlin/KotlinInsertBuilder.kt | 83 ++++++++++++++ .../kotlin/KotlinMultiRowInsertBuilder.kt | 78 ++++++++++++++ .../sql/util/kotlin/KotlinSubQueryBuilders.kt | 2 + .../util/kotlin/elements/InsertStatements.kt | 7 +- .../kotlin/model/ModelBuilderFunctions.kt | 32 ++++-- .../kotlin/mybatis3/MapperSupportFunctions.kt | 49 +++++---- .../mybatis3/ProviderBuilderFunctions.kt | 29 +++-- .../NamedParameterJdbcTemplateExtensions.kt | 87 ++++++++++++--- .../kotlin/spring/ProviderBuilderFunctions.kt | 35 ++++-- ...CanonicalSpringKotlinTemplateDirectTest.kt | 101 ++++++++++++++++++ .../canonical/CanonicalSpringKotlinTest.kt | 64 ++++++++++- 13 files changed, 585 insertions(+), 71 deletions(-) create mode 100644 src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt rename src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/{KotlinInsertHelpers.kt => KotlinGeneralInsertBuilder.kt} (83%) create mode 100644 src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt create mode 100644 src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt new file mode 100644 index 000000000..89e53e18d --- /dev/null +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2016-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.util.kotlin + +import org.mybatis.dynamic.sql.SqlBuilder +import org.mybatis.dynamic.sql.SqlColumn +import org.mybatis.dynamic.sql.SqlTable +import org.mybatis.dynamic.sql.insert.BatchInsertDSL +import org.mybatis.dynamic.sql.insert.BatchInsertModel +import org.mybatis.dynamic.sql.util.Buildable + +typealias KotlinBatchInsertCompleter = KotlinBatchInsertBuilder.() -> Unit + +@MyBatisDslMarker +class KotlinBatchInsertBuilder (private val rows: Collection): Buildable> { + + private lateinit var dsl: BatchInsertDSL + + fun into(table: SqlTable) { + dsl = SqlBuilder.insertBatch(rows).into(table) + } + + infix fun map(column: SqlColumn) = MapCompleter(column) + + override fun build(): BatchInsertModel { + return getDsl().build() + } + + private fun getDsl(): BatchInsertDSL { + try { + return dsl + } catch (e: UninitializedPropertyAccessException) { + throw UninitializedPropertyAccessException( + "You must specify an \"into\" clause before any other clauses in an insertBatch statement", e + ) + } + } + + @MyBatisDslMarker + inner class MapCompleter (private val column: SqlColumn) { + infix fun toProperty(property: String) = + applyToDsl { + map(column).toProperty(property) + } + + fun toNull() = + applyToDsl { + map(column).toNull() + } + + infix fun toConstant(constant: String) = + applyToDsl { + map(column).toConstant(constant) + } + + infix fun toStringConstant(constant: String) = + applyToDsl { + map(column).toStringConstant(constant) + } + + private fun applyToDsl(block: BatchInsertDSL.() -> Unit) { + this@KotlinBatchInsertBuilder.getDsl().apply(block) + } + } +} diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertHelpers.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinGeneralInsertBuilder.kt similarity index 83% rename from src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertHelpers.kt rename to src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinGeneralInsertBuilder.kt index 3c4331ea0..56bd66ef2 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertHelpers.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinGeneralInsertBuilder.kt @@ -16,23 +16,12 @@ package org.mybatis.dynamic.sql.util.kotlin import org.mybatis.dynamic.sql.SqlColumn -import org.mybatis.dynamic.sql.insert.BatchInsertDSL import org.mybatis.dynamic.sql.insert.GeneralInsertDSL import org.mybatis.dynamic.sql.insert.GeneralInsertModel -import org.mybatis.dynamic.sql.insert.InsertDSL -import org.mybatis.dynamic.sql.insert.MultiRowInsertDSL import org.mybatis.dynamic.sql.util.Buildable typealias GeneralInsertCompleter = @MyBatisDslMarker KotlinGeneralInsertBuilder.() -> Unit -typealias InsertCompleter = @MyBatisDslMarker InsertDSL.() -> Unit - -typealias MultiRowInsertCompleter = @MyBatisDslMarker MultiRowInsertDSL.() -> Unit - -typealias BatchInsertCompleter = @MyBatisDslMarker BatchInsertDSL.() -> Unit - -typealias InsertSelectCompleter = @MyBatisDslMarker KotlinInsertSelectSubQueryBuilder.() -> Unit - @MyBatisDslMarker class KotlinGeneralInsertBuilder(private val dsl: GeneralInsertDSL) : Buildable { diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt new file mode 100644 index 000000000..065e572ca --- /dev/null +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2016-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.util.kotlin + +import org.mybatis.dynamic.sql.SqlBuilder +import org.mybatis.dynamic.sql.SqlColumn +import org.mybatis.dynamic.sql.SqlTable +import org.mybatis.dynamic.sql.insert.InsertDSL +import org.mybatis.dynamic.sql.insert.InsertModel +import org.mybatis.dynamic.sql.util.Buildable + +typealias KotlinInsertCompleter = KotlinInsertBuilder.() -> Unit + +@MyBatisDslMarker +class KotlinInsertBuilder (private val row: T): Buildable> { + + private lateinit var dsl: InsertDSL + + fun into(table: SqlTable) { + dsl = SqlBuilder.insert(row).into(table) + } + + fun map(column: SqlColumn) = MapCompleter(column) + + override fun build(): InsertModel { + return getDsl().build() + } + + private fun getDsl(): InsertDSL { + try { + return dsl + } catch (e: UninitializedPropertyAccessException) { + throw UninitializedPropertyAccessException( + "You must specify an \"into\" clause before any other clauses in an insert statement", e + ) + } + } + + @MyBatisDslMarker + inner class MapCompleter (private val column: SqlColumn) { + infix fun toProperty(property: String) = + applyToDsl { + map(column).toProperty(property) + } + + fun toNull() = + applyToDsl { + map(column).toNull() + } + + infix fun toConstant(constant: String) = + applyToDsl { + map(column).toConstant(constant) + } + + infix fun toStringConstant(constant: String) = + applyToDsl { + map(column).toStringConstant(constant) + } + + fun toPropertyWhenPresent(property: String, valueSupplier: () -> C?) = + applyToDsl { + map(column).toPropertyWhenPresent(property, valueSupplier) + } + + private fun applyToDsl(block: InsertDSL.() -> Unit) { + this@KotlinInsertBuilder.getDsl().apply(block) + } + } +} diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt new file mode 100644 index 000000000..0caccb591 --- /dev/null +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2016-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.util.kotlin + +import org.mybatis.dynamic.sql.SqlBuilder +import org.mybatis.dynamic.sql.SqlColumn +import org.mybatis.dynamic.sql.SqlTable +import org.mybatis.dynamic.sql.insert.MultiRowInsertDSL +import org.mybatis.dynamic.sql.insert.MultiRowInsertModel +import org.mybatis.dynamic.sql.util.Buildable + +typealias KotlinMultiRowInsertCompleter = KotlinMultiRowInsertBuilder.() -> Unit + +@MyBatisDslMarker +class KotlinMultiRowInsertBuilder (private val rows: Collection): Buildable> { + + private lateinit var dsl: MultiRowInsertDSL + + fun into(table: SqlTable) { + dsl = SqlBuilder.insertMultiple(rows).into(table) + } + + infix fun map(column: SqlColumn) = MapCompleter(column) + + override fun build(): MultiRowInsertModel { + return getDsl().build() + } + + private fun getDsl(): MultiRowInsertDSL { + try { + return dsl + } catch (e: UninitializedPropertyAccessException) { + throw UninitializedPropertyAccessException( + "You must specify an \"into\" clause before any other clauses in an insertMultiple statement", e + ) + } + } + + @MyBatisDslMarker + inner class MapCompleter (private val column: SqlColumn) { + infix fun toProperty(property: String) = + applyToDsl { + map(column).toProperty(property) + } + + fun toNull() = + applyToDsl { + map(column).toNull() + } + + infix fun toConstant(constant: String) = + applyToDsl { + map(column).toConstant(constant) + } + + infix fun toStringConstant(constant: String) = + applyToDsl { + map(column).toStringConstant(constant) + } + + private fun applyToDsl(block: MultiRowInsertDSL.() -> Unit) { + this@KotlinMultiRowInsertBuilder.getDsl().apply(block) + } + } +} diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt index 5810225f2..d57312ab7 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt @@ -59,6 +59,8 @@ class KotlinQualifiedSubQueryBuilder : KotlinBaseSubQueryBuilder() { } } +typealias InsertSelectCompleter = KotlinInsertSelectSubQueryBuilder.() -> Unit + class KotlinInsertSelectSubQueryBuilder : KotlinBaseSubQueryBuilder() { private lateinit var lateColumnList: List> diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/InsertStatements.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/InsertStatements.kt index feecc6d86..94a1899b5 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/InsertStatements.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/elements/InsertStatements.kt @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,12 +22,17 @@ import org.mybatis.dynamic.sql.insert.MultiRowInsertDSL // These insert functions help avoid the use of org.mybatis.dynamic.sql.SqlBuilder in Kotlin +@Deprecated("Please see the deprecation message on the following \"into\" function for advice") fun insert(row: T): InsertDSL.IntoGatherer = SqlBuilder.insert(row) +@Deprecated("Please see the deprecation message on the following \"into\" function for advice") fun insertBatch(vararg records: T): BatchInsertDSL.IntoGatherer = insertBatch(records.asList()) +@Deprecated("Please see the deprecation message on the following \"into\" function for advice") fun insertBatch(records: Collection): BatchInsertDSL.IntoGatherer = SqlBuilder.insertBatch(records) +@Deprecated("Please see the deprecation message on the following \"into\" function for advice") fun insertMultiple(vararg records: T): MultiRowInsertDSL.IntoGatherer = insertMultiple(records.asList()) +@Deprecated("Please see the deprecation message on the following \"into\" function for advice") fun insertMultiple(records: Collection): MultiRowInsertDSL.IntoGatherer = SqlBuilder.insertMultiple(records) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderFunctions.kt index cf9db8c3f..ae4a3d73f 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderFunctions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,19 +31,22 @@ import org.mybatis.dynamic.sql.insert.MultiRowInsertDSL import org.mybatis.dynamic.sql.insert.MultiRowInsertModel import org.mybatis.dynamic.sql.select.SelectModel import org.mybatis.dynamic.sql.update.UpdateModel -import org.mybatis.dynamic.sql.util.kotlin.BatchInsertCompleter import org.mybatis.dynamic.sql.util.kotlin.CountCompleter import org.mybatis.dynamic.sql.util.kotlin.DeleteCompleter import org.mybatis.dynamic.sql.util.kotlin.GeneralInsertCompleter -import org.mybatis.dynamic.sql.util.kotlin.InsertCompleter import org.mybatis.dynamic.sql.util.kotlin.InsertSelectCompleter +import org.mybatis.dynamic.sql.util.kotlin.KotlinBatchInsertBuilder +import org.mybatis.dynamic.sql.util.kotlin.KotlinBatchInsertCompleter import org.mybatis.dynamic.sql.util.kotlin.KotlinCountBuilder import org.mybatis.dynamic.sql.util.kotlin.KotlinDeleteBuilder import org.mybatis.dynamic.sql.util.kotlin.KotlinGeneralInsertBuilder +import org.mybatis.dynamic.sql.util.kotlin.KotlinInsertBuilder +import org.mybatis.dynamic.sql.util.kotlin.KotlinInsertCompleter import org.mybatis.dynamic.sql.util.kotlin.KotlinInsertSelectSubQueryBuilder +import org.mybatis.dynamic.sql.util.kotlin.KotlinMultiRowInsertBuilder +import org.mybatis.dynamic.sql.util.kotlin.KotlinMultiRowInsertCompleter import org.mybatis.dynamic.sql.util.kotlin.KotlinSelectBuilder import org.mybatis.dynamic.sql.util.kotlin.KotlinUpdateBuilder -import org.mybatis.dynamic.sql.util.kotlin.MultiRowInsertCompleter import org.mybatis.dynamic.sql.util.kotlin.SelectCompleter import org.mybatis.dynamic.sql.util.kotlin.UpdateCompleter @@ -60,9 +63,18 @@ fun countFrom(table: SqlTable, completer: CountCompleter): SelectModel = fun deleteFrom(table: SqlTable, completer: DeleteCompleter): DeleteModel = KotlinDeleteBuilder(SqlBuilder.deleteFrom(table)).apply(completer).build() +fun insert(row: T, completer: KotlinInsertCompleter): InsertModel = + KotlinInsertBuilder(row).apply(completer).build() + +fun insertBatch(rows: Collection, completer: KotlinBatchInsertCompleter): BatchInsertModel = + KotlinBatchInsertBuilder(rows).apply(completer).build() + fun insertInto(table: SqlTable, completer: GeneralInsertCompleter): GeneralInsertModel = KotlinGeneralInsertBuilder(GeneralInsertDSL.insertInto(table)).apply(completer).build() +fun insertMultiple(rows: Collection, completer: KotlinMultiRowInsertCompleter): MultiRowInsertModel = + KotlinMultiRowInsertBuilder(rows).apply(completer).build() + fun insertSelect(table: SqlTable, completer: InsertSelectCompleter): InsertSelectModel = with(KotlinInsertSelectSubQueryBuilder().apply(completer)) { SqlBuilder.insertInto(table) @@ -71,15 +83,21 @@ fun insertSelect(table: SqlTable, completer: InsertSelectCompleter): InsertSelec .build() } -fun BatchInsertDSL.IntoGatherer.into(table: SqlTable, completer: BatchInsertCompleter): BatchInsertModel = +@Deprecated("Please switch to the insertBatch statement in the model package") +fun BatchInsertDSL.IntoGatherer.into( + table: SqlTable, + completer: BatchInsertDSL.() -> Unit +): BatchInsertModel = into(table).apply(completer).build() -fun InsertDSL.IntoGatherer.into(table: SqlTable, completer: InsertCompleter): InsertModel = +@Deprecated("Please switch to the insert statement in the model package") +fun InsertDSL.IntoGatherer.into(table: SqlTable, completer: InsertDSL.() -> Unit): InsertModel = into(table).apply(completer).build() +@Deprecated("Please switch to the insertMultiple statement in the model package") fun MultiRowInsertDSL.IntoGatherer.into( table: SqlTable, - completer: MultiRowInsertCompleter + completer: MultiRowInsertDSL.() -> Unit ): MultiRowInsertModel = into(table).apply(completer).build() diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/MapperSupportFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/MapperSupportFunctions.kt index f7b1ec457..16000c736 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/MapperSupportFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/MapperSupportFunctions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,18 +26,15 @@ import org.mybatis.dynamic.sql.insert.render.InsertStatementProvider import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider import org.mybatis.dynamic.sql.select.render.SelectStatementProvider import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider -import org.mybatis.dynamic.sql.util.kotlin.BatchInsertCompleter import org.mybatis.dynamic.sql.util.kotlin.CountCompleter import org.mybatis.dynamic.sql.util.kotlin.DeleteCompleter import org.mybatis.dynamic.sql.util.kotlin.GeneralInsertCompleter -import org.mybatis.dynamic.sql.util.kotlin.InsertCompleter import org.mybatis.dynamic.sql.util.kotlin.InsertSelectCompleter -import org.mybatis.dynamic.sql.util.kotlin.MultiRowInsertCompleter +import org.mybatis.dynamic.sql.util.kotlin.KotlinBatchInsertCompleter +import org.mybatis.dynamic.sql.util.kotlin.KotlinInsertCompleter +import org.mybatis.dynamic.sql.util.kotlin.KotlinMultiRowInsertCompleter import org.mybatis.dynamic.sql.util.kotlin.SelectCompleter import org.mybatis.dynamic.sql.util.kotlin.UpdateCompleter -import org.mybatis.dynamic.sql.util.kotlin.elements.insert -import org.mybatis.dynamic.sql.util.kotlin.elements.insertBatch -import org.mybatis.dynamic.sql.util.kotlin.elements.insertMultiple fun count( mapper: (SelectStatementProvider) -> Long, @@ -47,7 +44,7 @@ fun count( ): Long = count(column) { from(table) - completer() + run(completer) }.run(mapper) fun countDistinct( @@ -58,7 +55,7 @@ fun countDistinct( ): Long = countDistinct(column) { from(table) - completer() + run(completer) }.run(mapper) fun countFrom(mapper: (SelectStatementProvider) -> Long, table: SqlTable, completer: CountCompleter): Long = @@ -71,9 +68,12 @@ fun insert( mapper: (InsertStatementProvider) -> Int, row: T, table: SqlTable, - completer: InsertCompleter + completer: KotlinInsertCompleter ): Int = - insert(row).into(table, completer).run(mapper) + insert(row) { + into(table) + run(completer) + }.run(mapper) fun BatchInsert.execute(mapper: (InsertStatementProvider) -> Int): List = insertStatements().map(mapper) @@ -89,9 +89,12 @@ fun insertBatch( mapper: (InsertStatementProvider) -> Int, records: Collection, table: SqlTable, - completer: BatchInsertCompleter + completer: KotlinBatchInsertCompleter ): List = - insertBatch(records).into(table, completer).execute(mapper) + insertBatch(records) { + into(table) + run(completer) + }.execute(mapper) fun insertInto( mapper: (GeneralInsertStatementProvider) -> Int, @@ -104,17 +107,23 @@ fun insertMultiple( mapper: (MultiRowInsertStatementProvider) -> Int, records: Collection, table: SqlTable, - completer: MultiRowInsertCompleter + completer: KotlinMultiRowInsertCompleter ): Int = - insertMultiple(records).into(table, completer).run(mapper) + insertMultiple(records) { + into(table) + run(completer) + }.run(mapper) fun insertMultipleWithGeneratedKeys( mapper: (String, List) -> Int, records: Collection, table: SqlTable, - completer: MultiRowInsertCompleter + completer: KotlinMultiRowInsertCompleter ): Int = - insertMultiple(records).into(table, completer).run { + insertMultiple(records) { + into(table) + run(completer) + }.run { mapper(insertStatement, this.records) } @@ -133,7 +142,7 @@ fun selectDistinct( ): List = selectDistinct(selectList) { from(table) - completer() + run(completer) }.run(mapper) fun selectList( @@ -144,7 +153,7 @@ fun selectList( ): List = select(selectList) { from(table) - completer() + run(completer) }.run(mapper) fun selectOne( @@ -155,7 +164,7 @@ fun selectOne( ): T? = select(selectList) { from(table) - completer() + run(completer) }.run(mapper) fun update(mapper: (UpdateStatementProvider) -> Int, table: SqlTable, completer: UpdateCompleter): Int = diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/ProviderBuilderFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/ProviderBuilderFunctions.kt index c4c7acca4..c87ee4825 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/ProviderBuilderFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/ProviderBuilderFunctions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,20 +30,23 @@ import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider import org.mybatis.dynamic.sql.render.RenderingStrategies import org.mybatis.dynamic.sql.select.render.SelectStatementProvider import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider -import org.mybatis.dynamic.sql.util.kotlin.BatchInsertCompleter import org.mybatis.dynamic.sql.util.kotlin.CountCompleter import org.mybatis.dynamic.sql.util.kotlin.DeleteCompleter import org.mybatis.dynamic.sql.util.kotlin.GeneralInsertCompleter -import org.mybatis.dynamic.sql.util.kotlin.InsertCompleter import org.mybatis.dynamic.sql.util.kotlin.InsertSelectCompleter -import org.mybatis.dynamic.sql.util.kotlin.MultiRowInsertCompleter +import org.mybatis.dynamic.sql.util.kotlin.KotlinBatchInsertCompleter +import org.mybatis.dynamic.sql.util.kotlin.KotlinInsertCompleter +import org.mybatis.dynamic.sql.util.kotlin.KotlinMultiRowInsertCompleter import org.mybatis.dynamic.sql.util.kotlin.SelectCompleter import org.mybatis.dynamic.sql.util.kotlin.UpdateCompleter import org.mybatis.dynamic.sql.util.kotlin.model.count import org.mybatis.dynamic.sql.util.kotlin.model.countDistinct import org.mybatis.dynamic.sql.util.kotlin.model.countFrom import org.mybatis.dynamic.sql.util.kotlin.model.deleteFrom +import org.mybatis.dynamic.sql.util.kotlin.model.insert +import org.mybatis.dynamic.sql.util.kotlin.model.insertBatch import org.mybatis.dynamic.sql.util.kotlin.model.insertInto +import org.mybatis.dynamic.sql.util.kotlin.model.insertMultiple import org.mybatis.dynamic.sql.util.kotlin.model.insertSelect import org.mybatis.dynamic.sql.util.kotlin.model.into import org.mybatis.dynamic.sql.util.kotlin.model.select @@ -62,21 +65,33 @@ fun countFrom(table: SqlTable, completer: CountCompleter): SelectStatementProvid fun deleteFrom(table: SqlTable, completer: DeleteCompleter): DeleteStatementProvider = deleteFrom(table, completer).render(RenderingStrategies.MYBATIS3) +fun insert(row: T, completer: KotlinInsertCompleter): InsertStatementProvider = + insert(row, completer).render(RenderingStrategies.MYBATIS3) + +fun insertBatch(rows: Collection, completer: KotlinBatchInsertCompleter): BatchInsert = + insertBatch(rows, completer).render(RenderingStrategies.MYBATIS3) + fun insertInto(table: SqlTable, completer: GeneralInsertCompleter): GeneralInsertStatementProvider = insertInto(table, completer).render(RenderingStrategies.MYBATIS3) +fun insertMultiple(rows: Collection, completer: KotlinMultiRowInsertCompleter): MultiRowInsertStatementProvider = + insertMultiple(rows, completer).render(RenderingStrategies.MYBATIS3) + fun insertSelect(table: SqlTable, completer: InsertSelectCompleter): InsertSelectStatementProvider = insertSelect(table, completer).render(RenderingStrategies.MYBATIS3) -fun BatchInsertDSL.IntoGatherer.into(table: SqlTable, completer: BatchInsertCompleter): BatchInsert = +@Deprecated("Please switch to the insertBatch statement in the mybatis3 package") +fun BatchInsertDSL.IntoGatherer.into(table: SqlTable, completer: BatchInsertDSL.() -> Unit): BatchInsert = into(table, completer).render(RenderingStrategies.MYBATIS3) -fun InsertDSL.IntoGatherer.into(table: SqlTable, completer: InsertCompleter): InsertStatementProvider = +@Deprecated("Please switch to the insert statement in the mybatis3 package") +fun InsertDSL.IntoGatherer.into(table: SqlTable, completer: InsertDSL.() -> Unit): InsertStatementProvider = into(table, completer).render(RenderingStrategies.MYBATIS3) +@Deprecated("Please switch to the insertMultiple statement in the mybatis3 package") fun MultiRowInsertDSL.IntoGatherer.into( table: SqlTable, - completer: MultiRowInsertCompleter + completer: MultiRowInsertDSL.() -> Unit ): MultiRowInsertStatementProvider = into(table, completer).render(RenderingStrategies.MYBATIS3) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt index 965004a9e..f89ab6b58 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt @@ -26,19 +26,16 @@ import org.mybatis.dynamic.sql.insert.render.InsertStatementProvider import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider import org.mybatis.dynamic.sql.select.render.SelectStatementProvider import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider -import org.mybatis.dynamic.sql.util.kotlin.BatchInsertCompleter import org.mybatis.dynamic.sql.util.kotlin.CountCompleter import org.mybatis.dynamic.sql.util.kotlin.DeleteCompleter import org.mybatis.dynamic.sql.util.kotlin.GeneralInsertCompleter -import org.mybatis.dynamic.sql.util.kotlin.InsertCompleter import org.mybatis.dynamic.sql.util.kotlin.InsertSelectCompleter -import org.mybatis.dynamic.sql.util.kotlin.MultiRowInsertCompleter +import org.mybatis.dynamic.sql.util.kotlin.KotlinBatchInsertCompleter +import org.mybatis.dynamic.sql.util.kotlin.KotlinInsertCompleter +import org.mybatis.dynamic.sql.util.kotlin.KotlinMultiRowInsertCompleter import org.mybatis.dynamic.sql.util.kotlin.MyBatisDslMarker import org.mybatis.dynamic.sql.util.kotlin.SelectCompleter import org.mybatis.dynamic.sql.util.kotlin.UpdateCompleter -import org.mybatis.dynamic.sql.util.kotlin.elements.insert -import org.mybatis.dynamic.sql.util.kotlin.elements.insertBatch -import org.mybatis.dynamic.sql.util.kotlin.elements.insertMultiple import org.springframework.dao.EmptyResultDataAccessException import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource import org.springframework.jdbc.core.namedparam.MapSqlParameterSource @@ -70,9 +67,17 @@ fun NamedParameterJdbcTemplate.deleteFrom(table: SqlTable, completer: DeleteComp fun NamedParameterJdbcTemplate.insertBatch(insertStatement: BatchInsert): IntArray = batchUpdate(insertStatement.insertStatementSQL, SqlParameterSourceUtils.createBatch(insertStatement.records)) +fun NamedParameterJdbcTemplate.insertBatch(vararg records: T, completer: KotlinBatchInsertCompleter): IntArray = + insertBatch(records.asList(), completer) + +fun NamedParameterJdbcTemplate.insertBatch(records: List, completer: KotlinBatchInsertCompleter): IntArray = + insertBatch(org.mybatis.dynamic.sql.util.kotlin.spring.insertBatch(records, completer)) + +@Deprecated("Please move the into phrase inside the lambda") fun NamedParameterJdbcTemplate.insertBatch(vararg records: T): BatchInsertHelper = insertBatch(records.asList()) +@Deprecated("Please move the into phrase inside the lambda") fun NamedParameterJdbcTemplate.insertBatch(records: List): BatchInsertHelper = BatchInsertHelper(records, this) @@ -86,6 +91,10 @@ fun NamedParameterJdbcTemplate.insert( ): Int = update(insertStatement.insertStatement, BeanPropertySqlParameterSource(insertStatement.row), keyHolder) +fun NamedParameterJdbcTemplate.insert(row: T, completer: KotlinInsertCompleter): Int = + insert(org.mybatis.dynamic.sql.util.kotlin.spring.insert(row, completer)) + +@Deprecated("Please move the into phrase inside the lambda") fun NamedParameterJdbcTemplate.insert(row: T): SingleRowInsertHelper = SingleRowInsertHelper(row, this) @@ -103,9 +112,17 @@ fun NamedParameterJdbcTemplate.insertInto(table: SqlTable, completer: GeneralIns generalInsert(org.mybatis.dynamic.sql.util.kotlin.spring.insertInto(table, completer)) // multiple row insert +fun NamedParameterJdbcTemplate.insertMultiple(vararg records: T, completer: KotlinMultiRowInsertCompleter): Int = + insertMultiple(records.asList(), completer) + +fun NamedParameterJdbcTemplate.insertMultiple(records: List, completer: KotlinMultiRowInsertCompleter): Int = + insertMultiple(org.mybatis.dynamic.sql.util.kotlin.spring.insertMultiple(records, completer)) + +@Deprecated("Please move the into phrase inside the lambda") fun NamedParameterJdbcTemplate.insertMultiple(vararg records: T): MultiRowInsertHelper = insertMultiple(records.asList()) +@Deprecated("Please move the into phrase inside the lambda") fun NamedParameterJdbcTemplate.insertMultiple(records: List): MultiRowInsertHelper = MultiRowInsertHelper(records, this) @@ -238,12 +255,25 @@ class KeyHolderHelper(private val keyHolder: KeyHolder, private val template: Na fun insertInto(table: SqlTable, completer: GeneralInsertCompleter): Int = template.generalInsert(org.mybatis.dynamic.sql.util.kotlin.spring.insertInto(table, completer), keyHolder) + fun insert(row: T, completer: KotlinInsertCompleter): Int = + template.insert(org.mybatis.dynamic.sql.util.kotlin.spring.insert(row, completer), keyHolder) + + @Deprecated("Please move the into phrase inside the lambda") fun insert(row: T): SingleRowInsertWithKeyHolderHelper = SingleRowInsertWithKeyHolderHelper(row, template, keyHolder) + fun insertMultiple(vararg records: T, completer: KotlinMultiRowInsertCompleter): Int = + insertMultiple(records.asList(), completer) + + fun insertMultiple(records: List, completer: KotlinMultiRowInsertCompleter): Int = + template.insertMultiple(org.mybatis.dynamic.sql.util.kotlin.spring.insertMultiple(records, completer), + keyHolder) + + @Deprecated("Please move the into phrase inside the lambda") fun insertMultiple(vararg records: T): MultiRowInsertWithKeyHolderHelper = insertMultiple(records.asList()) + @Deprecated("Please move the into phrase inside the lambda") fun insertMultiple(records: List): MultiRowInsertWithKeyHolderHelper = MultiRowInsertWithKeyHolderHelper(records, template, keyHolder) @@ -253,8 +283,13 @@ class KeyHolderHelper(private val keyHolder: KeyHolder, private val template: Na @MyBatisDslMarker class BatchInsertHelper(private val records: List, private val template: NamedParameterJdbcTemplate) { - fun into(table: SqlTable, completer: BatchInsertCompleter): IntArray = - template.insertBatch(insertBatch(records).into(table, completer)) + fun into(table: SqlTable, completer: KotlinBatchInsertCompleter): IntArray = + template.insertBatch( + insertBatch(records) { + into(table) + run(completer) + } + ) } @MyBatisDslMarker @@ -262,8 +297,13 @@ class MultiRowInsertHelper( private val records: List, private val template: NamedParameterJdbcTemplate ) { - fun into(table: SqlTable, completer: MultiRowInsertCompleter): Int = - with(insertMultiple(records).into(table, completer)) { + fun into(table: SqlTable, completer: KotlinMultiRowInsertCompleter): Int = + with( + insertMultiple(records) { + into(table) + run(completer) + } + ) { template.insertMultiple(this) } } @@ -274,8 +314,13 @@ class MultiRowInsertWithKeyHolderHelper( private val template: NamedParameterJdbcTemplate, private val keyHolder: KeyHolder ) { - fun into(table: SqlTable, completer: MultiRowInsertCompleter): Int = - with(insertMultiple(records).into(table, completer)) { + fun into(table: SqlTable, completer: KotlinMultiRowInsertCompleter): Int = + with( + insertMultiple(records) { + into(table) + run(completer) + } + ) { template.insertMultiple(this, keyHolder) } } @@ -285,8 +330,13 @@ class SingleRowInsertHelper( private val row: T, private val template: NamedParameterJdbcTemplate ) { - fun into(table: SqlTable, completer: InsertCompleter): Int = - with(insert(row).into(table, completer)) { + fun into(table: SqlTable, completer: KotlinInsertCompleter): Int = + with( + insert(row) { + into(table) + run(completer) + } + ) { template.insert(this) } } @@ -297,8 +347,13 @@ class SingleRowInsertWithKeyHolderHelper( private val template: NamedParameterJdbcTemplate, private val keyHolder: KeyHolder ) { - fun into(table: SqlTable, completer: InsertCompleter): Int = - with(insert(row).into(table, completer)) { + fun into(table: SqlTable, completer: KotlinInsertCompleter): Int = + with( + insert(row) { + into(table) + run(completer) + } + ) { template.insert(this, keyHolder) } } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/ProviderBuilderFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/ProviderBuilderFunctions.kt index 9f472274f..b9e900a7c 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/ProviderBuilderFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/ProviderBuilderFunctions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,20 +30,23 @@ import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider import org.mybatis.dynamic.sql.render.RenderingStrategies import org.mybatis.dynamic.sql.select.render.SelectStatementProvider import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider -import org.mybatis.dynamic.sql.util.kotlin.BatchInsertCompleter import org.mybatis.dynamic.sql.util.kotlin.CountCompleter import org.mybatis.dynamic.sql.util.kotlin.DeleteCompleter import org.mybatis.dynamic.sql.util.kotlin.GeneralInsertCompleter -import org.mybatis.dynamic.sql.util.kotlin.InsertCompleter import org.mybatis.dynamic.sql.util.kotlin.InsertSelectCompleter -import org.mybatis.dynamic.sql.util.kotlin.MultiRowInsertCompleter +import org.mybatis.dynamic.sql.util.kotlin.KotlinBatchInsertCompleter +import org.mybatis.dynamic.sql.util.kotlin.KotlinInsertCompleter +import org.mybatis.dynamic.sql.util.kotlin.KotlinMultiRowInsertCompleter import org.mybatis.dynamic.sql.util.kotlin.SelectCompleter import org.mybatis.dynamic.sql.util.kotlin.UpdateCompleter import org.mybatis.dynamic.sql.util.kotlin.model.count import org.mybatis.dynamic.sql.util.kotlin.model.countDistinct import org.mybatis.dynamic.sql.util.kotlin.model.countFrom import org.mybatis.dynamic.sql.util.kotlin.model.deleteFrom +import org.mybatis.dynamic.sql.util.kotlin.model.insert +import org.mybatis.dynamic.sql.util.kotlin.model.insertBatch import org.mybatis.dynamic.sql.util.kotlin.model.insertInto +import org.mybatis.dynamic.sql.util.kotlin.model.insertMultiple import org.mybatis.dynamic.sql.util.kotlin.model.insertSelect import org.mybatis.dynamic.sql.util.kotlin.model.into import org.mybatis.dynamic.sql.util.kotlin.model.select @@ -62,21 +65,39 @@ fun countFrom(table: SqlTable, completer: CountCompleter): SelectStatementProvid fun deleteFrom(table: SqlTable, completer: DeleteCompleter): DeleteStatementProvider = deleteFrom(table, completer).render(RenderingStrategies.SPRING_NAMED_PARAMETER) +fun insert(row: T, completer: KotlinInsertCompleter): InsertStatementProvider = + insert(row, completer).render(RenderingStrategies.SPRING_NAMED_PARAMETER) + +fun insertBatch(rows: Collection, completer: KotlinBatchInsertCompleter): BatchInsert = + insertBatch(rows, completer).render(RenderingStrategies.SPRING_NAMED_PARAMETER) + fun insertInto(table: SqlTable, completer: GeneralInsertCompleter): GeneralInsertStatementProvider = insertInto(table, completer).render(RenderingStrategies.SPRING_NAMED_PARAMETER) +fun insertMultiple( + rows: Collection, + completer: KotlinMultiRowInsertCompleter +): MultiRowInsertStatementProvider = + insertMultiple(rows, completer).render(RenderingStrategies.SPRING_NAMED_PARAMETER) + fun insertSelect(table: SqlTable, completer: InsertSelectCompleter): InsertSelectStatementProvider = insertSelect(table, completer).render(RenderingStrategies.SPRING_NAMED_PARAMETER) -fun BatchInsertDSL.IntoGatherer.into(table: SqlTable, completer: BatchInsertCompleter): BatchInsert = +@Deprecated("Please switch to the insertBatch statement in the spring package") +fun BatchInsertDSL.IntoGatherer.into(table: SqlTable, completer: BatchInsertDSL.() -> Unit): BatchInsert = into(table, completer).render(RenderingStrategies.SPRING_NAMED_PARAMETER) -fun InsertDSL.IntoGatherer.into(table: SqlTable, completer: InsertCompleter): InsertStatementProvider = +@Deprecated("Please switch to the insert statement in the spring package") +fun InsertDSL.IntoGatherer.into( + table: SqlTable, + completer: InsertDSL.() -> Unit +): InsertStatementProvider = into(table, completer).render(RenderingStrategies.SPRING_NAMED_PARAMETER) +@Deprecated("Please switch to the insertMultiple statement in the spring package") fun MultiRowInsertDSL.IntoGatherer.into( table: SqlTable, - completer: MultiRowInsertCompleter + completer: MultiRowInsertDSL.() -> Unit ): MultiRowInsertStatementProvider = into(table, completer).render(RenderingStrategies.SPRING_NAMED_PARAMETER) diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt index f326ce5dd..ea489a06d 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt @@ -175,6 +175,24 @@ open class CanonicalSpringKotlinTemplateDirectTest { fun testInsert() { val record = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) + val rows = template.insert(record) { + into(person) + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastNameAsString" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employedAsString" + map(occupation).toPropertyWhenPresent("occupation", record::occupation) + map(addressId) toProperty "addressId" + } + + assertThat(rows).isEqualTo(1) + } + + @Test + fun testDeprecatedInsert() { + val record = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) + val rows = template.insert(record).into(person) { map(id).toProperty("id") map(firstName).toProperty("firstName") @@ -208,6 +226,25 @@ open class CanonicalSpringKotlinTemplateDirectTest { val record1 = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) val record2 = PersonRecord(101, "Sarah", LastName("Smith"), Date(), true, "Architect", 2) + val rows = template.insertMultiple(record1, record2) { + into(person) + map(id).toProperty("id") + map(firstName).toProperty("firstName") + map(lastName).toProperty("lastNameAsString") + map(birthDate).toProperty("birthDate") + map(employed).toProperty("employedAsString") + map(occupation).toProperty("occupation") + map(addressId).toProperty("addressId") + } + + assertThat(rows).isEqualTo(2) + } + + @Test + fun testDeprecatedMultiRowInsert() { + val record1 = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) + val record2 = PersonRecord(101, "Sarah", LastName("Smith"), Date(), true, "Architect", 2) + val rows = template.insertMultiple(record1, record2).into(person) { map(id).toProperty("id") map(firstName).toProperty("firstName") @@ -226,6 +263,27 @@ open class CanonicalSpringKotlinTemplateDirectTest { val record1 = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) val record2 = PersonRecord(101, "Sarah", LastName("Smith"), Date(), true, "Architect", 2) + val rows = template.insertBatch(record1, record2) { + into(person) + map(id).toProperty("id") + map(firstName).toProperty("firstName") + map(lastName).toProperty("lastNameAsString") + map(birthDate).toProperty("birthDate") + map(employed).toProperty("employedAsString") + map(occupation).toProperty("occupation") + map(addressId).toProperty("addressId") + } + + assertThat(rows).hasSize(2) + assertThat(rows[0]).isEqualTo(1) + assertThat(rows[1]).isEqualTo(1) + } + + @Test + fun testDeprecatedBatchInsert() { + val record1 = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) + val record2 = PersonRecord(101, "Sarah", LastName("Smith"), Date(), true, "Architect", 2) + val rows = template.insertBatch(record1, record2).into(person) { map(id).toProperty("id") map(firstName).toProperty("firstName") @@ -297,6 +355,26 @@ open class CanonicalSpringKotlinTemplateDirectTest { val keyHolder = GeneratedKeyHolder() + val rows = template.withKeyHolder(keyHolder) { + insert(command) { + into(generatedAlways) + map(generatedAlways.firstName).toProperty("firstName") + map(generatedAlways.lastName).toProperty("lastName") + } + } + + assertThat(rows).isEqualTo(1) + assertThat(keyHolder.keys).containsEntry("ID", 22) + assertThat(keyHolder.keys).containsEntry("FULL_NAME", "Fred Flintstone") + } + + @Test + @DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD) + fun testDeprecatedInsertWithGeneratedKey() { + val command = GeneratedAlwaysCommand(firstName = "Fred", lastName = "Flintstone") + + val keyHolder = GeneratedKeyHolder() + val rows = template.withKeyHolder(keyHolder) { insert(command).into(generatedAlways) { map(generatedAlways.firstName).toProperty("firstName") @@ -317,6 +395,29 @@ open class CanonicalSpringKotlinTemplateDirectTest { val keyHolder = GeneratedKeyHolder() + val rows = template.withKeyHolder(keyHolder) { + insertMultiple(command1, command2) { + into(generatedAlways) + map(generatedAlways.firstName).toProperty("firstName") + map(generatedAlways.lastName).toProperty("lastName") + } + } + + assertThat(rows).isEqualTo(2) + assertThat(keyHolder.keyList[0]).containsEntry("ID", 22) + assertThat(keyHolder.keyList[0]).containsEntry("FULL_NAME", "Fred Flintstone") + assertThat(keyHolder.keyList[1]).containsEntry("ID", 23) + assertThat(keyHolder.keyList[1]).containsEntry("FULL_NAME", "Barney Rubble") + } + + @Test + @DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD) + fun testDeprecatedMultiRowInsertWithGeneratedKey() { + val command1 = GeneratedAlwaysCommand(firstName = "Fred", lastName = "Flintstone") + val command2 = GeneratedAlwaysCommand(firstName = "Barney", lastName = "Rubble") + + val keyHolder = GeneratedKeyHolder() + val rows = template.withKeyHolder(keyHolder) { insertMultiple(command1, command2).into(generatedAlways) { map(generatedAlways.firstName).toProperty("firstName") diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt index 2e24fa0e2..7113fe33f 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt @@ -244,7 +244,8 @@ open class CanonicalSpringKotlinTest { val record = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) - val insertStatement = insert(record).into(person) { + val insertStatement = insert(record) { + into(person) map(id).toProperty("id") map(firstName).toProperty("firstName") map(lastName).toProperty("lastNameAsString") @@ -269,6 +270,36 @@ open class CanonicalSpringKotlinTest { assertThat(rows).isEqualTo(1) } + @Test + fun testDeprecatedInsert() { + + val record = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) + + val insertStatement = insert(record).into(person) { + map(id).toProperty("id") + map(firstName).toProperty("firstName") + map(lastName).toProperty("lastNameAsString") + map(birthDate).toProperty("birthDate") + map(employed).toProperty("employedAsString") + map(occupation).toProperty("occupation") + map(addressId).toProperty("addressId") + } + + val expected = + "insert into Person (id, first_name, last_name, birth_date, employed, occupation, address_id)" + + " values" + + " (:id, :firstName," + + " :lastNameAsString," + + " :birthDate, :employedAsString," + + " :occupation, :addressId)" + + assertThat(insertStatement.insertStatement).isEqualTo(expected) + + val rows = template.insert(insertStatement) + + assertThat(rows).isEqualTo(1) + } + @Test fun testGeneralInsert() { @@ -348,7 +379,8 @@ open class CanonicalSpringKotlinTest { val record1 = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) val record2 = PersonRecord(101, "Sarah", LastName("Smith"), Date(), true, "Architect", 2) - val insertStatement = insertMultiple(record1, record2).into(person) { + val insertStatement = insertMultiple(listOf(record1, record2)) { + into(person) map(id).toProperty("id") map(firstName).toProperty("firstName") map(lastName).toProperty("lastNameAsString") @@ -371,6 +403,34 @@ open class CanonicalSpringKotlinTest { assertThat(rows).isEqualTo(2) } + @Test + fun testDeprecatedMultiRowInsert() { + val record1 = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) + val record2 = PersonRecord(101, "Sarah", LastName("Smith"), Date(), true, "Architect", 2) + + val insertStatement = insertMultiple(record1, record2).into(person) { + map(id).toProperty("id") + map(firstName).toProperty("firstName") + map(lastName).toProperty("lastNameAsString") + map(birthDate).toProperty("birthDate") + map(employed).toProperty("employedAsString") + map(occupation).toProperty("occupation") + map(addressId).toProperty("addressId") + } + + assertThat(insertStatement.insertStatement).isEqualTo( + "insert into Person (id, first_name, last_name, birth_date, employed, occupation, address_id) " + + "values (:records[0].id, :records[0].firstName, :records[0].lastNameAsString, " + + ":records[0].birthDate, :records[0].employedAsString, " + + ":records[0].occupation, :records[0].addressId), " + + "(:records[1].id, :records[1].firstName, :records[1].lastNameAsString, " + + ":records[1].birthDate, :records[1].employedAsString, :records[1].occupation, :records[1].addressId)" + ) + + val rows = template.insertMultiple(insertStatement) + assertThat(rows).isEqualTo(2) + } + @Test fun testBatchInsert() { val record1 = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) From 7e5ba28953aa999a55399c51f7bee0509089c99e Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Mon, 14 Feb 2022 06:28:07 -0500 Subject: [PATCH 2/9] [Kotlin] Optimizations --- .../sql/util/kotlin/mybatis3/MapperSupportFunctions.kt | 6 +----- .../kotlin/spring/NamedParameterJdbcTemplateExtensions.kt | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/MapperSupportFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/MapperSupportFunctions.kt index 16000c736..fa4643563 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/MapperSupportFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/MapperSupportFunctions.kt @@ -19,7 +19,6 @@ package org.mybatis.dynamic.sql.util.kotlin.mybatis3 import org.mybatis.dynamic.sql.BasicColumn import org.mybatis.dynamic.sql.SqlTable import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider -import org.mybatis.dynamic.sql.insert.render.BatchInsert import org.mybatis.dynamic.sql.insert.render.GeneralInsertStatementProvider import org.mybatis.dynamic.sql.insert.render.InsertSelectStatementProvider import org.mybatis.dynamic.sql.insert.render.InsertStatementProvider @@ -75,9 +74,6 @@ fun insert( run(completer) }.run(mapper) -fun BatchInsert.execute(mapper: (InsertStatementProvider) -> Int): List = - insertStatements().map(mapper) - /** * This function simply inserts all rows using the supplied mapper. It is up * to the user to manage MyBatis3 batch processing externally. When executed with a SqlSession @@ -94,7 +90,7 @@ fun insertBatch( insertBatch(records) { into(table) run(completer) - }.execute(mapper) + }.insertStatements().map(mapper) fun insertInto( mapper: (GeneralInsertStatementProvider) -> Int, diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt index f89ab6b58..c4ab62d2d 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt @@ -148,8 +148,8 @@ fun NamedParameterJdbcTemplate.insertSelect( update(insertStatement.insertStatement, MapSqlParameterSource(insertStatement.parameters), keyHolder) // insert with KeyHolder support -fun NamedParameterJdbcTemplate.withKeyHolder(keyHolder: KeyHolder, build: KeyHolderHelper.() -> Int): Int = - build(KeyHolderHelper(keyHolder, this)) +fun NamedParameterJdbcTemplate.withKeyHolder(keyHolder: KeyHolder, block: KeyHolderHelper.() -> Int): Int = + KeyHolderHelper(keyHolder, this).run(block) fun NamedParameterJdbcTemplate.select( vararg selectList: BasicColumn, From 340b0100191a454a3aa568bff407bafc8f4176cb Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 15 Feb 2022 12:14:58 -0500 Subject: [PATCH 3/9] Refactor to reduce duplication --- .../dynamic/sql/insert/BatchInsertDSL.java | 48 ++++++++++-- .../dynamic/sql/insert/GeneralInsertDSL.java | 45 ++++++++--- .../mybatis/dynamic/sql/insert/InsertDSL.java | 38 ++++++++-- .../dynamic/sql/insert/MultiRowInsertDSL.java | 27 +++++-- .../util/kotlin/KotlinBatchInsertBuilder.kt | 57 ++++---------- .../util/kotlin/KotlinGeneralInsertBuilder.kt | 58 ++++---------- .../sql/util/kotlin/KotlinInsertBuilder.kt | 62 ++++----------- .../kotlin/KotlinInsertColumnMapCompleters.kt | 76 +++++++++++++++++++ .../kotlin/KotlinMultiRowInsertBuilder.kt | 57 ++++---------- .../kotlin/model/ModelBuilderFunctions.kt | 3 +- .../mybatis3/ProviderBuilderFunctions.kt | 10 ++- .../NamedParameterJdbcTemplateExtensions.kt | 20 ++++- .../mybatis3/general/GeneralKotlinTest.kt | 4 +- ...CanonicalSpringKotlinTemplateDirectTest.kt | 1 + .../canonical/CanonicalSpringKotlinTest.kt | 67 ++++++++++++++-- 15 files changed, 346 insertions(+), 227 deletions(-) create mode 100644 src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertColumnMapCompleters.kt diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java index edddd03e3..2baa0ca30 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 the original author or authors. + * Copyright 2016-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Objects; import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SqlColumn; @@ -34,11 +35,12 @@ public class BatchInsertDSL implements Buildable> { private final Collection records; private final SqlTable table; - private final List columnMappings = new ArrayList<>(); + private final List columnMappings; - private BatchInsertDSL(Collection records, SqlTable table) { - this.records = records; - this.table = table; + private BatchInsertDSL(AbstractBuilder builder) { + this.records = builder.records; + this.table = Objects.requireNonNull(builder.table); + this.columnMappings = builder.columnMappings; } public ColumnMappingFinisher map(SqlColumn column) { @@ -71,7 +73,7 @@ private IntoGatherer(Collection records) { } public BatchInsertDSL into(SqlTable table) { - return new BatchInsertDSL<>(records, table); + return new Builder().withRecords(records).withTable(table).build(); } } @@ -102,4 +104,38 @@ public BatchInsertDSL toStringConstant(String constant) { return BatchInsertDSL.this; } } + + public abstract static class AbstractBuilder> { + final Collection records = new ArrayList<>(); + SqlTable table; + final List columnMappings = new ArrayList<>(); + + public B withRecords(Collection records) { + this.records.addAll(records); + return getThis(); + } + + public B withTable(SqlTable table) { + this.table = table; + return getThis(); + } + + public B withColumnMappings(Collection columnMappings) { + this.columnMappings.addAll(columnMappings); + return getThis(); + } + + protected abstract B getThis(); + } + + public static class Builder extends AbstractBuilder> { + @Override + protected Builder getThis() { + return this; + } + + public BatchInsertDSL build() { + return new BatchInsertDSL<>(this); + } + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java index 9069184f7..5fea27fe2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.mybatis.dynamic.sql.insert; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.function.Supplier; @@ -33,11 +34,12 @@ import org.mybatis.dynamic.sql.util.ValueWhenPresentMapping; public class GeneralInsertDSL implements Buildable { - private final List insertMappings = new ArrayList<>(); + private final List columnMappings; private final SqlTable table; - private GeneralInsertDSL(SqlTable table) { - this.table = Objects.requireNonNull(table); + private GeneralInsertDSL(Builder builder) { + table = Objects.requireNonNull(builder.table); + columnMappings = builder.columnMappings; } public SetClauseFinisher set(SqlColumn column) { @@ -49,12 +51,12 @@ public SetClauseFinisher set(SqlColumn column) { public GeneralInsertModel build() { return new GeneralInsertModel.Builder() .withTable(table) - .withInsertMappings(insertMappings) + .withInsertMappings(columnMappings) .build(); } public static GeneralInsertDSL insertInto(SqlTable table) { - return new GeneralInsertDSL(table); + return new GeneralInsertDSL.Builder().withTable(table).build(); } public class SetClauseFinisher { @@ -66,17 +68,17 @@ public SetClauseFinisher(SqlColumn column) { } public GeneralInsertDSL toNull() { - insertMappings.add(NullMapping.of(column)); + columnMappings.add(NullMapping.of(column)); return GeneralInsertDSL.this; } public GeneralInsertDSL toConstant(String constant) { - insertMappings.add(ConstantMapping.of(column, constant)); + columnMappings.add(ConstantMapping.of(column, constant)); return GeneralInsertDSL.this; } public GeneralInsertDSL toStringConstant(String constant) { - insertMappings.add(StringConstantMapping.of(column, constant)); + columnMappings.add(StringConstantMapping.of(column, constant)); return GeneralInsertDSL.this; } @@ -85,7 +87,7 @@ public GeneralInsertDSL toValue(T value) { } public GeneralInsertDSL toValue(Supplier valueSupplier) { - insertMappings.add(ValueMapping.of(column, valueSupplier)); + columnMappings.add(ValueMapping.of(column, valueSupplier)); return GeneralInsertDSL.this; } @@ -94,7 +96,7 @@ public GeneralInsertDSL toValueOrNull(T value) { } public GeneralInsertDSL toValueOrNull(Supplier valueSupplier) { - insertMappings.add(ValueOrNullMapping.of(column, valueSupplier)); + columnMappings.add(ValueOrNullMapping.of(column, valueSupplier)); return GeneralInsertDSL.this; } @@ -103,8 +105,27 @@ public GeneralInsertDSL toValueWhenPresent(T value) { } public GeneralInsertDSL toValueWhenPresent(Supplier valueSupplier) { - insertMappings.add(ValueWhenPresentMapping.of(column, valueSupplier)); + columnMappings.add(ValueWhenPresentMapping.of(column, valueSupplier)); return GeneralInsertDSL.this; } } + + public static class Builder { + private final List columnMappings = new ArrayList<>(); + private SqlTable table; + + public Builder withTable(SqlTable table) { + this.table = table; + return this; + } + + public Builder withColumnMappings(Collection columnMappings) { + this.columnMappings.addAll(columnMappings); + return this; + } + + public GeneralInsertDSL build() { + return new GeneralInsertDSL(this); + } + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java index 35321b222..ce34347e5 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java @@ -16,7 +16,9 @@ package org.mybatis.dynamic.sql.insert; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.function.Supplier; import org.jetbrains.annotations.NotNull; @@ -34,11 +36,12 @@ public class InsertDSL implements Buildable> { private final T row; private final SqlTable table; - private final List columnMappings = new ArrayList<>(); + private final List columnMappings; - private InsertDSL(T row, SqlTable table) { - this.row = row; - this.table = table; + private InsertDSL(Builder builder) { + this.row = Objects.requireNonNull(builder.row); + this.table = Objects.requireNonNull(builder.table); + columnMappings = builder.columnMappings; } public ColumnMappingFinisher map(SqlColumn column) { @@ -66,7 +69,7 @@ private IntoGatherer(T row) { } public InsertDSL into(SqlTable table) { - return new InsertDSL<>(row, table); + return new InsertDSL.Builder().withRow(row).withTable(table).build(); } } @@ -102,4 +105,29 @@ public InsertDSL toStringConstant(String constant) { return InsertDSL.this; } } + + public static class Builder { + private T row; + private SqlTable table; + private final List columnMappings = new ArrayList<>(); + + public Builder withRow(T row) { + this.row = row; + return this; + } + + public Builder withTable(SqlTable table) { + this.table = table; + return this; + } + + public Builder withColumnMappings(Collection columnMappings) { + this.columnMappings.addAll(columnMappings); + return this; + } + + public InsertDSL build() { + return new InsertDSL<>(this); + } + } } diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java index 55994794d..0ccb426ac 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 the original author or authors. + * Copyright 2016-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,10 +15,10 @@ */ package org.mybatis.dynamic.sql.insert; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Objects; import org.jetbrains.annotations.NotNull; import org.mybatis.dynamic.sql.SqlColumn; @@ -34,11 +34,12 @@ public class MultiRowInsertDSL implements Buildable> { private final Collection records; private final SqlTable table; - private final List columnMappings = new ArrayList<>(); + private final List columnMappings; - private MultiRowInsertDSL(Collection records, SqlTable table) { - this.records = records; - this.table = table; + private MultiRowInsertDSL(BatchInsertDSL.AbstractBuilder builder) { + this.records = builder.records; + this.table = Objects.requireNonNull(builder.table); + this.columnMappings = builder.columnMappings; } public ColumnMappingFinisher map(SqlColumn column) { @@ -71,7 +72,7 @@ private IntoGatherer(Collection records) { } public MultiRowInsertDSL into(SqlTable table) { - return new MultiRowInsertDSL<>(records, table); + return new Builder().withRecords(records).withTable(table).build(); } } @@ -102,4 +103,16 @@ public MultiRowInsertDSL toStringConstant(String constant) { return MultiRowInsertDSL.this; } } + + public static class Builder extends BatchInsertDSL.AbstractBuilder> { + + @Override + protected Builder getThis() { + return this; + } + + public MultiRowInsertDSL build() { + return new MultiRowInsertDSL<>(this); + } + } } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt index 89e53e18d..fcdae8f1d 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt @@ -15,64 +15,33 @@ */ package org.mybatis.dynamic.sql.util.kotlin -import org.mybatis.dynamic.sql.SqlBuilder import org.mybatis.dynamic.sql.SqlColumn import org.mybatis.dynamic.sql.SqlTable import org.mybatis.dynamic.sql.insert.BatchInsertDSL import org.mybatis.dynamic.sql.insert.BatchInsertModel +import org.mybatis.dynamic.sql.util.AbstractColumnMapping import org.mybatis.dynamic.sql.util.Buildable typealias KotlinBatchInsertCompleter = KotlinBatchInsertBuilder.() -> Unit @MyBatisDslMarker class KotlinBatchInsertBuilder (private val rows: Collection): Buildable> { - - private lateinit var dsl: BatchInsertDSL + private var table: SqlTable? = null + private val columnMappings = mutableListOf() fun into(table: SqlTable) { - dsl = SqlBuilder.insertBatch(rows).into(table) + this.table = table } - infix fun map(column: SqlColumn) = MapCompleter(column) - - override fun build(): BatchInsertModel { - return getDsl().build() + fun map(column: SqlColumn) = MultiRowInsertColumnMapCompleter(column) { + columnMappings.add(it) } - private fun getDsl(): BatchInsertDSL { - try { - return dsl - } catch (e: UninitializedPropertyAccessException) { - throw UninitializedPropertyAccessException( - "You must specify an \"into\" clause before any other clauses in an insertBatch statement", e - ) - } - } - - @MyBatisDslMarker - inner class MapCompleter (private val column: SqlColumn) { - infix fun toProperty(property: String) = - applyToDsl { - map(column).toProperty(property) - } - - fun toNull() = - applyToDsl { - map(column).toNull() - } - - infix fun toConstant(constant: String) = - applyToDsl { - map(column).toConstant(constant) - } - - infix fun toStringConstant(constant: String) = - applyToDsl { - map(column).toStringConstant(constant) - } - - private fun applyToDsl(block: BatchInsertDSL.() -> Unit) { - this@KotlinBatchInsertBuilder.getDsl().apply(block) - } - } + override fun build(): BatchInsertModel = + with(BatchInsertDSL.Builder()) { + withRecords(rows) + withTable(table) + withColumnMappings(columnMappings) + build() + }.build() } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinGeneralInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinGeneralInsertBuilder.kt index 56bd66ef2..b7d402bbf 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinGeneralInsertBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinGeneralInsertBuilder.kt @@ -16,59 +16,27 @@ package org.mybatis.dynamic.sql.util.kotlin import org.mybatis.dynamic.sql.SqlColumn +import org.mybatis.dynamic.sql.SqlTable import org.mybatis.dynamic.sql.insert.GeneralInsertDSL import org.mybatis.dynamic.sql.insert.GeneralInsertModel +import org.mybatis.dynamic.sql.util.AbstractColumnMapping import org.mybatis.dynamic.sql.util.Buildable typealias GeneralInsertCompleter = @MyBatisDslMarker KotlinGeneralInsertBuilder.() -> Unit @MyBatisDslMarker -class KotlinGeneralInsertBuilder(private val dsl: GeneralInsertDSL) : Buildable { +class KotlinGeneralInsertBuilder(private val table: SqlTable) : Buildable { - fun set(column: SqlColumn): GeneralInsertSetClauseFinisher = GeneralInsertSetClauseFinisher(column) + private val columnMappings = mutableListOf() - override fun build(): GeneralInsertModel = dsl.build() - - @MyBatisDslMarker - inner class GeneralInsertSetClauseFinisher(private val column: SqlColumn) { - fun toNull(): Unit = - applyToDsl { - set(column).toNull() - } - - infix fun toConstant(constant: String): Unit = - applyToDsl { - set(column).toConstant(constant) - } - - infix fun toStringConstant(constant: String): Unit = - applyToDsl { - set(column).toStringConstant(constant) - } - - infix fun toValue(value: T): Unit = toValue { value } - - infix fun toValue(value: () -> T): Unit = - applyToDsl { - set(column).toValue(value) - } - - infix fun toValueOrNull(value: T?): Unit = toValueOrNull { value } - - infix fun toValueOrNull(value: () -> T?): Unit = - applyToDsl { - set(column).toValueOrNull(value) - } - - infix fun toValueWhenPresent(value: T?): Unit = toValueWhenPresent { value } - - infix fun toValueWhenPresent(value: () -> T?): Unit = - applyToDsl { - set(column).toValueWhenPresent(value) - } - - private fun applyToDsl(block: GeneralInsertDSL.() -> Unit) { - this@KotlinGeneralInsertBuilder.dsl.apply(block) - } + fun set(column: SqlColumn) = GeneralInsertColumnSetCompleter(column) { + columnMappings.add(it) } + + override fun build(): GeneralInsertModel = + with(GeneralInsertDSL.Builder()) { + withTable(table) + withColumnMappings(columnMappings) + build() + }.build() } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt index 065e572ca..f70a0ffb5 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt @@ -15,69 +15,33 @@ */ package org.mybatis.dynamic.sql.util.kotlin -import org.mybatis.dynamic.sql.SqlBuilder import org.mybatis.dynamic.sql.SqlColumn import org.mybatis.dynamic.sql.SqlTable import org.mybatis.dynamic.sql.insert.InsertDSL import org.mybatis.dynamic.sql.insert.InsertModel +import org.mybatis.dynamic.sql.util.AbstractColumnMapping import org.mybatis.dynamic.sql.util.Buildable typealias KotlinInsertCompleter = KotlinInsertBuilder.() -> Unit @MyBatisDslMarker class KotlinInsertBuilder (private val row: T): Buildable> { - - private lateinit var dsl: InsertDSL + private var table: SqlTable? = null + private val columnMappings = mutableListOf() fun into(table: SqlTable) { - dsl = SqlBuilder.insert(row).into(table) + this.table = table; } - fun map(column: SqlColumn) = MapCompleter(column) - - override fun build(): InsertModel { - return getDsl().build() + fun map(column: SqlColumn) = SingleRowInsertColumnMapCompleter(column) { + columnMappings.add(it) } - private fun getDsl(): InsertDSL { - try { - return dsl - } catch (e: UninitializedPropertyAccessException) { - throw UninitializedPropertyAccessException( - "You must specify an \"into\" clause before any other clauses in an insert statement", e - ) - } - } - - @MyBatisDslMarker - inner class MapCompleter (private val column: SqlColumn) { - infix fun toProperty(property: String) = - applyToDsl { - map(column).toProperty(property) - } - - fun toNull() = - applyToDsl { - map(column).toNull() - } - - infix fun toConstant(constant: String) = - applyToDsl { - map(column).toConstant(constant) - } - - infix fun toStringConstant(constant: String) = - applyToDsl { - map(column).toStringConstant(constant) - } - - fun toPropertyWhenPresent(property: String, valueSupplier: () -> C?) = - applyToDsl { - map(column).toPropertyWhenPresent(property, valueSupplier) - } - - private fun applyToDsl(block: InsertDSL.() -> Unit) { - this@KotlinInsertBuilder.getDsl().apply(block) - } - } + override fun build(): InsertModel = + with(InsertDSL.Builder()) { + withRow(row) + withTable(table) + withColumnMappings(columnMappings) + build() + }.build() } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertColumnMapCompleters.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertColumnMapCompleters.kt new file mode 100644 index 000000000..bd6012dae --- /dev/null +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertColumnMapCompleters.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2016-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mybatis.dynamic.sql.util.kotlin + +import org.mybatis.dynamic.sql.SqlColumn +import org.mybatis.dynamic.sql.util.AbstractColumnMapping +import org.mybatis.dynamic.sql.util.ConstantMapping +import org.mybatis.dynamic.sql.util.NullMapping +import org.mybatis.dynamic.sql.util.PropertyMapping +import org.mybatis.dynamic.sql.util.PropertyWhenPresentMapping +import org.mybatis.dynamic.sql.util.StringConstantMapping +import org.mybatis.dynamic.sql.util.ValueMapping +import org.mybatis.dynamic.sql.util.ValueOrNullMapping +import org.mybatis.dynamic.sql.util.ValueWhenPresentMapping + +@MyBatisDslMarker +sealed class AbstractInsertColumnMapCompleter( + internal val column: SqlColumn, + internal val mappingConsumer: (AbstractColumnMapping) -> Unit) { + + fun toNull() = mappingConsumer.invoke(NullMapping.of(column)) + + infix fun toConstant(constant: String) = mappingConsumer.invoke(ConstantMapping.of(column, constant)) + + infix fun toStringConstant(constant: String) = mappingConsumer.invoke(StringConstantMapping.of(column, constant)) +} + +class MultiRowInsertColumnMapCompleter( + column: SqlColumn, + mappingConsumer: (AbstractColumnMapping) -> Unit) + : AbstractInsertColumnMapCompleter(column, mappingConsumer) { + + infix fun toProperty(property: String) = mappingConsumer.invoke(PropertyMapping.of(column, property)) +} + +class SingleRowInsertColumnMapCompleter( + column: SqlColumn, + mappingConsumer: (AbstractColumnMapping) -> Unit) + : AbstractInsertColumnMapCompleter(column, mappingConsumer) { + + infix fun toProperty(property: String) = mappingConsumer.invoke(PropertyMapping.of(column, property)) + + fun toPropertyWhenPresent(property: String, valueSupplier: () -> T?) = + mappingConsumer.invoke(PropertyWhenPresentMapping.of(column, property, valueSupplier)) +} + +class GeneralInsertColumnSetCompleter( + column: SqlColumn, + mappingConsumer: (AbstractColumnMapping) -> Unit) + : AbstractInsertColumnMapCompleter(column, mappingConsumer) { + + infix fun toValue(value: T) = toValue { value } + + infix fun toValue(value: () -> T) = mappingConsumer.invoke(ValueMapping.of(column, value)) + + infix fun toValueOrNull(value: T?) = toValueOrNull { value } + + infix fun toValueOrNull(value: () -> T?) = mappingConsumer.invoke(ValueOrNullMapping.of(column, value)) + + infix fun toValueWhenPresent(value: T?) = toValueWhenPresent { value } + + infix fun toValueWhenPresent(value: () -> T?) = mappingConsumer.invoke(ValueWhenPresentMapping.of(column, value)) +} diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt index 0caccb591..ec55d2fe0 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt @@ -15,64 +15,33 @@ */ package org.mybatis.dynamic.sql.util.kotlin -import org.mybatis.dynamic.sql.SqlBuilder import org.mybatis.dynamic.sql.SqlColumn import org.mybatis.dynamic.sql.SqlTable import org.mybatis.dynamic.sql.insert.MultiRowInsertDSL import org.mybatis.dynamic.sql.insert.MultiRowInsertModel +import org.mybatis.dynamic.sql.util.AbstractColumnMapping import org.mybatis.dynamic.sql.util.Buildable typealias KotlinMultiRowInsertCompleter = KotlinMultiRowInsertBuilder.() -> Unit @MyBatisDslMarker class KotlinMultiRowInsertBuilder (private val rows: Collection): Buildable> { - - private lateinit var dsl: MultiRowInsertDSL + private var table: SqlTable? = null + private val columnMappings = mutableListOf() fun into(table: SqlTable) { - dsl = SqlBuilder.insertMultiple(rows).into(table) + this.table = table } - infix fun map(column: SqlColumn) = MapCompleter(column) - - override fun build(): MultiRowInsertModel { - return getDsl().build() + fun map(column: SqlColumn) = MultiRowInsertColumnMapCompleter(column) { + columnMappings.add(it) } - private fun getDsl(): MultiRowInsertDSL { - try { - return dsl - } catch (e: UninitializedPropertyAccessException) { - throw UninitializedPropertyAccessException( - "You must specify an \"into\" clause before any other clauses in an insertMultiple statement", e - ) - } - } - - @MyBatisDslMarker - inner class MapCompleter (private val column: SqlColumn) { - infix fun toProperty(property: String) = - applyToDsl { - map(column).toProperty(property) - } - - fun toNull() = - applyToDsl { - map(column).toNull() - } - - infix fun toConstant(constant: String) = - applyToDsl { - map(column).toConstant(constant) - } - - infix fun toStringConstant(constant: String) = - applyToDsl { - map(column).toStringConstant(constant) - } - - private fun applyToDsl(block: MultiRowInsertDSL.() -> Unit) { - this@KotlinMultiRowInsertBuilder.getDsl().apply(block) - } - } + override fun build(): MultiRowInsertModel = + with(MultiRowInsertDSL.Builder()) { + withRecords(rows) + withTable(table) + withColumnMappings(columnMappings) + build() + }.build() } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderFunctions.kt index ae4a3d73f..bc407605b 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderFunctions.kt @@ -22,7 +22,6 @@ import org.mybatis.dynamic.sql.SqlTable import org.mybatis.dynamic.sql.delete.DeleteModel import org.mybatis.dynamic.sql.insert.BatchInsertDSL import org.mybatis.dynamic.sql.insert.BatchInsertModel -import org.mybatis.dynamic.sql.insert.GeneralInsertDSL import org.mybatis.dynamic.sql.insert.GeneralInsertModel import org.mybatis.dynamic.sql.insert.InsertDSL import org.mybatis.dynamic.sql.insert.InsertModel @@ -70,7 +69,7 @@ fun insertBatch(rows: Collection, completer: KotlinBatchInsertCompleter insertMultiple(rows: Collection, completer: KotlinMultiRowInsertCompleter): MultiRowInsertModel = KotlinMultiRowInsertBuilder(rows).apply(completer).build() diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/ProviderBuilderFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/ProviderBuilderFunctions.kt index c87ee4825..0306bd374 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/ProviderBuilderFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/mybatis3/ProviderBuilderFunctions.kt @@ -74,7 +74,10 @@ fun insertBatch(rows: Collection, completer: KotlinBatchInsertCompleter insertMultiple(rows: Collection, completer: KotlinMultiRowInsertCompleter): MultiRowInsertStatementProvider = +fun insertMultiple( + rows: Collection, + completer: KotlinMultiRowInsertCompleter +): MultiRowInsertStatementProvider = insertMultiple(rows, completer).render(RenderingStrategies.MYBATIS3) fun insertSelect(table: SqlTable, completer: InsertSelectCompleter): InsertSelectStatementProvider = @@ -85,7 +88,10 @@ fun BatchInsertDSL.IntoGatherer.into(table: SqlTable, completer: BatchIns into(table, completer).render(RenderingStrategies.MYBATIS3) @Deprecated("Please switch to the insert statement in the mybatis3 package") -fun InsertDSL.IntoGatherer.into(table: SqlTable, completer: InsertDSL.() -> Unit): InsertStatementProvider = +fun InsertDSL.IntoGatherer.into( + table: SqlTable, + completer: InsertDSL.() -> Unit +): InsertStatementProvider = into(table, completer).render(RenderingStrategies.MYBATIS3) @Deprecated("Please switch to the insertMultiple statement in the mybatis3 package") diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt index c4ab62d2d..c492fea81 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/spring/NamedParameterJdbcTemplateExtensions.kt @@ -67,10 +67,16 @@ fun NamedParameterJdbcTemplate.deleteFrom(table: SqlTable, completer: DeleteComp fun NamedParameterJdbcTemplate.insertBatch(insertStatement: BatchInsert): IntArray = batchUpdate(insertStatement.insertStatementSQL, SqlParameterSourceUtils.createBatch(insertStatement.records)) -fun NamedParameterJdbcTemplate.insertBatch(vararg records: T, completer: KotlinBatchInsertCompleter): IntArray = +fun NamedParameterJdbcTemplate.insertBatch( + vararg records: T, + completer: KotlinBatchInsertCompleter +): IntArray = insertBatch(records.asList(), completer) -fun NamedParameterJdbcTemplate.insertBatch(records: List, completer: KotlinBatchInsertCompleter): IntArray = +fun NamedParameterJdbcTemplate.insertBatch( + records: List, + completer: KotlinBatchInsertCompleter +): IntArray = insertBatch(org.mybatis.dynamic.sql.util.kotlin.spring.insertBatch(records, completer)) @Deprecated("Please move the into phrase inside the lambda") @@ -112,10 +118,16 @@ fun NamedParameterJdbcTemplate.insertInto(table: SqlTable, completer: GeneralIns generalInsert(org.mybatis.dynamic.sql.util.kotlin.spring.insertInto(table, completer)) // multiple row insert -fun NamedParameterJdbcTemplate.insertMultiple(vararg records: T, completer: KotlinMultiRowInsertCompleter): Int = +fun NamedParameterJdbcTemplate.insertMultiple( + vararg records: T + , completer: KotlinMultiRowInsertCompleter +): Int = insertMultiple(records.asList(), completer) -fun NamedParameterJdbcTemplate.insertMultiple(records: List, completer: KotlinMultiRowInsertCompleter): Int = +fun NamedParameterJdbcTemplate.insertMultiple( + records: List, + completer: KotlinMultiRowInsertCompleter +): Int = insertMultiple(org.mybatis.dynamic.sql.util.kotlin.spring.insertMultiple(records, completer)) @Deprecated("Please move the into phrase inside the lambda") diff --git a/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt index 6834f5407..84e7037f7 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt @@ -291,7 +291,7 @@ class GeneralKotlinTest { } @Test - fun testInsert() { + fun testDeprecatedInsert() { newSession().use { session -> val mapper = session.getMapper(PersonMapper::class.java) @@ -326,7 +326,7 @@ class GeneralKotlinTest { } @Test - fun testInsertMultiple() { + fun testDeprecatedInsertMultiple() { newSession().use { session -> val mapper = session.getMapper(PersonMapper::class.java) diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt index ea489a06d..37c5932e0 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt @@ -52,6 +52,7 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig import org.springframework.transaction.annotation.Transactional import java.util.Date +@Suppress("LargeClass") @SpringJUnitConfig(classes = [SpringConfiguration::class]) @Transactional open class CanonicalSpringKotlinTemplateDirectTest { diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt index 7113fe33f..aa9687049 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt @@ -424,7 +424,8 @@ open class CanonicalSpringKotlinTest { ":records[0].birthDate, :records[0].employedAsString, " + ":records[0].occupation, :records[0].addressId), " + "(:records[1].id, :records[1].firstName, :records[1].lastNameAsString, " + - ":records[1].birthDate, :records[1].employedAsString, :records[1].occupation, :records[1].addressId)" + ":records[1].birthDate, :records[1].employedAsString, :records[1].occupation, " + + ":records[1].addressId)" ) val rows = template.insertMultiple(insertStatement) @@ -433,8 +434,62 @@ open class CanonicalSpringKotlinTest { @Test fun testBatchInsert() { - val record1 = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) - val record2 = PersonRecord(101, "Sarah", LastName("Smith"), Date(), true, "Architect", 2) + val record1 = PersonRecord( + 100, + "Joe", + LastName("Jones"), + Date(), + true, + "Developer", + 1 + ) + val record2 = PersonRecord( + 101, + "Sarah", + LastName("Smith"), + Date(), + true, + "Architect", + 2 + ) + + val insertStatement = insertBatch(listOf(record1, record2)) { + into(person) + map(id).toProperty("id") + map(firstName).toProperty("firstName") + map(lastName).toProperty("lastNameAsString") + map(birthDate).toProperty("birthDate") + map(employed).toProperty("employedAsString") + map(occupation).toProperty("occupation") + map(addressId).toProperty("addressId") + } + + val rows = template.insertBatch(insertStatement) + assertThat(rows).hasSize(2) + assertThat(rows[0]).isEqualTo(1) + assertThat(rows[1]).isEqualTo(1) + } + + @Test + fun testDeprecatedBatchInsert() { + val record1 = PersonRecord( + 100, + "Joe", + LastName("Jones"), + Date(), + true, + "Developer", + 1 + ) + val record2 = PersonRecord( + 101, + "Sarah", + LastName("Smith"), + Date(), + true, + "Architect", + 2 + ) val insertStatement = insertBatch(record1, record2).into(person) { map(id).toProperty("id") @@ -531,7 +586,8 @@ open class CanonicalSpringKotlinTest { fun testInsertWithGeneratedKey() { val command = GeneratedAlwaysCommand(firstName = "Fred", lastName = "Flintstone") - val insertStatement = insert(command).into(generatedAlways) { + val insertStatement = insert(command) { + into(generatedAlways) map(generatedAlways.firstName).toProperty("firstName") map(generatedAlways.lastName).toProperty("lastName") } @@ -550,7 +606,8 @@ open class CanonicalSpringKotlinTest { val command1 = GeneratedAlwaysCommand(firstName = "Fred", lastName = "Flintstone") val command2 = GeneratedAlwaysCommand(firstName = "Barney", lastName = "Rubble") - val insertStatement = insertMultiple(command1, command2).into(generatedAlways) { + val insertStatement = insertMultiple(listOf(command1, command2)) { + into(generatedAlways) map(generatedAlways.firstName).toProperty("firstName") map(generatedAlways.lastName).toProperty("lastName") } From 1c9ce84cb960ba305721d5e9859231e59d6a81cc Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 15 Feb 2022 13:20:46 -0500 Subject: [PATCH 4/9] Coverage --- .../mybatis3/canonical/GeneratedAlwaysTest.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/GeneratedAlwaysTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/GeneratedAlwaysTest.kt index 0556ba7c1..a9ad42759 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/GeneratedAlwaysTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/GeneratedAlwaysTest.kt @@ -28,7 +28,9 @@ import org.apache.ibatis.session.SqlSessionFactoryBuilder import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test +import org.mybatis.dynamic.sql.util.kotlin.elements.insertBatch import org.mybatis.dynamic.sql.util.kotlin.mybatis3.insertInto +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.into import java.io.InputStreamReader import java.sql.DriverManager @@ -123,6 +125,40 @@ class GeneratedAlwaysTest { } } + @Test + fun testDeprecatedInsertBatch() { + newSession(ExecutorType.BATCH).use { session -> + val mapper = session.getMapper(GeneratedAlwaysMapper::class.java) + + val record1 = GeneratedAlwaysRecord( + firstName = "Fred", + lastName = "Flintstone" + ) + + val record2 = GeneratedAlwaysRecord( + firstName = "Barney", + lastName = "Rubble" + ) + + insertBatch(record1, record2).into(generatedAlways) { + map(firstName).toProperty("firstName") + map(lastName).toProperty("lastName") + }.insertStatements().map(mapper::insert) + + val batchResults = mapper.flush() + + assertThat(batchResults).hasSize(1) + assertThat(batchResults[0].updateCounts).hasSize(2) + assertThat(batchResults[0].updateCounts[0]).isEqualTo(1) + assertThat(batchResults[0].updateCounts[1]).isEqualTo(1) + + assertThat(record1.id).isEqualTo(22) + assertThat(record1.fullName).isEqualTo("Fred Flintstone") + assertThat(record2.id).isEqualTo(23) + assertThat(record2.fullName).isEqualTo("Barney Rubble") + } + } + @Test fun testGeneralInsert() { newSession().use { session -> From 898993d75e34d4749fbfe2906b1137d2a78b402e Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 15 Feb 2022 17:10:44 -0500 Subject: [PATCH 5/9] Documentation --- CHANGELOG.md | 11 +++ src/site/markdown/docs/kotlinMyBatis3.md | 56 ++++++------ src/site/markdown/docs/kotlinOverview.md | 74 ++++++++------- src/site/markdown/docs/kotlinSpring.md | 109 ++++++++++++----------- 4 files changed, 139 insertions(+), 111 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac0bb470a..97b5379fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ This log will detail notable changes to MyBatis Dynamic SQL. Full details are av ## Release 1.4.0 - Unreleased +The release includes new function in the Where Clause DSL to support arbitrary grouping of conditions, and also use +of a "not" condition. It should now be possible to write any type of where clause. + +Additionally, there were significant updates to the Kotlin DSL - both to support the new functionality in the +where clause, and significant updates to insert statements. There were also many minor updates in Kotlin +to make more use of Kotlin language features like infix functions and operator overloads. + GitHub milestone: [https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.4.0+](https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.4.0+) 1. Added support for arbitrary placement of nested criteria. For example, it is now @@ -33,6 +40,10 @@ GitHub milestone: [https://github.com/mybatis/mybatis-dynamic-sql/issues?q=miles ([#446](https://github.com/mybatis/mybatis-dynamic-sql/pull/446)) 6. Minor update the Kotlin join DSL to make it closer to natural SQL. The existing join methods are deprecated and will be removed in version 1.5.0. ([#447](https://github.com/mybatis/mybatis-dynamic-sql/pull/447)) +7. Updated most of the Kotlin insert DSL functions to be more like natural SQL. The main difference is that for insert, + insertBatch, and insertMultiple, the "into" function is moved inside the completer lambda. The old methods are now + deprecated and will be removed in version 1.5.0 of the library. This also allowed us to make some insert DSL + methods into infix functions. ## Release 1.3.1 - December 18, 2021 diff --git a/src/site/markdown/docs/kotlinMyBatis3.md b/src/site/markdown/docs/kotlinMyBatis3.md index d2e5a76f3..5e5fa5721 100644 --- a/src/site/markdown/docs/kotlinMyBatis3.md +++ b/src/site/markdown/docs/kotlinMyBatis3.md @@ -349,13 +349,13 @@ import org.mybatis.dynamic.sql.util.kotlin.mybatis3.insert fun PersonMapper.insert(row: PersonRecord) = insert(this::insert, row, Person) { - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastName") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employed") - map(occupation).toProperty("occupation") - map(addressId).toProperty("addressId") + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastName" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employed" + map(occupation) toProperty "occupation" + map(addressId) toProperty "addressId" } ``` @@ -440,13 +440,13 @@ method as follows: ```kotlin val rows = mapper.generalInsert { - set(id).toValue(100) - set(firstName).toValue("Joe") - set(lastName).toValue(LastName("Jones")) - set(employed).toValue(true) - set(occupation).toValue("Developer") - set(addressId).toValue(1) - set(birthDate).toValue(Date()) + set(id) toValue 100 + set(firstName) toValue "Joe" + set(lastName) toValue LastName("Jones") + set(employed) toValue true + set(occupation) toValue "Developer" + set(addressId) toValue 1 + set(birthDate) toValue Date() } ``` @@ -532,13 +532,13 @@ fun PersonMapper.insertMultiple(vararg records: PersonRecord) = fun PersonMapper.insertMultiple(records: Collection) = insertMultiple(this::insertMultiple, records, person) { - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastName") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employed") - map(occupation).toProperty("occupation") - map(addressId).toProperty("addressId") + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastName" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employed" + map(occupation) toProperty "occupation" + map(addressId) toProperty "addressId" } ``` @@ -677,13 +677,13 @@ fun PersonMapper.insertBatch(vararg records: PersonRecord): List = fun PersonMapper.insertBatch(records: Collection): List = insertBatch(this::insert, records, person) { - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastName") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employed") - map(occupation).toProperty("occupation") - map(addressId).toProperty("addressId") + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastName" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employed" + map(occupation) toProperty "occupation" + map(addressId) toProperty "addressId" } ``` diff --git a/src/site/markdown/docs/kotlinOverview.md b/src/site/markdown/docs/kotlinOverview.md index 4b1d287c1..b21e5468e 100644 --- a/src/site/markdown/docs/kotlinOverview.md +++ b/src/site/markdown/docs/kotlinOverview.md @@ -228,20 +228,22 @@ data class PersonRecord( val row = PersonRecord(100, "Joe", "Jones", Date(), true, "Developer", 1) -val insertRecordStatement = insert(row).into(person) { - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastName") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employedAsString") +val insertRecordStatement = insert(row) { + into(person) + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastName" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employedAsString" map(occupation).toPropertyWhenPresent("occupation", row::occupation) - map(addressId).toProperty("addressId") + map(addressId) toProperty "addressId" } ``` This statement maps insert columns to properties in a class. Note the use of the `toPropertyWhenPresent` mapping - this will only set the insert value if the value of the property is non-null. Also note that you can use other mapping -methods to map insert fields to nulls and constants if desired. +methods to map insert fields to nulls and constants if desired. Many of the mappings can be called via infix +as shown above. This method creates models or providers depending on which package is used: @@ -260,13 +262,13 @@ The DSL for general insert statements looks like this: ```kotlin val generalInsertStatement = insertInto(person) { - set(id).toValue(100) - set(firstName).toValue("Joe") - set(lastName).toValue("Jones") - set(birthDate).toValue(Date()) - set(employed).toValue(true) - set(occupation).toValue("Developer") - set(addressId).toValue(1) + set(id) toValue 100 + set(firstName) toValue "Joe" + set(lastName) toValue "Jones" + set(birthDate) toValue Date() + set(employed) toValue true + set(occupation) toValue "Developer" + set(addressId) toValue 1 } ``` @@ -302,19 +304,24 @@ The DSL for multi-row insert statements looks like this: val record1 = PersonRecord(100, "Joe", "Jones", Date(), true, "Developer", 1) val record2 = PersonRecord(101, "Sarah", "Smith", Date(), true, "Architect", 2) -val multiRowInsertStatement = insertMultiple(record1, record2).into(person) { - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastNameAsString") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employedAsString") - map(occupation).toProperty("occupation") - map(addressId).toProperty("addressId") +val multiRowInsertStatement = insertMultiple(listOf(record1, record2)) { + into(person) + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastNameAsString" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employedAsString" + map(occupation) toProperty "occupation" + map(addressId) toProperty "addressId" } ``` Note there is no `toPropertyWhenPresent` mapping available on a multi-row insert. +Also note that there is no overload of this function that accepts a vararg of rows because it would cause an overload +resolution ambiguity error. This limitation is overcome in the utility functions for MyBatis and Spring as shown on +the documentation pages for those utilities. + This method creates models or providers depending on which package is used: | Package | Resulting Object | @@ -340,19 +347,24 @@ The DSL for batch insert statements looks like this: val record1 = PersonRecord(100, "Joe", "Jones", Date(), true, "Developer", 1) val record2 = PersonRecord(101, "Sarah", "Smith", Date(), true, "Architect", 2) -val batchInsertStatement = insertBatch(record1, record2).into(person) { - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastNameAsString") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employedAsString") - map(occupation).toProperty("occupation") - map(addressId).toProperty("addressId") +val batchInsertStatement = insertBatch(listOf(record1, record2)) { + into(person) + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastNameAsString" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employedAsString" + map(occupation) toProperty "occupation" + map(addressId) toProperty "addressId" } ``` Note there is no `toPropertyWhenPresent` mapping available on a batch insert. +Also note that there is no overload of this function that accepts a vararg of rows because it would cause an overload +resolution ambiguity error. This limitation is overcome in the utility functions for MyBatis and Spring as shown on +the documentation pages for those utilities. + This method creates models or providers depending on which package is used: | Package | Resulting Object | diff --git a/src/site/markdown/docs/kotlinSpring.md b/src/site/markdown/docs/kotlinSpring.md index 72472a957..adcfc7b3e 100644 --- a/src/site/markdown/docs/kotlinSpring.md +++ b/src/site/markdown/docs/kotlinSpring.md @@ -196,14 +196,15 @@ Single record insert statements can be constructed and executed in a single step ```kotlin val row = PersonRecord(100, "Joe", "Jones", Date(), true, "Developer", 1) -val rows = template.insert(row).into(Person) { - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastName") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employedAsString") +val rows = template.insert(row) { + into(Person) + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastName" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employedAsString" map(occupation).toPropertyWhenPresent("occupation", row::occupation) - map(addressId).toProperty("addressId") + map(addressId) toProperty "addressId" } ``` @@ -217,14 +218,15 @@ val keyHolder = GeneratedKeyHolder() val row = PersonRecord(100, "Joe", "Jones", Date(), true, "Developer", 1) val rows = template.withKeyHolder(keyHolder) { - insert(row).into(Person) { - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastName") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employedAsString") + insert(row) { + into(Person) + map(id) toProperty"id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastName" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employedAsString" map(occupation).toPropertyWhenPresent("occupation", row::occupation) - map(addressId).toProperty("addressId") + map(addressId) toProperty "addressId" } } ``` @@ -255,13 +257,13 @@ General insert statements can be constructed and executed in a single step with val myOccupation = "Developer" val rows = template.insertInto(Person) { - set(id).toValue(100) - set(firstName).toValue("Joe") - set(lastName).toValue("Jones") - set(birthDate).toValue(Date()) - set(employed).toValue(true) - set(occupation).toValueWhenPresent(myOccupation) - set(addressId).toValue(1) + set(id) toValue 100 + set(firstName) toValue "Joe" + set(lastName) toValue "Jones" + set(birthDate) toValue Date() + set(employed) toValue true + set(occupation) toValueWhenPresent myOccupation + set(addressId) toValue 1 } ``` @@ -276,13 +278,13 @@ val myOccupation = "Developer" val rows = template.withKeyHolder(keyHolder) { insertInto(Person) { - set(id).toValue(100) - set(firstName).toValue("Joe") - set(lastName).toValue("Jones") - set(birthDate).toValue(Date()) - set(employed).toValue(true) - set(occupation).toValueWhenPresent(myOccupation) - set(addressId).toValue(1) + set(id) toValue 100 + set(firstName) toValue "Joe" + set(lastName) toValue "Jones" + set(birthDate) toValue Date() + set(employed) toValue true + set(occupation) toValueWhenPresent myOccupation + set(addressId) toValue 1 } } ``` @@ -313,14 +315,15 @@ Multi-Row insert statements can be constructed and executed in a single step wit val record1 = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) val record2 = PersonRecord(101, "Sarah", LastName("Smith"), Date(), true, "Architect", 2) -val rows = template.insertMultiple(record1, record2).into(Person) { - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastNameAsString") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employedAsString") - map(occupation).toProperty("occupation") - map(addressId).toProperty("addressId") +val rows = template.insertMultiple(record1, record2) { + into(Person) + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastNameAsString" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employedAsString" + map(occupation) toProperty "occupation" + map(addressId) toProperty "addressId" } ``` @@ -332,14 +335,15 @@ val record1 = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Develop val record2 = PersonRecord(101, "Sarah", LastName("Smith"), Date(), true, "Architect", 2) val rows = template.withKeyHolder(keyHolder) { - insertMultiple(record1, record2).into(Person) { - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastNameAsString") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employedAsString") - map(occupation).toProperty("occupation") - map(addressId).toProperty("addressId") + insertMultiple(record1, record2) { + into(Person) + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastNameAsString" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employedAsString" + map(occupation) toProperty "occupation" + map(addressId) toProperty "addressId" } } ``` @@ -365,14 +369,15 @@ Batch statements can be constructed and executed in a single step with code like val record1 = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) val record2 = PersonRecord(101, "Sarah", LastName("Smith"), Date(), true, "Architect", 2) -val rows = template.insertBatch(record1, record2).into(Person) { - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastNameAsString") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employedAsString") - map(occupation).toProperty("occupation") - map(addressId).toProperty("addressId") +val rows = template.insertBatch(record1, record2) { + into(Person) + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastNameAsString" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employedAsString" + map(occupation) toProperty "occupation" + map(addressId) toProperty "addressId" } ``` From 7ba905027d18be162145d505da2ddd7d9df72a2a Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 15 Feb 2022 17:40:38 -0500 Subject: [PATCH 6/9] Copyright --- src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java b/src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java index ce34347e5..c5bd7f9d2 100644 --- a/src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java +++ b/src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From cddbccd801936ed18beb200161285de50643a0eb Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Tue, 15 Feb 2022 17:41:55 -0500 Subject: [PATCH 7/9] Consistent use of infix --- .../canonical/GeneratedAlwaysMapper.kt | 16 ++--- .../mybatis3/canonical/GeneratedAlwaysTest.kt | 2 +- .../canonical/PersonMapperExtensions.kt | 42 ++++++------- .../custom/render/KCustomRenderingTest.kt | 59 ++++++++++--------- ...CanonicalSpringKotlinTemplateDirectTest.kt | 36 +++++------ .../canonical/CanonicalSpringKotlinTest.kt | 22 +++---- 6 files changed, 92 insertions(+), 85 deletions(-) diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/GeneratedAlwaysMapper.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/GeneratedAlwaysMapper.kt index 653d83d60..f924bcacd 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/GeneratedAlwaysMapper.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/GeneratedAlwaysMapper.kt @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,21 +49,23 @@ interface GeneratedAlwaysMapper { fun GeneratedAlwaysMapper.insert(record: GeneratedAlwaysRecord): Int { return insert(this::insert, record, generatedAlways) { - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastName") + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastName" } } +fun GeneratedAlwaysMapper.insertMultiple(vararg records: GeneratedAlwaysRecord): Int = insertMultiple(records.asList()) + fun GeneratedAlwaysMapper.insertMultiple(records: Collection): Int { return insertMultipleWithGeneratedKeys(this::insertMultiple, records, generatedAlways) { - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastName") + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastName" } } fun GeneratedAlwaysMapper.insertBatch(records: Collection): List { return insertBatch(this::insert, records, generatedAlways) { - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastName") + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastName" } } diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/GeneratedAlwaysTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/GeneratedAlwaysTest.kt index a9ad42759..9c594b2d9 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/GeneratedAlwaysTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/GeneratedAlwaysTest.kt @@ -84,7 +84,7 @@ class GeneratedAlwaysTest { lastName = "Rubble" ) - val rows = mapper.insertMultiple(listOf(record1, record2)) + val rows = mapper.insertMultiple(record1, record2) assertThat(rows).isEqualTo(2) assertThat(record1.id).isEqualTo(22) diff --git a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperExtensions.kt b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperExtensions.kt index c170b00f1..86152125d 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperExtensions.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/canonical/PersonMapperExtensions.kt @@ -65,13 +65,13 @@ fun PersonMapper.deleteByPrimaryKey(id_: Int) = fun PersonMapper.insert(record: PersonRecord) = insert(this::insert, record, person) { - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastName") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employed") - map(occupation).toProperty("occupation") - map(addressId).toProperty("addressId") + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastName" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employed" + map(occupation) toProperty "occupation" + map(addressId) toProperty "addressId" } fun PersonMapper.generalInsert(completer: GeneralInsertCompleter) = @@ -85,13 +85,13 @@ fun PersonMapper.insertBatch(vararg records: PersonRecord): List = fun PersonMapper.insertBatch(records: Collection): List = insertBatch(this::insert, records, person) { - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastName") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employed") - map(occupation).toProperty("occupation") - map(addressId).toProperty("addressId") + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastName" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employed" + map(occupation) toProperty "occupation" + map(addressId) toProperty "addressId" } fun PersonMapper.insertMultiple(vararg records: PersonRecord) = @@ -99,13 +99,13 @@ fun PersonMapper.insertMultiple(vararg records: PersonRecord) = fun PersonMapper.insertMultiple(records: Collection) = insertMultiple(this::insertMultiple, records, person) { - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastName") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employed") - map(occupation).toProperty("occupation") - map(addressId).toProperty("addressId") + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastName" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employed" + map(occupation) toProperty "occupation" + map(addressId) toProperty "addressId" } fun PersonMapper.insertSelective(record: PersonRecord) = diff --git a/src/test/kotlin/examples/kotlin/mybatis3/custom/render/KCustomRenderingTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/custom/render/KCustomRenderingTest.kt index 292616108..5b845b595 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/custom/render/KCustomRenderingTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/custom/render/KCustomRenderingTest.kt @@ -31,11 +31,10 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import org.mybatis.dynamic.sql.SqlColumn import org.mybatis.dynamic.sql.util.kotlin.elements.`as` -import org.mybatis.dynamic.sql.util.kotlin.elements.insert -import org.mybatis.dynamic.sql.util.kotlin.elements.insertMultiple import org.mybatis.dynamic.sql.util.kotlin.mybatis3.deleteFrom +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.insert import org.mybatis.dynamic.sql.util.kotlin.mybatis3.insertInto -import org.mybatis.dynamic.sql.util.kotlin.mybatis3.into +import org.mybatis.dynamic.sql.util.kotlin.mybatis3.insertMultiple import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select import org.mybatis.dynamic.sql.util.kotlin.mybatis3.update import org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper @@ -84,10 +83,11 @@ class KCustomRenderingTest { info = "{\"firstName\": \"Fred\", \"lastName\": \"Flintstone\", \"age\": 30}" ) - var insertStatement = insert(record).into(jsonTest) { - map(id).toProperty("id") - map(description).toProperty("description") - map(info).toProperty("info") + var insertStatement = insert(record) { + into(jsonTest) + map(id) toProperty "id" + map(description) toProperty "description" + map(info) toProperty "info" } val expected = "insert into JsonTest (id, description, info) " + "values (#{record.id,jdbcType=INTEGER}, #{record.description,jdbcType=VARCHAR}, " + @@ -101,10 +101,11 @@ class KCustomRenderingTest { info = "{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}" ) - insertStatement = insert(record).into(jsonTest) { - map(id).toProperty("id") - map(description).toProperty("description") - map(info).toProperty("info") + insertStatement = insert(record) { + into(jsonTest) + map(id) toProperty "id" + map(description) toProperty "description" + map(info) toProperty "info" } rows = mapper.insert(insertStatement) assertThat(rows).isEqualTo(1) @@ -170,10 +171,11 @@ class KCustomRenderingTest { description = "Wilma", info = "{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}" ) - val insertStatement = insertMultiple(record1, record2).into(jsonTest) { - map(id).toProperty("id") - map(description).toProperty("description") - map(info).toProperty("info") + val insertStatement = insertMultiple(listOf(record1, record2)) { + into(jsonTest) + map(id) toProperty "id" + map(description) toProperty "description" + map(info) toProperty "info" } val expected = "insert into JsonTest (id, description, info) " + "values (#{records[0].id,jdbcType=INTEGER}, #{records[0].description,jdbcType=VARCHAR}, " + @@ -210,10 +212,11 @@ class KCustomRenderingTest { description = "Wilma", info = "{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}" ) - val insertStatement = insertMultiple(record1, record2).into(jsonTest) { - map(id).toProperty("id") - map(description).toProperty("description") - map(info).toProperty("info") + val insertStatement = insertMultiple(listOf(record1, record2)) { + into(jsonTest) + map(id) toProperty "id" + map(description) toProperty "description" + map(info) toProperty "info" } var rows = mapper.insertMultiple(insertStatement) assertThat(rows).isEqualTo(2) @@ -254,10 +257,11 @@ class KCustomRenderingTest { description = "Wilma", info = "{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}" ) - val insertStatement = insertMultiple(record1, record2).into(jsonTest) { - map(id).toProperty("id") - map(description).toProperty("description") - map(info).toProperty("info") + val insertStatement = insertMultiple(listOf(record1, record2)) { + into(jsonTest) + map(id) toProperty "id" + map(description) toProperty "description" + map(info) toProperty "info" } val rows = mapper.insertMultiple(insertStatement) assertThat(rows).isEqualTo(2) @@ -291,10 +295,11 @@ class KCustomRenderingTest { description = "Wilma", info = "{\"firstName\": \"Wilma\", \"lastName\": \"Flintstone\", \"age\": 25}" ) - val insertStatement = insertMultiple(record1, record2).into(jsonTest) { - map(id).toProperty("id") - map(description).toProperty("description") - map(info).toProperty("info") + val insertStatement = insertMultiple(listOf(record1, record2)) { + into(jsonTest) + map(id) toProperty "id" + map(description) toProperty "description" + map(info) toProperty "info" } val rows = mapper.insertMultiple(insertStatement) assertThat(rows).isEqualTo(2) diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt index 37c5932e0..90e7fce02 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt @@ -229,13 +229,13 @@ open class CanonicalSpringKotlinTemplateDirectTest { val rows = template.insertMultiple(record1, record2) { into(person) - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastNameAsString") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employedAsString") - map(occupation).toProperty("occupation") - map(addressId).toProperty("addressId") + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastNameAsString" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employedAsString" + map(occupation) toProperty "occupation" + map(addressId) toProperty "addressId" } assertThat(rows).isEqualTo(2) @@ -266,13 +266,13 @@ open class CanonicalSpringKotlinTemplateDirectTest { val rows = template.insertBatch(record1, record2) { into(person) - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastNameAsString") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employedAsString") - map(occupation).toProperty("occupation") - map(addressId).toProperty("addressId") + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastNameAsString" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employedAsString" + map(occupation) toProperty "occupation" + map(addressId) toProperty "addressId" } assertThat(rows).hasSize(2) @@ -359,8 +359,8 @@ open class CanonicalSpringKotlinTemplateDirectTest { val rows = template.withKeyHolder(keyHolder) { insert(command) { into(generatedAlways) - map(generatedAlways.firstName).toProperty("firstName") - map(generatedAlways.lastName).toProperty("lastName") + map(generatedAlways.firstName) toProperty "firstName" + map(generatedAlways.lastName) toProperty "lastName" } } @@ -399,8 +399,8 @@ open class CanonicalSpringKotlinTemplateDirectTest { val rows = template.withKeyHolder(keyHolder) { insertMultiple(command1, command2) { into(generatedAlways) - map(generatedAlways.firstName).toProperty("firstName") - map(generatedAlways.lastName).toProperty("lastName") + map(generatedAlways.firstName) toProperty "firstName" + map(generatedAlways.lastName) toProperty "lastName" } } diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt index aa9687049..5e66b0793 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt @@ -455,13 +455,13 @@ open class CanonicalSpringKotlinTest { val insertStatement = insertBatch(listOf(record1, record2)) { into(person) - map(id).toProperty("id") - map(firstName).toProperty("firstName") - map(lastName).toProperty("lastNameAsString") - map(birthDate).toProperty("birthDate") - map(employed).toProperty("employedAsString") - map(occupation).toProperty("occupation") - map(addressId).toProperty("addressId") + map(id) toProperty "id" + map(firstName) toProperty "firstName" + map(lastName) toProperty "lastNameAsString" + map(birthDate) toProperty "birthDate" + map(employed) toProperty "employedAsString" + map(occupation) toProperty "occupation" + map(addressId) toProperty "addressId" } val rows = template.insertBatch(insertStatement) @@ -588,8 +588,8 @@ open class CanonicalSpringKotlinTest { val insertStatement = insert(command) { into(generatedAlways) - map(generatedAlways.firstName).toProperty("firstName") - map(generatedAlways.lastName).toProperty("lastName") + map(generatedAlways.firstName) toProperty "firstName" + map(generatedAlways.lastName) toProperty "lastName" } val keyHolder = GeneratedKeyHolder() @@ -608,8 +608,8 @@ open class CanonicalSpringKotlinTest { val insertStatement = insertMultiple(listOf(command1, command2)) { into(generatedAlways) - map(generatedAlways.firstName).toProperty("firstName") - map(generatedAlways.lastName).toProperty("lastName") + map(generatedAlways.firstName) toProperty "firstName" + map(generatedAlways.lastName) toProperty "lastName" } val keyHolder = GeneratedKeyHolder() From 45bcf1ad7a2aff3ad498e8b8158c0d167b0a439f Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 16 Feb 2022 12:49:05 -0500 Subject: [PATCH 8/9] Remove some obscure coding and standardize on a common exception KInvalidSQLException will now be thrown from any misuse of the Kotlin DSL --- .../util/kotlin/GroupingCriteriaCollector.kt | 3 +- .../dynamic/sql/util/kotlin/JoinCollector.kt | 12 ++--- ...onException.kt => KInvalidSQLException.kt} | 9 +--- .../sql/util/kotlin/KotlinBaseBuilders.kt | 24 +++++----- .../util/kotlin/KotlinBatchInsertBuilder.kt | 16 ++++--- .../sql/util/kotlin/KotlinCountBuilder.kt | 14 ++---- .../sql/util/kotlin/KotlinInsertBuilder.kt | 18 +++++--- .../kotlin/KotlinMultiRowInsertBuilder.kt | 16 ++++--- .../sql/util/kotlin/KotlinSelectBuilder.kt | 12 ++--- .../sql/util/kotlin/KotlinSubQueryBuilders.kt | 25 +++-------- .../kotlin/model/ModelBuilderFunctions.kt | 2 +- .../mybatis3/general/GeneralKotlinTest.kt | 5 ++- .../kotlin/mybatis3/joins/JoinMapperTest.kt | 19 ++++++++ .../canonical/CanonicalSpringKotlinTest.kt | 44 +++++++++++++++++-- .../spring/canonical/InfixElementsTest.kt | 4 +- 15 files changed, 132 insertions(+), 91 deletions(-) rename src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/{DuplicateInitialCriterionException.kt => KInvalidSQLException.kt} (65%) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt index 4f593fa33..b80ef3bd3 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/GroupingCriteriaCollector.kt @@ -47,7 +47,8 @@ class GroupingCriteriaCollector { internal var initialCriterion: SqlCriterion? = null private set(value) { if (field != null) { - throw DuplicateInitialCriterionException() + throw KInvalidSQLException("Setting more than one initial criterion is not allowed. " + + "Additional criteria should be added with \"and\" or \"or\" expression") } field = value } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt index 20bff932c..c05aa7558 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/JoinCollector.kt @@ -24,12 +24,14 @@ typealias JoinReceiver = JoinCollector.() -> Unit @MyBatisDslMarker class JoinCollector { - val onJoinCriterion: JoinCriterion by lazy { internalOnCriterion } - val andJoinCriteria = mutableListOf() - private lateinit var internalOnCriterion: JoinCriterion + private var onJoinCriterion: JoinCriterion? = null + internal val andJoinCriteria = mutableListOf() + + internal fun onJoinCriterion() : JoinCriterion = + onJoinCriterion?: throw KInvalidSQLException("You must specify an \"on\" condition in a join") fun on(leftColumn: BasicColumn): RightColumnCollector = RightColumnCollector { - internalOnCriterion = JoinCriterion.Builder() + onJoinCriterion = JoinCriterion.Builder() .withConnector("on") .withJoinColumn(leftColumn) .withJoinCondition(it) @@ -48,7 +50,7 @@ class JoinCollector { @Deprecated("Please use: on(leftColumn) equalTo rightColumn") fun on(column: BasicColumn, condition: JoinCondition) { - internalOnCriterion = JoinCriterion.Builder() + onJoinCriterion = JoinCriterion.Builder() .withConnector("on") .withJoinColumn(column) .withJoinCondition(condition) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/DuplicateInitialCriterionException.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KInvalidSQLException.kt similarity index 65% rename from src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/DuplicateInitialCriterionException.kt rename to src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KInvalidSQLException.kt index 56d33246b..10d9c8b37 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/DuplicateInitialCriterionException.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KInvalidSQLException.kt @@ -16,11 +16,6 @@ package org.mybatis.dynamic.sql.util.kotlin /** - * This exception is thrown when a where clause contains more than one criterion and there - * is not an "and" or an "or" to connect them. - * - * @since 1.4.0 + * This exception is thrown if the library detects misuse of the Kotlin DSL that would result in invalid SQL */ -class DuplicateInitialCriterionException : RuntimeException( - "Setting more than one initial criterion is not allowed. " + - "Additional criteria should be added with \"and\" or \"or\" expression") +class KInvalidSQLException(message: String) : RuntimeException(message) diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt index 061e667b2..0d96df4ec 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt @@ -180,12 +180,12 @@ abstract class KotlinBaseJoiningBuilder> : fun join(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - join(table, jc.onJoinCriterion, jc.andJoinCriteria) + join(table, jc.onJoinCriterion(), jc.andJoinCriteria) } fun join(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - join(table, alias, jc.onJoinCriterion, jc.andJoinCriteria) + join(table, alias, jc.onJoinCriterion(), jc.andJoinCriteria) } fun join( @@ -193,17 +193,17 @@ abstract class KotlinBaseJoiningBuilder> : joinCriteria: JoinReceiver ): Unit = applyToDsl(subQuery, joinCriteria) { sq, jc -> - join(sq, sq.correlationName, jc.onJoinCriterion, jc.andJoinCriteria) + join(sq, sq.correlationName, jc.onJoinCriterion(), jc.andJoinCriteria) } fun fullJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - fullJoin(table, jc.onJoinCriterion, jc.andJoinCriteria) + fullJoin(table, jc.onJoinCriterion(), jc.andJoinCriteria) } fun fullJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - fullJoin(table, alias, jc.onJoinCriterion, jc.andJoinCriteria) + fullJoin(table, alias, jc.onJoinCriterion(), jc.andJoinCriteria) } fun fullJoin( @@ -211,17 +211,17 @@ abstract class KotlinBaseJoiningBuilder> : joinCriteria: JoinReceiver ): Unit = applyToDsl(subQuery, joinCriteria) { sq, jc -> - fullJoin(sq, sq.correlationName, jc.onJoinCriterion, jc.andJoinCriteria) + fullJoin(sq, sq.correlationName, jc.onJoinCriterion(), jc.andJoinCriteria) } fun leftJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - leftJoin(table, jc.onJoinCriterion, jc.andJoinCriteria) + leftJoin(table, jc.onJoinCriterion(), jc.andJoinCriteria) } fun leftJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - leftJoin(table, alias, jc.onJoinCriterion, jc.andJoinCriteria) + leftJoin(table, alias, jc.onJoinCriterion(), jc.andJoinCriteria) } fun leftJoin( @@ -229,17 +229,17 @@ abstract class KotlinBaseJoiningBuilder> : joinCriteria: JoinReceiver ): Unit = applyToDsl(subQuery, joinCriteria) { sq, jc -> - leftJoin(sq, sq.correlationName, jc.onJoinCriterion, jc.andJoinCriteria) + leftJoin(sq, sq.correlationName, jc.onJoinCriterion(), jc.andJoinCriteria) } fun rightJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - rightJoin(table, jc.onJoinCriterion, jc.andJoinCriteria) + rightJoin(table, jc.onJoinCriterion(), jc.andJoinCriteria) } fun rightJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit = applyToDsl(joinCriteria) { jc -> - rightJoin(table, alias, jc.onJoinCriterion, jc.andJoinCriteria) + rightJoin(table, alias, jc.onJoinCriterion(), jc.andJoinCriteria) } fun rightJoin( @@ -247,7 +247,7 @@ abstract class KotlinBaseJoiningBuilder> : joinCriteria: JoinReceiver ): Unit = applyToDsl(subQuery, joinCriteria) { sq, jc -> - rightJoin(sq, sq.correlationName, jc.onJoinCriterion, jc.andJoinCriteria) + rightJoin(sq, sq.correlationName, jc.onJoinCriterion(), jc.andJoinCriteria) } private fun applyToDsl(joinCriteria: JoinReceiver, applyJoin: D.(JoinCollector) -> Unit) { diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt index fcdae8f1d..0f278cd17 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt @@ -38,10 +38,14 @@ class KotlinBatchInsertBuilder (private val rows: Collection): Buildable = - with(BatchInsertDSL.Builder()) { - withRecords(rows) - withTable(table) - withColumnMappings(columnMappings) - build() - }.build() + if (table == null) { + throw KInvalidSQLException("Batch Insert Statements Must Contain an \"into\" phrase.") + } else { + with(BatchInsertDSL.Builder()) { + withRecords(rows) + withTable(table) + withColumnMappings(columnMappings) + build() + }.build() + } } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinCountBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinCountBuilder.kt index 7795a1587..8ec930035 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinCountBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinCountBuilder.kt @@ -26,7 +26,7 @@ class KotlinCountBuilder(private val fromGatherer: CountDSL.FromGatherer>(), Buildable { - private lateinit var dsl: CountDSL + private var dsl: CountDSL? = null fun from(table: SqlTable): KotlinCountBuilder = apply { @@ -35,13 +35,7 @@ class KotlinCountBuilder(private val fromGatherer: CountDSL.FromGatherer { - try { - return dsl - } catch (e: UninitializedPropertyAccessException) { - throw UninitializedPropertyAccessException( - "You must specify a \"from\" clause before any other clauses in a count statement", e - ) - } - } + override fun getDsl(): CountDSL = + dsl?: throw KInvalidSQLException( + "You must specify a \"from\" clause before any other clauses in a count statement") } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt index f70a0ffb5..ca2bee86e 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt @@ -30,7 +30,7 @@ class KotlinInsertBuilder (private val row: T): Buildable> { private val columnMappings = mutableListOf() fun into(table: SqlTable) { - this.table = table; + this.table = table } fun map(column: SqlColumn) = SingleRowInsertColumnMapCompleter(column) { @@ -38,10 +38,14 @@ class KotlinInsertBuilder (private val row: T): Buildable> { } override fun build(): InsertModel = - with(InsertDSL.Builder()) { - withRow(row) - withTable(table) - withColumnMappings(columnMappings) - build() - }.build() + if (table == null) { + throw KInvalidSQLException("Insert Statements Must Contain an \"into\" phrase.") + } else { + with(InsertDSL.Builder()) { + withRow(row) + withTable(table) + withColumnMappings(columnMappings) + build() + }.build() + } } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt index ec55d2fe0..71f79f2a7 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt @@ -38,10 +38,14 @@ class KotlinMultiRowInsertBuilder (private val rows: Collection): Buildabl } override fun build(): MultiRowInsertModel = - with(MultiRowInsertDSL.Builder()) { - withRecords(rows) - withTable(table) - withColumnMappings(columnMappings) - build() - }.build() + if (table == null) { + throw KInvalidSQLException("Multi Row Insert Statements Must Contain an \"into\" phrase.") + } else { + with(MultiRowInsertDSL.Builder()) { + withRecords(rows) + withTable(table) + withColumnMappings(columnMappings) + build() + }.build() + } } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSelectBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSelectBuilder.kt index f3bd3b651..1a1e09bb3 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSelectBuilder.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSelectBuilder.kt @@ -28,7 +28,7 @@ typealias SelectCompleter = KotlinSelectBuilder.() -> Unit class KotlinSelectBuilder(private val fromGatherer: QueryExpressionDSL.FromGatherer) : KotlinBaseJoiningBuilder>(), Buildable { - private lateinit var dsl: QueryExpressionDSL + private var dsl: QueryExpressionDSL? = null fun from(table: SqlTable) { dsl = fromGatherer.from(table) @@ -72,13 +72,7 @@ class KotlinSelectBuilder(private val fromGatherer: QueryExpressionDSL.FromGathe override fun build(): SelectModel = getDsl().build() override fun getDsl(): QueryExpressionDSL { - try { - return dsl - } catch (e: UninitializedPropertyAccessException) { - throw UninitializedPropertyAccessException( - "You must specify a \"from\" clause before any other clauses in a select statement", - e - ) - } + return dsl?: throw KInvalidSQLException( + "You must specify a \"from\" clause before any other clauses in a select statement") } } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt index d57312ab7..3767e7aa8 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinSubQueryBuilders.kt @@ -23,7 +23,7 @@ import org.mybatis.dynamic.sql.util.Buildable @MyBatisDslMarker sealed class KotlinBaseSubQueryBuilder : Buildable { - private lateinit var selectBuilder: KotlinSelectBuilder + private var selectBuilder: KotlinSelectBuilder? = null fun select(vararg selectList: BasicColumn, completer: SelectCompleter): Unit = select(selectList.toList(), completer) @@ -40,13 +40,7 @@ sealed class KotlinBaseSubQueryBuilder : Buildable { } override fun build(): SelectModel = - try { - selectBuilder.build() - } catch (e: UninitializedPropertyAccessException) { - throw UninitializedPropertyAccessException( - "You must specify a select statement", e - ) - } + selectBuilder?.build()?: throw KInvalidSQLException("You must specify a select statement in a sub query") } class KotlinSubQueryBuilder : KotlinBaseSubQueryBuilder() @@ -62,21 +56,14 @@ class KotlinQualifiedSubQueryBuilder : KotlinBaseSubQueryBuilder() { typealias InsertSelectCompleter = KotlinInsertSelectSubQueryBuilder.() -> Unit class KotlinInsertSelectSubQueryBuilder : KotlinBaseSubQueryBuilder() { - private lateinit var lateColumnList: List> + private var columnList: List>? = null - val columnList: List> - get(): List> = - try { - lateColumnList - } catch (e: UninitializedPropertyAccessException) { - throw UninitializedPropertyAccessException( - "You must specify a column list in an insert with select statement", e - ) - } + internal fun columnList(): List> = + columnList?: throw KInvalidSQLException("You must specify a column list in an insert select statement") fun columns(vararg columnList: SqlColumn<*>): Unit = columns(columnList.asList()) fun columns(columnList: List>) { - this.lateColumnList = columnList + this.columnList = columnList } } diff --git a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderFunctions.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderFunctions.kt index bc407605b..263f2f434 100644 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderFunctions.kt +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderFunctions.kt @@ -77,7 +77,7 @@ fun insertMultiple(rows: Collection, completer: KotlinMultiRowInsertCompl fun insertSelect(table: SqlTable, completer: InsertSelectCompleter): InsertSelectModel = with(KotlinInsertSelectSubQueryBuilder().apply(completer)) { SqlBuilder.insertInto(table) - .withColumnList(columnList) + .withColumnList(columnList()) .withSelectStatement(this) .build() } diff --git a/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt index 84e7037f7..6c0da36b4 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt @@ -41,6 +41,7 @@ import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.jupiter.api.Test +import org.mybatis.dynamic.sql.util.kotlin.KInvalidSQLException import org.mybatis.dynamic.sql.util.kotlin.elements.`as` import org.mybatis.dynamic.sql.util.kotlin.elements.count import org.mybatis.dynamic.sql.util.kotlin.elements.insert @@ -656,7 +657,7 @@ class GeneralKotlinTest { @Test fun testRawSelectWithoutFrom() { - assertThatExceptionOfType(UninitializedPropertyAccessException::class.java).isThrownBy { + assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { select(id `as` "A_ID", firstName, lastName, birthDate, employed, occupation, addressId) { where { id isEqualTo 5 } or { @@ -674,7 +675,7 @@ class GeneralKotlinTest { @Test fun testRawCountWithoutFrom() { - assertThatExceptionOfType(UninitializedPropertyAccessException::class.java).isThrownBy { + assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { count(id) { where { id isEqualTo 5 } or { diff --git a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt index 04e987804..7831ec31c 100644 --- a/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt +++ b/src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt @@ -28,14 +28,17 @@ import org.apache.ibatis.session.SqlSession import org.apache.ibatis.session.SqlSessionFactoryBuilder import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.assertj.core.api.Assertions.entry import org.junit.jupiter.api.Test +import org.mybatis.dynamic.sql.util.kotlin.KInvalidSQLException import org.mybatis.dynamic.sql.util.kotlin.elements.equalTo import org.mybatis.dynamic.sql.util.kotlin.elements.qualifiedWith import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select import java.io.InputStreamReader import java.sql.DriverManager +@Suppress("LargeClass") class JoinMapperTest { private fun newSession(): SqlSession { @@ -755,6 +758,22 @@ class JoinMapperTest { } } + @Test + fun testJoinWithNoOnCondition() { + // create second table instance for self-join + val user2 = user.withAlias("other_user") + + assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { + select(user.userId, user.userName, user.parentId) { + from(user, "u1") + join(user2, "u2") { + and(user.userId) equalTo user2.parentId + } + where { user2.userId isEqualTo 4 } + } + }.withMessage("You must specify an \"on\" condition in a join") + } + companion object { const val JDBC_URL = "jdbc:hsqldb:mem:aname" const val JDBC_DRIVER = "org.hsqldb.jdbcDriver" diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt index 5e66b0793..639f42e31 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTest.kt @@ -28,6 +28,7 @@ import examples.kotlin.spring.canonical.PersonDynamicSqlSupport.occupation import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.jupiter.api.Test +import org.mybatis.dynamic.sql.util.kotlin.KInvalidSQLException import org.mybatis.dynamic.sql.util.kotlin.elements.`as` import org.mybatis.dynamic.sql.util.kotlin.elements.add import org.mybatis.dynamic.sql.util.kotlin.elements.constant @@ -546,23 +547,58 @@ open class CanonicalSpringKotlinTest { @Test fun testInsertSelectNoColumns() { - assertThatExceptionOfType(UninitializedPropertyAccessException::class.java).isThrownBy { + assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { insertSelect(person) { select(add(id, constant("100")), firstName, lastName, birthDate, employed, occupation, addressId) { from(person) orderBy(id) } } - }.withMessage("You must specify a column list in an insert with select statement") + }.withMessage("You must specify a column list in an insert select statement") } @Test fun testInsertSelectNoSelectStatement() { - assertThatExceptionOfType(UninitializedPropertyAccessException::class.java).isThrownBy { + assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { insertSelect(person) { columns(id, firstName, lastName, birthDate, employed, occupation, addressId) } - }.withMessage("You must specify a select statement") + }.withMessage("You must specify a select statement in a sub query") + } + + @Test + fun testBatchInsertNoTable() { + val record1 = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) + val record2 = PersonRecord(101, "Sarah", LastName("Smith"), Date(), true, "Architect", 1) + + assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { + insertBatch(listOf(record1, record2)) { + map(person.firstName) toProperty "firstName" + } + }.withMessage("Batch Insert Statements Must Contain an \"into\" phrase.") + } + + @Test + fun testInsertNoTable() { + val record = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) + + assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { + insert(record) { + map(person.firstName) toProperty "firstName" + } + }.withMessage("Insert Statements Must Contain an \"into\" phrase.") + } + + @Test + fun testMultiRowInsertNoTable() { + val record1 = PersonRecord(100, "Joe", LastName("Jones"), Date(), true, "Developer", 1) + val record2 = PersonRecord(101, "Sarah", LastName("Smith"), Date(), true, "Architect", 1) + + assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { + insertMultiple(listOf(record1, record2)) { + map(person.firstName) toProperty "firstName" + } + }.withMessage("Multi Row Insert Statements Must Contain an \"into\" phrase.") } @Test diff --git a/src/test/kotlin/examples/kotlin/spring/canonical/InfixElementsTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/InfixElementsTest.kt index 41296fae6..d0b144ef6 100644 --- a/src/test/kotlin/examples/kotlin/spring/canonical/InfixElementsTest.kt +++ b/src/test/kotlin/examples/kotlin/spring/canonical/InfixElementsTest.kt @@ -24,7 +24,7 @@ import examples.kotlin.spring.canonical.PersonDynamicSqlSupport.lastName import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.jupiter.api.Test -import org.mybatis.dynamic.sql.util.kotlin.DuplicateInitialCriterionException +import org.mybatis.dynamic.sql.util.kotlin.KInvalidSQLException import org.mybatis.dynamic.sql.util.kotlin.elements.isLike import org.mybatis.dynamic.sql.util.kotlin.elements.stringConstant import org.mybatis.dynamic.sql.util.kotlin.elements.upper @@ -960,7 +960,7 @@ open class InfixElementsTest { @Test fun testThatTwoInitialCriteriaThrowsException() { - assertThatExceptionOfType(DuplicateInitialCriterionException::class.java).isThrownBy { + assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy { select(lastName) { from(person) where { From 193b8965324600213bedcd0aab340a309dff2957 Mon Sep 17 00:00:00 2001 From: Jeff Butler Date: Wed, 16 Feb 2022 14:01:41 -0500 Subject: [PATCH 9/9] Add PR to CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97b5379fe..0745ae19d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,7 +43,7 @@ GitHub milestone: [https://github.com/mybatis/mybatis-dynamic-sql/issues?q=miles 7. Updated most of the Kotlin insert DSL functions to be more like natural SQL. The main difference is that for insert, insertBatch, and insertMultiple, the "into" function is moved inside the completer lambda. The old methods are now deprecated and will be removed in version 1.5.0 of the library. This also allowed us to make some insert DSL - methods into infix functions. + methods into infix functions. ([#452](https://github.com/mybatis/mybatis-dynamic-sql/pull/452)) ## Release 1.3.1 - December 18, 2021