Skip to content

Commit ec75aae

Browse files
christophstroblmp911de
authored andcommitted
Add support for JPA 3.2 additions to EQL.
See: #3136 Original Pull Request: #3695
1 parent 4b30241 commit ec75aae

File tree

9 files changed

+352
-20
lines changed

9 files changed

+352
-20
lines changed

Diff for: spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4

+26-2
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ scalar_expression
309309
| datetime_expression
310310
| boolean_expression
311311
| case_expression
312+
| cast_function
312313
| entity_type_expression
313314
;
314315

@@ -455,6 +456,7 @@ string_expression
455456
| case_expression
456457
| function_invocation
457458
| '(' subquery ')'
459+
| string_expression '||' string_expression
458460
;
459461

460462
datetime_expression
@@ -539,6 +541,9 @@ functions_returning_strings
539541
| TRIM '(' ((trim_specification)? (trim_character)? FROM)? string_expression ')'
540542
| LOWER '(' string_expression ')'
541543
| UPPER '(' string_expression ')'
544+
| REPLACE '(' string_expression ',' string_expression ',' string_expression ')'
545+
| LEFT '(' string_expression ',' arithmetic_expression ')'
546+
| RIGHT '(' string_expression ',' arithmetic_expression ')'
542547
;
543548

544549
trim_specification
@@ -548,7 +553,7 @@ trim_specification
548553
;
549554

550555
cast_function
551-
: CAST '(' single_valued_path_expression identification_variable ('(' numeric_literal (',' numeric_literal)* ')')? ')'
556+
: CAST '(' single_valued_path_expression (identification_variable)? identification_variable ('(' numeric_literal (',' numeric_literal)* ')')? ')'
552557
;
553558

554559
function_invocation
@@ -614,6 +619,14 @@ nullif_expression
614619
: NULLIF '(' scalar_expression ',' scalar_expression ')'
615620
;
616621

622+
type_literal
623+
: STRING
624+
| INTEGER
625+
| LONG
626+
| FLOAT
627+
| DOUBLE
628+
;
629+
617630
/*******************
618631
Gaps in the spec.
619632
*******************/
@@ -626,6 +639,7 @@ trim_character
626639
identification_variable
627640
: IDENTIFICATION_VARIABLE
628641
| f=(COUNT
642+
| AS
629643
| DATE
630644
| FROM
631645
| INNER
@@ -635,11 +649,13 @@ identification_variable
635649
| ORDER
636650
| OUTER
637651
| POWER
652+
| RIGHT
638653
| FLOOR
639654
| SIGN
640655
| TIME
641656
| TYPE
642657
| VALUE)
658+
| type_literal
643659
;
644660

645661
constructor_name
@@ -820,6 +836,8 @@ reserved_word
820836
|OR
821837
|ORDER
822838
|OUTER
839+
|REPLACE
840+
|RIGHT
823841
|POWER
824842
|ROUND
825843
|SELECT
@@ -903,6 +921,7 @@ DATETIME : D A T E T I M E ;
903921
DELETE : D E L E T E;
904922
DESC : D E S C;
905923
DISTINCT : D I S T I N C T;
924+
DOUBLE : D O U B L E;
906925
END : E N D;
907926
ELSE : E L S E;
908927
EMPTY : E M P T Y;
@@ -915,6 +934,7 @@ EXTRACT : E X T R A C T;
915934
FALSE : F A L S E;
916935
FETCH : F E T C H;
917936
FIRST : F I R S T;
937+
FLOAT : F L O A T;
918938
FLOOR : F L O O R;
919939
FROM : F R O M;
920940
FUNCTION : F U N C T I O N;
@@ -923,6 +943,7 @@ HAVING : H A V I N G;
923943
IN : I N;
924944
INDEX : I N D E X;
925945
INNER : I N N E R;
946+
INTEGER : I N T E G E R;
926947
INTERSECT : I N T E R S E C T;
927948
IS : I S;
928949
JOIN : J O I N;
@@ -935,6 +956,7 @@ LIKE : L I K E;
935956
LN : L N;
936957
LOCAL : L O C A L;
937958
LOCATE : L O C A T E;
959+
LONG : L O N G;
938960
LOWER : L O W E R;
939961
MAX : M A X;
940962
MEMBER : M E M B E R;
@@ -953,13 +975,16 @@ ORDER : O R D E R;
953975
OUTER : O U T E R;
954976
POWER : P O W E R;
955977
REGEXP : R E G E X P;
978+
REPLACE : R E P L A C E;
979+
RIGHT : R I G H T;
956980
ROUND : R O U N D;
957981
SELECT : S E L E C T;
958982
SET : S E T;
959983
SIGN : S I G N;
960984
SIZE : S I Z E;
961985
SOME : S O M E;
962986
SQRT : S Q R T;
987+
STRING : S T R I N G;
963988
SUBSTRING : S U B S T R I N G;
964989
SUM : S U M;
965990
THEN : T H E N;
@@ -979,7 +1004,6 @@ WHERE : W H E R E;
9791004
EQUAL : '=' ;
9801005
NOT_EQUAL : '<>' | '!=' ;
9811006

