Skip to content

Commit fa80414

Browse files
Add support for JPA 3.2 additions to EQL.
See: #3136 Original Pull Request: #3695
1 parent b44271d commit fa80414

File tree

10 files changed

+352
-27
lines changed

10 files changed

+352
-27
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

@@ -450,6 +451,7 @@ string_expression
450451
| case_expression
451452
| function_invocation
452453
| '(' subquery ')'
454+
| string_expression '||' string_expression
453455
;
454456

455457
datetime_expression
@@ -534,6 +536,9 @@ functions_returning_strings
534536
| TRIM '(' ((trim_specification)? (trim_character)? FROM)? string_expression ')'
535537
| LOWER '(' string_expression ')'
536538
| UPPER '(' string_expression ')'
539+
| REPLACE '(' string_expression ',' string_expression ',' string_expression ')'
540+
| LEFT '(' string_expression ',' arithmetic_expression ')'
541+
| RIGHT '(' string_expression ',' arithmetic_expression ')'
537542
;
538543

539544
trim_specification
@@ -543,7 +548,7 @@ trim_specification
543548
;
544549

545550
cast_function
546-
: CAST '(' single_valued_path_expression identification_variable ('(' numeric_literal (',' numeric_literal)* ')')? ')'
551+
: CAST '(' single_valued_path_expression (identification_variable)? identification_variable ('(' numeric_literal (',' numeric_literal)* ')')? ')'
547552
;
548553

549554
function_invocation
@@ -609,6 +614,14 @@ nullif_expression
609614
: NULLIF '(' scalar_expression ',' scalar_expression ')'
610615
;
611616

617+
type_literal
618+
: STRING
619+
| INTEGER
620+
| LONG
621+
| FLOAT
622+
| DOUBLE
623+
;
624+
612625
/*******************
613626
Gaps in the spec.
614627
*******************/
@@ -621,6 +634,7 @@ trim_character
621634
identification_variable
622635
: IDENTIFICATION_VARIABLE
623636
| f=(COUNT
637+
| AS
624638
| DATE
625639
| FROM
626640
| INNER
@@ -630,11 +644,13 @@ identification_variable
630644
| ORDER
631645
| OUTER
632646
| POWER
647+
| RIGHT
633648
| FLOOR
634649
| SIGN
635650
| TIME
636651
| TYPE
637652
| VALUE)
653+
| type_literal
638654
;
639655

640656
constructor_name
@@ -811,6 +827,8 @@ reserved_word
811827
|OR
812828
|ORDER
813829
|OUTER
830+
|REPLACE
831+
|RIGHT
814832
|POWER
815833
|ROUND
816834
|SELECT
@@ -894,6 +912,7 @@ DATETIME : D A T E T I M E ;
894912
DELETE : D E L E T E;
895913
DESC : D E S C;
896914
DISTINCT : D I S T I N C T;
915+
DOUBLE : D O U B L E;
897916
END : E N D;
898917
ELSE : E L S E;
899918
EMPTY : E M P T Y;
@@ -906,6 +925,7 @@ EXTRACT : E X T R A C T;
906925
FALSE : F A L S E;
907926
FETCH : F E T C H;
908927
FIRST : F I R S T;
928+
FLOAT : F L O A T;
909929
FLOOR : F L O O R;
910930
FROM : F R O M;
911931
FUNCTION : F U N C T I O N;
@@ -914,6 +934,7 @@ HAVING : H A V I N G;
914934
IN : I N;
915935
INDEX : I N D E X;
916936
INNER : I N N E R;
937+
INTEGER : I N T E G E R;
917938
INTERSECT : I N T E R S E C T;
918939
IS : I S;
919940
JOIN : J O I N;
@@ -926,6 +947,7 @@ LIKE : L I K E;
926947
LN : L N;
927948
LOCAL : L O C A L;
928949
LOCATE : L O C A T E;
950+
LONG : L O N G;
929951
LOWER : L O W E R;
930952
MAX : M A X;
931953
MEMBER : M E M B E R;
@@ -944,13 +966,16 @@ ORDER : O R D E R;
944966
OUTER : O U T E R;
945967
POWER : P O W E R;
946968
REGEXP : R E G E X P;
969+
REPLACE : R E P L A C E;
970+
RIGHT : R I G H T;
947971
ROUND : R O U N D;
948972
SELECT : S E L E C T;
949973
SET : S E T;
950974
SIGN : S I G N;
951975
SIZE : S I Z E;
952976
SOME : S O M E;
953977
SQRT : S Q R T;
978+
STRING : S T R I N G;
954979
SUBSTRING : S U B S T R I N G;
955980
SUM : S U M;
956981
THEN : T H E N;
@@ -970,7 +995,6 @@ WHERE : W H E R E;
970995
EQUAL : '=' ;
971996
NOT_EQUAL : '<>' | '!=' ;
972997

