1515 */
1616package org .springframework .data .jpa .repository .query ;
1717
18+ import static org .springframework .data .jpa .repository .query .JSqlParserUtils .*;
19+ import static org .springframework .data .jpa .repository .query .QueryUtils .*;
20+
1821import net .sf .jsqlparser .JSQLParserException ;
1922import net .sf .jsqlparser .expression .Alias ;
2023import net .sf .jsqlparser .expression .Expression ;
2124import net .sf .jsqlparser .expression .Function ;
22- import net .sf .jsqlparser .expression .operators .conditional .AndExpression ;
23- import net .sf .jsqlparser .expression .operators .relational .EqualsTo ;
2425import net .sf .jsqlparser .parser .CCJSqlParserUtil ;
2526import 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+
2941import org .springframework .data .domain .Sort ;
30- import org .springframework .data . util . Streamable ;
42+ import org .springframework .lang . Nullable ;
3143import org .springframework .util .Assert ;
3244import org .springframework .util .CollectionUtils ;
3345import org .springframework .util .StringUtils ;
3446
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-
4147/**
4248 * The implementation of {@link QueryEnhancer} using JSqlParser.
4349 *
4450 * @author Diego Krupitza
51+ * @author Greg Turnquist
52+ * @since 2.7.0
4553 */
4654public class JSqlParserQueryEnhancer implements QueryEnhancer {
4755
48- private static final String DEFAULT_TABLE_ALIAS = "x" ;
49-
5056 private final DeclaredQuery query ;
5157
5258 /**
@@ -57,40 +63,8 @@ public JSqlParserQueryEnhancer(DeclaredQuery query) {
5763 }
5864
5965 @ 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 ) {
8267
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 ) {
9468 String queryString = query .getQueryString ();
9569 Assert .hasText (queryString , "Query must not be null or empty!" );
9670
@@ -145,6 +119,7 @@ private Set<String> getSelectionAliases(PlainSelect selectBody) {
145119 * @return a {@literal Set} containing all found aliases. Guaranteed to be not {@literal null}.
146120 */
147121 Set <String > getSelectionAliases () {
122+
148123 Select selectStatement = parseSelectStatement (this .query .getQueryString ());
149124 PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
150125 return this .getSelectionAliases (selectBody );
@@ -189,7 +164,7 @@ private Set<String> getJoinAliases(PlainSelect selectBody) {
189164 * @return a {@link OrderByElement} containing an order clause. Guaranteed to be not {@literal null}.
190165 */
191166 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 ) {
193168
194169 final OrderByElement orderByElement = new OrderByElement ();
195170 orderByElement .setAsc (order .getDirection ().isAscending ());
@@ -233,7 +208,9 @@ public String detectAlias() {
233208 * @param query must not be {@literal null}.
234209 * @return Might return {@literal null}.
235210 */
211+ @ Nullable
236212 private String detectAlias (String query ) {
213+
237214 Select selectStatement = parseSelectStatement (query );
238215 PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
239216 return detectAlias (selectBody );
@@ -246,13 +223,15 @@ private String detectAlias(String query) {
246223 * @param selectBody must not be {@literal null}.
247224 * @return Might return {@literal null}.
248225 */
226+ @ Nullable
249227 private static String detectAlias (PlainSelect selectBody ) {
228+
250229 Alias alias = selectBody .getFromItem ().getAlias ();
251230 return alias == null ? null : alias .getName ();
252231 }
253232
254233 @ Override
255- public String createCountQueryFor (String countProjection ) {
234+ public String createCountQueryFor (@ Nullable String countProjection ) {
256235
257236 Assert .hasText (this .query .getQueryString (), "OriginalQuery must not be null or empty!" );
258237
@@ -298,6 +277,7 @@ public String createCountQueryFor(String countProjection) {
298277
299278 @ Override
300279 public String getProjection () {
280+
301281 Assert .hasText (query .getQueryString (), "Query must not be null or empty!" );
302282
303283 Select selectStatement = parseSelectStatement (query .getQueryString ());
@@ -321,6 +301,7 @@ public Set<String> getJoinAliases() {
321301 * @return the parsed query
322302 */
323303 private static Select parseSelectStatement (String query ) {
304+
324305 try {
325306 return (Select ) CCJSqlParserUtil .parse (query );
326307 } catch (JSQLParserException e ) {
@@ -329,12 +310,13 @@ private static Select parseSelectStatement(String query) {
329310 }
330311
331312 /**
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. )
333314 *
334315 * @param projection the projection to analyse
335316 * @return <code>true</code> when the projection only contains a single column definition otherwise <code>false</code>
336317 */
337318 private boolean onlyASingleColumnProjection (List <SelectItem > projection ) {
319+
338320 // this is unfortunately the only way to check without any hacky & hard string regex magic
339321 return projection .size () == 1 && projection .get (0 ) instanceof SelectExpressionItem
340322 && (((SelectExpressionItem ) projection .get (0 )).getExpression ()) instanceof Column ;
0 commit comments