982-
9831007
CHARACTER : '\'' (~ ('\'' | '\\')) '\'' ;
9841008
IDENTIFICATION_VARIABLE : ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '$' | '_') ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '0' .. '9' | '$' | '_')* ;
9851009
STRINGLITERAL : '\'' (~ ('\'' | '\\')|'\\')* '\'' ;

Diff for: spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4

+45-5
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,25 @@ ql_statement
4343
;
4444

4545
select_statement
46-
: select_clause from_clause (where_clause)? (groupby_clause)? (having_clause)? (orderby_clause)? (setOperator_with_select_statement)*
46+
: select_query
4747
;
4848

49-
setOperator_with_select_statement
50-
: INTERSECT select_statement
51-
| UNION select_statement
52-
| EXCEPT select_statement
49+
select_query
50+
: select_clause from_clause (where_clause)? (groupby_clause)? (having_clause)? (orderby_clause)? (set_fuction)?
51+
;
52+
53+
setOperator
54+
: UNION ALL?
55+
| INTERSECT ALL?
56+
| EXCEPT ALL?
57+
;
58+
59+
set_fuction
60+
: setOperator set_function_select
61+
;
62+
63+
set_function_select
64+
: select_query
5365
;
5466

5567
update_statement
@@ -303,6 +315,7 @@ scalar_expression
303315
| datetime_expression
304316
| boolean_expression
305317
| case_expression
318+
| cast_expression
306319
| entity_type_expression
307320
;
308321

@@ -447,6 +460,7 @@ string_expression
447460
| function_invocation
448461
| string_expression op='||' string_expression
449462
| '(' subquery ')'
463+
| string_expression '||' string_expression
450464
;
451465

452466
datetime_expression
@@ -530,7 +544,10 @@ functions_returning_strings
530544
| SUBSTRING '(' string_expression ',' arithmetic_expression (',' arithmetic_expression)? ')'
531545
| TRIM '(' ((trim_specification)? (trim_character)? FROM)? string_expression ')'
532546
| LOWER '(' string_expression ')'
547+
| REPLACE '(' string_expression ',' string_expression ',' string_expression ')'
533548
| UPPER '(' string_expression ')'
549+
| LEFT '(' string_expression ',' arithmetic_expression ')'
550+
| RIGHT '(' string_expression ',' arithmetic_expression ')'
534551
;
535552

536553
trim_specification
@@ -603,6 +620,10 @@ nullif_expression
603620
: NULLIF '(' scalar_expression ',' scalar_expression ')'
604621
;
605622

623+
cast_expression
624+
: CAST '(' string_expression AS type_literal ')'
625+
;
626+
606627
/*******************
607628
Gaps in the spec.
608629
*******************/
@@ -624,6 +645,7 @@ identification_variable
624645
| ORDER
625646
| OUTER
626647
| POWER
648+
| RIGHT
627649
| FLOOR
628650
| SIGN
629651
| TIME
@@ -673,6 +695,14 @@ numeric_literal
673695
| LONGLITERAL
674696
;
675697

