15
15
*/
16
16
package org .springframework .data .jpa .repository .query ;
17
17
18
+ import static org .springframework .data .jpa .repository .query .JSqlParserUtils .*;
19
+ import static org .springframework .data .jpa .repository .query .QueryUtils .*;
20
+
18
21
import net .sf .jsqlparser .JSQLParserException ;
19
22
import net .sf .jsqlparser .expression .Alias ;
20
23
import net .sf .jsqlparser .expression .Expression ;
21
24
import net .sf .jsqlparser .expression .Function ;
22
- import net .sf .jsqlparser .expression .operators .conditional .AndExpression ;
23
- import net .sf .jsqlparser .expression .operators .relational .EqualsTo ;
24
25
import net .sf .jsqlparser .parser .CCJSqlParserUtil ;
25
26
import net .sf .jsqlparser .schema .Column ;
26
- import net .sf .jsqlparser .schema .Table ;
27
- import net .sf .jsqlparser .statement .select .*;
28
- import net .sf .jsqlparser .util .SelectUtils ;
27
+ import net .sf .jsqlparser .statement .select .OrderByElement ;
28
+ import net .sf .jsqlparser .statement .select .PlainSelect ;
29
+ import net .sf .jsqlparser .statement .select .Select ;
30
+ import net .sf .jsqlparser .statement .select .SelectExpressionItem ;
31
+ import net .sf .jsqlparser .statement .select .SelectItem ;
32
+
33
+ import java .util .ArrayList ;
34
+ import java .util .Collections ;
35
+ import java .util .HashSet ;
36
+ import java .util .List ;
37
+ import java .util .Objects ;
38
+ import java .util .Set ;
39
+ import java .util .stream .Collectors ;
40
+
29
41
import org .springframework .data .domain .Sort ;
30
- import org .springframework .data . util . Streamable ;
42
+ import org .springframework .lang . Nullable ;
31
43
import org .springframework .util .Assert ;
32
44
import org .springframework .util .CollectionUtils ;
33
45
import org .springframework .util .StringUtils ;
34
46
35
- import java .util .*;
36
- import java .util .stream .Collectors ;
37
-
38
- import static org .springframework .data .jpa .repository .query .JSqlParserUtils .*;
39
- import static org .springframework .data .jpa .repository .query .QueryUtils .checkSortExpression ;
40
-
41
47
/**
42
48
* The implementation of {@link QueryEnhancer} using JSqlParser.
43
49
*
44
50
* @author Diego Krupitza
51
+ * @author Greg Turnquist
52
+ * @since 2.7.0
45
53
*/
46
54
public class JSqlParserQueryEnhancer implements QueryEnhancer {
47
55
48
- private static final String DEFAULT_TABLE_ALIAS = "x" ;
49
-
50
56
private final DeclaredQuery query ;
51
57
52
58
/**
@@ -57,40 +63,8 @@ public JSqlParserQueryEnhancer(DeclaredQuery query) {
57
63
}
58
64
59
65
@ Override
60
- public String getExistsQueryString (String entityName , String countQueryPlaceHolder , Iterable <String > idAttributes ) {
61
- final Table tableNameWithAlias = getTableWithAlias (entityName , DEFAULT_TABLE_ALIAS );
62
- Function jSqlCount = getJSqlCount (Collections .singletonList (countQueryPlaceHolder ), false );
63
-
64
- Select select = SelectUtils .buildSelectFromTableAndSelectItems (tableNameWithAlias ,
65
- new SelectExpressionItem (jSqlCount ));
66
-
67
- PlainSelect selectBody = (PlainSelect ) select .getSelectBody ();
68
-
69
- List <Expression > equalityExpressions = Streamable .of (idAttributes ).stream () //
70
- .map (field -> {
71
- Expression tableNameField = new Column ().withTable (tableNameWithAlias ).withColumnName (field );
72
- Expression inputField = new Column (":" .concat (field ));
73
- return new EqualsTo (tableNameField , inputField );
74
- }).collect (Collectors .toList ());
75
-
76
- if (equalityExpressions .size () > 1 ) {
77
- AndExpression rootOfWhereClause = concatenateWithAndExpression (equalityExpressions );
78
- selectBody .setWhere (rootOfWhereClause );
79
- } else if (equalityExpressions .size () == 1 ) {
80
- selectBody .setWhere (equalityExpressions .get (0 ));
81
- }
66
+ public String applySorting (Sort sort , @ Nullable String alias ) {
82
67
83
- return selectBody .toString ();
84
- }
85
-
86
- @ Override
87
- public String getQueryString (String template , String entityName ) {
88
- Assert .hasText (entityName , "Entity name must not be null or empty!" );
89
- return String .format (template , entityName );
90
- }
91
-
92
- @ Override
93
- public String applySorting (Sort sort , String alias ) {
94
68
String queryString = query .getQueryString ();
95
69
Assert .hasText (queryString , "Query must not be null or empty!" );
96
70
@@ -145,6 +119,7 @@ private Set<String> getSelectionAliases(PlainSelect selectBody) {
145
119
* @return a {@literal Set} containing all found aliases. Guaranteed to be not {@literal null}.
146
120
*/
147
121
Set <String > getSelectionAliases () {
122
+
148
123
Select selectStatement = parseSelectStatement (this .query .getQueryString ());
149
124
PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
150
125
return this .getSelectionAliases (selectBody );
@@ -189,7 +164,7 @@ private Set<String> getJoinAliases(PlainSelect selectBody) {
189
164
* @return a {@link OrderByElement} containing an order clause. Guaranteed to be not {@literal null}.
190
165
*/
191
166
private OrderByElement getOrderClause (final Set <String > joinAliases , final Set <String > selectionAliases ,
192
- final String alias , final Sort .Order order ) {
167
+ @ Nullable final String alias , final Sort .Order order ) {
193
168
194
169
final OrderByElement orderByElement = new OrderByElement ();
195
170
orderByElement .setAsc (order .getDirection ().isAscending ());
@@ -233,7 +208,9 @@ public String detectAlias() {
233
208
* @param query must not be {@literal null}.
234
209
* @return Might return {@literal null}.
235
210
*/
211
+ @ Nullable
236
212
private String detectAlias (String query ) {
213
+
237
214
Select selectStatement = parseSelectStatement (query );
238
215
PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
239
216
return detectAlias (selectBody );
@@ -246,13 +223,15 @@ private String detectAlias(String query) {
246
223
* @param selectBody must not be {@literal null}.
247
224
* @return Might return {@literal null}.
248
225
*/
226
+ @ Nullable
249
227
private static String detectAlias (PlainSelect selectBody ) {
228
+
250
229
Alias alias = selectBody .getFromItem ().getAlias ();
251
230
return alias == null ? null : alias .getName ();
252
231
}
253
232
254
233
@ Override
255
- public String createCountQueryFor (String countProjection ) {
234
+ public String createCountQueryFor (@ Nullable String countProjection ) {
256
235
257
236
Assert .hasText (this .query .getQueryString (), "OriginalQuery must not be null or empty!" );
258
237
@@ -298,6 +277,7 @@ public String createCountQueryFor(String countProjection) {
298
277
299
278
@ Override
300
279
public String getProjection () {
280
+
301
281
Assert .hasText (query .getQueryString (), "Query must not be null or empty!" );
302
282
303
283
Select selectStatement = parseSelectStatement (query .getQueryString ());
@@ -321,6 +301,7 @@ public Set<String> getJoinAliases() {
321
301
* @return the parsed query
322
302
*/
323
303
private static Select parseSelectStatement (String query ) {
304
+
324
305
try {
325
306
return (Select ) CCJSqlParserUtil .parse (query );
326
307
} catch (JSQLParserException e ) {
@@ -329,12 +310,13 @@ private static Select parseSelectStatement(String query) {
329
310
}
330
311
331
312
/**
332
- * Checks whether a given projection only contains a single column definition (aka without functions, etc)
313
+ * Checks whether a given projection only contains a single column definition (aka without functions, etc. )
333
314
*
334
315
* @param projection the projection to analyse
335
316
* @return <code>true</code> when the projection only contains a single column definition otherwise <code>false</code>
336
317
*/
337
318
private boolean onlyASingleColumnProjection (List <SelectItem > projection ) {
319
+
338
320
// this is unfortunately the only way to check without any hacky & hard string regex magic
339
321
return projection .size () == 1 && projection .get (0 ) instanceof SelectExpressionItem
340
322
&& (((SelectExpressionItem ) projection .get (0 )).getExpression ()) instanceof Column ;
0 commit comments