From 3effe559296c3057813c1957abed78beed9648d0 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 27 Nov 2024 08:25:32 +0100 Subject: [PATCH] Polishing. Inline select_query into select_statement, simplify set_function resolution. Align JPQL and EQL grammars. Adopt Hibernate version guards in tests. Original Pull Request: #3695 --- .../data/jpa/repository/query/Eql.g4 | 10 +- .../data/jpa/repository/query/Jpql.g4 | 33 +- .../query/EqlCountQueryTransformer.java | 4 +- .../repository/query/EqlQueryRenderer.java | 448 +++++++++--------- .../query/EqlSortedQueryTransformer.java | 15 +- .../query/JpqlCountQueryTransformer.java | 12 +- .../repository/query/JpqlQueryRenderer.java | 258 +++++----- .../query/JpqlSortedQueryTransformer.java | 13 +- ...stgresStoredProcedureIntegrationTests.java | 3 +- .../repository/query/EqlComplianceTests.java | 14 +- .../query/EqlQueryRendererTests.java | 54 +++ .../query/EqlSpecificationTests.java | 52 +- .../query/HqlQueryRendererTests.java | 4 +- .../repository/query/JpqlComplianceTests.java | 207 +++++++- .../query/JpqlSpecificationTests.java | 32 ++ 15 files changed, 723 insertions(+), 436 deletions(-) diff --git a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 index 266890d8a..2181baec6 100644 --- a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 +++ b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 @@ -43,7 +43,7 @@ ql_statement ; select_statement - : select_clause from_clause (where_clause)? (groupby_clause)? (having_clause)? (orderby_clause)? (setOperator select_statement)* + : select_clause from_clause (where_clause)? (groupby_clause)? (having_clause)? (orderby_clause)? (set_fuction)? ; setOperator @@ -52,6 +52,10 @@ setOperator | EXCEPT ALL? ; +set_fuction + : setOperator select_statement + ; + update_statement : update_clause (where_clause)? ; @@ -675,6 +679,7 @@ constructor_name literal : STRINGLITERAL + | JAVASTRINGLITERAL | INTLITERAL | FLOATLITERAL | LONGLITERAL @@ -848,9 +853,9 @@ reserved_word |OR |ORDER |OUTER + |POWER |REPLACE |RIGHT - |POWER |ROUND |SELECT |SET @@ -1021,6 +1026,7 @@ NOT_EQUAL : '<>' | '!=' ; CHARACTER : '\'' (~ ('\'' | '\\')) '\'' ; IDENTIFICATION_VARIABLE : ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '$' | '_') ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '0' .. '9' | '$' | '_')* ; +JAVASTRINGLITERAL : '"' ( ('\\' [btnfr"']) | ~('"'))* '"'; STRINGLITERAL : '\'' (~ ('\'' | '\\')|'\\')* '\'' ; FLOATLITERAL : ('0' .. '9')* '.' ('0' .. '9')+ (E ('0' .. '9')+)* (F|D)?; INTLITERAL : ('0' .. '9')+ ; diff --git a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 index 070874edb..90e590cd1 100644 --- a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 +++ b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 @@ -43,10 +43,6 @@ ql_statement ; select_statement - : select_query - ; - -select_query : select_clause from_clause (where_clause)? (groupby_clause)? (having_clause)? (orderby_clause)? (set_fuction)? ; @@ -57,11 +53,7 @@ setOperator ; set_fuction - : setOperator set_function_select - ; - -set_function_select - : select_query + : setOperator select_statement ; update_statement @@ -95,7 +87,7 @@ join ; fetch_join - : join_spec FETCH join_association_path_expression + : join_spec FETCH join_association_path_expression AS? identification_variable? join_condition? ; join_spec @@ -315,7 +307,7 @@ scalar_expression | datetime_expression | boolean_expression | case_expression - | cast_expression + | cast_function | entity_type_expression ; @@ -550,8 +542,8 @@ functions_returning_strings | SUBSTRING '(' string_expression ',' arithmetic_expression (',' arithmetic_expression)? ')' | TRIM '(' ((trim_specification)? (trim_character)? FROM)? string_expression ')' | LOWER '(' string_expression ')' - | REPLACE '(' string_expression ',' string_expression ',' string_expression ')' | UPPER '(' string_expression ')' + | REPLACE '(' string_expression ',' string_expression ',' string_expression ')' | LEFT '(' string_expression ',' arithmetic_expression ')' | RIGHT '(' string_expression ',' arithmetic_expression ')' ; @@ -637,9 +629,6 @@ nullif_expression : NULLIF '(' scalar_expression ',' scalar_expression ')' ; -cast_expression - : CAST '(' string_expression AS type_literal ')' - ; /******************* Gaps in the spec. @@ -653,6 +642,7 @@ trim_character identification_variable : IDENTIFICATION_VARIABLE | f=(COUNT + | AS | DATE | FROM | INNER @@ -668,6 +658,7 @@ identification_variable | TIME | TYPE | VALUE) + | type_literal ; constructor_name @@ -695,6 +686,9 @@ pattern_value date_time_timestamp_literal : STRINGLITERAL + | DATELITERAL + | TIMELITERAL + | TIMESTAMPLITERAL ; entity_type_literal @@ -995,10 +989,10 @@ ON : O N; OR : O R; ORDER : O R D E R; OUTER : O U T E R; -REPLACE : R E P L A C E; -RIGHT : R I G H T; POWER : P O W E R; REGEXP : R E G E X P; +REPLACE : R E P L A C E; +RIGHT : R I G H T; ROUND : R O U N D; SELECT : S E L E C T; SET : S E T; @@ -1033,4 +1027,7 @@ STRINGLITERAL : '\'' (~ ('\'' | '\\')|'\\')* '\'' ; JAVASTRINGLITERAL : '"' ( ('\\' [btnfr"']) | ~('"'))* '"'; FLOATLITERAL : ('0' .. '9')* '.' ('0' .. '9')+ (E ('0' .. '9')+)* (F|D)?; INTLITERAL : ('0' .. '9')+ ; -LONGLITERAL : ('0' .. '9')+L ; +LONGLITERAL : ('0' .. '9')+ L; +DATELITERAL : '{' D STRINGLITERAL '}'; +TIMELITERAL : '{' T STRINGLITERAL '}'; +TIMESTAMPLITERAL : '{' T S STRINGLITERAL '}'; diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlCountQueryTransformer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlCountQueryTransformer.java index 0221aff83..81b5e9a8f 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlCountQueryTransformer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlCountQueryTransformer.java @@ -42,7 +42,7 @@ class EqlCountQueryTransformer extends EqlQueryRenderer { } @Override - public QueryRendererBuilder visitSelect_statement(EqlParser.Select_statementContext ctx) { + public QueryTokenStream visitSelect_statement(EqlParser.Select_statementContext ctx) { QueryRendererBuilder builder = QueryRenderer.builder(); @@ -92,7 +92,7 @@ class EqlCountQueryTransformer extends EqlQueryRenderer { return builder; } - private QueryRendererBuilder getDistinctCountSelection(QueryTokenStream selectionListbuilder) { + private QueryTokenStream getDistinctCountSelection(QueryTokenStream selectionListbuilder) { QueryRendererBuilder nested = new QueryRendererBuilder(); CountSelectionTokenStream countSelection = CountSelectionTokenStream.create(selectionListbuilder); diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java index 516b7c360..b36a7fb98 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java @@ -79,30 +79,8 @@ class EqlQueryRenderer extends EqlBaseVisitor { builder.appendExpression(visit(ctx.orderby_clause())); } - for (int i = 0; i < ctx.setOperator().size(); i++) { - - builder.appendExpression(visit(ctx.setOperator(i))); - builder.appendExpression(visit(ctx.select_statement(i))); - } - - return builder; - } - - @Override - public QueryTokenStream visitSetOperator(EqlParser.SetOperatorContext ctx) { - - QueryRendererBuilder builder = QueryRenderer.builder(); - - if (ctx.UNION() != null) { - builder.append(QueryTokens.expression(ctx.UNION())); - } else if (ctx.INTERSECT() != null) { - builder.append(QueryTokens.expression(ctx.INTERSECT())); - } else if (ctx.EXCEPT() != null) { - builder.append(QueryTokens.expression(ctx.EXCEPT())); - } - - if (ctx.ALL() != null) { - builder.append(QueryTokens.expression(ctx.ALL())); + if (ctx.set_fuction() != null) { + builder.appendExpression(visit(ctx.set_fuction())); } return builder; @@ -228,9 +206,11 @@ class EqlQueryRenderer extends EqlBaseVisitor { if (ctx.AS() != null) { builder.append(QueryTokens.expression(ctx.AS())); } + if (ctx.identification_variable() != null) { builder.appendExpression(visit(ctx.identification_variable())); } + if (ctx.join_condition() != null) { builder.appendExpression(visit(ctx.join_condition())); } @@ -293,8 +273,7 @@ class EqlQueryRenderer extends EqlBaseVisitor { } @Override - public QueryTokenStream visitJoin_association_path_expression( - EqlParser.Join_association_path_expressionContext ctx) { + public QueryTokenStream visitJoin_association_path_expression(EqlParser.Join_association_path_expressionContext ctx) { QueryRendererBuilder builder = QueryRenderer.builder(); @@ -306,31 +285,25 @@ class EqlQueryRenderer extends EqlBaseVisitor { builder.appendExpression(visit(ctx.join_single_valued_path_expression())); } } else { + QueryRendererBuilder nested = QueryRenderer.builder(); + if (ctx.join_collection_valued_path_expression() != null) { - QueryRendererBuilder nested = QueryRenderer.builder(); - - nested.append(QueryTokens.token(ctx.TREAT())); - nested.append(TOKEN_OPEN_PAREN); - nested.appendInline(visit(ctx.join_collection_valued_path_expression())); + nested.appendExpression(visit(ctx.join_collection_valued_path_expression())); nested.append(QueryTokens.expression(ctx.AS())); - nested.appendInline(visit(ctx.subtype())); - nested.append(TOKEN_CLOSE_PAREN); + nested.appendExpression(visit(ctx.subtype())); - builder.appendExpression(nested); } else if (ctx.join_single_valued_path_expression() != null) { - QueryRendererBuilder nested = QueryRenderer.builder(); - - nested.append(QueryTokens.token(ctx.TREAT())); - nested.append(TOKEN_OPEN_PAREN); - nested.appendInline(visit(ctx.join_single_valued_path_expression())); + nested.appendExpression(visit(ctx.join_single_valued_path_expression())); nested.append(QueryTokens.expression(ctx.AS())); - nested.appendInline(visit(ctx.subtype())); - nested.append(TOKEN_CLOSE_PAREN); - - builder.appendExpression(nested); + nested.appendExpression(visit(ctx.subtype())); } + + builder.append(QueryTokens.token(ctx.TREAT())); + builder.append(TOKEN_OPEN_PAREN); + builder.appendInline(nested); + builder.append(TOKEN_CLOSE_PAREN); } return builder; @@ -452,8 +425,7 @@ class EqlQueryRenderer extends EqlBaseVisitor { } @Override - public QueryTokenStream visitGeneral_identification_variable( - EqlParser.General_identification_variableContext ctx) { + public QueryTokenStream visitGeneral_identification_variable(EqlParser.General_identification_variableContext ctx) { QueryRendererBuilder builder = QueryRenderer.builder(); @@ -496,12 +468,15 @@ class EqlQueryRenderer extends EqlBaseVisitor { public QueryTokenStream visitTreated_subpath(EqlParser.Treated_subpathContext ctx) { QueryRendererBuilder builder = QueryRenderer.builder(); + QueryRendererBuilder nested = QueryRenderer.builder(); + + nested.appendExpression(visit(ctx.general_subpath())); + nested.append(QueryTokens.expression(ctx.AS())); + nested.appendExpression(visit(ctx.subtype())); builder.append(QueryTokens.token(ctx.TREAT())); builder.append(TOKEN_OPEN_PAREN); - builder.appendInline(visit(ctx.general_subpath())); - builder.append(QueryTokens.expression(ctx.AS())); - builder.appendInline(visit(ctx.subtype())); + builder.appendInline(nested); builder.append(TOKEN_CLOSE_PAREN); return builder; @@ -854,15 +829,15 @@ class EqlQueryRenderer extends EqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); if (ctx.state_field_path_expression() != null) { - builder.append(visit(ctx.state_field_path_expression())); + builder.appendExpression(visit(ctx.state_field_path_expression())); } else if (ctx.general_identification_variable() != null) { - builder.append(visit(ctx.general_identification_variable())); + builder.appendExpression(visit(ctx.general_identification_variable())); } else if (ctx.result_variable() != null) { - builder.append(visit(ctx.result_variable())); + builder.appendExpression(visit(ctx.result_variable())); } else if (ctx.string_expression() != null) { - builder.append(visit(ctx.string_expression())); + builder.appendExpression(visit(ctx.string_expression())); } else if (ctx.scalar_expression() != null) { - builder.append(visit(ctx.scalar_expression())); + builder.appendExpression(visit(ctx.scalar_expression())); } if (ctx.ASC() != null) { @@ -884,12 +859,44 @@ class EqlQueryRenderer extends EqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); - builder.append(TOKEN_NULLS); + builder.append(QueryTokens.expression(ctx.NULLS())); if (ctx.FIRST() != null) { - builder.append(TOKEN_FIRST); + builder.append(QueryTokens.expression(ctx.FIRST())); } else if (ctx.LAST() != null) { - builder.append(TOKEN_LAST); + builder.append(QueryTokens.expression(ctx.LAST())); + } + + return builder; + } + + @Override + public QueryTokenStream visitSet_fuction(EqlParser.Set_fuctionContext ctx) { + + QueryRendererBuilder builder = QueryRenderer.builder(); + + if (ctx.setOperator() != null) { + builder.append(visit(ctx.setOperator())); + } + + builder.appendExpression(visit(ctx.select_statement())); + + return builder; + } + + @Override + public QueryTokenStream visitSetOperator(EqlParser.SetOperatorContext ctx) { + + QueryRendererBuilder builder = QueryRenderer.builder(); + + if (ctx.INTERSECT() != null) { + builder.append(QueryTokens.expression(ctx.INTERSECT())); + } else if (ctx.UNION() != null) { + builder.append(QueryTokens.expression(ctx.UNION())); + } else if (ctx.EXCEPT() != null) { + builder.append(QueryTokens.expression(ctx.EXCEPT())); + } else if (ctx.ALL() != null) { + builder.append(QueryTokens.expression(ctx.ALL())); } return builder; @@ -994,83 +1001,82 @@ class EqlQueryRenderer extends EqlBaseVisitor { @Override public QueryTokenStream visitScalar_expression(EqlParser.Scalar_expressionContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.arithmetic_expression() != null) { - builder.append(visit(ctx.arithmetic_expression())); + return visit(ctx.arithmetic_expression()); } else if (ctx.string_expression() != null) { - builder.append(visit(ctx.string_expression())); + return visit(ctx.string_expression()); } else if (ctx.enum_expression() != null) { - builder.append(visit(ctx.enum_expression())); + return visit(ctx.enum_expression()); } else if (ctx.datetime_expression() != null) { - builder.append(visit(ctx.datetime_expression())); + return visit(ctx.datetime_expression()); } else if (ctx.boolean_expression() != null) { - builder.append(visit(ctx.boolean_expression())); + return visit(ctx.boolean_expression()); } else if (ctx.case_expression() != null) { - builder.append(visit(ctx.case_expression())); + return visit(ctx.case_expression()); } else if (ctx.entity_type_expression() != null) { - builder.append(visit(ctx.entity_type_expression())); + return visit(ctx.entity_type_expression()); } else if (ctx.cast_function() != null) { return (visit(ctx.cast_function())); } - return builder; + return QueryTokenStream.empty(); } @Override public QueryTokenStream visitConditional_expression(EqlParser.Conditional_expressionContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.conditional_expression() != null) { - builder.append(visit(ctx.conditional_expression())); - builder.append(QueryTokens.expression(ctx.OR())); - builder.append(visit(ctx.conditional_term())); - } else { - builder.append(visit(ctx.conditional_term())); - } + QueryRendererBuilder builder = QueryRenderer.builder(); - return builder; + builder.appendExpression(visit(ctx.conditional_expression())); + builder.append(QueryTokens.expression(ctx.OR())); + builder.appendExpression(visit(ctx.conditional_term())); + + return builder; + } else { + return visit(ctx.conditional_term()); + } } @Override public QueryTokenStream visitConditional_term(EqlParser.Conditional_termContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.conditional_term() != null) { - builder.append(visit(ctx.conditional_term())); - builder.append(QueryTokens.expression(ctx.AND())); - builder.append(visit(ctx.conditional_factor())); - } else { - builder.append(visit(ctx.conditional_factor())); - } + QueryRendererBuilder builder = QueryRenderer.builder(); - return builder; + builder.appendExpression(visit(ctx.conditional_term())); + builder.append(QueryTokens.expression(ctx.AND())); + builder.appendExpression(visit(ctx.conditional_factor())); + + return builder; + } else { + return visit(ctx.conditional_factor()); + } } @Override public QueryTokenStream visitConditional_factor(EqlParser.Conditional_factorContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.NOT() != null) { + QueryRendererBuilder builder = QueryRenderer.builder(); builder.append(QueryTokens.expression(ctx.NOT())); + builder.appendExpression(visit(ctx.conditional_primary())); + return builder; } - builder.append(visit(ctx.conditional_primary())); - - return builder; + return visit(ctx.conditional_primary()); } @Override public QueryTokenStream visitConditional_primary(EqlParser.Conditional_primaryContext ctx) { + if (ctx.simple_cond_expression() != null) { + return visit(ctx.simple_cond_expression()); + } + QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.simple_cond_expression() != null) { - builder.append(visit(ctx.simple_cond_expression())); - } else if (ctx.conditional_expression() != null) { + if (ctx.conditional_expression() != null) { builder.append(TOKEN_OPEN_PAREN); builder.appendInline(visit(ctx.conditional_expression())); @@ -1083,27 +1089,25 @@ class EqlQueryRenderer extends EqlBaseVisitor { @Override public QueryTokenStream visitSimple_cond_expression(EqlParser.Simple_cond_expressionContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.comparison_expression() != null) { - builder.append(visit(ctx.comparison_expression())); + return visit(ctx.comparison_expression()); } else if (ctx.between_expression() != null) { - builder.append(visit(ctx.between_expression())); + return visit(ctx.between_expression()); } else if (ctx.in_expression() != null) { - builder.append(visit(ctx.in_expression())); + return visit(ctx.in_expression()); } else if (ctx.like_expression() != null) { - builder.append(visit(ctx.like_expression())); + return visit(ctx.like_expression()); } else if (ctx.null_comparison_expression() != null) { - builder.append(visit(ctx.null_comparison_expression())); + return visit(ctx.null_comparison_expression()); } else if (ctx.empty_collection_comparison_expression() != null) { - builder.append(visit(ctx.empty_collection_comparison_expression())); + return visit(ctx.empty_collection_comparison_expression()); } else if (ctx.collection_member_expression() != null) { - builder.append(visit(ctx.collection_member_expression())); + return visit(ctx.collection_member_expression()); } else if (ctx.exists_expression() != null) { - builder.append(visit(ctx.exists_expression())); + return visit(ctx.exists_expression()); } - return builder; + return QueryTokenStream.empty(); } @Override @@ -1113,7 +1117,7 @@ class EqlQueryRenderer extends EqlBaseVisitor { if (ctx.arithmetic_expression(0) != null) { - builder.append(visit(ctx.arithmetic_expression(0))); + builder.appendExpression(visit(ctx.arithmetic_expression(0))); if (ctx.NOT() != null) { builder.append(QueryTokens.expression(ctx.NOT())); @@ -1139,7 +1143,7 @@ class EqlQueryRenderer extends EqlBaseVisitor { } else if (ctx.datetime_expression(0) != null) { - builder.append(visit(ctx.datetime_expression(0))); + builder.appendExpression(visit(ctx.datetime_expression(0))); if (ctx.NOT() != null) { builder.append(QueryTokens.expression(ctx.NOT())); @@ -1160,10 +1164,10 @@ class EqlQueryRenderer extends EqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); if (ctx.string_expression() != null) { - builder.append(visit(ctx.string_expression())); + builder.appendExpression(visit(ctx.string_expression())); } if (ctx.type_discriminator() != null) { - builder.append(visit(ctx.type_discriminator())); + builder.appendExpression(visit(ctx.type_discriminator())); } if (ctx.NOT() != null) { builder.append(QueryTokens.expression(ctx.NOT())); @@ -1176,7 +1180,6 @@ class EqlQueryRenderer extends EqlBaseVisitor { builder.append(TOKEN_OPEN_PAREN); builder.appendInline(QueryTokenStream.concat(ctx.in_item(), this::visit, TOKEN_COMMA)); - builder.append(TOKEN_CLOSE_PAREN); } else if (ctx.subquery() != null) { @@ -1217,7 +1220,8 @@ class EqlQueryRenderer extends EqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); - builder.append(visit(ctx.string_expression())); + builder.appendExpression(visit(ctx.string_expression())); + if (ctx.NOT() != null) { builder.append(QueryTokens.expression(ctx.NOT())); } @@ -1239,11 +1243,11 @@ class EqlQueryRenderer extends EqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); if (ctx.single_valued_path_expression() != null) { - builder.append(visit(ctx.single_valued_path_expression())); + builder.appendExpression(visit(ctx.single_valued_path_expression())); } else if (ctx.input_parameter() != null) { - builder.append(visit(ctx.input_parameter())); + builder.appendExpression(visit(ctx.input_parameter())); } else if (ctx.nullif_expression() != null) { - builder.append(visit(ctx.nullif_expression())); + builder.appendExpression(visit(ctx.nullif_expression())); } if (ctx.op != null) { @@ -1265,7 +1269,7 @@ class EqlQueryRenderer extends EqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); - builder.append(visit(ctx.collection_valued_path_expression())); + builder.appendExpression(visit(ctx.collection_valued_path_expression())); builder.append(QueryTokens.expression(ctx.IS())); if (ctx.NOT() != null) { builder.append(QueryTokens.expression(ctx.NOT())); @@ -1280,7 +1284,7 @@ class EqlQueryRenderer extends EqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); - builder.append(visit(ctx.entity_or_value_expression())); + builder.appendExpression(visit(ctx.entity_or_value_expression())); if (ctx.NOT() != null) { builder.append(QueryTokens.expression(ctx.NOT())); } @@ -1296,25 +1300,21 @@ class EqlQueryRenderer extends EqlBaseVisitor { @Override public QueryTokenStream visitEntity_or_value_expression(EqlParser.Entity_or_value_expressionContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.single_valued_object_path_expression() != null) { - builder.append(visit(ctx.single_valued_object_path_expression())); + return visit(ctx.single_valued_object_path_expression()); } else if (ctx.state_field_path_expression() != null) { - builder.append(visit(ctx.state_field_path_expression())); + return visit(ctx.state_field_path_expression()); } else if (ctx.simple_entity_or_value_expression() != null) { - builder.append(visit(ctx.simple_entity_or_value_expression())); + return visit(ctx.simple_entity_or_value_expression()); } - return builder; + return QueryTokenStream.empty(); } @Override public QueryTokenStream visitSimple_entity_or_value_expression( EqlParser.Simple_entity_or_value_expressionContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.identification_variable() != null) { return visit(ctx.identification_variable()); } else if (ctx.input_parameter() != null) { @@ -1368,13 +1368,13 @@ class EqlQueryRenderer extends EqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); - builder.appendInline(visit(ctx.string_expression(0))); - builder.append(visit(ctx.comparison_operator())); + builder.appendExpression(visit(ctx.string_expression(0))); + builder.appendExpression(visit(ctx.comparison_operator())); if (ctx.string_expression(1) != null) { - builder.append(visit(ctx.string_expression(1))); + builder.appendExpression(visit(ctx.string_expression(1))); } else { - builder.append(visit(ctx.all_or_any_expression())); + builder.appendExpression(visit(ctx.all_or_any_expression())); } return builder; @@ -1389,9 +1389,9 @@ class EqlQueryRenderer extends EqlBaseVisitor { builder.append(QueryTokens.ventilated(ctx.op)); if (ctx.boolean_expression(1) != null) { - builder.append(visit(ctx.boolean_expression(1))); + builder.appendExpression(visit(ctx.boolean_expression(1))); } else { - builder.append(visit(ctx.all_or_any_expression())); + builder.appendExpression(visit(ctx.all_or_any_expression())); } return builder; @@ -1411,9 +1411,9 @@ class EqlQueryRenderer extends EqlBaseVisitor { builder.append(QueryTokens.ventilated(ctx.op)); if (ctx.enum_expression(1) != null) { - builder.append(visit(ctx.enum_expression(1))); + builder.appendExpression(visit(ctx.enum_expression(1))); } else { - builder.append(visit(ctx.all_or_any_expression())); + builder.appendExpression(visit(ctx.all_or_any_expression())); } return builder; @@ -1428,9 +1428,9 @@ class EqlQueryRenderer extends EqlBaseVisitor { builder.append(QueryTokens.ventilated(ctx.comparison_operator().op)); if (ctx.datetime_expression(1) != null) { - builder.append(visit(ctx.datetime_expression(1))); + builder.appendExpression(visit(ctx.datetime_expression(1))); } else { - builder.append(visit(ctx.all_or_any_expression())); + builder.appendExpression(visit(ctx.all_or_any_expression())); } return builder; @@ -1445,9 +1445,9 @@ class EqlQueryRenderer extends EqlBaseVisitor { builder.append(QueryTokens.expression(ctx.op)); if (ctx.entity_expression(1) != null) { - builder.append(visit(ctx.entity_expression(1))); + builder.appendExpression(visit(ctx.entity_expression(1))); } else { - builder.append(visit(ctx.all_or_any_expression())); + builder.appendExpression(visit(ctx.all_or_any_expression())); } return builder; @@ -1458,13 +1458,13 @@ class EqlQueryRenderer extends EqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); - builder.append(visit(ctx.arithmetic_expression(0))); - builder.append(visit(ctx.comparison_operator())); + builder.appendExpression(visit(ctx.arithmetic_expression(0))); + builder.appendExpression(visit(ctx.comparison_operator())); if (ctx.arithmetic_expression(1) != null) { - builder.append(visit(ctx.arithmetic_expression(1))); + builder.appendExpression(visit(ctx.arithmetic_expression(1))); } else { - builder.append(visit(ctx.all_or_any_expression())); + builder.appendExpression(visit(ctx.all_or_any_expression())); } return builder; @@ -1477,7 +1477,7 @@ class EqlQueryRenderer extends EqlBaseVisitor { builder.appendInline(visit(ctx.entity_type_expression(0))); builder.append(QueryTokens.ventilated(ctx.op)); - builder.append(visit(ctx.entity_type_expression(1))); + builder.appendExpression(visit(ctx.entity_type_expression(1))); return builder; } @@ -1496,42 +1496,37 @@ class EqlQueryRenderer extends EqlBaseVisitor { @Override public QueryTokenStream visitComparison_operator(EqlParser.Comparison_operatorContext ctx) { - return QueryRendererBuilder.from(QueryTokens.ventilated(ctx.op)); + return QueryRenderer.from(QueryTokens.token(ctx.op)); } @Override public QueryTokenStream visitArithmetic_expression(EqlParser.Arithmetic_expressionContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.arithmetic_expression() != null) { + QueryRendererBuilder builder = QueryRenderer.builder(); builder.append(visit(ctx.arithmetic_expression())); - builder.append(QueryTokens.expression(ctx.op)); + builder.append(QueryTokens.ventilated(ctx.op)); builder.append(visit(ctx.arithmetic_term())); + return builder; } else { - builder.append(visit(ctx.arithmetic_term())); + return visit(ctx.arithmetic_term()); } - - return builder; } @Override public QueryTokenStream visitArithmetic_term(EqlParser.Arithmetic_termContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.arithmetic_term() != null) { - + QueryRendererBuilder builder = QueryRenderer.builder(); builder.appendInline(visit(ctx.arithmetic_term())); builder.append(QueryTokens.ventilated(ctx.op)); builder.append(visit(ctx.arithmetic_factor())); + return builder; } else { - builder.append(visit(ctx.arithmetic_factor())); + return visit(ctx.arithmetic_factor()); } - - return builder; } @Override @@ -1542,7 +1537,8 @@ class EqlQueryRenderer extends EqlBaseVisitor { if (ctx.op != null) { builder.append(QueryTokens.token(ctx.op)); } - builder.appendInline(visit(ctx.arithmetic_primary())); + + builder.append(visit(ctx.arithmetic_primary())); return builder; } @@ -1705,45 +1701,39 @@ class EqlQueryRenderer extends EqlBaseVisitor { @Override public QueryTokenStream visitEntity_expression(EqlParser.Entity_expressionContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.single_valued_object_path_expression() != null) { - builder.append(visit(ctx.single_valued_object_path_expression())); + return visit(ctx.single_valued_object_path_expression()); } else if (ctx.simple_entity_expression() != null) { - builder.append(visit(ctx.simple_entity_expression())); + return visit(ctx.simple_entity_expression()); } - return builder; + return QueryTokenStream.empty(); } @Override public QueryTokenStream visitSimple_entity_expression(EqlParser.Simple_entity_expressionContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.identification_variable() != null) { - builder.append(visit(ctx.identification_variable())); + return visit(ctx.identification_variable()); } else if (ctx.input_parameter() != null) { - builder.append(visit(ctx.input_parameter())); + return visit(ctx.input_parameter()); } - return builder; + return QueryTokenStream.empty(); } @Override public QueryTokenStream visitEntity_type_expression(EqlParser.Entity_type_expressionContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.type_discriminator() != null) { - builder.append(visit(ctx.type_discriminator())); + return visit(ctx.type_discriminator()); } else if (ctx.entity_type_literal() != null) { - builder.append(visit(ctx.entity_type_literal())); + return visit(ctx.entity_type_literal()); } else if (ctx.input_parameter() != null) { - builder.append(visit(ctx.input_parameter())); + return visit(ctx.input_parameter()); } - return builder; + return QueryTokenStream.empty(); } @Override @@ -1918,7 +1908,7 @@ class EqlQueryRenderer extends EqlBaseVisitor { builder.append(QueryTokens.token(ctx.SUBSTRING())); builder.append(TOKEN_OPEN_PAREN); - builder.appendInline(visit(ctx.string_expression(0))); + builder.append(visit(ctx.string_expression(0))); builder.append(TOKEN_COMMA); builder.appendInline(QueryTokenStream.concat(ctx.arithmetic_expression(), this::visit, TOKEN_COMMA)); builder.append(TOKEN_CLOSE_PAREN); @@ -1935,7 +1925,7 @@ class EqlQueryRenderer extends EqlBaseVisitor { if (ctx.FROM() != null) { builder.append(QueryTokens.expression(ctx.FROM())); } - builder.appendInline(visit(ctx.string_expression(0))); + builder.append(visit(ctx.string_expression(0))); builder.append(TOKEN_CLOSE_PAREN); } else if (ctx.LOWER() != null) { @@ -1947,10 +1937,9 @@ class EqlQueryRenderer extends EqlBaseVisitor { builder.append(QueryTokens.token(ctx.UPPER())); builder.append(TOKEN_OPEN_PAREN); - builder.appendInline(visit(ctx.string_expression(0))); + builder.append(visit(ctx.string_expression(0))); builder.append(TOKEN_CLOSE_PAREN); } else if (ctx.LEFT() != null) { - builder.append(QueryTokens.token(ctx.LEFT())); builder.append(TOKEN_OPEN_PAREN); builder.appendInline(visit(ctx.string_expression(0))); @@ -1958,7 +1947,6 @@ class EqlQueryRenderer extends EqlBaseVisitor { builder.appendInline(visit(ctx.arithmetic_expression(0))); builder.append(TOKEN_CLOSE_PAREN); } else if (ctx.RIGHT() != null) { - builder.append(QueryTokens.token(ctx.RIGHT())); builder.append(TOKEN_OPEN_PAREN); builder.appendInline(visit(ctx.string_expression(0))); @@ -1966,7 +1954,6 @@ class EqlQueryRenderer extends EqlBaseVisitor { builder.appendInline(visit(ctx.arithmetic_expression(0))); builder.append(TOKEN_CLOSE_PAREN); } else if (ctx.REPLACE() != null) { - builder.append(QueryTokens.token(ctx.REPLACE())); builder.append(TOKEN_OPEN_PAREN); builder.appendInline(visit(ctx.string_expression(0))); @@ -1984,11 +1971,11 @@ class EqlQueryRenderer extends EqlBaseVisitor { public QueryTokenStream visitTrim_specification(EqlParser.Trim_specificationContext ctx) { if (ctx.LEADING() != null) { - return QueryRendererBuilder.from(QueryTokens.expression(ctx.LEADING())); + return QueryRenderer.from(QueryTokens.expression(ctx.LEADING())); } else if (ctx.TRAILING() != null) { - return QueryRendererBuilder.from(QueryTokens.expression(ctx.TRAILING())); + return QueryRenderer.from(QueryTokens.expression(ctx.TRAILING())); } else { - return QueryRendererBuilder.from(QueryTokens.expression(ctx.BOTH())); + return QueryRenderer.from(QueryTokens.expression(ctx.BOTH())); } } @@ -2076,12 +2063,15 @@ class EqlQueryRenderer extends EqlBaseVisitor { public QueryTokenStream visitExtract_datetime_field(EqlParser.Extract_datetime_fieldContext ctx) { QueryRendererBuilder builder = QueryRenderer.builder(); + QueryRendererBuilder nested = QueryRenderer.builder(); + + nested.appendExpression(visit(ctx.datetime_field())); + nested.append(QueryTokens.expression(ctx.FROM())); + nested.appendExpression(visit(ctx.datetime_expression())); builder.append(QueryTokens.token(ctx.EXTRACT())); builder.append(TOKEN_OPEN_PAREN); - builder.appendExpression(visit(ctx.datetime_field())); - builder.append(QueryTokens.expression(ctx.FROM())); - builder.appendInline(visit(ctx.datetime_expression())); + builder.appendInline(nested); builder.append(TOKEN_CLOSE_PAREN); return builder; @@ -2096,12 +2086,15 @@ class EqlQueryRenderer extends EqlBaseVisitor { public QueryTokenStream visitExtract_datetime_part(EqlParser.Extract_datetime_partContext ctx) { QueryRendererBuilder builder = QueryRenderer.builder(); + QueryRendererBuilder nested = QueryRenderer.builder(); + + nested.appendExpression(visit(ctx.datetime_part())); + nested.append(QueryTokens.expression(ctx.FROM())); + nested.appendExpression(visit(ctx.datetime_expression())); builder.append(QueryTokens.token(ctx.EXTRACT())); builder.append(TOKEN_OPEN_PAREN); - builder.appendExpression(visit(ctx.datetime_part())); - builder.append(QueryTokens.expression(ctx.FROM())); - builder.appendInline(visit(ctx.datetime_expression())); + builder.appendInline(nested); builder.append(TOKEN_CLOSE_PAREN); return builder; @@ -2154,10 +2147,7 @@ class EqlQueryRenderer extends EqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); builder.append(QueryTokens.expression(ctx.CASE())); - - ctx.when_clause().forEach(whenClauseContext -> { - builder.appendExpression(visit(whenClauseContext)); - }); + builder.appendExpression(QueryTokenStream.concat(ctx.when_clause(), this::visit, TOKEN_SPACE)); builder.append(QueryTokens.expression(ctx.ELSE())); builder.appendExpression(visit(ctx.scalar_expression())); @@ -2172,9 +2162,9 @@ class EqlQueryRenderer extends EqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); builder.append(QueryTokens.expression(ctx.WHEN())); - builder.append(visit(ctx.conditional_expression())); + builder.appendExpression(visit(ctx.conditional_expression())); builder.append(QueryTokens.expression(ctx.THEN())); - builder.append(visit(ctx.scalar_expression())); + builder.appendExpression(visit(ctx.scalar_expression())); return builder; } @@ -2185,14 +2175,11 @@ class EqlQueryRenderer extends EqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); builder.append(QueryTokens.expression(ctx.CASE())); - builder.append(visit(ctx.case_operand())); - - ctx.simple_when_clause().forEach(simpleWhenClauseContext -> { - builder.append(visit(simpleWhenClauseContext)); - }); + builder.appendExpression(visit(ctx.case_operand())); + builder.appendExpression(QueryTokenStream.concat(ctx.simple_when_clause(), this::visit, TOKEN_SPACE)); builder.append(QueryTokens.expression(ctx.ELSE())); - builder.append(visit(ctx.scalar_expression())); + builder.appendExpression(visit(ctx.scalar_expression())); builder.append(QueryTokens.expression(ctx.END())); return builder; @@ -2253,11 +2240,11 @@ class EqlQueryRenderer extends EqlBaseVisitor { public QueryTokenStream visitTrim_character(EqlParser.Trim_characterContext ctx) { if (ctx.CHARACTER() != null) { - return QueryRendererBuilder.from(QueryTokens.expression(ctx.CHARACTER())); + return QueryRenderer.from(QueryTokens.expression(ctx.CHARACTER())); } else if (ctx.character_valued_input_parameter() != null) { return visit(ctx.character_valued_input_parameter()); } else { - return QueryRenderer.builder(); + return QueryTokenStream.empty(); } } @@ -2265,14 +2252,14 @@ class EqlQueryRenderer extends EqlBaseVisitor { public QueryTokenStream visitIdentification_variable(EqlParser.Identification_variableContext ctx) { if (ctx.IDENTIFICATION_VARIABLE() != null) { - return QueryRendererBuilder.from(QueryTokens.expression(ctx.IDENTIFICATION_VARIABLE())); - } else if (ctx.f != null) { - return QueryRendererBuilder.from(QueryTokens.expression(ctx.f)); + return QueryRenderer.from(QueryTokens.token(ctx.IDENTIFICATION_VARIABLE())); } else if (ctx.type_literal() != null) { return visit(ctx.type_literal()); + } else if (ctx.f != null) { + return QueryRenderer.from(QueryTokens.token(ctx.f)); + } else { + return QueryTokenStream.empty(); } - - return QueryRenderer.builder(); } @Override @@ -2283,23 +2270,23 @@ class EqlQueryRenderer extends EqlBaseVisitor { @Override public QueryTokenStream visitLiteral(EqlParser.LiteralContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.STRINGLITERAL() != null) { - builder.append(QueryTokens.expression(ctx.STRINGLITERAL())); + return QueryRenderer.from(QueryTokens.expression(ctx.STRINGLITERAL())); + } else if (ctx.JAVASTRINGLITERAL() != null) { + return QueryRenderer.from(QueryTokens.expression(ctx.JAVASTRINGLITERAL())); } else if (ctx.INTLITERAL() != null) { - builder.append(QueryTokens.expression(ctx.INTLITERAL())); + return QueryRenderer.from(QueryTokens.expression(ctx.INTLITERAL())); } else if (ctx.FLOATLITERAL() != null) { - builder.append(QueryTokens.expression(ctx.FLOATLITERAL())); + return QueryRenderer.from(QueryTokens.expression(ctx.FLOATLITERAL())); } else if (ctx.LONGLITERAL() != null) { - builder.append(QueryTokens.expression(ctx.LONGLITERAL())); + return QueryRenderer.from(QueryTokens.expression(ctx.LONGLITERAL())); } else if (ctx.boolean_literal() != null) { - builder.append(visit(ctx.boolean_literal())); + return visit(ctx.boolean_literal()); } else if (ctx.entity_type_literal() != null) { - builder.append(visit(ctx.entity_type_literal())); + return visit(ctx.entity_type_literal()); } - return builder; + return QueryTokenStream.empty(); } @Override @@ -2355,7 +2342,7 @@ class EqlQueryRenderer extends EqlBaseVisitor { public QueryTokenStream visitEscape_character(EqlParser.Escape_characterContext ctx) { if (ctx.CHARACTER() != null) { - return QueryRendererBuilder.from(QueryTokens.token(ctx.CHARACTER())); + return QueryRenderer.from(QueryTokens.expression(ctx.CHARACTER())); } else if (ctx.character_valued_input_parameter() != null) { return visit(ctx.character_valued_input_parameter()); } else if (ctx.string_literal() != null) { @@ -2369,13 +2356,13 @@ class EqlQueryRenderer extends EqlBaseVisitor { public QueryTokenStream visitNumeric_literal(EqlParser.Numeric_literalContext ctx) { if (ctx.INTLITERAL() != null) { - return QueryRendererBuilder.from(QueryTokens.token(ctx.INTLITERAL())); + return QueryRenderer.from(QueryTokens.token(ctx.INTLITERAL())); } else if (ctx.FLOATLITERAL() != null) { - return QueryRendererBuilder.from(QueryTokens.token(ctx.FLOATLITERAL())); + return QueryRenderer.from(QueryTokens.token(ctx.FLOATLITERAL())); } else if (ctx.LONGLITERAL() != null) { - return QueryRendererBuilder.from(QueryTokens.token(ctx.LONGLITERAL())); + return QueryRenderer.from(QueryTokens.token(ctx.LONGLITERAL())); } else { - return QueryRenderer.builder(); + return QueryTokenStream.empty(); } } @@ -2383,11 +2370,11 @@ class EqlQueryRenderer extends EqlBaseVisitor { public QueryTokenStream visitBoolean_literal(EqlParser.Boolean_literalContext ctx) { if (ctx.TRUE() != null) { - return QueryRendererBuilder.from(QueryTokens.token(ctx.TRUE())); + return QueryRenderer.from(QueryTokens.expression(ctx.TRUE())); } else if (ctx.FALSE() != null) { - return QueryRendererBuilder.from(QueryTokens.token(ctx.FALSE())); + return QueryRenderer.from(QueryTokens.expression(ctx.FALSE())); } else { - return QueryRenderer.builder(); + return QueryTokenStream.empty(); } } @@ -2400,11 +2387,11 @@ class EqlQueryRenderer extends EqlBaseVisitor { public QueryTokenStream visitString_literal(EqlParser.String_literalContext ctx) { if (ctx.CHARACTER() != null) { - return QueryRendererBuilder.from(QueryTokens.expression(ctx.CHARACTER())); + return QueryRenderer.from(QueryTokens.expression(ctx.CHARACTER())); } else if (ctx.STRINGLITERAL() != null) { - return QueryRendererBuilder.from(QueryTokens.expression(ctx.STRINGLITERAL())); + return QueryRenderer.from(QueryTokens.expression(ctx.STRINGLITERAL())); } else { - return QueryRenderer.builder(); + return QueryTokenStream.empty(); } } @@ -2461,7 +2448,7 @@ class EqlQueryRenderer extends EqlBaseVisitor { @Override public QueryTokenStream visitEntity_name(EqlParser.Entity_nameContext ctx) { - return QueryTokenStream.concat(ctx.reserved_word(), this::visit, QueryRenderer::inline, TOKEN_DOT); + return QueryTokenStream.concat(ctx.reserved_word(), this::visit, TOKEN_DOT); } @Override @@ -2492,26 +2479,25 @@ class EqlQueryRenderer extends EqlBaseVisitor { } @Override - public QueryTokenStream visitCharacter_valued_input_parameter( - EqlParser.Character_valued_input_parameterContext ctx) { + public QueryTokenStream visitCharacter_valued_input_parameter(EqlParser.Character_valued_input_parameterContext ctx) { if (ctx.CHARACTER() != null) { - return QueryRendererBuilder.from(QueryTokens.expression(ctx.CHARACTER())); + return QueryRenderer.from(QueryTokens.expression(ctx.CHARACTER())); } else if (ctx.input_parameter() != null) { return visit(ctx.input_parameter()); } else { - return QueryRenderer.builder(); + return QueryTokenStream.empty(); } } @Override public QueryTokenStream visitReserved_word(EqlParser.Reserved_wordContext ctx) { if (ctx.IDENTIFICATION_VARIABLE() != null) { - return QueryRendererBuilder.from(QueryTokens.expression(ctx.IDENTIFICATION_VARIABLE())); + return QueryRenderer.from(QueryTokens.token(ctx.IDENTIFICATION_VARIABLE())); } else if (ctx.f != null) { - return QueryRendererBuilder.from(QueryTokens.expression(ctx.f)); + return QueryRenderer.from(QueryTokens.token(ctx.f)); } else { - return QueryRenderer.builder(); + return QueryTokenStream.empty(); } } } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlSortedQueryTransformer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlSortedQueryTransformer.java index e54402475..04fdc9e7c 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlSortedQueryTransformer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlSortedQueryTransformer.java @@ -24,7 +24,6 @@ import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRenderer import org.springframework.data.repository.query.ReturnedType; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; /** * An ANTLR {@link org.antlr.v4.runtime.tree.ParseTreeVisitor} that transforms a parsed EQL query by applying @@ -54,7 +53,7 @@ class EqlSortedQueryTransformer extends EqlQueryRenderer { } @Override - public QueryRendererBuilder visitSelect_statement(EqlParser.Select_statementContext ctx) { + public QueryTokenStream visitSelect_statement(EqlParser.Select_statementContext ctx) { QueryRendererBuilder builder = QueryRenderer.builder(); @@ -73,12 +72,10 @@ class EqlSortedQueryTransformer extends EqlQueryRenderer { builder.appendExpression(visit(ctx.having_clause())); } - doVisitOrderBy(builder, ctx, ObjectUtils.isEmpty(ctx.setOperator()) ? this.sort : Sort.unsorted()); - - for (int i = 0; i < ctx.setOperator().size(); i++) { - - builder.appendExpression(visit(ctx.setOperator(i))); - builder.appendExpression(visit(ctx.select_statement(i))); + if (ctx.set_fuction() != null) { + builder.appendExpression(visit(ctx.set_fuction())); + } else { + doVisitOrderBy(builder, ctx); } return builder; @@ -104,7 +101,7 @@ class EqlSortedQueryTransformer extends EqlQueryRenderer { return builder.append(dtoDelegate.transformSelectionList(tokenStream)); } - private void doVisitOrderBy(QueryRendererBuilder builder, EqlParser.Select_statementContext ctx, Sort sort) { + private void doVisitOrderBy(QueryRendererBuilder builder, EqlParser.Select_statementContext ctx) { if (ctx.orderby_clause() != null) { QueryTokenStream existingOrder = visit(ctx.orderby_clause()); diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlCountQueryTransformer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlCountQueryTransformer.java index 923c2d48c..289e6a5b6 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlCountQueryTransformer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlCountQueryTransformer.java @@ -44,16 +44,6 @@ class JpqlCountQueryTransformer extends JpqlQueryRenderer { @Override public QueryTokenStream visitSelect_statement(JpqlParser.Select_statementContext ctx) { - if(ctx.select_query() != null) { - return visitSelect_query(ctx.select_query()); - } - - return QueryTokenStream.empty(); - } - - @Override - public QueryTokenStream visitSelect_query(JpqlParser.Select_queryContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); builder.appendExpression(visit(ctx.select_clause())); @@ -68,7 +58,7 @@ class JpqlCountQueryTransformer extends JpqlQueryRenderer { if (ctx.having_clause() != null) { builder.appendExpression(visit(ctx.having_clause())); } - if(ctx.set_fuction() != null) { + if (ctx.set_fuction() != null) { builder.appendExpression(visit(ctx.set_fuction())); } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java index f07e8a0de..03b486688 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java @@ -15,28 +15,14 @@ */ package org.springframework.data.jpa.repository.query; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_CLOSE_PAREN; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_COLON; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_COMMA; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_DOT; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_EQUALS; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_OPEN_PAREN; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_QUESTION_MARK; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_DOUBLE_PIPE; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_SPACE; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_CLOSE_PAREN; -import static org.springframework.data.jpa.repository.query.QueryTokens.TOKEN_OPEN_PAREN; +import static org.springframework.data.jpa.repository.query.QueryTokens.*; import java.util.ArrayList; import java.util.List; import org.antlr.v4.runtime.tree.ParseTree; -import org.springframework.data.jpa.repository.query.JpqlParser.Except_clauseContext; -import org.springframework.data.jpa.repository.query.JpqlParser.Intersect_clauseContext; -import org.springframework.data.jpa.repository.query.JpqlParser.Relation_fuctions_selectContext; import org.springframework.data.jpa.repository.query.JpqlParser.NullsPrecedenceContext; -import org.springframework.data.jpa.repository.query.JpqlParser.Cast_expressionContext; import org.springframework.data.jpa.repository.query.JpqlParser.Reserved_wordContext; import org.springframework.data.jpa.repository.query.JpqlParser.Set_fuctionContext; import org.springframework.data.jpa.repository.query.JpqlParser.Type_literalContext; @@ -73,17 +59,8 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { } } - @Override - public QueryTokenStream visitSelect_statement(JpqlParser.Select_statementContext ctx) { - - if(ctx.select_query() != null) { - return visitSelect_query(ctx.select_query()); - } - - return QueryTokenStream.empty(); - } - - public QueryTokenStream visitSelect_query(JpqlParser.Select_queryContext ctx) { + @Override + public QueryTokenStream visitSelect_statement(JpqlParser.Select_statementContext ctx) { QueryRendererBuilder builder = QueryRenderer.builder(); @@ -106,32 +83,13 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { builder.appendExpression(visit(ctx.orderby_clause())); } - if(ctx.set_fuction() != null) { - builder.appendExpression(visit(ctx.set_fuction())); + if (ctx.set_fuction() != null) { + builder.appendExpression(visit(ctx.set_fuction())); } return builder; } - @Override - public List visitSetOperator_with_select_statement( - JpqlParser.SetOperator_with_select_statementContext ctx) { - - List tokens = new ArrayList<>(); - - if (ctx.INTERSECT() != null) { - tokens.add(new JpaQueryParsingToken(ctx.INTERSECT())); - } else if (ctx.UNION() != null) { - tokens.add(new JpaQueryParsingToken(ctx.UNION())); - } else if (ctx.EXCEPT() != null) { - tokens.add(new JpaQueryParsingToken(ctx.EXCEPT())); - } - - tokens.addAll(visit(ctx.select_statement())); - - return builder; - } - @Override public QueryTokenStream visitUpdate_statement(JpqlParser.Update_statementContext ctx) { @@ -230,14 +188,19 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); - builder.append(visit(ctx.join_spec())); - builder.append(visit(ctx.join_association_path_expression())); + builder.appendExpression(visit(ctx.join_spec())); + builder.appendExpression(visit(ctx.join_association_path_expression())); + if (ctx.AS() != null) { builder.append(QueryTokens.expression(ctx.AS())); } - builder.append(visit(ctx.identification_variable())); + + if (ctx.identification_variable() != null) { + builder.appendExpression(visit(ctx.identification_variable())); + } + if (ctx.join_condition() != null) { - builder.append(visit(ctx.join_condition())); + builder.appendExpression(visit(ctx.join_condition())); } return builder; @@ -248,9 +211,19 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); - builder.append(visit(ctx.join_spec())); + builder.appendExpression(visit(ctx.join_spec())); builder.append(QueryTokens.expression(ctx.FETCH())); - builder.append(visit(ctx.join_association_path_expression())); + builder.appendExpression(visit(ctx.join_association_path_expression())); + + if (ctx.AS() != null) { + builder.append(QueryTokens.expression(ctx.AS())); + } + if (ctx.identification_variable() != null) { + builder.appendExpression(visit(ctx.identification_variable())); + } + if (ctx.join_condition() != null) { + builder.appendExpression(visit(ctx.join_condition())); + } return builder; } @@ -301,23 +274,25 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { builder.appendExpression(visit(ctx.join_single_valued_path_expression())); } } else { + QueryRendererBuilder nested = QueryRenderer.builder(); + if (ctx.join_collection_valued_path_expression() != null) { - builder.append(QueryTokens.token(ctx.TREAT())); - builder.append(TOKEN_OPEN_PAREN); - builder.appendInline(visit(ctx.join_collection_valued_path_expression())); - builder.append(QueryTokens.expression(ctx.AS())); - builder.appendInline(visit(ctx.subtype())); - builder.append(TOKEN_CLOSE_PAREN); + nested.appendExpression(visit(ctx.join_collection_valued_path_expression())); + nested.append(QueryTokens.expression(ctx.AS())); + nested.appendExpression(visit(ctx.subtype())); + } else if (ctx.join_single_valued_path_expression() != null) { - builder.append(QueryTokens.token(ctx.TREAT())); - builder.append(TOKEN_OPEN_PAREN); - builder.appendInline(visit(ctx.join_single_valued_path_expression())); - builder.append(QueryTokens.expression(ctx.AS())); - builder.appendInline(visit(ctx.subtype())); - builder.append(TOKEN_CLOSE_PAREN); + nested.appendExpression(visit(ctx.join_single_valued_path_expression())); + nested.append(QueryTokens.expression(ctx.AS())); + nested.appendExpression(visit(ctx.subtype())); } + + builder.append(QueryTokens.token(ctx.TREAT())); + builder.append(TOKEN_OPEN_PAREN); + builder.appendInline(nested); + builder.append(TOKEN_CLOSE_PAREN); } return builder; @@ -477,12 +452,15 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { public QueryTokenStream visitTreated_subpath(JpqlParser.Treated_subpathContext ctx) { QueryRendererBuilder builder = QueryRenderer.builder(); + QueryRendererBuilder nested = QueryRenderer.builder(); + + nested.appendExpression(visit(ctx.general_subpath())); + nested.append(QueryTokens.expression(ctx.AS())); + nested.appendExpression(visit(ctx.subtype())); builder.append(QueryTokens.token(ctx.TREAT())); builder.append(TOKEN_OPEN_PAREN); - builder.appendInline(visit(ctx.general_subpath())); - builder.append(QueryTokens.expression(ctx.AS())); - builder.appendInline(visit(ctx.subtype())); + builder.appendInline(nested); builder.append(TOKEN_CLOSE_PAREN); return builder; @@ -826,19 +804,6 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { return builder; } - @Override - public QueryTokenStream visitSet_fuction(Set_fuctionContext ctx) { - - QueryRendererBuilder builder = QueryRenderer.builder(); - - builder.append(QueryTokens.expression(ctx.setOperator().getStart())); - if(ctx.setOperator().ALL() != null) { - builder.append(QueryTokens.expression(ctx.setOperator().ALL())); - } - builder.appendExpression(visit(ctx.set_function_select().select_query())); - return builder; - } - @Override public QueryTokenStream visitOrderby_item(JpqlParser.Orderby_itemContext ctx) { @@ -854,33 +819,13 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { if (ctx.ASC() != null) { builder.append(QueryTokens.expression(ctx.ASC())); - } - if (ctx.DESC() != null) { + } else if (ctx.DESC() != null) { builder.append(QueryTokens.expression(ctx.DESC())); } if (ctx.nullsPrecedence() != null) { builder.append(visit(ctx.nullsPrecedence())); } - if (ctx.nullsPrecedence() != null) { - tokens.addAll(visit(ctx.nullsPrecedence())); - } - - return tokens; - } - - @Override - public List visitNullsPrecedence(JpqlParser.NullsPrecedenceContext ctx) { - - List tokens = new ArrayList<>(); - - tokens.add(new JpaQueryParsingToken(ctx.NULLS())); - - if (ctx.FIRST() != null) { - tokens.add(new JpaQueryParsingToken(ctx.FIRST())); - } else if (ctx.LAST() != null) { - tokens.add(new JpaQueryParsingToken(ctx.LAST())); - } return builder; } @@ -890,12 +835,44 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); - builder.append(TOKEN_NULLS); + builder.append(QueryTokens.expression(ctx.NULLS())); if (ctx.FIRST() != null) { - builder.append(TOKEN_FIRST); + builder.append(QueryTokens.expression(ctx.FIRST())); } else if (ctx.LAST() != null) { - builder.append(TOKEN_LAST); + builder.append(QueryTokens.expression(ctx.LAST())); + } + + return builder; + } + + @Override + public QueryTokenStream visitSet_fuction(Set_fuctionContext ctx) { + + QueryRendererBuilder builder = QueryRenderer.builder(); + + if (ctx.setOperator() != null) { + builder.append(visit(ctx.setOperator())); + } + + builder.appendExpression(visit(ctx.select_statement())); + + return builder; + } + + @Override + public QueryTokenStream visitSetOperator(JpqlParser.SetOperatorContext ctx) { + + QueryRendererBuilder builder = QueryRenderer.builder(); + + if (ctx.INTERSECT() != null) { + builder.append(QueryTokens.expression(ctx.INTERSECT())); + } else if (ctx.UNION() != null) { + builder.append(QueryTokens.expression(ctx.UNION())); + } else if (ctx.EXCEPT() != null) { + builder.append(QueryTokens.expression(ctx.EXCEPT())); + } else if (ctx.ALL() != null) { + builder.append(QueryTokens.expression(ctx.ALL())); } return builder; @@ -1013,8 +990,8 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { return visit(ctx.case_expression()); } else if (ctx.entity_type_expression() != null) { return visit(ctx.entity_type_expression()); - } else if (ctx.cast_expression() != null) { - return (visit(ctx.cast_expression())); + } else if (ctx.cast_function() != null) { + return (visit(ctx.cast_function())); } return QueryTokenStream.empty(); @@ -1248,9 +1225,11 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { } builder.append(QueryTokens.expression(ctx.IS())); + if (ctx.NOT() != null) { builder.append(QueryTokens.expression(ctx.NOT())); } + builder.append(QueryTokens.expression(ctx.NULL())); return builder; @@ -1601,11 +1580,6 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { builder.append(visit(ctx.type_cast_function())); } else if (ctx.function_invocation() != null) { builder.append(visit(ctx.function_invocation())); - } else if (ctx.op != null) { - - tokens.addAll(visit(ctx.string_expression(0))); - tokens.add(new JpaQueryParsingToken(ctx.op)); - tokens.addAll(visit(ctx.string_expression(1))); } else if (ctx.subquery() != null) { builder.append(TOKEN_OPEN_PAREN); @@ -1859,6 +1833,8 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { builder.append(TOKEN_OPEN_PAREN); builder.appendInline(visit(ctx.identification_variable())); builder.append(TOKEN_CLOSE_PAREN); + } else if (ctx.extract_datetime_field() != null) { + builder.append(visit(ctx.extract_datetime_field())); } return builder; @@ -1886,6 +1862,8 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { } else if (ctx.DATETIME() != null) { builder.append(QueryTokens.expression(ctx.DATETIME())); } + } else if (ctx.extract_datetime_part() != null) { + builder.append(visit(ctx.extract_datetime_part())); } return builder; @@ -1907,6 +1885,7 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { builder.append(QueryTokens.token(ctx.SUBSTRING())); builder.append(TOKEN_OPEN_PAREN); builder.append(visit(ctx.string_expression(0))); + builder.append(TOKEN_COMMA); builder.appendInline(QueryTokenStream.concat(ctx.arithmetic_expression(), this::visit, TOKEN_COMMA)); builder.append(TOKEN_CLOSE_PAREN); } else if (ctx.TRIM() != null) { @@ -2053,12 +2032,15 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { public QueryTokenStream visitExtract_datetime_field(JpqlParser.Extract_datetime_fieldContext ctx) { QueryRendererBuilder builder = QueryRenderer.builder(); + QueryRendererBuilder nested = QueryRenderer.builder(); - builder.append(QueryTokens.expression(ctx.EXTRACT())); + nested.appendExpression(visit(ctx.datetime_field())); + nested.append(QueryTokens.expression(ctx.FROM())); + nested.appendExpression(visit(ctx.datetime_expression())); + + builder.append(QueryTokens.token(ctx.EXTRACT())); builder.append(TOKEN_OPEN_PAREN); - builder.appendExpression(visit(ctx.datetime_field())); - builder.append(QueryTokens.expression(ctx.FROM())); - builder.appendInline(visit(ctx.datetime_expression())); + builder.appendInline(nested); builder.append(TOKEN_CLOSE_PAREN); return builder; @@ -2073,12 +2055,15 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { public QueryTokenStream visitExtract_datetime_part(JpqlParser.Extract_datetime_partContext ctx) { QueryRendererBuilder builder = QueryRenderer.builder(); + QueryRendererBuilder nested = QueryRenderer.builder(); - builder.append(QueryTokens.expression(ctx.EXTRACT())); + nested.appendExpression(visit(ctx.datetime_part())); + nested.append(QueryTokens.expression(ctx.FROM())); + nested.appendExpression(visit(ctx.datetime_expression())); + + builder.append(QueryTokens.token(ctx.EXTRACT())); builder.append(TOKEN_OPEN_PAREN); - builder.appendExpression(visit(ctx.datetime_part())); - builder.append(QueryTokens.expression(ctx.FROM())); - builder.append(visit(ctx.datetime_expression())); + builder.appendInline(nested); builder.append(TOKEN_CLOSE_PAREN); return builder; @@ -2117,18 +2102,6 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { } } - @Override - public QueryRendererBuilder visitCast_expression(Cast_expressionContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - builder.append(QueryTokens.token(ctx.CAST())); - builder.append(TOKEN_OPEN_PAREN); - builder.appendInline(visit(ctx.string_expression())); - builder.append(QueryTokens.expression(ctx.AS())); - builder.appendInline(visit(ctx.type_literal())); - builder.append(TOKEN_CLOSE_PAREN); - return builder; - } - @Override public QueryRendererBuilder visitType_literal(Type_literalContext ctx) { @@ -2222,7 +2195,7 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { QueryRendererBuilder builder = QueryRenderer.builder(); - builder.append(QueryTokens.expression(ctx.NULLIF())); + builder.append(QueryTokens.token(ctx.NULLIF())); builder.append(TOKEN_OPEN_PAREN); builder.appendInline(visit(ctx.scalar_expression(0))); builder.append(TOKEN_COMMA); @@ -2248,7 +2221,9 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { public QueryTokenStream visitIdentification_variable(JpqlParser.Identification_variableContext ctx) { if (ctx.IDENTIFICATION_VARIABLE() != null) { - return QueryRenderer.from(QueryTokens.expression(ctx.IDENTIFICATION_VARIABLE())); + return QueryRenderer.from(QueryTokens.token(ctx.IDENTIFICATION_VARIABLE())); + } else if (ctx.type_literal() != null) { + return visit(ctx.type_literal()); } else if (ctx.f != null) { return QueryRenderer.from(QueryTokens.token(ctx.f)); } else { @@ -2308,7 +2283,18 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { @Override public QueryTokenStream visitDate_time_timestamp_literal(JpqlParser.Date_time_timestamp_literalContext ctx) { - return QueryRenderer.from(QueryTokens.expression(ctx.STRINGLITERAL())); + + if (ctx.STRINGLITERAL() != null) { + return QueryRendererBuilder.from(QueryTokens.expression(ctx.STRINGLITERAL())); + } else if (ctx.DATELITERAL() != null) { + return QueryRendererBuilder.from(QueryTokens.expression(ctx.DATELITERAL())); + } else if (ctx.TIMELITERAL() != null) { + return QueryRendererBuilder.from(QueryTokens.expression(ctx.TIMELITERAL())); + } else if (ctx.TIMESTAMPLITERAL() != null) { + return QueryRendererBuilder.from(QueryTokens.expression(ctx.TIMESTAMPLITERAL())); + } else { + return QueryRenderer.builder(); + } } @Override @@ -2421,7 +2407,7 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { @Override public QueryTokenStream visitEntity_name(JpqlParser.Entity_nameContext ctx) { - return QueryTokenStream.concat(ctx.reserved_word(), this::visitReserved_word, TOKEN_DOT); + return QueryTokenStream.concat(ctx.reserved_word(), this::visit, TOKEN_DOT); } @Override diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlSortedQueryTransformer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlSortedQueryTransformer.java index a3e9fddbf..3cef78794 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlSortedQueryTransformer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlSortedQueryTransformer.java @@ -54,16 +54,6 @@ class JpqlSortedQueryTransformer extends JpqlQueryRenderer { @Override public QueryTokenStream visitSelect_statement(JpqlParser.Select_statementContext ctx) { - if(ctx.select_query() != null) { - return visitSelect_query(ctx.select_query()); - } - - return QueryTokenStream.empty(); - } - - @Override - public QueryTokenStream visitSelect_query(JpqlParser.Select_queryContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); builder.appendExpression(visit(ctx.select_clause())); @@ -110,7 +100,7 @@ class JpqlSortedQueryTransformer extends JpqlQueryRenderer { return builder.append(dtoDelegate.transformSelectionList(tokenStream)); } - private void doVisitOrderBy(QueryRendererBuilder builder, JpqlParser.Select_queryContext ctx) { + private void doVisitOrderBy(QueryRendererBuilder builder, JpqlParser.Select_statementContext ctx) { if (ctx.orderby_clause() != null) { QueryTokenStream existingOrder = visit(ctx.orderby_clause()); @@ -160,4 +150,5 @@ class JpqlSortedQueryTransformer extends JpqlQueryRenderer { return tokens; } + } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/PostgresStoredProcedureIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/PostgresStoredProcedureIntegrationTests.java index af07eb001..a88e23f9a 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/PostgresStoredProcedureIntegrationTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/PostgresStoredProcedureIntegrationTests.java @@ -106,7 +106,8 @@ class PostgresStoredProcedureIntegrationTests { new Employee(4, "Gabriel")); } - @DisabledOnHibernate("6") + @DisabledOnHibernate(value = "7", + disabledReason = "class org.hibernate.metamodel.model.domain.internal.EntityTypeImpl cannot be cast to class org.hibernate.query.OutputableType (org.hibernate.metamodel.model.domain.internal.EntityTypeImpl and org.hibernate.query.OutputableType are in unnamed module of loader 'app')") @Test // 2256 void testSingleEntityFromResultSet() { diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlComplianceTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlComplianceTests.java index c0819dc92..8ae77e555 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlComplianceTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlComplianceTests.java @@ -98,6 +98,7 @@ class EqlComplianceTests { assertQuery("SELECT e FROM Employee e JOIN FETCH e.address"); assertQuery("SELECT e FROM Employee e JOIN FETCH e.address a ORDER BY a.city"); + assertQuery("SELECT e FROM Employee e JOIN FETCH e.address AS a ORDER BY a.city"); } @Test @@ -118,6 +119,16 @@ class EqlComplianceTests { "SELECT e, c.city FROM Employee e, (SELECT DISTINCT a.city FROM Address a) c WHERE e.address.city = c.city"); } + @Test // GH-3277 + void numericLiterals() { + + assertQuery("SELECT e FROM Employee e WHERE e.id = 1234"); + assertQuery("SELECT e FROM Employee e WHERE e.id = 1234L"); + assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14"); + assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14F"); + assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14e32D"); + } + @Test void orderByClause() { @@ -442,7 +453,7 @@ class EqlComplianceTests { @ParameterizedTest // GH-3136 @ValueSource(strings = { "STRING", "INTEGER", "FLOAT", "DOUBLE" }) - void jpqlCast(String targetType) { + void cast(String targetType) { assertQuery("SELECT CAST(e.salary AS %s) FROM Employee e".formatted(targetType)); } @@ -462,4 +473,5 @@ class EqlComplianceTests { void stringConcatWithPipes() { assertQuery("SELECT e.firstname || e.lastname AS name FROM Employee e"); } + } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java index 9ad73bae5..f78dc6a1f 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java @@ -1041,6 +1041,59 @@ class EqlQueryRendererTests { assertQuery("select e.power.id from MyEntity e"); } + @Test // GH-3136 + void doublePipeShouldBeValidAsAStringConcatOperator() { + + assertQuery(""" + select e.name || ' ' || e.title + from Employee e + """); + } + + @Test // GH-3136 + void combinedSelectStatementsShouldWork() { + + assertQuery(""" + select e from Employee e where e.last_name = 'Baggins' + intersect + select e from Employee e where e.first_name = 'Samwise' + union + select e from Employee e where e.home = 'The Shire' + except + select e from Employee e where e.home = 'Isengard' + """); + } + + @Disabled + @Test // GH-3136 + void additionalStringOperationsShouldWork() { + + assertQuery(""" + select + replace(e.name, 'Baggins', 'Proudfeet'), + left(e.role, 4), + right(e.home, 5), + cast(e.distance_from_home, int) + from Employee e + """); + } + + @Test // GH-3136 + void orderByWithNullsFirstOrLastShouldWork() { + + assertQuery(""" + select a + from Element a + order by mutationAm desc nulls first + """); + + assertQuery(""" + select a + from Element a + order by mutationAm desc nulls last + """); + } + @ParameterizedTest // GH-3342 @ValueSource(strings = { "select 1 from User u", "select -1 from User u", "select +1 from User u", "select +1 * -100 from User u", "select count(u) * -0.7f from User u", @@ -1089,4 +1142,5 @@ class EqlQueryRendererTests { assertQuery("select f from FooEntity f where upper(f.name) IN :names"); assertQuery("select f from FooEntity f where f.size IN :sizes"); } + } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlSpecificationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlSpecificationTests.java index bff45ec75..df67e51b7 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlSpecificationTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlSpecificationTests.java @@ -275,7 +275,7 @@ class EqlSpecificationTests { assertQuery(""" SELECT b.name, b.ISBN FROM Order o JOIN TREAT(o.product AS Book) b - """); + """); } @Test @@ -284,7 +284,7 @@ class EqlSpecificationTests { assertQuery(""" SELECT e FROM Employee e JOIN TREAT(e.projects AS LargeProject) lp WHERE lp.budget > 1000 - """); + """); } /** @@ -299,7 +299,7 @@ class EqlSpecificationTests { WHERE TREAT(p AS LargeProject).budget > 1000 OR TREAT(p AS SmallProject).name LIKE 'Persist%' OR p.description LIKE "cost overrun" - """); + """); } @Test @@ -310,7 +310,7 @@ class EqlSpecificationTests { WHERE TREAT(p AS LargeProject).budget > 1000 OR TREAT(p AS SmallProject).name LIKE 'Persist%' OR p.description LIKE 'cost overrun' - """); + """); } @Test @@ -320,7 +320,39 @@ class EqlSpecificationTests { SELECT e FROM Employee e WHERE TREAT(e AS Exempt).vacationDays > 10 OR TREAT(e AS Contractor).hours > 100 - """); + """); + } + + @Test // GH-3136 + void substring() { + + assertQuery("select substring(c.number, 1, 2) " + // + "from Call c"); + + assertQuery("select substring(c.number, 1) " + // + "from Call c"); + } + + @Test // GH-3136 + void currentDateFunctions() { + + assertQuery("select CURRENT_DATE " + // + "from Call c "); + + assertQuery("select CURRENT_TIME " + // + "from Call c "); + + assertQuery("select CURRENT_TIMESTAMP " + // + "from Call c "); + + assertQuery("select LOCAL_DATE " + // + "from Call c "); + + assertQuery("select LOCAL_TIME " + // + "from Call c "); + + assertQuery("select LOCAL_DATETIME " + // + "from Call c "); } @Test @@ -384,7 +416,7 @@ class EqlSpecificationTests { WHERE emp.salary > ALL (SELECT m.salary FROM Manager m WHERE m.department = emp.department) - """); + """); } @Test @@ -396,7 +428,7 @@ class EqlSpecificationTests { WHERE EXISTS (SELECT spouseEmp FROM Employee spouseEmp WHERE spouseEmp = emp.spouse) - """); + """); } @Test @@ -464,7 +496,7 @@ class EqlSpecificationTests { WHEN e.rating = 2 THEN e.salary * 1.05 ELSE e.salary * 1.01 END - """); + """); } @Test @@ -477,7 +509,7 @@ class EqlSpecificationTests { WHEN 2 THEN e.salary * 1.05 ELSE e.salary * 1.01 END - """); + """); } @Test @@ -517,7 +549,7 @@ class EqlSpecificationTests { SELECT e FROM Employee e WHERE TYPE(e) IN (Exempt, Contractor) - """); + """); } @Test diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java index 03286b1d2..1f273c639 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java @@ -1669,7 +1669,7 @@ class HqlQueryRendererTests { from Element a where a.erstelltDurch = :variable order by mutationAm desc nulls last - """); + """); } @Test // GH-3882 @@ -1690,7 +1690,7 @@ class HqlQueryRendererTests { void roundFunctionShouldWorkLikeAnyOtherFunction() { assertQuery(""" - select round(count(ri)*100/max(ri.receipt.positions), 0) as perc + select round(count(ri) * 100 / max(ri.receipt.positions), 0) as perc from StockOrderItem oi right join StockReceiptItem ri on ri.article = oi.article diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlComplianceTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlComplianceTests.java index f7bc8f76c..a346c8c39 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlComplianceTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlComplianceTests.java @@ -27,6 +27,7 @@ import org.junit.jupiter.params.provider.ValueSource; * suffix. * * @author Christoph Strobl + * @author Mark Paluch */ class JpqlComplianceTests { @@ -50,6 +51,52 @@ class JpqlComplianceTests { .trim(); } + @Test + void selectQueries() { + + assertQuery("Select e FROM Employee e WHERE e.salary > 100000"); + assertQuery("Select e FROM Employee e WHERE e.id = :id"); + assertQuery("Select MAX(e.salary) FROM Employee e"); + assertQuery("Select e.firstName FROM Employee e"); + assertQuery("Select e.firstName, e.lastName FROM Employee e"); + } + + @Test + void selectClause() { + + assertQuery("SELECT COUNT(e) FROM Employee e"); + assertQuery("SELECT MAX(e.salary) FROM Employee e"); + assertQuery("SELECT NEW com.acme.reports.EmpReport(e.firstName, e.lastName, e.salary) FROM Employee e"); + } + + @Test + void fromClause() { + + assertQuery("SELECT e FROM Employee e"); + assertQuery("SELECT e, a FROM Employee e, MailingAddress a WHERE e.address = a.address"); + assertQuery("SELECT e FROM com.acme.Employee e"); + } + + @Test + void join() { + + assertQuery("SELECT e FROM Employee e JOIN e.address a WHERE a.city = :city"); + assertQuery("SELECT e FROM Employee e JOIN e.projects p JOIN e.projects p2 WHERE p.name = :p1 AND p2.name = :p2"); + } + + @Test + void joinFetch() { + + assertQuery("SELECT e FROM Employee e JOIN FETCH e.address"); + assertQuery("SELECT e FROM Employee e JOIN FETCH e.address a ORDER BY a.city"); + assertQuery("SELECT e FROM Employee e JOIN FETCH e.address AS a ORDER BY a.city"); + } + + @Test + void leftJoin() { + assertQuery("SELECT e FROM Employee e LEFT JOIN e.address a ORDER BY a.city"); + } + @Test // GH-3277 void numericLiterals() { @@ -65,6 +112,27 @@ class JpqlComplianceTests { assertQuery("select new com.example.demo.SampleObject(se.id, se.sampleValue, \"java\") from SampleEntity se"); } + @Test + void orderByClause() { + + assertQuery("SELECT e FROM Employee e ORDER BY e.lastName ASC, e.firstName ASC"); // Typo in EQL document + assertQuery("SELECT e FROM Employee e LEFT JOIN e.manager m ORDER BY m.lastName NULLS FIRST"); + assertQuery("SELECT e FROM Employee e ORDER BY e.address"); + } + + @Test + void groupByClause() { + + assertQuery("SELECT AVG(e.salary), e.address.city FROM Employee e GROUP BY e.address.city"); + assertQuery("SELECT e, COUNT(p) FROM Employee e LEFT JOIN e.projects p GROUP BY e"); + } + + @Test + void havingClause() { + assertQuery( + "SELECT AVG(e.salary), e.address.city FROM Employee e GROUP BY e.address.city HAVING AVG(e.salary) > 100000"); + } + @Test // GH-3136 void union() { @@ -72,6 +140,141 @@ class JpqlComplianceTests { SELECT MAX(e.salary) FROM Employee e WHERE e.address.city = :city1 UNION SELECT MAX(e.salary) FROM Employee e WHERE e.address.city = :city2 """); + assertQuery(""" + SELECT e FROM Employee e JOIN e.phones p WHERE p.areaCode = :areaCode1 + INTERSECT SELECT e FROM Employee e JOIN e.phones p WHERE p.areaCode = :areaCode2 + """); + assertQuery(""" + SELECT e FROM Employee e + EXCEPT SELECT e FROM Employee e WHERE e.salary > e.manager.salary + """); + } + + @Test + void whereClause() { + // TBD + } + + @Test + void updateQueries() { + assertQuery("UPDATE Employee e SET e.salary = 60000 WHERE e.salary = 50000"); + } + + @Test + void deleteQueries() { + assertQuery("DELETE FROM Employee e WHERE e.department IS NULL"); + } + + @Test + void literals() { + + assertQuery("SELECT e FROM Employee e WHERE e.name = 'Bob'"); + assertQuery("SELECT e FROM Employee e WHERE e.id = 1234"); + assertQuery("SELECT e FROM Employee e WHERE e.id = 1234L"); + assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14F"); + assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14e32D"); + assertQuery("SELECT e FROM Employee e WHERE e.active = TRUE"); + assertQuery("SELECT e FROM Employee e WHERE e.startDate = {d'2012-01-03'}"); + assertQuery("SELECT e FROM Employee e WHERE e.startTime = {t'09:00:00'}"); + assertQuery("SELECT e FROM Employee e WHERE e.version = {ts'2012-01-03 09:00:00.000000001'}"); + assertQuery("SELECT e FROM Employee e WHERE e.gender = org.acme.Gender.MALE"); + assertQuery("UPDATE Employee e SET e.manager = NULL WHERE e.manager = :manager"); + } + + @Test + void functionsInSelect() { + + assertQuery("SELECT e.salary - 1000 FROM Employee e"); + assertQuery("SELECT e.salary + 1000 FROM Employee e"); + assertQuery("SELECT e.salary * 2 FROM Employee e"); + assertQuery("SELECT e.salary * 2.0 FROM Employee e"); + assertQuery("SELECT e.salary / 2 FROM Employee e"); + assertQuery("SELECT e.salary / 2.0 FROM Employee e"); + assertQuery("SELECT ABS(e.salary - e.manager.salary) FROM Employee e"); + assertQuery( + "select e from Employee e where case e.firstName when 'Bob' then 'Robert' when 'Jill' then 'Gillian' else '' end = 'Robert'"); + assertQuery( + "select case when e.firstName = 'Bob' then 'Robert' when e.firstName = 'Jill' then 'Gillian' else '' end from Employee e where e.firstName = 'Bob' or e.firstName = 'Jill'"); + assertQuery( + "select e from Employee e where case when e.firstName = 'Bob' then 'Robert' when e.firstName = 'Jill' then 'Gillian' else '' end = 'Robert'"); + assertQuery("SELECT COALESCE(e.salary, 0) FROM Employee e"); + assertQuery("SELECT CONCAT(e.firstName, ' ', e.lastName) FROM Employee e"); + assertQuery("SELECT e.name, CURRENT_DATE FROM Employee e"); + assertQuery("SELECT e.name, CURRENT_TIME FROM Employee e"); + assertQuery("SELECT e.name, CURRENT_TIMESTAMP FROM Employee e"); + assertQuery("SELECT LENGTH(e.lastName) FROM Employee e"); + assertQuery("SELECT LOWER(e.lastName) FROM Employee e"); + assertQuery("SELECT MOD(e.hoursWorked, 8) FROM Employee e"); + assertQuery("SELECT NULLIF(e.salary, 0) FROM Employee e"); + assertQuery("SELECT SQRT(o.RESULT) FROM Output o"); + assertQuery("SELECT SUBSTRING(e.lastName, 0, 2) FROM Employee e"); + assertQuery( + "SELECT TRIM(TRAILING FROM e.lastName), TRIM(e.lastName), TRIM(LEADING '-' FROM e.lastName) FROM Employee e"); + assertQuery("SELECT UPPER(e.lastName) FROM Employee e"); + assertQuery("SELECT CAST(e.salary NUMERIC(10, 2)) FROM Employee e"); + assertQuery("SELECT EXTRACT(YEAR FROM e.startDate) FROM Employee e"); + } + + @Test + void functionsInWhere() { + + assertQuery("SELECT e FROM Employee e WHERE e.salary - 1000 > 0"); + assertQuery("SELECT e FROM Employee e WHERE e.salary + 1000 > 0"); + assertQuery("SELECT e FROM Employee e WHERE e.salary * 2 > 0"); + assertQuery("SELECT e FROM Employee e WHERE e.salary * 2.0 > 0.0"); + assertQuery("SELECT e FROM Employee e WHERE e.salary / 2 > 0"); + assertQuery("SELECT e FROM Employee e WHERE e.salary / 2.0 > 0.0"); + assertQuery("SELECT e FROM Employee e WHERE ABS(e.salary - e.manager.salary) > 0"); + assertQuery("SELECT e FROM Employee e WHERE COALESCE(e.salary, 0) > 0"); + assertQuery("SELECT e FROM Employee e WHERE CONCAT(e.firstName, ' ', e.lastName) = 'Bilbo'"); + assertQuery("SELECT e FROM Employee e WHERE CURRENT_DATE > CURRENT_TIME"); + assertQuery("SELECT e FROM Employee e WHERE CURRENT_TIME > CURRENT_TIMESTAMP"); + assertQuery("SELECT e FROM Employee e WHERE LENGTH(e.lastName) > 0"); + assertQuery("SELECT e FROM Employee e WHERE LOWER(e.lastName) = 'bilbo'"); + assertQuery("SELECT e FROM Employee e WHERE MOD(e.hoursWorked, 8) > 0"); + assertQuery("SELECT e FROM Employee e WHERE SQRT(o.RESULT) > 0.0"); + assertQuery("SELECT e FROM Employee e WHERE SUBSTRING(e.lastName, 0, 2) = 'Bilbo'"); + assertQuery("SELECT e FROM Employee e WHERE TRIM(TRAILING FROM e.lastName) = 'Bilbo'"); + assertQuery("SELECT e FROM Employee e WHERE TRIM(e.lastName) = 'Bilbo'"); + assertQuery("SELECT e FROM Employee e WHERE TRIM(LEADING '-' FROM e.lastName) = 'Bilbo'"); + assertQuery("SELECT e FROM Employee e WHERE UPPER(e.lastName) = 'BILBO'"); + assertQuery("SELECT e FROM Employee e WHERE CAST(e.salary NUMERIC(10, 2)) > 0.0"); + assertQuery("SELECT e FROM Employee e WHERE EXTRACT(YEAR FROM e.startDate) = '2023'"); + } + + @Test + void specialOperators() { + + assertQuery("SELECT toDo FROM Employee e JOIN e.toDoList toDo WHERE INDEX(toDo) = 1"); + assertQuery("SELECT p FROM Employee e JOIN e.priorities p WHERE KEY(p) = 'high'"); + assertQuery("SELECT e FROM Employee e WHERE SIZE(e.managedEmployees) < 2"); + assertQuery("SELECT e FROM Employee e WHERE e.managedEmployees IS EMPTY"); + assertQuery("SELECT e FROM Employee e WHERE 'write code' MEMBER OF e.responsibilities"); + assertQuery("SELECT p FROM Project p WHERE TYPE(p) = LargeProject"); + + /** + * NOTE: The following query has been altered to properly align with EclipseLink test code despite NOT matching + * their ref docs. See https://github.com/eclipse-ee4j/eclipselink/issues/1949 for more details. + */ + assertQuery("SELECT e FROM Employee e JOIN TREAT(e.projects AS LargeProject) p WHERE p.budget > 1000000"); + + assertQuery("SELECT p FROM Phone p WHERE FUNCTION('TO_NUMBER', p.areaCode) > 613"); + } + + @Test // GH-3314 + void isNullAndIsNotNull() { + + assertQuery("SELECT e FROM Employee e WHERE (e.active IS null OR e.active = true)"); + assertQuery("SELECT e FROM Employee e WHERE (e.active IS NULL OR e.active = true)"); + assertQuery("SELECT e FROM Employee e WHERE (e.active IS NOT null OR e.active = true)"); + assertQuery("SELECT e FROM Employee e WHERE (e.active IS NOT NULL OR e.active = true)"); + } + + @Test // GH-3496 + void lateralShouldBeAValidParameter() { + + assertQuery("select e from Employee e where e.lateral = :_lateral"); + assertQuery("select te from TestEntity te where te.lateral = :lateral"); } @Test // GH-3136 @@ -93,13 +296,13 @@ class JpqlComplianceTests { } @ParameterizedTest // GH-3136 - @ValueSource(strings = {"STRING", "INTEGER", "FLOAT", "DOUBLE"}) + @ValueSource(strings = { "STRING", "INTEGER", "FLOAT", "DOUBLE" }) void cast(String targetType) { assertQuery("SELECT CAST(e.salary AS %s) FROM Employee e".formatted(targetType)); } @ParameterizedTest // GH-3136 - @ValueSource(strings = {"LEFT", "RIGHT"}) + @ValueSource(strings = { "LEFT", "RIGHT" }) void leftRightStringFunctions(String keyword) { assertQuery("SELECT %s(e.name, 3) FROM Employee e".formatted(keyword)); } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlSpecificationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlSpecificationTests.java index 289e52245..566bfb880 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlSpecificationTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlSpecificationTests.java @@ -327,6 +327,38 @@ class JpqlSpecificationTests { """); } + @Test // GH-3136 + void substring() { + + assertQuery("select substring(c.number, 1, 2) " + // + "from Call c"); + + assertQuery("select substring(c.number, 1) " + // + "from Call c"); + } + + @Test // GH-3136 + void currentDateFunctions() { + + assertQuery("select CURRENT_DATE " + // + "from Call c "); + + assertQuery("select CURRENT_TIME " + // + "from Call c "); + + assertQuery("select CURRENT_TIMESTAMP " + // + "from Call c "); + + assertQuery("select LOCAL_DATE " + // + "from Call c "); + + assertQuery("select LOCAL_TIME " + // + "from Call c "); + + assertQuery("select LOCAL_DATETIME " + // + "from Call c "); + } + @Test void pathExpressionsNamedParametersExample() {