698+
type_literal
699+
: STRING
700+
| INTEGER
701+
| LONG
702+
| FLOAT
703+
| DOUBLE
704+
;
705+
676706
boolean_literal
677707
: TRUE
678708
| FALSE
@@ -808,6 +838,8 @@ reserved_word
808838
|ORDER
809839
|OUTER
810840
|POWER
841+
|REPLACE
842+
|RIGHT
811843
|ROUND
812844
|SELECT
813845
|SET
@@ -877,6 +909,7 @@ BETWEEN : B E T W E E N;
877909
BOTH : B O T H;
878910
BY : B Y;
879911
CASE : C A S E;
912+
CAST : C A S T;
880913
CEILING : C E I L I N G;
881914
COALESCE : C O A L E S C E;
882915
CONCAT : C O N C A T;
@@ -889,6 +922,7 @@ DATETIME : D A T E T I M E ;
889922
DELETE : D E L E T E;
890923
DESC : D E S C;
891924
DISTINCT : D I S T I N C T;
925+
DOUBLE : D O U B L E;
892926
END : E N D;
893927
ELSE : E L S E;
894928
EMPTY : E M P T Y;
@@ -901,6 +935,7 @@ EXTRACT : E X T R A C T;
901935
FALSE : F A L S E;
902936
FETCH : F E T C H;
903937
FIRST : F I R S T;
938+
FLOAT : F L O A T;
904939
FLOOR : F L O O R;
905940
FROM : F R O M;
906941
FUNCTION : F U N C T I O N;
@@ -909,6 +944,7 @@ HAVING : H A V I N G;
909944
IN : I N;
910945
INDEX : I N D E X;
911946
INNER : I N N E R;
947+
INTEGER : I N T E G E R;
912948
INTERSECT : I N T E R S E C T;
913949
IS : I S;
914950
JOIN : J O I N;
@@ -921,6 +957,7 @@ LIKE : L I K E;
921957
LN : L N;
922958
LOCAL : L O C A L;
923959
LOCATE : L O C A T E;
960+
LONG : L O N G;
924961
LOWER : L O W E R;
925962
MAX : M A X;
926963
MEMBER : M E M B E R;
@@ -937,6 +974,8 @@ ON : O N;
937974
OR : O R;
938975
ORDER : O R D E R;
939976
OUTER : O U T E R;
977+
REPLACE : R E P L A C E;
978+
RIGHT : R I G H T;
940979
POWER : P O W E R;
941980
ROUND : R O U N D;
942981
SELECT : S E L E C T;
@@ -945,6 +984,7 @@ SIGN : S I G N;
945984
SIZE : S I Z E;
946985
SOME : S O M E;
947986
SQRT : S Q R T;
987+
STRING : S T R I N G;
948988
SUBSTRING : S U B S T R I N G;
949989
SUM : S U M;
950990
THEN : T H E N;

Diff for: spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java

+48-4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.antlr.v4.runtime.tree.ParseTree;
2424

2525
import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRendererBuilder;
26+
import org.springframework.util.ObjectUtils;
2627

