Skip to content

Commit 66731ee

Browse files
committed
KotlinUpdateBuilder should be composable
Also, add support for Kotlin DSL subqueries in update statements
1 parent fdbcd3f commit 66731ee

File tree

7 files changed

+278
-23
lines changed

7 files changed

+278
-23
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ For example, a typical search can be coded with a query like this (the following
2020

2121
```kotlin
2222
fun search(id: String?, firstName: String?, lastName: String?) =
23-
select(Customer.id, Customer.firstName, Customer.lastName).from(Customer) {
23+
select(Customer.id, Customer.firstName, Customer.lastName) {
24+
from(Customer)
2425
where(Customer.active, isEqualTo(true))
2526
and(Customer.id, isEqualToWhenPresent(id).then{ it?.padStart(5, '0') })
2627
and(Customer.firstName, isLikeCaseInsensitiveWhenPresent(firstName)

src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ import org.mybatis.dynamic.sql.insert.GeneralInsertDSL
2323
import org.mybatis.dynamic.sql.insert.InsertDSL
2424
import org.mybatis.dynamic.sql.insert.MultiRowInsertDSL
2525

26+
/**
27+
* Collection of functions that will create various DSL models in a Kotlin native way.
28+
* They are wrapped in an object as a namespacing technique to avoid collision
29+
* with the similar functions that build providers for the different rendering
30+
* strategies.
31+
*/
2632
object KotlinModelBuilderFunctions {
2733
fun count(column: BasicColumn, completer: CountCompleter) =
2834
completer(KotlinCountBuilder(SqlBuilder.countColumn(column))).build()

src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinUpdateBuilder.kt

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,75 @@
1515
*/
1616
package org.mybatis.dynamic.sql.util.kotlin
1717

18+
import org.mybatis.dynamic.sql.BasicColumn
1819
import org.mybatis.dynamic.sql.SqlColumn
1920
import org.mybatis.dynamic.sql.update.UpdateDSL
2021
import org.mybatis.dynamic.sql.update.UpdateModel
2122
import org.mybatis.dynamic.sql.util.Buildable
2223

23-
typealias UpdateCompleter = KotlinUpdateBuilder.() -> Buildable<UpdateModel>
24+
typealias UpdateCompleter = KotlinUpdateBuilder.() -> KotlinUpdateBuilder
2425

2526
class KotlinUpdateBuilder(private val dsl: UpdateDSL<UpdateModel>) :
2627
KotlinBaseBuilder<UpdateDSL<UpdateModel>.UpdateWhereBuilder, KotlinUpdateBuilder>(), Buildable<UpdateModel> {
2728

28-
fun <T> set(column: SqlColumn<T>): UpdateDSL<UpdateModel>.SetClauseFinisher<T> = dsl.set(column)
29+
fun <T> set(column: SqlColumn<T>) = KotlinSetClauseFinisher(column)
2930

3031
override fun build(): UpdateModel = dsl.build()
3132

3233
override fun getWhere(): UpdateDSL<UpdateModel>.UpdateWhereBuilder = dsl.where()
3334

3435
override fun self() = this
36+
37+
@MyBatisDslMarker
38+
inner class KotlinSetClauseFinisher<T>(private val column: SqlColumn<T>) {
39+
fun equalToNull() =
40+
applyToDsl {
41+
set(column).equalToNull()
42+
}
43+
44+
fun equalToConstant(constant: String) =
45+
applyToDsl {
46+
set(column).equalToConstant(constant)
47+
}
48+
49+
fun equalToStringConstant(constant: String) =
50+
applyToDsl {
51+
set(column).equalToStringConstant(constant)
52+
}
53+
54+
fun equalTo(value: T) =
55+
applyToDsl {
56+
set(column).equalTo(value)
57+
}
58+
59+
fun equalTo(value: () -> T) =
60+
applyToDsl {
61+
set(column).equalTo(value)
62+
}
63+
64+
fun equalTo(rightColumn: BasicColumn) =
65+
applyToDsl {
66+
set(column).equalTo(rightColumn)
67+
}
68+
69+
fun equalToQueryResult(subQuery: KotlinSubQueryBuilder.() -> KotlinSubQueryBuilder) =
70+
applyToDsl {
71+
set(column).equalTo(subQuery(KotlinSubQueryBuilder()).selectBuilder)
72+
}
73+
74+
fun equalToWhenPresent(value: () -> T?) =
75+
applyToDsl {
76+
set(column).equalToWhenPresent(value)
77+
}
78+
79+
fun equalToWhenPresent(value: T?) =
80+
applyToDsl {
81+
set(column).equalToWhenPresent(value)
82+
}
83+
84+
private fun applyToDsl(block: UpdateDSL<UpdateModel>.() -> Unit) =
85+
this@KotlinUpdateBuilder.also {
86+
it.dsl.apply(block)
87+
}
88+
}
3589
}

src/site/markdown/docs/subQueries.md

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
# SubQuery Support
2-
The library currently supports subQueries in the following areas:
1+
# Subquery Support
2+
The library currently supports subqueries in the following areas:
33

44
1. In certain where conditions
55
1. In certain insert statements
6+
1. In update statements
67
1. In the "from" clause of a select statement
78

8-
## SubQueries in Where Conditions
9-
The library support subQueries in the following where conditions:
9+
## Subqueries in Where Conditions
10+
The library support subqueries in the following where conditions:
1011

1112
- isEqualTo
1213
- isNotEqualTo
@@ -33,7 +34,7 @@ SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, bra
3334
```
3435

3536
### Kotlin Support
36-
The library includes Kotlin versions of the where conditions that allow use of the Kotlin subQuery builder. The Kotlin
37+
The library includes Kotlin versions of the where conditions that allow use of the Kotlin subquery builder. The Kotlin
3738
where conditions are in the `org.mybatis.dynamic.sql.util.kotlin` package. An example is as follows:
3839

3940
```kotlin
@@ -47,7 +48,7 @@ val selectStatement = select(id, firstName, lastName, birthDate, employed, occup
4748
}
4849
```
4950

50-
## SubQueries in Insert Statements
51+
## Subqueries in Insert Statements
5152
The library supports an INSERT statement that retrieves values from a SELECT statement. For example:
5253

5354
```java
@@ -64,7 +65,7 @@ InsertSelectStatementProvider insertSelectStatement = insertInto(animalDataCopy)
6465

6566
### Kotlin Support
6667

67-
The library includes a Kotlin builder for subQueries in insert statements that integrates with the select DSL. You
68+
The library includes a Kotlin builder for subqueries in insert statements that integrates with the select DSL. You
6869
can write inserts like this:
6970

7071
```kotlin
@@ -77,9 +78,42 @@ val insertStatement = insertSelect(Person) {
7778
}
7879
```
7980

80-
## SubQueries in a From Clause
81+
## Subqueries in Update Statements
82+
The library supports setting update values based on the results of a subquery. For example:
8183

82-
The library supports subQueries in from clauses and the syntax is a natural extension of the
84+
```java
85+
UpdateStatementProvider updateStatement = update(animalData)
86+
.set(brainWeight).equalTo(
87+
select(avg(brainWeight))
88+
.from(animalData)
89+
.where(brainWeight, isGreaterThan(22.0))
90+
)
91+
.where(brainWeight, isLessThan(1.0))
92+
.build()
93+
.render(RenderingStrategies.MYBATIS3);
94+
```
95+
96+
### Kotlin Support
97+
The library includes a Kotlin builder for subqueries in update statements that integrates
98+
with the select DSL. You can write subqueries like this:
99+
100+
```kotlin
101+
val updateStatement = update(Person) {
102+
set(addressId).equalToQueryResult {
103+
select(add(max(addressId), constant<Int>("1"))) {
104+
from(Person)
105+
}
106+
}
107+
where(id, isEqualTo(3))
108+
}
109+
```
110+
111+
Note the Kotlin method name is `set(xxx).equalToQueryResult(...)` - this is to avoid a collison with
112+
other methods in the update DSL.
113+
114+
## Subqueries in a From Clause
115+
116+
The library supports subqueries in from clauses and the syntax is a natural extension of the
83117
select DSL. An example is as follows:
84118

85119
```java
@@ -102,7 +136,7 @@ SelectStatementProvider selectStatement =
102136
Notice the use of a `DerivedColumn` to easily specify a function like `rownum()` that can be
103137
used both in the select list and in a where condition.
104138

105-
### Table Qualifiers with SubQueries
139+
### Table Qualifiers with Subqueries
106140

107141
The library attempts to automatically calculate table qualifiers. If a table qualifier is specified,
108142
the library will automatically render the table qualifier on all columns associated with the
@@ -128,12 +162,12 @@ Notice that the table qualifier `ad` is automatically applied to columns in the
128162
In the case of join queries the table qualifier specified, or if not specified the table name
129163
itself, will be used as the table qualifier.
130164

131-
With subQueries, it is important to understand the limits of automatic table qualifiers. The rules are
165+
With subqueries, it is important to understand the limits of automatic table qualifiers. The rules are
132166
as follows:
133167

134-
1. The scope of automatic table qualifiers is limited to a single select statement. For subQueries, the outer
135-
query has a different scope than the subQuery.
136-
1. A qualifier can be applied to a subQuery as a whole, but that qualifier is not automatically applied to
168+
1. The scope of automatic table qualifiers is limited to a single select statement. For subqueries, the outer
169+
query has a different scope than the subquery.
170+
1. A qualifier can be applied to a subquery as a whole, but that qualifier is not automatically applied to
137171
any column
138172

139173
As an example, consider the following query:
@@ -168,10 +202,10 @@ where rownum() < #{parameters.p2}
168202
and animal_name like #{parameters.p3}
169203
```
170204

171-
Notice that the qualifier `a` is automatically applied to columns in the subQuery and that the
205+
Notice that the qualifier `a` is automatically applied to columns in the subquery and that the
172206
qualifier `b` is not applied anywhere.
173207

174-
If your query requires the subQuery qualifier to be applied to columns in the outer select list,
208+
If your query requires the subquery qualifier to be applied to columns in the outer select list,
175209
you can manually apply the qualifier to columns as follows:
176210

177211
```java
@@ -207,7 +241,7 @@ where rownum() < #{parameters.p2}
207241

208242
### Kotlin Support
209243

210-
The library includes a Kotlin builder for subQueries that integrates with the select DSL. You
244+
The library includes a Kotlin builder for subqueries that integrates with the select DSL. You
211245
can write queries like this:
212246

213247
```kotlin
@@ -225,7 +259,7 @@ val selectStatement =
225259
}
226260
```
227261

228-
The same rules about table qualifiers apply as stated above. In Kotlin, a subQuery qualifier
262+
The same rules about table qualifiers apply as stated above. In Kotlin, a subquery qualifier
229263
can be added with the overloaded "+" operator as shown below:
230264

231265
```kotlin
@@ -245,4 +279,4 @@ val selectStatement =
245279
```
246280

247281
In this case the `a` qualifier is used in the context of the inner select statement and
248-
the `b` qualifier is applied to the subQuery as a whole.
282+
the `b` qualifier is applied to the subquery as a whole.

0 commit comments

Comments
 (0)