diff --git a/CHANGELOG.md b/CHANGELOG.md index ac0bb470a..0745ae19d 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. ([#452](https://github.com/mybatis/mybatis-dynamic-sql/pull/452)) ## Release 1.3.1 - December 18, 2021 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..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. @@ -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/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 new file mode 100644 index 000000000..0f278cd17 --- /dev/null +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBatchInsertBuilder.kt @@ -0,0 +1,51 @@ +/* + * 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.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 var table: SqlTable? = null + private val columnMappings = mutableListOf() + + fun into(table: SqlTable) { + this.table = table + } + + fun map(column: SqlColumn) = MultiRowInsertColumnMapCompleter(column) { + columnMappings.add(it) + } + + override fun build(): BatchInsertModel = + 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/KotlinGeneralInsertBuilder.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinGeneralInsertBuilder.kt new file mode 100644 index 000000000..b7d402bbf --- /dev/null +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinGeneralInsertBuilder.kt @@ -0,0 +1,42 @@ +/* + * 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.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 table: SqlTable) : Buildable { + + private val columnMappings = mutableListOf() + + 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 new file mode 100644 index 000000000..ca2bee86e --- /dev/null +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertBuilder.kt @@ -0,0 +1,51 @@ +/* + * 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.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 var table: SqlTable? = null + private val columnMappings = mutableListOf() + + fun into(table: SqlTable) { + this.table = table + } + + fun map(column: SqlColumn) = SingleRowInsertColumnMapCompleter(column) { + columnMappings.add(it) + } + + override fun build(): InsertModel = + 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/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/KotlinInsertHelpers.kt b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertHelpers.kt deleted file mode 100644 index 3c4331ea0..000000000 --- a/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinInsertHelpers.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.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 { - - fun set(column: SqlColumn): GeneralInsertSetClauseFinisher = GeneralInsertSetClauseFinisher(column) - - 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) - } - } -} 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..71f79f2a7 --- /dev/null +++ b/src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinMultiRowInsertBuilder.kt @@ -0,0 +1,51 @@ +/* + * 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.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 var table: SqlTable? = null + private val columnMappings = mutableListOf() + + fun into(table: SqlTable) { + this.table = table + } + + fun map(column: SqlColumn) = MultiRowInsertColumnMapCompleter(column) { + columnMappings.add(it) + } + + override fun build(): MultiRowInsertModel = + 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 5810225f2..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() @@ -59,22 +53,17 @@ 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/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..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 @@ -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,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 @@ -31,19 +30,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,26 +62,41 @@ 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() + KotlinGeneralInsertBuilder(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) - .withColumnList(columnList) + .withColumnList(columnList()) .withSelectStatement(this) .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..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 @@ -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. @@ -19,25 +19,21 @@ 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 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 +43,7 @@ fun count( ): Long = count(column) { from(table) - completer() + run(completer) }.run(mapper) fun countDistinct( @@ -58,7 +54,7 @@ fun countDistinct( ): Long = countDistinct(column) { from(table) - completer() + run(completer) }.run(mapper) fun countFrom(mapper: (SelectStatementProvider) -> Long, table: SqlTable, completer: CountCompleter): Long = @@ -71,12 +67,12 @@ fun insert( mapper: (InsertStatementProvider) -> Int, row: T, table: SqlTable, - completer: InsertCompleter + completer: KotlinInsertCompleter ): Int = - insert(row).into(table, completer).run(mapper) - -fun BatchInsert.execute(mapper: (InsertStatementProvider) -> Int): List = - insertStatements().map(mapper) + insert(row) { + into(table) + run(completer) + }.run(mapper) /** * This function simply inserts all rows using the supplied mapper. It is up @@ -89,9 +85,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) + }.insertStatements().map(mapper) fun insertInto( mapper: (GeneralInsertStatementProvider) -> Int, @@ -104,17 +103,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 +138,7 @@ fun selectDistinct( ): List = selectDistinct(selectList) { from(table) - completer() + run(completer) }.run(mapper) fun selectList( @@ -144,7 +149,7 @@ fun selectList( ): List = select(selectList) { from(table) - completer() + run(completer) }.run(mapper) fun selectOne( @@ -155,7 +160,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..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 @@ -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.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..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 @@ -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,23 @@ 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 +97,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 +118,23 @@ 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) @@ -131,8 +160,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, @@ -238,12 +267,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 +295,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 +309,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 +326,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 +342,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 +359,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/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" } ``` 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 0556ba7c1..9c594b2d9 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 @@ -82,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) @@ -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 -> 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/mybatis3/general/GeneralKotlinTest.kt b/src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt index 6834f5407..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 @@ -291,7 +292,7 @@ class GeneralKotlinTest { } @Test - fun testInsert() { + fun testDeprecatedInsert() { newSession().use { session -> val mapper = session.getMapper(PersonMapper::class.java) @@ -326,7 +327,7 @@ class GeneralKotlinTest { } @Test - fun testInsertMultiple() { + fun testDeprecatedInsertMultiple() { newSession().use { session -> val mapper = session.getMapper(PersonMapper::class.java) @@ -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/CanonicalSpringKotlinTemplateDirectTest.kt b/src/test/kotlin/examples/kotlin/spring/canonical/CanonicalSpringKotlinTemplateDirectTest.kt index f326ce5dd..90e7fce02 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 { @@ -175,6 +176,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 +227,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 +264,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 +356,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 +396,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..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 @@ -244,7 +245,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 +271,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 +380,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") @@ -372,10 +405,93 @@ open class CanonicalSpringKotlinTest { } @Test - fun testBatchInsert() { + 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 + ) + 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") map(firstName).toProperty("firstName") @@ -431,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 @@ -471,9 +622,10 @@ open class CanonicalSpringKotlinTest { fun testInsertWithGeneratedKey() { val command = GeneratedAlwaysCommand(firstName = "Fred", lastName = "Flintstone") - val insertStatement = insert(command).into(generatedAlways) { - map(generatedAlways.firstName).toProperty("firstName") - map(generatedAlways.lastName).toProperty("lastName") + val insertStatement = insert(command) { + into(generatedAlways) + map(generatedAlways.firstName) toProperty "firstName" + map(generatedAlways.lastName) toProperty "lastName" } val keyHolder = GeneratedKeyHolder() @@ -490,9 +642,10 @@ open class CanonicalSpringKotlinTest { val command1 = GeneratedAlwaysCommand(firstName = "Fred", lastName = "Flintstone") val command2 = GeneratedAlwaysCommand(firstName = "Barney", lastName = "Rubble") - val insertStatement = insertMultiple(command1, command2).into(generatedAlways) { - map(generatedAlways.firstName).toProperty("firstName") - map(generatedAlways.lastName).toProperty("lastName") + val insertStatement = insertMultiple(listOf(command1, command2)) { + into(generatedAlways) + map(generatedAlways.firstName) toProperty "firstName" + map(generatedAlways.lastName) toProperty "lastName" } val keyHolder = GeneratedKeyHolder() 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 {