Skip to content

Commit 45bcf1a

Browse files
committed
Remove some obscure coding and standardize on a common exception
KInvalidSQLException will now be thrown from any misuse of the Kotlin DSL
1 parent cddbccd commit 45bcf1a

15 files changed

+132
-91
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ class GroupingCriteriaCollector {
4747
internal var initialCriterion: SqlCriterion? = null
4848
private set(value) {
4949
if (field != null) {
50-
throw DuplicateInitialCriterionException()
50+
throw KInvalidSQLException("Setting more than one initial criterion is not allowed. " +
51+
"Additional criteria should be added with \"and\" or \"or\" expression")
5152
}
5253
field = value
5354
}

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ typealias JoinReceiver = JoinCollector.() -> Unit
2424

2525
@MyBatisDslMarker
2626
class JoinCollector {
27-
val onJoinCriterion: JoinCriterion by lazy { internalOnCriterion }
28-
val andJoinCriteria = mutableListOf<JoinCriterion>()
29-
private lateinit var internalOnCriterion: JoinCriterion
27+
private var onJoinCriterion: JoinCriterion? = null
28+
internal val andJoinCriteria = mutableListOf<JoinCriterion>()
29+
30+
internal fun onJoinCriterion() : JoinCriterion =
31+
onJoinCriterion?: throw KInvalidSQLException("You must specify an \"on\" condition in a join")
3032

3133
fun on(leftColumn: BasicColumn): RightColumnCollector = RightColumnCollector {
32-
internalOnCriterion = JoinCriterion.Builder()
34+
onJoinCriterion = JoinCriterion.Builder()
3335
.withConnector("on")
3436
.withJoinColumn(leftColumn)
3537
.withJoinCondition(it)
@@ -48,7 +50,7 @@ class JoinCollector {
4850

4951
@Deprecated("Please use: on(leftColumn) equalTo rightColumn")
5052
fun on(column: BasicColumn, condition: JoinCondition) {
51-
internalOnCriterion = JoinCriterion.Builder()
53+
onJoinCriterion = JoinCriterion.Builder()
5254
.withConnector("on")
5355
.withJoinColumn(column)
5456
.withJoinCondition(condition)
Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@
1616
package org.mybatis.dynamic.sql.util.kotlin
1717

1818
/**
19-
* This exception is thrown when a where clause contains more than one criterion and there
20-
* is not an "and" or an "or" to connect them.
21-
*
22-
* @since 1.4.0
19+
* This exception is thrown if the library detects misuse of the Kotlin DSL that would result in invalid SQL
2320
*/
24-
class DuplicateInitialCriterionException : RuntimeException(
25-
"Setting more than one initial criterion is not allowed. " +
26-
"Additional criteria should be added with \"and\" or \"or\" expression")
21+
class KInvalidSQLException(message: String) : RuntimeException(message)

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -180,74 +180,74 @@ abstract class KotlinBaseJoiningBuilder<D : AbstractQueryExpressionDSL<*, *>> :
180180

181181
fun join(table: SqlTable, joinCriteria: JoinReceiver): Unit =
182182
applyToDsl(joinCriteria) { jc ->
183-
join(table, jc.onJoinCriterion, jc.andJoinCriteria)
183+
join(table, jc.onJoinCriterion(), jc.andJoinCriteria)
184184
}
185185

186186
fun join(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit =
187187
applyToDsl(joinCriteria) { jc ->
188-
join(table, alias, jc.onJoinCriterion, jc.andJoinCriteria)
188+
join(table, alias, jc.onJoinCriterion(), jc.andJoinCriteria)
189189
}
190190

191191
fun join(
192192
subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit,
193193
joinCriteria: JoinReceiver
194194
): Unit =
195195
applyToDsl(subQuery, joinCriteria) { sq, jc ->
196-
join(sq, sq.correlationName, jc.onJoinCriterion, jc.andJoinCriteria)
196+
join(sq, sq.correlationName, jc.onJoinCriterion(), jc.andJoinCriteria)
197197
}
198198

199199
fun fullJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit =
200200
applyToDsl(joinCriteria) { jc ->
201-
fullJoin(table, jc.onJoinCriterion, jc.andJoinCriteria)
201+
fullJoin(table, jc.onJoinCriterion(), jc.andJoinCriteria)
202202
}
203203

204204
fun fullJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit =
205205
applyToDsl(joinCriteria) { jc ->
206-
fullJoin(table, alias, jc.onJoinCriterion, jc.andJoinCriteria)
206+
fullJoin(table, alias, jc.onJoinCriterion(), jc.andJoinCriteria)
207207
}
208208

209209
fun fullJoin(
210210
subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit,
211211
joinCriteria: JoinReceiver
212212
): Unit =
213213
applyToDsl(subQuery, joinCriteria) { sq, jc ->
214-
fullJoin(sq, sq.correlationName, jc.onJoinCriterion, jc.andJoinCriteria)
214+
fullJoin(sq, sq.correlationName, jc.onJoinCriterion(), jc.andJoinCriteria)
215215
}
216216

217217
fun leftJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit =
218218
applyToDsl(joinCriteria) { jc ->
219-
leftJoin(table, jc.onJoinCriterion, jc.andJoinCriteria)
219+
leftJoin(table, jc.onJoinCriterion(), jc.andJoinCriteria)
220220
}
221221

222222
fun leftJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit =
223223
applyToDsl(joinCriteria) { jc ->
224-
leftJoin(table, alias, jc.onJoinCriterion, jc.andJoinCriteria)
224+
leftJoin(table, alias, jc.onJoinCriterion(), jc.andJoinCriteria)
225225
}
226226

227227
fun leftJoin(
228228
subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit,
229229
joinCriteria: JoinReceiver
230230
): Unit =
231231
applyToDsl(subQuery, joinCriteria) { sq, jc ->
232-
leftJoin(sq, sq.correlationName, jc.onJoinCriterion, jc.andJoinCriteria)
232+
leftJoin(sq, sq.correlationName, jc.onJoinCriterion(), jc.andJoinCriteria)
233233
}
234234

235235
fun rightJoin(table: SqlTable, joinCriteria: JoinReceiver): Unit =
236236
applyToDsl(joinCriteria) { jc ->
237-
rightJoin(table, jc.onJoinCriterion, jc.andJoinCriteria)
237+
rightJoin(table, jc.onJoinCriterion(), jc.andJoinCriteria)
238238
}
239239

240240
fun rightJoin(table: SqlTable, alias: String, joinCriteria: JoinReceiver): Unit =
241241
applyToDsl(joinCriteria) { jc ->
242-
rightJoin(table, alias, jc.onJoinCriterion, jc.andJoinCriteria)
242+
rightJoin(table, alias, jc.onJoinCriterion(), jc.andJoinCriteria)
243243
}
244244

245245
fun rightJoin(
246246
subQuery: KotlinQualifiedSubQueryBuilder.() -> Unit,
247247
joinCriteria: JoinReceiver
248248
): Unit =
249249
applyToDsl(subQuery, joinCriteria) { sq, jc ->
250-
rightJoin(sq, sq.correlationName, jc.onJoinCriterion, jc.andJoinCriteria)
250+
rightJoin(sq, sq.correlationName, jc.onJoinCriterion(), jc.andJoinCriteria)
251251
}
252252

253253
private fun applyToDsl(joinCriteria: JoinReceiver, applyJoin: D.(JoinCollector) -> Unit) {

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,14 @@ class KotlinBatchInsertBuilder<T> (private val rows: Collection<T>): Buildable<B
3838
}
3939

4040
override fun build(): BatchInsertModel<T> =
41-
with(BatchInsertDSL.Builder<T>()) {
42-
withRecords(rows)
43-
withTable(table)
44-
withColumnMappings(columnMappings)
45-
build()
46-
}.build()
41+
if (table == null) {
42+
throw KInvalidSQLException("Batch Insert Statements Must Contain an \"into\" phrase.")
43+
} else {
44+
with(BatchInsertDSL.Builder<T>()) {
45+
withRecords(rows)
46+
withTable(table)
47+
withColumnMappings(columnMappings)
48+
build()
49+
}.build()
50+
}
4751
}

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

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class KotlinCountBuilder(private val fromGatherer: CountDSL.FromGatherer<SelectM
2626
KotlinBaseJoiningBuilder<CountDSL<SelectModel>>(),
2727
Buildable<SelectModel> {
2828

29-
private lateinit var dsl: CountDSL<SelectModel>
29+
private var dsl: CountDSL<SelectModel>? = null
3030

3131
fun from(table: SqlTable): KotlinCountBuilder =
3232
apply {
@@ -35,13 +35,7 @@ class KotlinCountBuilder(private val fromGatherer: CountDSL.FromGatherer<SelectM
3535

3636
override fun build(): SelectModel = getDsl().build()
3737

38-
override fun getDsl(): CountDSL<SelectModel> {
39-
try {
40-
return dsl
41-
} catch (e: UninitializedPropertyAccessException) {
42-
throw UninitializedPropertyAccessException(
43-
"You must specify a \"from\" clause before any other clauses in a count statement", e
44-
)
45-
}
46-
}
38+
override fun getDsl(): CountDSL<SelectModel> =
39+
dsl?: throw KInvalidSQLException(
40+
"You must specify a \"from\" clause before any other clauses in a count statement")
4741
}

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,22 @@ class KotlinInsertBuilder<T> (private val row: T): Buildable<InsertModel<T>> {
3030
private val columnMappings = mutableListOf<AbstractColumnMapping>()
3131

3232
fun into(table: SqlTable) {
33-
this.table = table;
33+
this.table = table
3434
}
3535

3636
fun <C : Any> map(column: SqlColumn<C>) = SingleRowInsertColumnMapCompleter(column) {
3737
columnMappings.add(it)
3838
}
3939

4040
override fun build(): InsertModel<T> =
41-
with(InsertDSL.Builder<T>()) {
42-
withRow(row)
43-
withTable(table)
44-
withColumnMappings(columnMappings)
45-
build()
46-
}.build()
41+
if (table == null) {
42+
throw KInvalidSQLException("Insert Statements Must Contain an \"into\" phrase.")
43+
} else {
44+
with(InsertDSL.Builder<T>()) {
45+
withRow(row)
46+
withTable(table)
47+
withColumnMappings(columnMappings)
48+
build()
49+
}.build()
50+
}
4751
}

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,14 @@ class KotlinMultiRowInsertBuilder<T> (private val rows: Collection<T>): Buildabl
3838
}
3939

4040
override fun build(): MultiRowInsertModel<T> =
41-
with(MultiRowInsertDSL.Builder<T>()) {
42-
withRecords(rows)
43-
withTable(table)
44-
withColumnMappings(columnMappings)
45-
build()
46-
}.build()
41+
if (table == null) {
42+
throw KInvalidSQLException("Multi Row Insert Statements Must Contain an \"into\" phrase.")
43+
} else {
44+
with(MultiRowInsertDSL.Builder<T>()) {
45+
withRecords(rows)
46+
withTable(table)
47+
withColumnMappings(columnMappings)
48+
build()
49+
}.build()
50+
}
4751
}

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

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ typealias SelectCompleter = KotlinSelectBuilder.() -> Unit
2828
class KotlinSelectBuilder(private val fromGatherer: QueryExpressionDSL.FromGatherer<SelectModel>) :
2929
KotlinBaseJoiningBuilder<QueryExpressionDSL<SelectModel>>(), Buildable<SelectModel> {
3030

31-
private lateinit var dsl: QueryExpressionDSL<SelectModel>
31+
private var dsl: QueryExpressionDSL<SelectModel>? = null
3232

3333
fun from(table: SqlTable) {
3434
dsl = fromGatherer.from(table)
@@ -72,13 +72,7 @@ class KotlinSelectBuilder(private val fromGatherer: QueryExpressionDSL.FromGathe
7272
override fun build(): SelectModel = getDsl().build()
7373

7474
override fun getDsl(): QueryExpressionDSL<SelectModel> {
75-
try {
76-
return dsl
77-
} catch (e: UninitializedPropertyAccessException) {
78-
throw UninitializedPropertyAccessException(
79-
"You must specify a \"from\" clause before any other clauses in a select statement",
80-
e
81-
)
82-
}
75+
return dsl?: throw KInvalidSQLException(
76+
"You must specify a \"from\" clause before any other clauses in a select statement")
8377
}
8478
}

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

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import org.mybatis.dynamic.sql.util.Buildable
2323

2424
@MyBatisDslMarker
2525
sealed class KotlinBaseSubQueryBuilder : Buildable<SelectModel> {
26-
private lateinit var selectBuilder: KotlinSelectBuilder
26+
private var selectBuilder: KotlinSelectBuilder? = null
2727

2828
fun select(vararg selectList: BasicColumn, completer: SelectCompleter): Unit =
2929
select(selectList.toList(), completer)
@@ -40,13 +40,7 @@ sealed class KotlinBaseSubQueryBuilder : Buildable<SelectModel> {
4040
}
4141

4242
override fun build(): SelectModel =
43-
try {
44-
selectBuilder.build()
45-
} catch (e: UninitializedPropertyAccessException) {
46-
throw UninitializedPropertyAccessException(
47-
"You must specify a select statement", e
48-
)
49-
}
43+
selectBuilder?.build()?: throw KInvalidSQLException("You must specify a select statement in a sub query")
5044
}
5145

5246
class KotlinSubQueryBuilder : KotlinBaseSubQueryBuilder()
@@ -62,21 +56,14 @@ class KotlinQualifiedSubQueryBuilder : KotlinBaseSubQueryBuilder() {
6256
typealias InsertSelectCompleter = KotlinInsertSelectSubQueryBuilder.() -> Unit
6357

6458
class KotlinInsertSelectSubQueryBuilder : KotlinBaseSubQueryBuilder() {
65-
private lateinit var lateColumnList: List<SqlColumn<*>>
59+
private var columnList: List<SqlColumn<*>>? = null
6660

67-
val columnList: List<SqlColumn<*>>
68-
get(): List<SqlColumn<*>> =
69-
try {
70-
lateColumnList
71-
} catch (e: UninitializedPropertyAccessException) {
72-
throw UninitializedPropertyAccessException(
73-
"You must specify a column list in an insert with select statement", e
74-
)
75-
}
61+
internal fun columnList(): List<SqlColumn<*>> =
62+
columnList?: throw KInvalidSQLException("You must specify a column list in an insert select statement")
7663

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

7966
fun columns(columnList: List<SqlColumn<*>>) {
80-
this.lateColumnList = columnList
67+
this.columnList = columnList
8168
}
8269
}

src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/model/ModelBuilderFunctions.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ fun <T> insertMultiple(rows: Collection<T>, completer: KotlinMultiRowInsertCompl
7777
fun insertSelect(table: SqlTable, completer: InsertSelectCompleter): InsertSelectModel =
7878
with(KotlinInsertSelectSubQueryBuilder().apply(completer)) {
7979
SqlBuilder.insertInto(table)
80-
.withColumnList(columnList)
80+
.withColumnList(columnList())
8181
.withSelectStatement(this)
8282
.build()
8383
}

src/test/kotlin/examples/kotlin/mybatis3/general/GeneralKotlinTest.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory
4141
import org.assertj.core.api.Assertions.assertThat
4242
import org.assertj.core.api.Assertions.assertThatExceptionOfType
4343
import org.junit.jupiter.api.Test
44+
import org.mybatis.dynamic.sql.util.kotlin.KInvalidSQLException
4445
import org.mybatis.dynamic.sql.util.kotlin.elements.`as`
4546
import org.mybatis.dynamic.sql.util.kotlin.elements.count
4647
import org.mybatis.dynamic.sql.util.kotlin.elements.insert
@@ -656,7 +657,7 @@ class GeneralKotlinTest {
656657

657658
@Test
658659
fun testRawSelectWithoutFrom() {
659-
assertThatExceptionOfType(UninitializedPropertyAccessException::class.java).isThrownBy {
660+
assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy {
660661
select(id `as` "A_ID", firstName, lastName, birthDate, employed, occupation, addressId) {
661662
where { id isEqualTo 5 }
662663
or {
@@ -674,7 +675,7 @@ class GeneralKotlinTest {
674675

675676
@Test
676677
fun testRawCountWithoutFrom() {
677-
assertThatExceptionOfType(UninitializedPropertyAccessException::class.java).isThrownBy {
678+
assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy {
678679
count(id) {
679680
where { id isEqualTo 5 }
680681
or {

src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,17 @@ import org.apache.ibatis.session.SqlSession
2828
import org.apache.ibatis.session.SqlSessionFactoryBuilder
2929
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory
3030
import org.assertj.core.api.Assertions.assertThat
31+
import org.assertj.core.api.Assertions.assertThatExceptionOfType
3132
import org.assertj.core.api.Assertions.entry
3233
import org.junit.jupiter.api.Test
34+
import org.mybatis.dynamic.sql.util.kotlin.KInvalidSQLException
3335
import org.mybatis.dynamic.sql.util.kotlin.elements.equalTo
3436
import org.mybatis.dynamic.sql.util.kotlin.elements.qualifiedWith
3537
import org.mybatis.dynamic.sql.util.kotlin.mybatis3.select
3638
import java.io.InputStreamReader
3739
import java.sql.DriverManager
3840

41+
@Suppress("LargeClass")
3942
class JoinMapperTest {
4043

4144
private fun newSession(): SqlSession {
@@ -755,6 +758,22 @@ class JoinMapperTest {
755758
}
756759
}
757760

761+
@Test
762+
fun testJoinWithNoOnCondition() {
763+
// create second table instance for self-join
764+
val user2 = user.withAlias("other_user")
765+
766+
assertThatExceptionOfType(KInvalidSQLException::class.java).isThrownBy {
767+
select(user.userId, user.userName, user.parentId) {
768+
from(user, "u1")
769+
join(user2, "u2") {
770+
and(user.userId) equalTo user2.parentId
771+
}
772+
where { user2.userId isEqualTo 4 }
773+
}
774+
}.withMessage("You must specify an \"on\" condition in a join")
775+
}
776+
758777
companion object {
759778
const val JDBC_URL = "jdbc:hsqldb:mem:aname"
760779
const val JDBC_DRIVER = "org.hsqldb.jdbcDriver"

0 commit comments

Comments
 (0)