Skip to content

Commit 651ec32

Browse files
committed
Add support for IS TRUE|FALSE|EMPTY and CONTAINS|INCLUDES|INTERSECTS HQL predicates.
Closes #3628
1 parent ea0bd8c commit 651ec32

File tree

3 files changed

+187
-78
lines changed

3 files changed

+187
-78
lines changed

spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4

+12-14
Original file line numberDiff line numberDiff line change
@@ -571,13 +571,15 @@ pathContinutation
571571
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-conditional-expressions
572572
predicate
573573
: '(' predicate ')' # GroupedPredicate
574-
| dealingWithNullExpression # NullExpressionPredicate
574+
| expression IS NOT? (NULL|EMPTY|TRUE|FALSE) # IsBooleanPredicate
575+
| expression IS NOT? DISTINCT FROM expression # IsDistinctFromPredicate
576+
| expression NOT? MEMBER OF? path # MemberOfPredicate
575577
| inExpression # InPredicate
576578
| betweenExpression # BetweenPredicate
579+
| expression NOT? (CONTAINS|INCLUDES|INTERSECTS) expression # ContainsPredicate
577580
| relationalExpression # RelationalPredicate
578581
| stringPatternMatching # LikePredicate
579582
| existsExpression # ExistsPredicate
580-
| collectionExpression # CollectionPredicate
581583
| NOT predicate # NotPredicate
582584
| predicate AND predicate # AndPredicate
583585
| predicate OR predicate # OrPredicate
@@ -600,12 +602,6 @@ betweenExpression
600602
: expression NOT? BETWEEN expression AND expression
601603
;
602604

603-
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-null-predicate
604-
dealingWithNullExpression
605-
: expression IS NOT? NULL
606-
| expression IS NOT? DISTINCT FROM expression
607-
;
608-
609605
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-like-predicate
610606
stringPatternMatching
611607
: expression NOT? (LIKE | ILIKE) expression (ESCAPE (stringLiteral|parameter))?
@@ -632,12 +628,6 @@ existsExpression
632628
| EXISTS expression
633629
;
634630

635-
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-collection-operators
636-
collectionExpression
637-
: expression IS NOT? EMPTY
638-
| expression NOT? MEMBER OF path
639-
;
640-
641631
// Projection
642632
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-select-new
643633
instantiationTarget
@@ -707,6 +697,7 @@ reservedWord
707697
| CASE
708698
| CAST
709699
| COLLATE
700+
| CONTAINS
710701
| COUNT
711702
| CROSS
712703
| CUBE
@@ -739,6 +730,7 @@ reservedWord
739730
| EXISTS
740731
| EXP
741732
| EXTRACT
733+
| FALSE
742734
| FETCH
743735
| FILTER
744736
| FIRST
@@ -757,12 +749,14 @@ reservedWord
757749
| IGNORE
758750
| ILIKE
759751
| IN
752+
| INCLUDES
760753
| INDEX
761754
| INDICES
762755
| INNER
763756
| INSERT
764757
| INSTANT
765758
| INTERSECT
759+
| INTERSECTS
766760
| INTO
767761
| IS
768762
| JOIN
@@ -834,6 +828,7 @@ reservedWord
834828
| SOME
835829
| SUBSTRING
836830
| SUM
831+
| TRUE
837832
| THEN
838833
| TIES
839834
| TIME
@@ -917,6 +912,7 @@ CASE : C A S E;
917912
CAST : C A S T;
918913
CEILING : C E I L I N G;
919914
COLLATE : C O L L A T E;
915+
CONTAINS : C O N T A I N S;
920916
COUNT : C O U N T;
921917
CROSS : C R O S S;
922918
CUBE : C U B E;
@@ -969,12 +965,14 @@ ID : I D;
969965
IGNORE : I G N O R E;
970966
ILIKE : I L I K E;
971967
IN : I N;
968+
INCLUDES : I N C L U D E S;
972969
INDEX : I N D E X;
973970
INDICES : I N D I C E S;
974971
INNER : I N N E R;
975972
INSERT : I N S E R T;
976973
INSTANT : I N S T A N T;
977974
INTERSECT : I N T E R S E C T;
975+
INTERSECTS : I N T E R S E C T S;
978976
INTO : I N T O;
979977
IS : I S;
980978
JOIN : J O I N;

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryRenderer.java