2728
/**
2829
* An ANTLR {@link org.antlr.v4.runtime.tree.ParseTreeVisitor} that renders an EQL query without making any changes.
@@ -1008,6 +1009,8 @@ public QueryTokenStream visitScalar_expression(EqlParser.Scalar_expressionContex
10081009
builder.append(visit(ctx.case_expression()));
10091010
} else if (ctx.entity_type_expression() != null) {
10101011
builder.append(visit(ctx.entity_type_expression()));
1012+
} else if (ctx.cast_function() != null) {
1013+
return (visit(ctx.cast_function()));
10111014
}
10121015

10131016
return builder;
@@ -1603,6 +1606,11 @@ public QueryTokenStream visitString_expression(EqlParser.String_expressionContex
16031606
builder.append(TOKEN_OPEN_PAREN);
16041607
builder.appendInline(visit(ctx.subquery()));
16051608
builder.append(TOKEN_CLOSE_PAREN);
1609+
} else if (!ObjectUtils.isEmpty(ctx.string_expression())) {
1610+
1611+
builder.appendInline(visit(ctx.string_expression(0)));
1612+
builder.append(TOKEN_DOUBLE_PIPE);
1613+
builder.appendExpression(visit(ctx.string_expression(1)));
16061614
}
16071615

16081616
return builder;
@@ -1934,6 +1942,32 @@ public QueryTokenStream visitFunctions_returning_strings(EqlParser.Functions_ret
19341942
builder.append(TOKEN_OPEN_PAREN);
19351943
builder.appendInline(visit(ctx.string_expression(0)));
19361944
builder.append(TOKEN_CLOSE_PAREN);
1945+
} else if (ctx.LEFT() != null) {
1946+
1947+
builder.append(QueryTokens.token(ctx.LEFT()));
1948+
builder.append(TOKEN_OPEN_PAREN);
1949+
builder.appendInline(visit(ctx.string_expression(0)));
1950+
builder.append(TOKEN_COMMA);
1951+
builder.appendInline(visit(ctx.arithmetic_expression(0)));
1952+
builder.append(TOKEN_CLOSE_PAREN);
1953+
} else if (ctx.RIGHT() != null) {
1954+
1955+
builder.append(QueryTokens.token(ctx.RIGHT()));
1956+
builder.append(TOKEN_OPEN_PAREN);
1957+
builder.appendInline(visit(ctx.string_expression(0)));
1958+
builder.append(TOKEN_COMMA);
1959+
builder.appendInline(visit(ctx.arithmetic_expression(0)));
1960+
builder.append(TOKEN_CLOSE_PAREN);
1961+
} else if (ctx.REPLACE() != null) {
1962+
1963+
builder.append(QueryTokens.token(ctx.REPLACE()));
1964+
builder.append(TOKEN_OPEN_PAREN);
1965+
builder.appendInline(visit(ctx.string_expression(0)));
1966+
builder.append(TOKEN_COMMA);
1967+
builder.appendInline(visit(ctx.string_expression(1)));
1968+
builder.append(TOKEN_COMMA);
1969+
builder.appendInline(visit(ctx.string_expression(2)));
1970+
builder.append(TOKEN_CLOSE_PAREN);
19371971
}
19381972

19391973
return builder;
@@ -1960,9 +1994,9 @@ public QueryTokenStream visitCast_function(EqlParser.Cast_functionContext ctx) {
19601994
builder.append(TOKEN_OPEN_PAREN);
19611995
builder.appendInline(visit(ctx.single_valued_path_expression()));
19621996
builder.append(TOKEN_SPACE);
1963-
builder.appendInline(visit(ctx.identification_variable()));
1997+
builder.appendInline(QueryTokenStream.concat(ctx.identification_variable(), this::visit, TOKEN_SPACE));
19641998

1965-
if (ctx.numeric_literal() != null) {
1999+
if (!ObjectUtils.isEmpty(ctx.numeric_literal())) {
19662000

19672001
builder.append(TOKEN_OPEN_PAREN);
19682002
builder.appendInline(QueryTokenStream.concat(ctx.numeric_literal(), this::visit, TOKEN_COMMA));
@@ -2063,6 +2097,14 @@ public QueryTokenStream visitCase_expression(EqlParser.Case_expressionContext ct
20632097
}
20642098
}
20652099

2100+
@Override
2101+
public QueryRendererBuilder visitType_literal(EqlParser.Type_literalContext ctx) {
2102+
2103+
QueryRendererBuilder builder = QueryRenderer.builder();
2104+
ctx.children.forEach(it -> builder.append(QueryTokens.expression(it.getText())));
2105+
return builder;
2106+
}
2107+
20662108
@Override
20672109
public QueryTokenStream visitGeneral_case_expression(EqlParser.General_case_expressionContext ctx) {
20682110

@@ -2183,9 +2225,11 @@ public QueryTokenStream visitIdentification_variable(EqlParser.Identification_va
21832225
return QueryRendererBuilder.from(QueryTokens.expression(ctx.IDENTIFICATION_VARIABLE()));
21842226
} else if (ctx.f != null) {
21852227
return QueryRendererBuilder.from(QueryTokens.expression(ctx.f));
2186-
} else {
2187-
return QueryRenderer.builder();
2228+
} else if (ctx.type_literal() != null) {
2229+
return visit(ctx.type_literal());
21882230
}
2231+
2232+
return QueryRenderer.builder();
21892233
}
21902234

21912235
@Override

0 commit comments

Comments
 (0)