973-
974998
CHARACTER : '\'' (~ ('\'' | '\\')) '\'' ;
975999
IDENTIFICATION_VARIABLE : ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '$' | '_') ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '0' .. '9' | '$' | '_')* ;
9761000
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

@@ -442,6 +455,7 @@ string_expression
442455
| function_invocation
443456
| string_expression op='||' string_expression
444457
| '(' subquery ')'
458+
| string_expression '||' string_expression
445459
;
446460

447461
datetime_expression
@@ -525,7 +539,10 @@ functions_returning_strings
525539
| SUBSTRING '(' string_expression ',' arithmetic_expression (',' arithmetic_expression)? ')'
526540
| TRIM '(' ((trim_specification)? (trim_character)? FROM)? string_expression ')'
527541
| LOWER '(' string_expression ')'
542+
| REPLACE '(' string_expression ',' string_expression ',' string_expression ')'
528543
| UPPER '(' string_expression ')'
544+
| LEFT '(' string_expression ',' arithmetic_expression ')'
545+
| RIGHT '(' string_expression ',' arithmetic_expression ')'
529546
;
530547

531548
trim_specification
@@ -598,6 +615,10 @@ nullif_expression
598615
: NULLIF '(' scalar_expression ',' scalar_expression ')'
599616
;
600617

618+
cast_expression
619+
: CAST '(' string_expression AS type_literal ')'
620+
;
621+
601622
/*******************
602623
Gaps in the spec.
603624
*******************/
@@ -619,6 +640,7 @@ identification_variable
619640
| ORDER
620641
| OUTER
621642
| POWER
643+
| RIGHT
622644
| FLOOR
623645
| SIGN
624646
| TIME
@@ -668,6 +690,14 @@ numeric_literal
668690
| LONGLITERAL
669691
;
670692

693+
type_literal
694+
: STRING
695+
| INTEGER
696+
| LONG
697+
| FLOAT
698+
| DOUBLE
699+
;
700+
671701
boolean_literal
672702
: TRUE
673703
| FALSE
@@ -799,6 +829,8 @@ reserved_word
799829
|ORDER
800830
|OUTER
801831
|POWER
832+
|REPLACE
833+
|RIGHT
802834
|ROUND
803835
|SELECT
804836
|SET
@@ -868,6 +900,7 @@ BETWEEN : B E T W E E N;
868900
BOTH : B O T H;
869901
BY : B Y;
870902
CASE : C A S E;
903+
CAST : C A S T;
871904
CEILING : C E I L I N G;
872905
COALESCE : C O A L E S C E;
873906
CONCAT : C O N C A T;
@@ -880,6 +913,7 @@ DATETIME : D A T E T I M E ;
880913
DELETE : D E L E T E;
881914
DESC : D E S C;
882915
DISTINCT : D I S T I N C T;
916+
DOUBLE : D O U B L E;
883917
END : E N D;
884918
ELSE : E L S E;
885919
EMPTY : E M P T Y;
@@ -892,6 +926,7 @@ EXTRACT : E X T R A C T;
892926
FALSE : F A L S E;
893927
FETCH : F E T C H;
894928
FIRST : F I R S T;
929+
FLOAT : F L O A T;
895930
FLOOR : F L O O R;
896931
FROM : F R O M;
897932
FUNCTION : F U N C T I O N;
@@ -900,6 +935,7 @@ HAVING : H A V I N G;
900935
IN : I N;
901936
INDEX : I N D E X;
902937
INNER : I N N E R;
938+
INTEGER : I N T E G E R;
903939
INTERSECT : I N T E R S E C T;
904940
IS : I S;
905941
JOIN : J O I N;
@@ -912,6 +948,7 @@ LIKE : L I K E;
912948
LN : L N;
913949
LOCAL : L O C A L;
914950
LOCATE : L O C A T E;
951+
LONG : L O N G;
915952
LOWER : L O W E R;
916953
MAX : M A X;
917954
MEMBER : M E M B E R;
@@ -928,6 +965,8 @@ ON : O N;
928965
OR : O R;
929966
ORDER : O R D E R;
930967
OUTER : O U T E R;
968+
REPLACE : R E P L A C E;
969+
RIGHT : R I G H T;
931970
POWER : P O W E R;
932971
ROUND : R O U N D;
933972
SELECT : S E L E C T;
@@ -936,6 +975,7 @@ SIGN : S I G N;
936975
SIZE : S I Z E;
937976
SOME : S O M E;
938977
SQRT : S Q R T;
978+
STRING : S T R I N G;
939979
SUBSTRING : S U B S T R I N G;
940980
SUM : S U M;
941981
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;
@@ -1595,6 +1598,11 @@ public QueryTokenStream visitString_expression(EqlParser.String_expressionContex
15951598
builder.append(TOKEN_OPEN_PAREN);
15961599
builder.appendInline(visit(ctx.subquery()));
15971600
builder.append(TOKEN_CLOSE_PAREN);
1601+
} else if (!ObjectUtils.isEmpty(ctx.string_expression())) {
1602+
1603+
builder.appendInline(visit(ctx.string_expression(0)));
1604+
builder.append(TOKEN_DOUBLE_PIPE);
1605+
builder.appendExpression(visit(ctx.string_expression(1)));
15981606
}
15991607

