Skip to content

Commit cab7f18

Browse files
authored
Merge pull request #452 from jeffgbutler/insert-builders
[Kotlin] Improve Insert DSL
2 parents 15d63c0 + 193b896 commit cab7f18

36 files changed

+1173
-432
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ This log will detail notable changes to MyBatis Dynamic SQL. Full details are av
44

55
## Release 1.4.0 - Unreleased
66

7+
The release includes new function in the Where Clause DSL to support arbitrary grouping of conditions, and also use
8+
of a "not" condition. It should now be possible to write any type of where clause.
9+
10+
Additionally, there were significant updates to the Kotlin DSL - both to support the new functionality in the
11+
where clause, and significant updates to insert statements. There were also many minor updates in Kotlin
12+
to make more use of Kotlin language features like infix functions and operator overloads.
13+
714
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+)
815

916
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
3340
([#446](https://github.com/mybatis/mybatis-dynamic-sql/pull/446))
3441
6. Minor update the Kotlin join DSL to make it closer to natural SQL. The existing join methods are deprecated and
3542
will be removed in version 1.5.0. ([#447](https://github.com/mybatis/mybatis-dynamic-sql/pull/447))
43+
7. Updated most of the Kotlin insert DSL functions to be more like natural SQL. The main difference is that for insert,
44+
insertBatch, and insertMultiple, the "into" function is moved inside the completer lambda. The old methods are now
45+
deprecated and will be removed in version 1.5.0 of the library. This also allowed us to make some insert DSL
46+
methods into infix functions. ([#452](https://github.com/mybatis/mybatis-dynamic-sql/pull/452))
3647

3748
## Release 1.3.1 - December 18, 2021
3849

src/main/java/org/mybatis/dynamic/sql/insert/BatchInsertDSL.java

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2020 the original author or authors.
2+
* Copyright 2016-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
1919
import java.util.Arrays;
2020
import java.util.Collection;
2121
import java.util.List;
22+
import java.util.Objects;
2223

2324
import org.jetbrains.annotations.NotNull;
2425
import org.mybatis.dynamic.sql.SqlColumn;
@@ -34,11 +35,12 @@ public class BatchInsertDSL<T> implements Buildable<BatchInsertModel<T>> {
3435

3536
private final Collection<T> records;
3637
private final SqlTable table;
37-
private final List<AbstractColumnMapping> columnMappings = new ArrayList<>();
38+
private final List<AbstractColumnMapping> columnMappings;
3839

39-
private BatchInsertDSL(Collection<T> records, SqlTable table) {
40-
this.records = records;
41-
this.table = table;
40+
private BatchInsertDSL(AbstractBuilder<T, ?> builder) {
41+
this.records = builder.records;
42+
this.table = Objects.requireNonNull(builder.table);
43+
this.columnMappings = builder.columnMappings;
4244
}
4345

4446
public <F> ColumnMappingFinisher<F> map(SqlColumn<F> column) {
@@ -71,7 +73,7 @@ private IntoGatherer(Collection<T> records) {
7173
}
7274

7375
public BatchInsertDSL<T> into(SqlTable table) {
74-
return new BatchInsertDSL<>(records, table);
76+
return new Builder<T>().withRecords(records).withTable(table).build();
7577
}
7678
}
7779

@@ -102,4 +104,38 @@ public BatchInsertDSL<T> toStringConstant(String constant) {
102104
return BatchInsertDSL.this;
103105
}
104106
}
107+
108+
public abstract static class AbstractBuilder<T, B extends AbstractBuilder<T, B>> {
109+
final Collection<T> records = new ArrayList<>();
110+
SqlTable table;
111+
final List<AbstractColumnMapping> columnMappings = new ArrayList<>();
112+
113+
public B withRecords(Collection<T> records) {
114+
this.records.addAll(records);
115+
return getThis();
116+
}
117+
118+
public B withTable(SqlTable table) {
119+
this.table = table;
120+
return getThis();
121+
}
122+
123+
public B withColumnMappings(Collection<AbstractColumnMapping> columnMappings) {
124+
this.columnMappings.addAll(columnMappings);
125+
return getThis();
126+
}
127+
128+
protected abstract B getThis();
129+
}
130+
131+
public static class Builder<T> extends AbstractBuilder<T, Builder<T>> {
132+
@Override
133+
protected Builder<T> getThis() {
134+
return this;
135+
}
136+
137+
public BatchInsertDSL<T> build() {
138+
return new BatchInsertDSL<>(this);
139+
}
140+
}
105141
}

src/main/java/org/mybatis/dynamic/sql/insert/GeneralInsertDSL.java

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2021 the original author or authors.
2+
* Copyright 2016-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616
package org.mybatis.dynamic.sql.insert;
1717

1818
import java.util.ArrayList;
19+
import java.util.Collection;
1920
import java.util.List;
2021
import java.util.Objects;
2122
import java.util.function.Supplier;
@@ -33,11 +34,12 @@
3334
import org.mybatis.dynamic.sql.util.ValueWhenPresentMapping;
3435

3536
public class GeneralInsertDSL implements Buildable<GeneralInsertModel> {
36-
private final List<AbstractColumnMapping> insertMappings = new ArrayList<>();
37+
private final List<AbstractColumnMapping> columnMappings;
3738
private final SqlTable table;
3839

39-
private GeneralInsertDSL(SqlTable table) {
40-
this.table = Objects.requireNonNull(table);
40+
private GeneralInsertDSL(Builder builder) {
41+
table = Objects.requireNonNull(builder.table);
42+
columnMappings = builder.columnMappings;
4143
}
4244

4345
public <T> SetClauseFinisher<T> set(SqlColumn<T> column) {
@@ -49,12 +51,12 @@ public <T> SetClauseFinisher<T> set(SqlColumn<T> column) {
4951
public GeneralInsertModel build() {
5052
return new GeneralInsertModel.Builder()
5153
.withTable(table)
52-
.withInsertMappings(insertMappings)
54+
.withInsertMappings(columnMappings)
5355
.build();
5456
}
5557

5658
public static GeneralInsertDSL insertInto(SqlTable table) {
57-
return new GeneralInsertDSL(table);
59+
return new GeneralInsertDSL.Builder().withTable(table).build();
5860
}
5961

6062
public class SetClauseFinisher<T> {
@@ -66,17 +68,17 @@ public SetClauseFinisher(SqlColumn<T> column) {
6668
}
6769

6870
public GeneralInsertDSL toNull() {
69-
insertMappings.add(NullMapping.of(column));
71+
columnMappings.add(NullMapping.of(column));
7072
return GeneralInsertDSL.this;
7173
}
7274

7375
public GeneralInsertDSL toConstant(String constant) {
74-
insertMappings.add(ConstantMapping.of(column, constant));
76+
columnMappings.add(ConstantMapping.of(column, constant));
7577
return GeneralInsertDSL.this;
7678
}
7779

7880
public GeneralInsertDSL toStringConstant(String constant) {
79-
insertMappings.add(StringConstantMapping.of(column, constant));
81+
columnMappings.add(StringConstantMapping.of(column, constant));
8082
return GeneralInsertDSL.this;
8183
}
8284

@@ -85,7 +87,7 @@ public GeneralInsertDSL toValue(T value) {
8587
}
8688

8789
public GeneralInsertDSL toValue(Supplier<T> valueSupplier) {
88-
insertMappings.add(ValueMapping.of(column, valueSupplier));
90+
columnMappings.add(ValueMapping.of(column, valueSupplier));
8991
return GeneralInsertDSL.this;
9092
}
9193

@@ -94,7 +96,7 @@ public GeneralInsertDSL toValueOrNull(T value) {
9496
}
9597

9698
public GeneralInsertDSL toValueOrNull(Supplier<T> valueSupplier) {
97-
insertMappings.add(ValueOrNullMapping.of(column, valueSupplier));
99+
columnMappings.add(ValueOrNullMapping.of(column, valueSupplier));
98100
return GeneralInsertDSL.this;
99101
}
100102

@@ -103,8 +105,27 @@ public GeneralInsertDSL toValueWhenPresent(T value) {
103105
}
104106

105107
public GeneralInsertDSL toValueWhenPresent(Supplier<T> valueSupplier) {
106-
insertMappings.add(ValueWhenPresentMapping.of(column, valueSupplier));
108+
columnMappings.add(ValueWhenPresentMapping.of(column, valueSupplier));
107109
return GeneralInsertDSL.this;
108110
}
109111
}
112+
113+
public static class Builder {
114+
private final List<AbstractColumnMapping> columnMappings = new ArrayList<>();
115+
private SqlTable table;
116+
117+
public Builder withTable(SqlTable table) {
118+
this.table = table;
119+
return this;
120+
}
121+
122+
public Builder withColumnMappings(Collection<AbstractColumnMapping> columnMappings) {
123+
this.columnMappings.addAll(columnMappings);
124+
return this;
125+
}
126+
127+
public GeneralInsertDSL build() {
128+
return new GeneralInsertDSL(this);
129+
}
130+
}
110131
}

src/main/java/org/mybatis/dynamic/sql/insert/InsertDSL.java

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2021 the original author or authors.
2+
* Copyright 2016-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,7 +16,9 @@
1616
package org.mybatis.dynamic.sql.insert;
1717

1818
import java.util.ArrayList;
19+
import java.util.Collection;
1920
import java.util.List;
21+
import java.util.Objects;
2022
import java.util.function.Supplier;
2123

2224
import org.jetbrains.annotations.NotNull;
@@ -34,11 +36,12 @@ public class InsertDSL<T> implements Buildable<InsertModel<T>> {
3436

3537
private final T row;
3638
private final SqlTable table;
37-
private final List<AbstractColumnMapping> columnMappings = new ArrayList<>();
39+
private final List<AbstractColumnMapping> columnMappings;
3840

39-
private InsertDSL(T row, SqlTable table) {
40-
this.row = row;
41-
this.table = table;
41+
private InsertDSL(Builder<T> builder) {
42+
this.row = Objects.requireNonNull(builder.row);
43+
this.table = Objects.requireNonNull(builder.table);
44+
columnMappings = builder.columnMappings;
4245
}
4346

4447
public <F> ColumnMappingFinisher<F> map(SqlColumn<F> column) {
@@ -66,7 +69,7 @@ private IntoGatherer(T row) {
6669
}
6770

6871
public InsertDSL<T> into(SqlTable table) {
69-
return new InsertDSL<>(row, table);
72+
return new InsertDSL.Builder<T>().withRow(row).withTable(table).build();
7073
}
7174
}
7275

@@ -102,4 +105,29 @@ public InsertDSL<T> toStringConstant(String constant) {
102105
return InsertDSL.this;
103106
}
104107
}
108+
109+
public static class Builder<T> {
110+
private T row;
111+
private SqlTable table;
112+
private final List<AbstractColumnMapping> columnMappings = new ArrayList<>();
113+
114+
public Builder<T> withRow(T row) {
115+
this.row = row;
116+
return this;
117+
}
118+
119+
public Builder<T> withTable(SqlTable table) {
120+
this.table = table;
121+
return this;
122+
}
123+
124+
public Builder<T> withColumnMappings(Collection<AbstractColumnMapping> columnMappings) {
125+
this.columnMappings.addAll(columnMappings);
126+
return this;
127+
}
128+
129+
public InsertDSL<T> build() {
130+
return new InsertDSL<>(this);
131+
}
132+
}
105133
}

src/main/java/org/mybatis/dynamic/sql/insert/MultiRowInsertDSL.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2020 the original author or authors.
2+
* Copyright 2016-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,10 +15,10 @@
1515
*/
1616
package org.mybatis.dynamic.sql.insert;
1717

18-
import java.util.ArrayList;
1918
import java.util.Arrays;
2019
import java.util.Collection;
2120
import java.util.List;
21+
import java.util.Objects;
2222

2323
import org.jetbrains.annotations.NotNull;
2424
import org.mybatis.dynamic.sql.SqlColumn;
@@ -34,11 +34,12 @@ public class MultiRowInsertDSL<T> implements Buildable<MultiRowInsertModel<T>> {
3434

3535
private final Collection<T> records;
3636
private final SqlTable table;
37-
private final List<AbstractColumnMapping> columnMappings = new ArrayList<>();
37+
private final List<AbstractColumnMapping> columnMappings;
3838

39-
private MultiRowInsertDSL(Collection<T> records, SqlTable table) {
40-
this.records = records;
41-
this.table = table;
39+
private MultiRowInsertDSL(BatchInsertDSL.AbstractBuilder<T, ?> builder) {
40+
this.records = builder.records;
41+
this.table = Objects.requireNonNull(builder.table);
42+
this.columnMappings = builder.columnMappings;
4243
}
4344

4445
public <F> ColumnMappingFinisher<F> map(SqlColumn<F> column) {
@@ -71,7 +72,7 @@ private IntoGatherer(Collection<T> records) {
7172
}
7273

7374
public MultiRowInsertDSL<T> into(SqlTable table) {
74-
return new MultiRowInsertDSL<>(records, table);
75+
return new Builder<T>().withRecords(records).withTable(table).build();
7576
}
7677
}
7778

@@ -102,4 +103,16 @@ public MultiRowInsertDSL<T> toStringConstant(String constant) {
102103
return MultiRowInsertDSL.this;
103104
}
104105
}
106+
107+
public static class Builder<T> extends BatchInsertDSL.AbstractBuilder<T, Builder<T>> {
108+
109+
@Override
110+
protected Builder<T> getThis() {
111+
return this;
112+
}
113+
114+
public MultiRowInsertDSL<T> build() {
115+
return new MultiRowInsertDSL<>(this);
116+
}
117+
}
105118
}

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)

0 commit comments

Comments
 (0)