Skip to content

Commit 9b8c5eb

Browse files
authored
Merge pull request #119 from jeffgbutler/new-style-by-example
New Utility Functions for *ByExample Support
2 parents b79c092 + e70ab37 commit 9b8c5eb

File tree

10 files changed

+943
-20
lines changed

10 files changed

+943
-20
lines changed

CHANGELOG.md

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

55
## Release 1.1.3 - Unreleased
66

7-
GitHub milestone: [https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.1.2+](https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.1.3+)
7+
GitHub milestone: [https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.1.3+](https://github.com/mybatis/mybatis-dynamic-sql/issues?q=milestone%3A1.1.3+)
88

99
### Added
1010

11-
- Added support for `count(distinct ...)` [#112](https://github.com/mybatis/mybatis-dynamic-sql/issues/112)
12-
- Added support for multiple row inserts [#116](https://github.com/mybatis/mybatis-dynamic-sql/issues/116)
11+
- Added support for `count(distinct ...)` ([#112](https://github.com/mybatis/mybatis-dynamic-sql/issues/112))
12+
- Added support for multiple row inserts ([#116](https://github.com/mybatis/mybatis-dynamic-sql/issues/116))
13+
- Added utility functions to support better *ByExample methods ([#118](https://github.com/mybatis/mybatis-dynamic-sql/issues/118))
1314

1415

1516
## Release 1.1.2 - July 5, 2019
@@ -18,12 +19,12 @@ GitHub milestone: [https://github.com/mybatis/mybatis-dynamic-sql/issues?q=miles
1819

1920
### Added
2021

21-
- Changed the public SQLBuilder API to accept Collection instead of List for in conditions and batch record inserts. This should have no impact on existing code, but allow for some future flexibility [#88](https://github.com/mybatis/mybatis-dynamic-sql/pull/88)
22-
- Added the ability have have table catalog and/or schema calculated at query runtime. This is useful for situations where there are different database schemas for different environments, or in some sharding situations [#92](https://github.com/mybatis/mybatis-dynamic-sql/pull/92)
23-
- Add support for paging queries with "offset" and "fetch first" - this seems to be standard on most databases [#96](https://github.com/mybatis/mybatis-dynamic-sql/pull/96)
24-
- Added the ability to call a builder method on any intermediate object in a select statement and receive a fully rendered statement. This makes it easier to build very dynamic queries [#106](https://github.com/mybatis/mybatis-dynamic-sql/pull/106)
25-
- Add the ability to modify values on any condition before they are placed in the parameter map [#105](https://github.com/mybatis/mybatis-dynamic-sql/issues/105)
26-
- Add the ability to call `where()` with no parameters. This aids in constructing very dynamic queries [#107](https://github.com/mybatis/mybatis-dynamic-sql/issues/107)
22+
- Changed the public SQLBuilder API to accept Collection instead of List for in conditions and batch record inserts. This should have no impact on existing code, but allow for some future flexibility ([#88](https://github.com/mybatis/mybatis-dynamic-sql/pull/88))
23+
- Added the ability have have table catalog and/or schema calculated at query runtime. This is useful for situations where there are different database schemas for different environments, or in some sharding situations ([#92](https://github.com/mybatis/mybatis-dynamic-sql/pull/92))
24+
- Add support for paging queries with "offset" and "fetch first" - this seems to be standard on most databases ([#96](https://github.com/mybatis/mybatis-dynamic-sql/pull/96))
25+
- Added the ability to call a builder method on any intermediate object in a select statement and receive a fully rendered statement. This makes it easier to build very dynamic queries ([#106](https://github.com/mybatis/mybatis-dynamic-sql/pull/106))
26+
- Add the ability to modify values on any condition before they are placed in the parameter map ([#105](https://github.com/mybatis/mybatis-dynamic-sql/issues/105))
27+
- Add the ability to call `where()` with no parameters. This aids in constructing very dynamic queries ([#107](https://github.com/mybatis/mybatis-dynamic-sql/issues/107))
2728

2829

2930
## Release 1.1.1 - April 7, 2019

src/main/java/org/mybatis/dynamic/sql/delete/DeleteDSL.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323
import org.mybatis.dynamic.sql.SqlTable;
2424
import org.mybatis.dynamic.sql.VisitableCondition;
2525
import org.mybatis.dynamic.sql.delete.render.DeleteStatementProvider;
26+
import org.mybatis.dynamic.sql.util.Buildable;
2627
import org.mybatis.dynamic.sql.where.AbstractWhereDSL;
2728

28-
public class DeleteDSL<R> {
29+
public class DeleteDSL<R> implements Buildable<R> {
2930

3031
private Function<DeleteModel, R> adapterFunction;
3132
private SqlTable table;
@@ -54,6 +55,7 @@ public <T> DeleteWhereBuilder where(BindableColumn<T> column, VisitableCondition
5455
*
5556
* @return the model class
5657
*/
58+
@Override
5759
public R build() {
5860
DeleteModel deleteModel = DeleteModel.withTable(table).build();
5961
return adapterFunction.apply(deleteModel);
@@ -72,7 +74,7 @@ public static <T> DeleteDSL<MyBatis3DeleteModelAdapter<T>> deleteFromWithMapper(
7274
return deleteFrom(deleteModel -> MyBatis3DeleteModelAdapter.of(deleteModel, mapperMethod), table);
7375
}
7476

75-
public class DeleteWhereBuilder extends AbstractWhereDSL<DeleteWhereBuilder> {
77+
public class DeleteWhereBuilder extends AbstractWhereDSL<DeleteWhereBuilder> implements Buildable<R> {
7678

7779
private <T> DeleteWhereBuilder() {
7880
super();
@@ -87,6 +89,7 @@ private <T> DeleteWhereBuilder(BindableColumn<T> column, VisitableCondition<T> c
8789
super(column, condition, subCriteria);
8890
}
8991

92+
@Override
9093
public R build() {
9194
DeleteModel deleteModel = DeleteModel.withTable(table)
9295
.withWhereModel(buildWhereModel())

src/main/java/org/mybatis/dynamic/sql/update/UpdateDSL.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
import org.mybatis.dynamic.sql.util.ValueMapping;
4040
import org.mybatis.dynamic.sql.where.AbstractWhereDSL;
4141

42-
public class UpdateDSL<R> {
42+
public class UpdateDSL<R> implements Buildable<R> {
4343

4444
private Function<UpdateModel, R> adapterFunction;
4545
private List<UpdateMapping> columnMappings = new ArrayList<>();
@@ -73,6 +73,7 @@ public <T> UpdateWhereBuilder where(BindableColumn<T> column, VisitableCondition
7373
*
7474
* @return the update model
7575
*/
76+
@Override
7677
public R build() {
7778
UpdateModel updateModel = UpdateModel.withTable(table)
7879
.withColumnMappings(columnMappings)
@@ -147,7 +148,7 @@ public UpdateDSL<R> equalToWhenPresent(Supplier<T> valueSupplier) {
147148
}
148149
}
149150

150-
public class UpdateWhereBuilder extends AbstractWhereDSL<UpdateWhereBuilder> {
151+
public class UpdateWhereBuilder extends AbstractWhereDSL<UpdateWhereBuilder> implements Buildable<R> {
151152

152153
public <T> UpdateWhereBuilder() {
153154
super();
@@ -162,6 +163,7 @@ public <T> UpdateWhereBuilder(BindableColumn<T> column, VisitableCondition<T> co
162163
super(column, condition, subCriteria);
163164
}
164165

166+
@Override
165167
public R build() {
166168
UpdateModel updateModel = UpdateModel.withTable(table)
167169
.withColumnMappings(columnMappings)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* Copyright 2016-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.mybatis.dynamic.sql.util.mybatis3;
17+
18+
import java.util.function.Function;
19+
20+
import org.mybatis.dynamic.sql.select.MyBatis3SelectModelAdapter;
21+
import org.mybatis.dynamic.sql.select.QueryExpressionDSL;
22+
import org.mybatis.dynamic.sql.util.Buildable;
23+
24+
/**
25+
* Represents a function that can be used to create a "CountByExample" method in the style
26+
* of MyBatis Generator. When using this function, you can create a method that does not require a user to
27+
* call the build().execute() methods - making client code look a bit cleaner.
28+
*
29+
* <p>For example, you can create mapper interface methods like this:
30+
*
31+
* <pre>
32+
* &#64;SelectProvider(type=SqlProviderAdapter.class, method="select")
33+
* long count(SelectStatementProvider selectStatement);
34+
*
35+
* default long countByExample(MyBatis3CountByExampleHelper helper) {
36+
* return helper.apply(SelectDSL.selectWithMapper(this::count, SqlBuilder.count())
37+
* .from(simpleTable))
38+
* .build()
39+
* .execute();
40+
* }
41+
* </pre>
42+
*
43+
* <p>And then call the simplified default method like this:
44+
*
45+
* <pre>
46+
* long rows = mapper.countByExample(q -&gt;
47+
* q.where(occupation, isNull()));
48+
* </pre>
49+
*
50+
* <p>You can also do a "count all" with the following code:
51+
*
52+
* <pre>
53+
* long rows = mapper.countByExample(q -&gt; q);
54+
* </pre>
55+
*
56+
* @author Jeff Butler
57+
*/
58+
@FunctionalInterface
59+
public interface MyBatis3CountByExampleHelper extends
60+
Function<QueryExpressionDSL<MyBatis3SelectModelAdapter<Long>>, Buildable<MyBatis3SelectModelAdapter<Long>>> {
61+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* Copyright 2016-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.mybatis.dynamic.sql.util.mybatis3;
17+
18+
import java.util.function.Function;
19+
20+
import org.mybatis.dynamic.sql.delete.DeleteDSL;
21+
import org.mybatis.dynamic.sql.delete.MyBatis3DeleteModelAdapter;
22+
import org.mybatis.dynamic.sql.util.Buildable;
23+
24+
/**
25+
* Represents a function that can be used to create a "DeleteByExample" method in the style
26+
* of MyBatis Generator. When using this function, you can create a method that does not require a user to
27+
* call the build().execute() methods - making client code look a bit cleaner.
28+
*
29+
* <p>For example, you can create mapper interface methods like this:
30+
*
31+
* <pre>
32+
* &#64;DeleteProvider(type=SqlProviderAdapter.class, method="delete")
33+
* int delete(DeleteStatementProvider deleteStatement);
34+
*
35+
* default int deleteByExample(MyBatis3DeleteByExampleHelper helper) {
36+
* return helper.apply(DeleteDSL.deleteFromWithMapper(this::delete, simpleTable))
37+
* .build()
38+
* .execute();
39+
* }
40+
* </pre>
41+
*
42+
* <p>And then call the simplified default method like this:
43+
*
44+
* <pre>
45+
* int rows = mapper.deleteByExample(q -&gt;
46+
* q.where(occupation, isNull()));
47+
* </pre>
48+
*
49+
* <p>You can also do a "delete all" with the following code:
50+
*
51+
* <pre>
52+
* int rows = mapper.deleteByExample(q -&gt; q);
53+
* </pre>
54+
*
55+
* @author Jeff Butler
56+
*/
57+
@FunctionalInterface
58+
public interface MyBatis3DeleteByExampleHelper extends
59+
Function<DeleteDSL<MyBatis3DeleteModelAdapter<Integer>>, Buildable<MyBatis3DeleteModelAdapter<Integer>>> {
60+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Copyright 2016-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.mybatis.dynamic.sql.util.mybatis3;
17+
18+
import java.util.List;
19+
import java.util.function.Function;
20+
21+
import org.mybatis.dynamic.sql.select.MyBatis3SelectModelAdapter;
22+
import org.mybatis.dynamic.sql.select.QueryExpressionDSL;
23+
import org.mybatis.dynamic.sql.util.Buildable;
24+
25+
/**
26+
* Represents a function that can be used to create a "SelectByExample" method in the style
27+
* of MyBatis Generator. When using this function, you can create a method that does not require a user to
28+
* call the build().execute() methods - making client code look a bit cleaner.
29+
*
30+
* <p>For example, you can create mapper interface methods like this:
31+
*
32+
* <pre>
33+
* &#64;SelectProvider(type=SqlProviderAdapter.class, method="select")
34+
* &#64;Results(id="SimpleTableResult", value= {
35+
* &#64;Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
36+
* &#64;Result(column="first_name", property="firstName", jdbcType=JdbcType.VARCHAR),
37+
* &#64;Result(column="last_name", property="lastName", jdbcType=JdbcType.VARCHAR),
38+
* &#64;Result(column="birth_date", property="birthDate", jdbcType=JdbcType.DATE),
39+
* &#64;Result(column="employed", property="employed", jdbcType=JdbcType.VARCHAR),
40+
* &#64;Result(column="occupation", property="occupation", jdbcType=JdbcType.VARCHAR)
41+
* })
42+
* List&lt;SimpleRecord&gt; selectMany(SelectStatementProvider selectStatement);
43+
*
44+
* default List&lt;SimpleRecord&gt; selectByExample(MyBatis3SelectByExampleHelper&lt;SimpleRecord&gt; helper) {
45+
* return helper.apply(SelectDSL.selectWithMapper(this::selectMany, simpleTable.allColumns())
46+
* .from(simpleTable))
47+
* .build()
48+
* .execute();
49+
* }
50+
* </pre>
51+
*
52+
* <p>And then call the simplified default method like this:
53+
*
54+
* <pre>
55+
* List&lt;SimpleRecord&gt; rows = mapper.selectByExample(q -&gt;
56+
* q.where(id, isEqualTo(1))
57+
* .or(occupation, isNull()));
58+
* </pre>
59+
*
60+
* <p>You can also do a "select all" with the following code:
61+
*
62+
* <pre>
63+
* List&lt;SimpleRecord&gt; rows = mapper.selectByExample(q -&gt; q);
64+
* </pre>
65+
*
66+
* @author Jeff Butler
67+
*/
68+
@FunctionalInterface
69+
public interface MyBatis3SelectByExampleHelper<T> extends
70+
Function<QueryExpressionDSL<MyBatis3SelectModelAdapter<List<T>>>,
71+
Buildable<MyBatis3SelectModelAdapter<List<T>>>> {
72+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* Copyright 2016-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.mybatis.dynamic.sql.util.mybatis3;
17+
18+
import java.util.function.Function;
19+
20+
import org.mybatis.dynamic.sql.update.MyBatis3UpdateModelAdapter;
21+
import org.mybatis.dynamic.sql.update.UpdateDSL;
22+
import org.mybatis.dynamic.sql.util.Buildable;
23+
24+
/**
25+
* Represents a function that can be used to create an "UpdateByExample" method in the style
26+
* of MyBatis Generator. When using this function, you can create a method that does not require a user to
27+
* call the build().execute() methods - making client code look a bit cleaner.
28+
*
29+
* <p>For example, you can create mapper interface methods like this:
30+
*
31+
* <pre>
32+
* &#64;UpdateProvider(type=SqlProviderAdapter.class, method="update")
33+
* int update(UpdateStatementProvider updateStatement);
34+
*
35+
* default int updateByExampleSelective(SimpleTableRecord record, MyBatis3UpdateByExampleHelper helper) {
36+
* return helper.apply(UpdateDSL.updateWithMapper(this::update, simpleTable)
37+
* .set(id).equalToWhenPresent(record.getId())
38+
* .set(firstName).equalToWhenPresent(record::getFirstName)
39+
* .set(lastName).equalToWhenPresent(record::getLastName)
40+
* .set(birthDate).equalToWhenPresent(record::getBirthDate)
41+
* .set(employed).equalToWhenPresent(record::getEmployed)
42+
* .set(occupation).equalToWhenPresent(record::getOccupation))
43+
* .build()
44+
* .execute();
45+
* }
46+
* </pre>
47+
*
48+
* <p>And then call the simplified default method like this:
49+
*
50+
* <pre>
51+
* int rows = mapper.updateByExampleSelective(record, q -&gt;
52+
* q.where(id, isEqualTo(100))
53+
* .and(firstName, isEqualTo("Joe")));
54+
* </pre>
55+
*
56+
* <p>You can also do an "update all" with the following code:
57+
*
58+
* <pre>
59+
* int rows = mapper.updateByExampleSelective(record, q -&gt; q);
60+
* </pre>
61+
*
62+
* @author Jeff Butler
63+
*/
64+
@FunctionalInterface
65+
public interface MyBatis3UpdateByExampleHelper extends
66+
Function<UpdateDSL<MyBatis3UpdateModelAdapter<Integer>>, Buildable<MyBatis3UpdateModelAdapter<Integer>>> {
67+
}

0 commit comments

Comments
 (0)