16001608
return builder;
@@ -1926,6 +1934,32 @@ public QueryTokenStream visitFunctions_returning_strings(EqlParser.Functions_ret
19261934
builder.append(TOKEN_OPEN_PAREN);
19271935
builder.appendInline(visit(ctx.string_expression(0)));
19281936
builder.append(TOKEN_CLOSE_PAREN);
1937+
} else if (ctx.LEFT() != null) {
1938+
1939+
builder.append(QueryTokens.token(ctx.LEFT()));
1940+
builder.append(TOKEN_OPEN_PAREN);
1941+
builder.appendInline(visit(ctx.string_expression(0)));
1942+
builder.append(TOKEN_COMMA);
1943+
builder.appendInline(visit(ctx.arithmetic_expression(0)));
1944+
builder.append(TOKEN_CLOSE_PAREN);
1945+
} else if (ctx.RIGHT() != null) {
1946+
1947+
builder.append(QueryTokens.token(ctx.RIGHT()));
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.REPLACE() != null) {
1954+
1955+
builder.append(QueryTokens.token(ctx.REPLACE()));
1956+
builder.append(TOKEN_OPEN_PAREN);
1957+
builder.appendInline(visit(ctx.string_expression(0)));
1958+
builder.append(TOKEN_COMMA);
1959+
builder.appendInline(visit(ctx.string_expression(1)));
1960+
builder.append(TOKEN_COMMA);
1961+
builder.appendInline(visit(ctx.string_expression(2)));
1962+
builder.append(TOKEN_CLOSE_PAREN);
19291963
}
19301964

19311965
return builder;
@@ -1952,9 +1986,9 @@ public QueryTokenStream visitCast_function(EqlParser.Cast_functionContext ctx) {
19521986
builder.append(TOKEN_OPEN_PAREN);
19531987
builder.appendInline(visit(ctx.single_valued_path_expression()));
19541988
builder.append(TOKEN_SPACE);
1955-
builder.appendInline(visit(ctx.identification_variable()));
1989+
builder.appendInline(QueryTokenStream.concat(ctx.identification_variable(), this::visit, TOKEN_SPACE));
19561990

1957-
if (ctx.numeric_literal() != null) {
1991+
if (!ObjectUtils.isEmpty(ctx.numeric_literal())) {
19581992

19591993
builder.append(TOKEN_OPEN_PAREN);
19601994
builder.appendInline(QueryTokenStream.concat(ctx.numeric_literal(), this::visit, TOKEN_COMMA));
@@ -2055,6 +2089,14 @@ public QueryTokenStream visitCase_expression(EqlParser.Case_expressionContext ct
20552089
}
20562090
}
20572091

2092+
@Override
2093+
public QueryRendererBuilder visitType_literal(EqlParser.Type_literalContext ctx) {
2094+
2095+
QueryRendererBuilder builder = QueryRenderer.builder();
2096+
ctx.children.forEach(it -> builder.append(QueryTokens.expression(it.getText())));
2097+
return builder;
2098+
}
2099+
20582100
@Override
20592101
public QueryTokenStream visitGeneral_case_expression(EqlParser.General_case_expressionContext ctx) {
20602102

@@ -2175,9 +2217,11 @@ public QueryTokenStream visitIdentification_variable(EqlParser.Identification_va
21752217
return QueryRendererBuilder.from(QueryTokens.expression(ctx.IDENTIFICATION_VARIABLE()));
21762218
} else if (ctx.f != null) {
21772219
return QueryRendererBuilder.from(QueryTokens.expression(ctx.f));
2178-
} else {
2179-
return QueryRenderer.builder();
2220+
} else if (ctx.type_literal() != null) {
2221+
return visit(ctx.type_literal());
21802222
}
2223+
2224+
return QueryRenderer.builder();
21812225
}
21822226

21832227
@Override

0 commit comments

Comments
 (0)