+98-61
Original file line numberDiff line numberDiff line change
@@ -2015,15 +2015,111 @@ public QueryTokenStream visitPathContinutation(HqlParser.PathContinutationContex
20152015
}
20162016

20172017
@Override
2018-
public QueryTokenStream visitNullExpressionPredicate(HqlParser.NullExpressionPredicateContext ctx) {
2019-
return visit(ctx.dealingWithNullExpression());
2018+
public QueryTokenStream visitIsBooleanPredicate(HqlParser.IsBooleanPredicateContext ctx) {
2019+
2020+
QueryRendererBuilder builder = QueryRenderer.builder();
2021+
2022+
builder.appendExpression(visit(ctx.expression()));
2023+
builder.append(QueryTokens.expression(ctx.IS()));
2024+
2025+
if (ctx.NOT() != null) {
2026+
builder.append(QueryTokens.expression(ctx.NOT()));
2027+
}
2028+
2029+
if (ctx.NULL() != null) {
2030+
builder.append(QueryTokens.expression(ctx.NULL()));
2031+
}
2032+
2033+
if (ctx.TRUE() != null) {
2034+
builder.append(QueryTokens.expression(ctx.TRUE()));
2035+
}
2036+
2037+
if (ctx.FALSE() != null) {
2038+
builder.append(QueryTokens.expression(ctx.FALSE()));
2039+
}
2040+
2041+
if (ctx.EMPTY() != null) {
2042+
builder.append(QueryTokens.expression(ctx.EMPTY()));
2043+
}
2044+
2045+
return builder;
2046+
}
2047+
2048+
@Override
2049+
public QueryTokenStream visitMemberOfPredicate(HqlParser.MemberOfPredicateContext ctx) {
2050+
2051+
QueryRendererBuilder builder = QueryRenderer.builder();
2052+
2053+
builder.appendExpression(visit(ctx.expression()));
2054+
if (ctx.NOT() != null) {
2055+
builder.append(QueryTokens.expression(ctx.NOT()));
2056+
}
2057+
if (ctx.MEMBER() != null) {
2058+
builder.append(QueryTokens.expression(ctx.MEMBER()));
2059+
}
2060+
if (ctx.OF() != null) {
2061+
builder.append(QueryTokens.expression(ctx.OF()));
2062+
}
2063+
2064+
builder.append(visit(ctx.path()));
2065+
2066+
return builder;
2067+
}
2068+
2069+
@Override
2070+
public QueryTokenStream visitIsDistinctFromPredicate(HqlParser.IsDistinctFromPredicateContext ctx) {
2071+
2072+
QueryRendererBuilder builder = QueryRenderer.builder();
2073+
2074+
builder.appendExpression(visit(ctx.expression(0)));
2075+
builder.append(QueryTokens.expression(ctx.IS()));
2076+
2077+
if (ctx.NOT() != null) {
2078+
builder.append(QueryTokens.expression(ctx.NOT()));
2079+
}
2080+
2081+
if (ctx.DISTINCT() != null) {
2082+
2083+
builder.append(QueryTokens.expression(ctx.DISTINCT()));
2084+
builder.append(QueryTokens.expression(ctx.FROM()));
2085+
builder.appendExpression(visit(ctx.expression(1)));
2086+
}
2087+
2088+
return builder;
20202089
}
20212090

20222091
@Override
20232092
public QueryTokenStream visitBetweenPredicate(HqlParser.BetweenPredicateContext ctx) {
20242093
return visit(ctx.betweenExpression());
20252094
}
20262095

2096+
@Override
2097+
public QueryTokenStream visitContainsPredicate(HqlParser.ContainsPredicateContext ctx) {
2098+
2099+
QueryRendererBuilder builder = QueryRenderer.builder();
2100+
2101+
builder.appendExpression(visit(ctx.expression(0)));
2102+
2103+
if (ctx.NOT() != null) {
2104+
builder.append(QueryTokens.expression(ctx.NOT()));
2105+
}
2106+
2107+
if (ctx.CONTAINS() != null) {
2108+
builder.append(QueryTokens.expression(ctx.CONTAINS()));
2109+
}
2110+
if (ctx.INCLUDES() != null) {
2111+
builder.append(QueryTokens.expression(ctx.INCLUDES()));
2112+
}
2113+
if (ctx.INTERSECTS() != null) {
2114+
builder.append(QueryTokens.expression(ctx.INTERSECTS()));
2115+
}
2116+
2117+
builder.appendExpression(visit(ctx.expression(1)));
2118+
2119+
return builder;
2120+
2121+
}
2122+
20272123
@Override
20282124
public QueryTokenStream visitOrPredicate(HqlParser.OrPredicateContext ctx) {
20292125

@@ -2046,11 +2142,6 @@ public QueryTokenStream visitExistsPredicate(HqlParser.ExistsPredicateContext ct
20462142
return visit(ctx.existsExpression());
20472143
}
20482144

2049-
@Override
2050-
public QueryTokenStream visitCollectionPredicate(HqlParser.CollectionPredicateContext ctx) {
2051-
return visit(ctx.collectionExpression());
2052-
}
2053-
20542145
@Override
20552146
public QueryTokenStream visitAndPredicate(HqlParser.AndPredicateContext ctx) {
20562147

@@ -2144,30 +2235,6 @@ public QueryTokenStream visitBetweenExpression(HqlParser.BetweenExpressionContex
21442235
return builder;
21452236
}
21462237

2147-
@Override
2148-
public QueryTokenStream visitDealingWithNullExpression(HqlParser.DealingWithNullExpressionContext ctx) {
2149-
2150-
QueryRendererBuilder builder = QueryRenderer.builder();
2151-
2152-
builder.appendExpression(visit(ctx.expression(0)));
2153-
builder.append(QueryTokens.expression(ctx.IS()));
2154-
2155-
if (ctx.NOT() != null) {
2156-
builder.append(QueryTokens.expression(ctx.NOT()));
2157-
}
2158-
2159-
if (ctx.NULL() != null) {
2160-
builder.append(QueryTokens.expression(ctx.NULL()));
2161-
} else if (ctx.DISTINCT() != null) {
2162-
2163-
builder.append(QueryTokens.expression(ctx.DISTINCT()));
2164-
builder.append(QueryTokens.expression(ctx.FROM()));
2165-
builder.appendExpression(visit(ctx.expression(1)));
2166-
}
2167-
2168-
return builder;
2169-
}
2170-
21712238
@Override
21722239
public QueryTokenStream visitStringPatternMatching(HqlParser.StringPatternMatchingContext ctx) {
21732240

@@ -2279,36 +2346,6 @@ public QueryTokenStream visitExistsExpression(HqlParser.ExistsExpressionContext
22792346
return builder;
22802347
}
22812348

2282-
@Override
2283-
public QueryTokenStream visitCollectionExpression(HqlParser.CollectionExpressionContext ctx) {
2284-
2285-
QueryRendererBuilder builder = QueryRenderer.builder();
2286-
2287-
builder.appendExpression(visit(ctx.expression()));
2288-
2289-
if (ctx.IS() != null) {
2290-
2291-
builder.append(QueryTokens.expression(ctx.IS()));
2292-
2293-
if (ctx.NOT() != null) {
2294-
builder.append(QueryTokens.expression(ctx.NOT()));
2295-
}
2296-
2297-
builder.append(QueryTokens.expression(ctx.EMPTY()));
2298-
} else if (ctx.MEMBER() != null) {
2299-
2300-
if (ctx.NOT() != null) {
2301-
builder.append(QueryTokens.expression(ctx.NOT()));
2302-
}
2303-
2304-
builder.append(QueryTokens.expression(ctx.MEMBER()));
2305-
builder.append(QueryTokens.expression(ctx.OF()));
2306-
builder.append(visit(ctx.path()));
2307-
}
2308-
2309-
return builder;
2310-
}
2311-
23122349
@Override
23132350
public QueryTokenStream visitInstantiationTarget(HqlParser.InstantiationTargetContext ctx) {
23142351

0 commit comments

Comments
 (0)