Skip to content

Commit 18c043b

Browse files
committed
Initial work on multi-select
1 parent 4b20284 commit 18c043b

File tree

12 files changed

+936
-11
lines changed

12 files changed

+936
-11
lines changed

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

Lines changed: 5 additions & 0 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
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
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+
public class MultiSelectDSL implements Buildable<MultiSelectModel> {
28+
private final List<MultiSelectModel.UnionQuery> unionQueries = new ArrayList<>();
29+
private final SelectModel initialSelect;
30+
private OrderByModel orderByModel;
31+
private Long limit;
32+
private Long offset;
33+
private Long fetchFirstRows;
34+
35+
public MultiSelectDSL(Buildable<SelectModel> builder) {
36+
initialSelect = builder.build();
37+
}
38+
39+
public MultiSelectDSL union(Buildable<SelectModel> builder) {
40+
unionQueries.add(new MultiSelectModel.UnionQuery("union", builder.build())); //$NON-NLS-1$
41+
return this;
42+
}
43+
44+
public MultiSelectDSL unionAll(Buildable<SelectModel> builder) {
45+
unionQueries.add(new MultiSelectModel.UnionQuery("union all", builder.build())); //$NON-NLS-1$
46+
return this;
47+
}
48+
49+
public MultiSelectDSL orderBy(SortSpecification... columns) {
50+
return orderBy(Arrays.asList(columns));
51+
}
52+
53+
public MultiSelectDSL orderBy(Collection<SortSpecification> columns) {
54+
orderByModel = OrderByModel.of(columns);
55+
return this;
56+
}
57+
58+
public LimitFinisher limit(long limit) {
59+
this.limit = limit;
60+
return new LimitFinisher();
61+
}
62+
63+
public OffsetFirstFinisher offset(long offset) {
64+
this.offset = offset;
65+
return new OffsetFirstFinisher();
66+
}
67+
68+
public FetchFirstFinisher fetchFirst(long fetchFirstRows) {
69+
this.fetchFirstRows = fetchFirstRows;
70+
return new FetchFirstFinisher();
71+
}
72+
73+
@NotNull
74+
@Override
75+
public MultiSelectModel build() {
76+
return new MultiSelectModel.Builder()
77+
.withInitialSelect(initialSelect)
78+
.withUnionQueries(unionQueries)
79+
.withOrderByModel(orderByModel)
80+
.withPagingModel(buildPagingModel())
81+
.build();
82+
}
83+
84+
private PagingModel buildPagingModel() {
85+
if (limit == null && offset == null && fetchFirstRows == null) {
86+
return null;
87+
}
88+
89+
return new PagingModel.Builder()
90+
.withLimit(limit)
91+
.withOffset(offset)
92+
.withFetchFirstRows(fetchFirstRows)
93+
.build();
94+
}
95+
96+
public class LimitFinisher implements Buildable<MultiSelectModel> {
97+
public OffsetFinisher offset(long offset) {
98+
MultiSelectDSL.this.offset(offset);
99+
return new OffsetFinisher();
100+
}
101+
102+
@NotNull
103+
@Override
104+
public MultiSelectModel build() {
105+
return MultiSelectDSL.this.build();
106+
}
107+
}
108+
109+
public class OffsetFinisher implements Buildable<MultiSelectModel> {
110+
@NotNull
111+
@Override
112+
public MultiSelectModel build() {
113+
return MultiSelectDSL.this.build();
114+
}
115+
}
116+
117+
public class OffsetFirstFinisher implements Buildable<MultiSelectModel> {
118+
public FetchFirstFinisher fetchFirst(long fetchFirstRows) {
119+
MultiSelectDSL.this.fetchFirst(fetchFirstRows);
120+
return new FetchFirstFinisher();
121+
}
122+
123+
@NotNull
124+
@Override
125+
public MultiSelectModel build() {
126+
return MultiSelectDSL.this.build();
127+
}
128+
}
129+
130+
public class FetchFirstFinisher {
131+
public RowsOnlyFinisher rowsOnly() {
132+
return new RowsOnlyFinisher();
133+
}
134+
}
135+
136+
public class RowsOnlyFinisher implements Buildable<MultiSelectModel> {
137+
@NotNull
138+
@Override
139+
public MultiSelectModel build() {
140+
return MultiSelectDSL.this.build();
141+
}
142+
}
143+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
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+
105+
public static class UnionQuery {
106+
private final String connector;
107+
private final SelectModel selectModel;
108+
109+
public UnionQuery(String connector, SelectModel selectModel) {
110+
this.connector = Objects.requireNonNull(connector);
111+
this.selectModel = Objects.requireNonNull(selectModel);
112+
}
113+
114+
public String connector() {
115+
return connector;
116+
}
117+
118+
public SelectModel selectModel() {
119+
return selectModel;
120+
}
121+
}
122+
}

0 commit comments

Comments
 (0)