1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 import java.util.Objects;
23 import java.util.Optional;
24 import java.util.function.Consumer;
25 import java.util.function.Function;
26
27 import org.jspecify.annotations.Nullable;
28 import org.mybatis.dynamic.sql.BasicColumn;
29 import org.mybatis.dynamic.sql.SortSpecification;
30 import org.mybatis.dynamic.sql.common.OrderByModel;
31 import org.mybatis.dynamic.sql.configuration.StatementConfiguration;
32 import org.mybatis.dynamic.sql.select.QueryExpressionDSL.FromGatherer;
33 import org.mybatis.dynamic.sql.util.Buildable;
34 import org.mybatis.dynamic.sql.util.ConfigurableStatement;
35 import org.mybatis.dynamic.sql.util.Validator;
36
37
38
39
40
41
42
43
44
45 public class SelectDSL<R> implements Buildable<R>, ConfigurableStatement<SelectDSL<R>> {
46
47 private final Function<SelectModel, R> adapterFunction;
48 private final List<QueryExpressionDSL<R>> queryExpressions = new ArrayList<>();
49 private @Nullable OrderByModel orderByModel;
50 private @Nullable Long limit;
51 private @Nullable Long offset;
52 private @Nullable Long fetchFirstRows;
53 final StatementConfiguration statementConfiguration = new StatementConfiguration();
54 private @Nullable String forClause;
55 private @Nullable String waitClause;
56
57 private SelectDSL(Function<SelectModel, R> adapterFunction) {
58 this.adapterFunction = Objects.requireNonNull(adapterFunction);
59 }
60
61 public static QueryExpressionDSL.FromGatherer<SelectModel> select(BasicColumn... selectList) {
62 return select(Arrays.asList(selectList));
63 }
64
65 public static QueryExpressionDSL.FromGatherer<SelectModel> select(Collection<? extends BasicColumn> selectList) {
66 return select(Function.identity(), selectList);
67 }
68
69 public static <R> QueryExpressionDSL.FromGatherer<R> select(Function<SelectModel, R> adapterFunction,
70 BasicColumn... selectList) {
71 return select(adapterFunction, Arrays.asList(selectList));
72 }
73
74 public static <R> QueryExpressionDSL.FromGatherer<R> select(Function<SelectModel, R> adapterFunction,
75 Collection<? extends BasicColumn> selectList) {
76 return new FromGatherer.Builder<R>()
77 .withSelectList(selectList)
78 .withSelectDSL(new SelectDSL<>(adapterFunction))
79 .build();
80 }
81
82 public static QueryExpressionDSL.FromGatherer<SelectModel> selectDistinct(BasicColumn... selectList) {
83 return selectDistinct(Function.identity(), selectList);
84 }
85
86 public static QueryExpressionDSL.FromGatherer<SelectModel> selectDistinct(
87 Collection<? extends BasicColumn> selectList) {
88 return selectDistinct(Function.identity(), selectList);
89 }
90
91 public static <R> QueryExpressionDSL.FromGatherer<R> selectDistinct(Function<SelectModel, R> adapterFunction,
92 BasicColumn... selectList) {
93 return selectDistinct(adapterFunction, Arrays.asList(selectList));
94 }
95
96 public static <R> QueryExpressionDSL.FromGatherer<R> selectDistinct(Function<SelectModel, R> adapterFunction,
97 Collection<? extends BasicColumn> selectList) {
98 return new FromGatherer.Builder<R>()
99 .withSelectList(selectList)
100 .withSelectDSL(new SelectDSL<>(adapterFunction))
101 .isDistinct()
102 .build();
103 }
104
105 void registerQueryExpression(QueryExpressionDSL<R> queryExpression) {
106 queryExpressions.add(queryExpression);
107 }
108
109 void orderBy(Collection<? extends SortSpecification> columns) {
110 orderByModel = OrderByModel.of(columns);
111 }
112
113 public SelectDSL<R>.LimitFinisher limit(long limit) {
114 return limitWhenPresent(limit);
115 }
116
117 public SelectDSL<R>.LimitFinisher limitWhenPresent(@Nullable Long limit) {
118 this.limit = limit;
119 return new LimitFinisher();
120 }
121
122 public SelectDSL<R>.OffsetFirstFinisher offset(long offset) {
123 return offsetWhenPresent(offset);
124 }
125
126 public SelectDSL<R>.OffsetFirstFinisher offsetWhenPresent(@Nullable Long offset) {
127 this.offset = offset;
128 return new OffsetFirstFinisher();
129 }
130
131 public SelectDSL<R>.FetchFirstFinisher fetchFirst(long fetchFirstRows) {
132 return fetchFirstWhenPresent(fetchFirstRows);
133 }
134
135 public SelectDSL<R>.FetchFirstFinisher fetchFirstWhenPresent(@Nullable Long fetchFirstRows) {
136 this.fetchFirstRows = fetchFirstRows;
137 return new FetchFirstFinisher();
138 }
139
140 public SelectDSL<R> forUpdate() {
141 Validator.assertNull(forClause, "ERROR.48");
142 forClause = "for update";
143 return this;
144 }
145
146 public SelectDSL<R> forNoKeyUpdate() {
147 Validator.assertNull(forClause, "ERROR.48");
148 forClause = "for no key update";
149 return this;
150 }
151
152 public SelectDSL<R> forShare() {
153 Validator.assertNull(forClause, "ERROR.48");
154 forClause = "for share";
155 return this;
156 }
157
158 public SelectDSL<R> forKeyShare() {
159 Validator.assertNull(forClause, "ERROR.48");
160 forClause = "for key share";
161 return this;
162 }
163
164 public SelectDSL<R> skipLocked() {
165 Validator.assertNull(waitClause, "ERROR.49");
166 waitClause = "skip locked";
167 return this;
168 }
169
170 public SelectDSL<R> nowait() {
171 Validator.assertNull(waitClause, "ERROR.49");
172 waitClause = "nowait";
173 return this;
174 }
175
176 @Override
177 public SelectDSL<R> configureStatement(Consumer<StatementConfiguration> consumer) {
178 consumer.accept(statementConfiguration);
179 return this;
180 }
181
182 @Override
183 public R build() {
184 SelectModel selectModel = SelectModel.withQueryExpressions(buildModels())
185 .withOrderByModel(orderByModel)
186 .withPagingModel(buildPagingModel().orElse(null))
187 .withStatementConfiguration(statementConfiguration)
188 .withForClause(forClause)
189 .withWaitClause(waitClause)
190 .build();
191 return adapterFunction.apply(selectModel);
192 }
193
194 private List<QueryExpressionModel> buildModels() {
195 return queryExpressions.stream()
196 .map(QueryExpressionDSL::buildModel)
197 .toList();
198 }
199
200 private Optional<PagingModel> buildPagingModel() {
201 return new PagingModel.Builder()
202 .withLimit(limit)
203 .withOffset(offset)
204 .withFetchFirstRows(fetchFirstRows)
205 .build();
206 }
207
208 public class OffsetFirstFinisher implements SelectDSLForAndWaitOperations<R>, Buildable<R> {
209 public FetchFirstFinisher fetchFirst(long fetchFirstRows) {
210 return fetchFirstWhenPresent(fetchFirstRows);
211 }
212
213 public FetchFirstFinisher fetchFirstWhenPresent(@Nullable Long fetchFirstRows) {
214 SelectDSL.this.fetchFirstRows = fetchFirstRows;
215 return new FetchFirstFinisher();
216 }
217
218 @Override
219 public SelectDSL<R> getSelectDSL() {
220 return SelectDSL.this;
221 }
222
223 @Override
224 public R build() {
225 return SelectDSL.this.build();
226 }
227 }
228
229 public class LimitFinisher implements SelectDSLForAndWaitOperations<R>, Buildable<R> {
230 public SelectDSL<R> offset(long offset) {
231 return offsetWhenPresent(offset);
232 }
233
234 public SelectDSL<R> offsetWhenPresent(@Nullable Long offset) {
235 SelectDSL.this.offset = offset;
236 return SelectDSL.this;
237 }
238
239 @Override
240 public SelectDSL<R> getSelectDSL() {
241 return SelectDSL.this;
242 }
243
244 @Override
245 public R build() {
246 return SelectDSL.this.build();
247 }
248 }
249
250 public class FetchFirstFinisher {
251 public SelectDSL<R> rowsOnly() {
252 return SelectDSL.this;
253 }
254 }
255 }