48
48
import java .util .List ;
49
49
import java .util .Set ;
50
50
import java .util .StringJoiner ;
51
+ import java .util .function .Predicate ;
52
+ import java .util .function .Supplier ;
51
53
52
54
import org .springframework .data .domain .Sort ;
55
+ import org .springframework .data .util .Predicates ;
53
56
import org .springframework .lang .Nullable ;
54
57
import org .springframework .util .Assert ;
55
58
import org .springframework .util .CollectionUtils ;
@@ -145,24 +148,8 @@ private static String detectAlias(ParsedType parsedType, Statement statement) {
145
148
146
149
if (ParsedType .SELECT .equals (parsedType )) {
147
150
148
- Select selectStatement = (Select ) statement ;
149
-
150
- /*
151
- * For all the other types ({@link ValuesStatement} and {@link SetOperationList}) it does not make sense to provide
152
- * alias since:
153
- * ValuesStatement has no alias
154
- * SetOperation can have multiple alias for each operation item
155
- */
156
- if (!(selectStatement instanceof PlainSelect selectBody )) {
157
- return null ;
158
- }
159
-
160
- if (selectBody .getFromItem () == null ) {
161
- return null ;
162
- }
163
-
164
- Alias alias = selectBody .getFromItem ().getAlias ();
165
- return alias == null ? null : alias .getName ();
151
+ return doWithPlainSelect (statement , it -> it .getFromItem () == null || it .getFromItem ().getAlias () == null ,
152
+ it -> it .getFromItem ().getAlias ().getName (), () -> null );
166
153
}
167
154
168
155
return null ;
@@ -175,20 +162,24 @@ private static String detectAlias(ParsedType parsedType, Statement statement) {
175
162
*/
176
163
private static Set <String > getSelectionAliases (Statement statement ) {
177
164
178
- if (!( statement instanceof PlainSelect select ) || CollectionUtils . isEmpty ( select . getSelectItems ()) ) {
179
- return Collections . emptySet ( );
165
+ if (statement instanceof SetOperationList sel ) {
166
+ statement = sel . getSelect ( 0 );
180
167
}
181
168
182
- Set <String > set = new HashSet <>(select .getSelectItems ().size ());
169
+ return doWithPlainSelect (statement , it -> CollectionUtils .isEmpty (it .getSelectItems ()), it -> {
170
+
171
+ Set <String > set = new HashSet <>(it .getSelectItems ().size (), 1.0f );
183
172
184
- for (SelectItem <?> selectItem : select .getSelectItems ()) {
185
- Alias alias = selectItem .getAlias ();
186
- if (alias != null ) {
187
- set .add (alias .getName ());
173
+ for (SelectItem <?> selectItem : it .getSelectItems ()) {
174
+ Alias alias = selectItem .getAlias ();
175
+ if (alias != null ) {
176
+ set .add (alias .getName ());
177
+ }
188
178
}
189
- }
190
179
191
- return set ;
180
+ return set ;
181
+
182
+ }, Collections ::emptySet );
192
183
}
193
184
194
185
/**
@@ -198,21 +189,74 @@ private static Set<String> getSelectionAliases(Statement statement) {
198
189
*/
199
190
private static Set <String > getJoinAliases (Statement statement ) {
200
191
201
- if (!( statement instanceof PlainSelect selectBody ) || CollectionUtils . isEmpty ( selectBody . getJoins ()) ) {
202
- return Collections . emptySet ( );
192
+ if (statement instanceof SetOperationList sel ) {
193
+ statement = sel . getSelect ( 0 );
203
194
}
204
195
205
- Set < String > set = new HashSet <>( selectBody .getJoins (). size ());
196
+ return doWithPlainSelect ( statement , it -> CollectionUtils . isEmpty ( it .getJoins ()), it -> {
206
197
207
- for (Join join : selectBody .getJoins ()) {
208
- Alias alias = join .getRightItem ().getAlias ();
209
- if (alias != null ) {
210
- set .add (alias .getName ());
198
+ Set <String > set = new HashSet <>(it .getJoins ().size (), 1.0f );
199
+
200
+ for (Join join : it .getJoins ()) {
201
+ Alias alias = join .getRightItem ().getAlias ();
202
+ if (alias != null ) {
203
+ set .add (alias .getName ());
204
+ }
211
205
}
206
+ return set ;
207
+
208
+ }, Collections ::emptySet );
209
+ }
210
+
211
+ /**
212
+ * Apply a {@link java.util.function.Function mapping function} to the {@link PlainSelect} of the given
213
+ * {@link Statement} is or contains a {@link PlainSelect}.
214
+ *
215
+ * @param statement
216
+ * @param mapper
217
+ * @param fallback
218
+ * @return
219
+ * @param <T>
220
+ */
221
+ private static <T > T doWithPlainSelect (Statement statement , java .util .function .Function <PlainSelect , T > mapper ,
222
+ Supplier <T > fallback ) {
223
+
224
+ Predicate <PlainSelect > neverSkip = Predicates .isFalse ();
225
+ return doWithPlainSelect (statement , neverSkip , mapper , fallback );
226
+ }
227
+
228
+ /**
229
+ * Apply a {@link java.util.function.Function mapping function} to the {@link PlainSelect} of the given
230
+ * {@link Statement} is or contains a {@link PlainSelect}.
231
+ * <p>
232
+ * The operation is only applied if {@link Predicate skipIf} returns {@literal false} for the given statement
233
+ * returning the fallback value from {@code fallback}.
234
+ *
235
+ * @param statement
236
+ * @param skipIf
237
+ * @param mapper
238
+ * @param fallback
239
+ * @return
240
+ * @param <T>
241
+ */
242
+ private static <T > T doWithPlainSelect (Statement statement , Predicate <PlainSelect > skipIf ,
243
+ java .util .function .Function <PlainSelect , T > mapper , Supplier <T > fallback ) {
244
+
245
+ if (!(statement instanceof Select select )) {
246
+ return fallback .get ();
212
247
}
213
248
214
- return set ;
249
+ try {
250
+ if (skipIf .test (select .getPlainSelect ())) {
251
+ return fallback .get ();
252
+ }
253
+ }
254
+ // e.g. SetOperationList is a subclass of Select but it is not a PlainSelect
255
+ catch (ClassCastException e ) {
256
+ return fallback .get ();
257
+ }
215
258
259
+ return mapper .apply (select .getPlainSelect ());
216
260
}
217
261
218
262
private static String detectProjection (Statement statement ) {
@@ -231,18 +275,17 @@ private static String detectProjection(Statement statement) {
231
275
232
276
// using the first one since for setoperations the projection has to be the same
233
277
selectBody = setOperationList .getSelects ().get (0 );
234
-
235
- if (!(selectBody instanceof PlainSelect )) {
236
- return "" ;
237
- }
238
278
}
239
279
240
- StringJoiner joiner = new StringJoiner (", " );
241
- for (SelectItem <?> selectItem : selectBody .getPlainSelect ().getSelectItems ()) {
242
- joiner .add (selectItem .toString ());
243
- }
244
- return joiner .toString ().trim ();
280
+ return doWithPlainSelect (selectBody , it -> CollectionUtils .isEmpty (it .getSelectItems ()), it -> {
281
+
282
+ StringJoiner joiner = new StringJoiner (", " );
283
+ for (SelectItem <?> selectItem : it .getSelectItems ()) {
284
+ joiner .add (selectItem .toString ());
285
+ }
286
+ return joiner .toString ().trim ();
245
287
288
+ }, () -> "" );
246
289
}
247
290
248
291
/**
@@ -328,20 +371,22 @@ private String applySorting(Select selectStatement, Sort sort, @Nullable String
328
371
return applySortingToSetOperationList (setOperationList , sort );
329
372
}
330
373
331
- if (!(selectStatement instanceof PlainSelect selectBody )) {
332
- return selectStatement .toString ();
333
- }
374
+ doWithPlainSelect (selectStatement , it -> {
334
375
335
- List <OrderByElement > orderByElements = new ArrayList <>(16 );
336
- for (Sort .Order order : sort ) {
337
- orderByElements .add (getOrderClause (joinAliases , selectAliases , alias , order ));
338
- }
376
+ List <OrderByElement > orderByElements = new ArrayList <>(16 );
377
+ for (Sort .Order order : sort ) {
378
+ orderByElements .add (getOrderClause (joinAliases , selectAliases , alias , order ));
379
+ }
339
380
340
- if (CollectionUtils .isEmpty (selectBody .getOrderByElements ())) {
341
- selectBody .setOrderByElements (orderByElements );
342
- } else {
343
- selectBody .getOrderByElements ().addAll (orderByElements );
344
- }
381
+ if (CollectionUtils .isEmpty (it .getOrderByElements ())) {
382
+ it .setOrderByElements (orderByElements );
383
+ } else {
384
+ it .getOrderByElements ().addAll (orderByElements );
385
+ }
386
+
387
+ return null ;
388
+
389
+ }, () -> "" );
345
390
346
391
return selectStatement .toString ();
347
392
}
@@ -356,18 +401,13 @@ public String createCountQueryFor(@Nullable String countProjection) {
356
401
Assert .hasText (this .query .getQueryString (), "OriginalQuery must not be null or empty" );
357
402
358
403
Statement statement = (Statement ) deserialize (this .serialized );
359
- /*
360
- We only support count queries for {@link PlainSelect}.
361
- */
362
- if (!(statement instanceof PlainSelect selectBody )) {
363
- return this .query .getQueryString ();
364
- }
365
404
366
- return createCountQueryFor (this .query , selectBody , countProjection , primaryAlias );
405
+ return doWithPlainSelect (statement , it -> createCountQueryFor (it , countProjection , primaryAlias ),
406
+ this .query ::getQueryString );
367
407
}
368
408
369
- private static String createCountQueryFor (DeclaredQuery query , PlainSelect selectBody ,
370
- @ Nullable String countProjection , @ Nullable String primaryAlias ) {
409
+ private static String createCountQueryFor (PlainSelect selectBody , @ Nullable String countProjection ,
410
+ @ Nullable String primaryAlias ) {
371
411
372
412
// remove order by
373
413
selectBody .setOrderByElements (null );
0 commit comments