Skip to content

Commit 7836e10

Browse files
committed
Merge branch 'master' into reusable-where-clauses-v2
2 parents 09ffcdf + 4d1957d commit 7836e10

File tree

20 files changed

+1115
-78
lines changed

20 files changed

+1115
-78
lines changed

.mvn/wrapper/maven-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@
1414
# KIND, either express or implied. See the License for the
1515
# specific language governing permissions and limitations
1616
# under the License.
17-
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
17+
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.0/apache-maven-3.9.0-bin.zip
1818
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ functions in the Kotlin DSL still only apply to the where clause.
3535

3636
The pull request for this change is ([#550](https://github.com/mybatis/mybatis-dynamic-sql/pull/550))
3737

38+
### Multi-Select Queries
39+
40+
A multi-select query is a special case of a union select statement. The difference is that it allows "order by" and
41+
paging clauses to be applied to the nested queries.
42+
43+
The pull request for this change is ([#591](https://github.com/mybatis/mybatis-dynamic-sql/pull/591))
44+
3845
### Other Changes
3946

4047
1. Added support for specifying "limit" and "order by" on the DELETE and UPDATE statements. Not all databases support

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,15 @@
5353

5454
<properties>
5555
<junit.jupiter.version>5.9.2</junit.jupiter.version>
56-
<spring.batch.version>4.3.7</spring.batch.version>
56+
<spring.batch.version>4.3.8</spring.batch.version>
5757

5858
<checkstyle.config>checkstyle-override.xml</checkstyle.config>
5959

6060
<clirr.comparisonVersion>1.2.0</clirr.comparisonVersion>
6161

6262
<module.name>org.mybatis.dynamic.sql</module.name>
6363

64-
<kotlin.version>1.8.0</kotlin.version>
64+
<kotlin.version>1.8.10</kotlin.version>
6565
<kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget>
6666

6767
<sonar.sources>pom.xml,src/main/java,src/main/kotlin</sonar.sources>
@@ -313,7 +313,7 @@
313313
<dependency>
314314
<groupId>org.postgresql</groupId>
315315
<artifactId>postgresql</artifactId>
316-
<version>42.5.2</version>
316+
<version>42.5.4</version>
317317
<scope>test</scope>
318318
</dependency>
319319
<dependency>

src/main/java/org/mybatis/dynamic/sql/SqlBuilder.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.mybatis.dynamic.sql.insert.MultiRowInsertDSL;
3131
import org.mybatis.dynamic.sql.select.ColumnSortSpecification;
3232
import org.mybatis.dynamic.sql.select.CountDSL;
33+
import org.mybatis.dynamic.sql.select.MultiSelectDSL;
3334
import org.mybatis.dynamic.sql.select.QueryExpressionDSL.FromGatherer;
3435
import org.mybatis.dynamic.sql.select.SelectDSL;
3536
import org.mybatis.dynamic.sql.select.SelectModel;
@@ -227,6 +228,10 @@ static FromGatherer<SelectModel> selectDistinct(Collection<BasicColumn> selectLi
227228
return SelectDSL.selectDistinct(selectList);
228229
}
229230

231+
static MultiSelectDSL multiSelect(Buildable<SelectModel> selectModelBuilder) {
232+
return new MultiSelectDSL(selectModelBuilder);
233+
}
234+
230235
static UpdateDSL<UpdateModel> update(SqlTable table) {
231236
return UpdateDSL.update(table);
232237
}
@@ -496,8 +501,8 @@ static <T> Subtract<T> subtract(BindableColumn<T> firstColumn, BasicColumn secon
496501
* @param firstColumn first column
497502
* @param secondColumn second column
498503
* @param subsequentColumns subsequent columns
499-
* @return a Concatenate instance
500504
* @param <T> type of column
505+
* @return a Concatenate instance
501506
*/
502507
static <T> Concatenate<T> concatenate(BindableColumn<T> firstColumn, BasicColumn secondColumn,
503508
BasicColumn... subsequentColumns) {
@@ -510,8 +515,8 @@ static <T> Concatenate<T> concatenate(BindableColumn<T> firstColumn, BasicColumn
510515
*
511516
* @param firstColumn first column
512517
* @param subsequentColumns subsequent columns
513-
* @return a Concat instance
514518
* @param <T> type of column
519+
* @return a Concat instance
515520
*/
516521
static <T> Concat<T> concat(BindableColumn<T> firstColumn, BasicColumn... subsequentColumns) {
517522
return Concat.concat(firstColumn, subsequentColumns);
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
* Copyright 2016-2023 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+
* https://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.select;
17+
18+
import java.util.ArrayList;
19+
import java.util.Arrays;
20+
import java.util.Collection;
21+
import java.util.List;
22+
23+
import org.jetbrains.annotations.NotNull;
24+
import org.mybatis.dynamic.sql.SortSpecification;
25+
import org.mybatis.dynamic.sql.common.OrderByModel;
26+
import org.mybatis.dynamic.sql.util.Buildable;
27+
28+
public class MultiSelectDSL implements Buildable<MultiSelectModel> {
29+
private final List<UnionQuery> unionQueries = new ArrayList<>();
30+
private final SelectModel initialSelect;
31+
private OrderByModel orderByModel;
32+
private Long limit;
33+
private Long offset;
34+
private Long fetchFirstRows;
35+
36+
public MultiSelectDSL(Buildable<SelectModel> builder) {
37+
initialSelect = builder.build();
38+
}
39+
40+
public MultiSelectDSL union(Buildable<SelectModel> builder) {
41+
unionQueries.add(new UnionQuery("union", builder.build())); //$NON-NLS-1$
42+
return this;
43+
}
44+
45+
public MultiSelectDSL unionAll(Buildable<SelectModel> builder) {
46+
unionQueries.add(new UnionQuery("union all", builder.build())); //$NON-NLS-1$
47+
return this;
48+
}
49+
50+
public MultiSelectDSL orderBy(SortSpecification... columns) {
51+
return orderBy(Arrays.asList(columns));
52+
}
53+
54+
public MultiSelectDSL orderBy(Collection<SortSpecification> columns) {
55+
orderByModel = OrderByModel.of(columns);
56+
return this;
57+
}
58+
59+
public LimitFinisher limit(long limit) {
60+
this.limit = limit;
61+
return new LimitFinisher();
62+
}
63+
64+
public OffsetFirstFinisher offset(long offset) {
65+
this.offset = offset;
66+
return new OffsetFirstFinisher();
67+
}
68+
69+
public FetchFirstFinisher fetchFirst(long fetchFirstRows) {
70+
this.fetchFirstRows = fetchFirstRows;
71+
return new FetchFirstFinisher();
72+
}
73+
74+
@NotNull
75+
@Override
76+
public MultiSelectModel build() {
77+
return new MultiSelectModel.Builder()
78+
.withInitialSelect(initialSelect)
79+
.withUnionQueries(unionQueries)
80+
.withOrderByModel(orderByModel)
81+
.withPagingModel(buildPagingModel())
82+
.build();
83+
}
84+
85+
private PagingModel buildPagingModel() {
86+
if (limit == null && offset == null && fetchFirstRows == null) {
87+
return null;
88+
}
89+
90+
return new PagingModel.Builder()
91+
.withLimit(limit)
92+
.withOffset(offset)
93+
.withFetchFirstRows(fetchFirstRows)
94+
.build();
95+
}
96+
97+
public class LimitFinisher implements Buildable<MultiSelectModel> {
98+
public OffsetFinisher offset(long offset) {
99+
MultiSelectDSL.this.offset(offset);
100+
return new OffsetFinisher();
101+
}
102+
103+
@NotNull
104+
@Override
105+
public MultiSelectModel build() {
106+
return MultiSelectDSL.this.build();
107+
}
108+
}
109+
110+
public class OffsetFinisher implements Buildable<MultiSelectModel> {
111+
@NotNull
112+
@Override
113+
public MultiSelectModel build() {
114+
return MultiSelectDSL.this.build();
115+
}
116+
}
117+
118+
public class OffsetFirstFinisher implements Buildable<MultiSelectModel> {
119+
public FetchFirstFinisher fetchFirst(long fetchFirstRows) {
120+
MultiSelectDSL.this.fetchFirst(fetchFirstRows);
121+
return new FetchFirstFinisher();
122+
}
123+
124+
@NotNull
125+
@Override
126+
public MultiSelectModel build() {
127+
return MultiSelectDSL.this.build();
128+
}
129+
}
130+
131+
public class FetchFirstFinisher {
132+
public RowsOnlyFinisher rowsOnly() {
133+
return new RowsOnlyFinisher();
134+
}
135+
}
136+
137+
public class RowsOnlyFinisher implements Buildable<MultiSelectModel> {
138+
@NotNull
139+
@Override
140+
public MultiSelectModel build() {
141+
return MultiSelectDSL.this.build();
142+
}
143+
}
144+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright 2016-2023 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+
* https://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.select;
17+
18+
import java.util.ArrayList;
19+
import java.util.List;
20+
import java.util.Objects;
21+
import java.util.Optional;
22+
import java.util.function.Function;
23+
import java.util.stream.Stream;
24+
25+
import org.jetbrains.annotations.NotNull;
26+
import org.mybatis.dynamic.sql.common.OrderByModel;
27+
import org.mybatis.dynamic.sql.exception.InvalidSqlException;
28+
import org.mybatis.dynamic.sql.render.RenderingStrategy;
29+
import org.mybatis.dynamic.sql.select.render.MultiSelectRenderer;
30+
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
31+
import org.mybatis.dynamic.sql.util.Messages;
32+
33+
public class MultiSelectModel {
34+
private final SelectModel initialSelect;
35+
private final List<UnionQuery> unionQueries;
36+
private final OrderByModel orderByModel;
37+
private final PagingModel pagingModel;
38+
39+
private MultiSelectModel(Builder builder) {
40+
initialSelect = Objects.requireNonNull(builder.initialSelect);
41+
unionQueries = builder.unionQueries;
42+
orderByModel = builder.orderByModel;
43+
pagingModel = builder.pagingModel;
44+
if (unionQueries.isEmpty()) {
45+
throw new InvalidSqlException(Messages.getString("ERROR.35")); //$NON-NLS-1$
46+
}
47+
}
48+
49+
public SelectModel initialSelect() {
50+
return initialSelect;
51+
}
52+
53+
public <R> Stream<R> mapUnionQueries(Function<UnionQuery, R> mapper) {
54+
return unionQueries.stream().map(mapper);
55+
}
56+
57+
public Optional<OrderByModel> orderByModel() {
58+
return Optional.ofNullable(orderByModel);
59+
}
60+
61+
public Optional<PagingModel> pagingModel() {
62+
return Optional.ofNullable(pagingModel);
63+
}
64+
65+
@NotNull
66+
public SelectStatementProvider render(RenderingStrategy renderingStrategy) {
67+
return new MultiSelectRenderer.Builder()
68+
.withMultiSelectModel(this)
69+
.withRenderingStrategy(renderingStrategy)
70+
.build()
71+
.render();
72+
}
73+
74+
public static class Builder {
75+
private SelectModel initialSelect;
76+
private final List<UnionQuery> unionQueries = new ArrayList<>();
77+
private OrderByModel orderByModel;
78+
private PagingModel pagingModel;
79+
80+
public Builder withInitialSelect(SelectModel initialSelect) {
81+
this.initialSelect = initialSelect;
82+
return this;
83+
}
84+
85+
public Builder withUnionQueries(List<UnionQuery> unionQueries) {
86+
this.unionQueries.addAll(unionQueries);
87+
return this;
88+
}
89+
90+
public Builder withOrderByModel(OrderByModel orderByModel) {
91+
this.orderByModel = orderByModel;
92+
return this;
93+
}
94+
95+
public Builder withPagingModel(PagingModel pagingModel) {
96+
this.pagingModel = pagingModel;
97+
return this;
98+
}
99+
100+
public MultiSelectModel build() {
101+
return new MultiSelectModel(this);
102+
}
103+
}
104+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2016-2023 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+
* https://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.select;
17+
18+
import java.util.Objects;
19+
20+
public class UnionQuery {
21+
private final String connector;
22+
private final SelectModel selectModel;
23+
24+
public UnionQuery(String connector, SelectModel selectModel) {
25+
this.connector = Objects.requireNonNull(connector);
26+
this.selectModel = Objects.requireNonNull(selectModel);
27+
}
28+
29+
public String connector() {
30+
return connector;
31+
}
32+
33+
public SelectModel selectModel() {
34+
return selectModel;
35+
}
36+
}

0 commit comments

Comments
 (0)