Skip to content

[Kotlin] Improve insert select #524

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ For examples of global and statement configuration, see the "Configuration of th
page for details. ([#515](https://github.com/mybatis/mybatis-dynamic-sql/pull/515))
5. Added several checks for invalid SQL ([#516](https://github.com/mybatis/mybatis-dynamic-sql/pull/516))
6. Added documentation for the various exceptions thrown by the library ([#517](https://github.com/mybatis/mybatis-dynamic-sql/pull/517))
7. Update the "insertSelect" method in the Kotlin DSL to make it consistent with the other insert methods ([#524](https://github.com/mybatis/mybatis-dynamic-sql/pull/524))

## Release 1.4.0 - March 3, 2022

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ package org.mybatis.dynamic.sql.util.kotlin
import org.mybatis.dynamic.sql.BasicColumn
import org.mybatis.dynamic.sql.SqlBuilder
import org.mybatis.dynamic.sql.SqlColumn
import org.mybatis.dynamic.sql.SqlTable
import org.mybatis.dynamic.sql.insert.InsertSelectModel
import org.mybatis.dynamic.sql.select.SelectModel
import org.mybatis.dynamic.sql.util.Buildable
import org.mybatis.dynamic.sql.util.Messages

@MyBatisDslMarker
sealed class KotlinBaseSubQueryBuilder : Buildable<SelectModel> {
sealed class KotlinBaseSubQueryBuilder {
private var selectBuilder: KotlinSelectBuilder? = null

fun select(vararg selectList: BasicColumn, completer: SelectCompleter): Unit =
Expand All @@ -40,28 +42,54 @@ sealed class KotlinBaseSubQueryBuilder : Buildable<SelectModel> {
selectBuilder = KotlinSelectBuilder(SqlBuilder.selectDistinct(selectList)).apply(completer)
}

override fun build(): SelectModel =
internal fun buildSelectModel(): SelectModel =
selectBuilder?.build()?: throw KInvalidSQLException(Messages.getString("ERROR.28")) //$NON-NLS-1$
}

class KotlinSubQueryBuilder : KotlinBaseSubQueryBuilder()
class KotlinSubQueryBuilder : KotlinBaseSubQueryBuilder(), Buildable<SelectModel> {
override fun build(): SelectModel = buildSelectModel()
}

class KotlinQualifiedSubQueryBuilder : KotlinBaseSubQueryBuilder() {
class KotlinQualifiedSubQueryBuilder : KotlinBaseSubQueryBuilder(), Buildable<SelectModel> {
var correlationName: String? = null

operator fun String.unaryPlus() {
correlationName = this
}

override fun build(): SelectModel = buildSelectModel()
}

typealias InsertSelectCompleter = KotlinInsertSelectSubQueryBuilder.() -> Unit

class KotlinInsertSelectSubQueryBuilder : KotlinBaseSubQueryBuilder() {
internal var columnList: List<SqlColumn<*>>? = null
class KotlinInsertSelectSubQueryBuilder : KotlinBaseSubQueryBuilder(), Buildable<InsertSelectModel> {
private var columnList: List<SqlColumn<*>>? = null
private var table: SqlTable? = null

fun into(table: SqlTable) {
this.table = table
}

fun columns(vararg columnList: SqlColumn<*>): Unit = columns(columnList.asList())

fun columns(columnList: List<SqlColumn<*>>) {
this.columnList = columnList
}

override fun build(): InsertSelectModel {
if (table == null) {
throw KInvalidSQLException(Messages.getString("ERROR.29")) //$NON-NLS-1$
}

return if (columnList == null) {
SqlBuilder.insertInto(table)
.withSelectStatement { buildSelectModel() }
.build()
} else {
SqlBuilder.insertInto(table)
.withColumnList(columnList)
.withSelectStatement { buildSelectModel() }
.build()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,17 @@ fun insertInto(table: SqlTable, completer: GeneralInsertCompleter): GeneralInser
fun <T : Any> insertMultiple(rows: Collection<T>, completer: KotlinMultiRowInsertCompleter<T>): MultiRowInsertModel<T> =
KotlinMultiRowInsertBuilder(rows).apply(completer).build()

@Deprecated("Please use the new form - move the table into the lambda with into(table)")
fun insertSelect(table: SqlTable, completer: InsertSelectCompleter): InsertSelectModel =
with(KotlinInsertSelectSubQueryBuilder().apply(completer)) {
if (columnList == null) {
SqlBuilder.insertInto(table)
.withSelectStatement(this)
.build()
} else {
SqlBuilder.insertInto(table)
.withColumnList(columnList)
.withSelectStatement(this)
.build()
}
with(KotlinInsertSelectSubQueryBuilder()) {
into(table)
apply(completer)
build()
}

fun insertSelect(completer: InsertSelectCompleter): InsertSelectModel =
KotlinInsertSelectSubQueryBuilder().apply(completer).build()

@Deprecated("Please switch to the insertBatch statement in the model package")
fun <T> BatchInsertDSL.IntoGatherer<T>.into(
table: SqlTable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,10 @@ fun insertSelect(
table: SqlTable,
completer: InsertSelectCompleter
): Int =
insertSelect(table, completer).run(mapper)
insertSelect {
into(table)
run(completer)
}.run(mapper)

fun <T> selectDistinct(
mapper: (SelectStatementProvider) -> List<T>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,13 @@ fun <T : Any> insertMultiple(
): MultiRowInsertStatementProvider<T> =
insertMultiple(rows, completer).render(RenderingStrategies.MYBATIS3)

@Deprecated("Please use the new form - move the table into the lambda with into(table)")
fun insertSelect(table: SqlTable, completer: InsertSelectCompleter): InsertSelectStatementProvider =
insertSelect(table, completer).render(RenderingStrategies.MYBATIS3)

fun insertSelect(completer: InsertSelectCompleter): InsertSelectStatementProvider =
insertSelect(completer).render(RenderingStrategies.MYBATIS3)

@Deprecated("Please switch to the insertBatch statement in the mybatis3 package")
fun <T> BatchInsertDSL.IntoGatherer<T>.into(table: SqlTable, completer: BatchInsertDSL<T>.() -> Unit): BatchInsert<T> =
into(table, completer).render(RenderingStrategies.MYBATIS3)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,13 @@ fun <T> NamedParameterJdbcTemplate.insertMultiple(
): Int =
update(insertStatement.insertStatement, BeanPropertySqlParameterSource(insertStatement), keyHolder)

@Deprecated("Please use the new form - move the table into the lambda with into(table)")
fun NamedParameterJdbcTemplate.insertSelect(table: SqlTable, completer: InsertSelectCompleter): Int =
insertSelect(org.mybatis.dynamic.sql.util.kotlin.spring.insertSelect(table, completer))

fun NamedParameterJdbcTemplate.insertSelect(completer: InsertSelectCompleter): Int =
insertSelect(org.mybatis.dynamic.sql.util.kotlin.spring.insertSelect(completer))

fun NamedParameterJdbcTemplate.insertSelect(insertStatement: InsertSelectStatementProvider): Int =
update(insertStatement.insertStatement, MapSqlParameterSource(insertStatement.parameters))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,13 @@ fun <T : Any> insertMultiple(
): MultiRowInsertStatementProvider<T> =
insertMultiple(rows, completer).render(RenderingStrategies.SPRING_NAMED_PARAMETER)

@Deprecated("Please use the new form - move the table into the lambda with into(table)")
fun insertSelect(table: SqlTable, completer: InsertSelectCompleter): InsertSelectStatementProvider =
insertSelect(table, completer).render(RenderingStrategies.SPRING_NAMED_PARAMETER)

fun insertSelect(completer: InsertSelectCompleter): InsertSelectStatementProvider =
insertSelect(completer).render(RenderingStrategies.SPRING_NAMED_PARAMETER)

@Deprecated("Please switch to the insertBatch statement in the spring package")
fun <T> BatchInsertDSL.IntoGatherer<T>.into(table: SqlTable, completer: BatchInsertDSL<T>.() -> Unit): BatchInsert<T> =
into(table, completer).render(RenderingStrategies.SPRING_NAMED_PARAMETER)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ ERROR.25=Insert Statements Must Contain an "into" phrase
ERROR.26=Multiple Row Insert Statements Must Contain an "into" phrase
ERROR.27=You must specify a "from" clause before any other clauses in a select statement
ERROR.28=You must specify a select statement in a sub query
ERROR.29=Insert Select Statements Must Contain an "into" phrase
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import org.mybatis.dynamic.sql.util.kotlin.elements.add
import org.mybatis.dynamic.sql.util.kotlin.elements.constant
import org.mybatis.dynamic.sql.util.kotlin.elements.isIn
import org.mybatis.dynamic.sql.util.kotlin.mybatis3.insertInto
import org.mybatis.dynamic.sql.util.kotlin.mybatis3.insertSelect
import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select
import java.io.InputStreamReader
import java.sql.DriverManager
Expand Down Expand Up @@ -258,6 +259,32 @@ class PersonMapperTest {
}
}

@Test
fun testDeprecatedInsertSelect() {
newSession().use { session ->
val mapper = session.getMapper(PersonMapper::class.java)

val insertStatement = insertSelect(person) {
columns(id, firstName, lastName, employed, occupation, addressId, birthDate)
select(add(id, constant<Int>("100")), firstName, lastName, employed, occupation, addressId, birthDate) {
from(person)
orderBy(id)
}
}

val expected = "insert into Person " +
"(id, first_name, last_name, employed, occupation, address_id, birth_date) " +
"select (id + 100), first_name, last_name, employed, occupation, address_id, birth_date " +
"from Person order by id"

assertThat(insertStatement.insertStatement).isEqualTo(expected)

val rows = mapper.insertSelect(insertStatement)

assertThat(rows).isEqualTo(6)
}
}

@Test
fun testInsertBatch() {
newSession(ExecutorType.BATCH).use { session ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,39 @@ open class CanonicalSpringKotlinTemplateDirectTest {

@Test
fun testInsertSelect() {
val rows = template.insertSelect {
into(person)
columns(id, firstName, lastName, birthDate, employed, occupation, addressId)
select(
add(id, constant<Int>("100")), firstName, lastName, birthDate, employed, occupation, addressId
) {
from(person)
orderBy(id)
}
}

assertThat(rows).isEqualTo(6)

val records = template.select(id, firstName, lastName, birthDate, employed, occupation, addressId) {
from(person)
where { id isGreaterThanOrEqualTo 100 }
orderBy(id)
}.withRowMapper(personRowMapper)

assertThat(records).hasSize(6)
with(records[1]) {
assertThat(id).isEqualTo(102)
assertThat(firstName).isEqualTo("Wilma")
assertThat(lastName).isEqualTo(LastName("Flintstone"))
assertThat(birthDate).isNotNull
assertThat(employed).isTrue
assertThat(occupation).isEqualTo("Accountant")
assertThat(addressId).isEqualTo(1)
}
}

@Test
fun testDeprecatedInsertSelect() {
val rows = template.insertSelect(person) {
columns(id, firstName, lastName, birthDate, employed, occupation, addressId)
select(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,8 @@ open class CanonicalSpringKotlinTest {

@Test
fun testInsertSelect() {
val insertStatement = insertSelect(person) {
val insertStatement = insertSelect {
into(person)
columns(id, firstName, lastName, birthDate, employed, occupation, addressId)
select(add(id, constant<Int>("100")), firstName, lastName, birthDate, employed, occupation, addressId) {
from(person)
Expand Down Expand Up @@ -547,6 +548,56 @@ open class CanonicalSpringKotlinTest {
}
}

@Test
fun testInsertSelectNoTable() {
assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy {
insertSelect {
columns(id, firstName, lastName, birthDate, employed, occupation, addressId)
select(add(id, constant<Int>("100")), firstName, lastName, birthDate, employed, occupation, addressId) {
from(person)
orderBy(id)
}
}
}.withMessage(Messages.getString("ERROR.29"))
}

@Test
fun testDeprecatedInsertSelect() {
val insertStatement = insertSelect(person) {
columns(id, firstName, lastName, birthDate, employed, occupation, addressId)
select(add(id, constant<Int>("100")), firstName, lastName, birthDate, employed, occupation, addressId) {
from(person)
orderBy(id)
}
}

assertThat(insertStatement.insertStatement).isEqualTo(
"insert into Person (id, first_name, last_name, birth_date, employed, occupation, address_id) " +
"select (id + 100), first_name, last_name, birth_date, employed, occupation, address_id " +
"from Person " +
"order by id"
)
val rows = template.insertSelect(insertStatement)
assertThat(rows).isEqualTo(6)

val records = template.select(id, firstName, lastName, birthDate, employed, occupation, addressId) {
from(person)
where { id isGreaterThanOrEqualTo 100 }
orderBy(id)
}.withRowMapper(personRowMapper)

assertThat(records).hasSize(6)
with(records[1]) {
assertThat(id).isEqualTo(102)
assertThat(firstName).isEqualTo("Wilma")
assertThat(lastName).isEqualTo(LastName("Flintstone"))
assertThat(birthDate).isNotNull
assertThat(employed).isTrue
assertThat(occupation).isEqualTo("Accountant")
assertThat(addressId).isEqualTo(1)
}
}

@Test
fun testInsertSelectNoColumns() {
val insertStatement = insertSelect(person) {
Expand Down