Handle dateTimeField property with HQL.
Hibernate supports varisous duration literals. They also support a couple formats for binary literals. See #3025
This commit is contained in:
@@ -299,6 +299,7 @@ literal
|
||||
| stringLiteral
|
||||
| numericLiteral
|
||||
| dateTimeLiteral
|
||||
| binaryLiteral
|
||||
;
|
||||
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-boolean-literals
|
||||
@@ -337,10 +338,24 @@ dateTimeLiteral
|
||||
;
|
||||
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-duration-literals
|
||||
// TBD
|
||||
datetimeField
|
||||
: YEAR
|
||||
| MONTH
|
||||
| DAY
|
||||
| WEEK
|
||||
| QUARTER
|
||||
| HOUR
|
||||
| MINUTE
|
||||
| SECOND
|
||||
| NANOSECOND
|
||||
| EPOCH
|
||||
;
|
||||
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-binary-literals
|
||||
// TBD
|
||||
binaryLiteral
|
||||
: BINARY_LITERAL
|
||||
| '{' HEXLITERAL (',' HEXLITERAL)* '}'
|
||||
;
|
||||
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-enum-literals
|
||||
// TBD
|
||||
@@ -362,6 +377,8 @@ expression
|
||||
| primaryExpression # PlainPrimaryExpression
|
||||
| op=('+' | '-') numericLiteral # SignedNumericLiteral
|
||||
| op=('+' | '-') expression # SignedExpression
|
||||
| expression datetimeField # ToDurationExpression
|
||||
| expression BY datetimeField # FromDurationExpression
|
||||
| expression op=('*' | '/') expression # MultiplicationExpression
|
||||
| expression op=('+' | '-') expression # AdditionExpression
|
||||
| expression '||' expression # HqlConcatenationExpression
|
||||
@@ -607,7 +624,6 @@ inList
|
||||
;
|
||||
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-exists-predicate
|
||||
// TBD
|
||||
existsExpression
|
||||
: EXISTS (ELEMENTS | INDICES) '(' simplePath ')'
|
||||
| EXISTS expression
|
||||
@@ -1058,13 +1074,18 @@ YEAR : Y E A R;
|
||||
|
||||
fragment INTEGER_NUMBER : ('0' .. '9')+ ;
|
||||
fragment FLOAT_NUMBER : INTEGER_NUMBER+ '.'? INTEGER_NUMBER* (E [+-]? INTEGER_NUMBER)? ;
|
||||
fragment HEX_DIGIT : [0-9a-fA-F];
|
||||
|
||||
|
||||
CHARACTER : '\'' (~ ('\'' | '\\' )) '\'' ;
|
||||
STRINGLITERAL : '\'' ('\'' '\'' | ~('\'' | '\\'))* '\'' ;
|
||||
JAVASTRINGLITERAL : '"' ( ('\\' [btnfr"']) | ~('"'))* '"';
|
||||
INTEGER_LITERAL : INTEGER_NUMBER (L | B I)? ;
|
||||
FLOAT_LITERAL : FLOAT_NUMBER (D | F | B D)?;
|
||||
HEXLITERAL : '0' X ('0' .. '9' | A | B | C | D | E)+ ;
|
||||
HEXLITERAL : '0' X HEX_DIGIT+ ;
|
||||
BINARY_LITERAL : [xX] '\'' HEX_DIGIT+ '\''
|
||||
| [xX] '"' HEX_DIGIT+ '"'
|
||||
;
|
||||
|
||||
IDENTIFICATION_VARIABLE : ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '$' | '_') ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '0' .. '9' | '$' | '_')* ;
|
||||
|
||||
|
||||
@@ -1047,6 +1047,8 @@ class HqlQueryRenderer extends HqlBaseVisitor<List<JpaQueryParsingToken>> {
|
||||
return visit(ctx.numericLiteral());
|
||||
} else if (ctx.dateTimeLiteral() != null) {
|
||||
return visit(ctx.dateTimeLiteral());
|
||||
} else if (ctx.binaryLiteral() != null) {
|
||||
return visit(ctx.binaryLiteral());
|
||||
} else {
|
||||
return List.of();
|
||||
}
|
||||
@@ -1135,6 +1137,56 @@ class HqlQueryRenderer extends HqlBaseVisitor<List<JpaQueryParsingToken>> {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JpaQueryParsingToken> visitDatetimeField(HqlParser.DatetimeFieldContext ctx) {
|
||||
|
||||
if (ctx.YEAR() != null) {
|
||||
return List.of(new JpaQueryParsingToken(ctx.YEAR()));
|
||||
} else if (ctx.MONTH() != null) {
|
||||
return List.of(new JpaQueryParsingToken(ctx.MONTH()));
|
||||
} else if (ctx.DAY() != null) {
|
||||
return List.of(new JpaQueryParsingToken(ctx.DAY()));
|
||||
} else if (ctx.WEEK() != null) {
|
||||
return List.of(new JpaQueryParsingToken(ctx.WEEK()));
|
||||
} else if (ctx.QUARTER() != null) {
|
||||
return List.of(new JpaQueryParsingToken(ctx.QUARTER()));
|
||||
} else if (ctx.HOUR() != null) {
|
||||
return List.of(new JpaQueryParsingToken(ctx.HOUR()));
|
||||
} else if (ctx.MINUTE() != null) {
|
||||
return List.of(new JpaQueryParsingToken(ctx.MINUTE()));
|
||||
} else if (ctx.SECOND() != null) {
|
||||
return List.of(new JpaQueryParsingToken(ctx.SECOND()));
|
||||
} else if (ctx.NANOSECOND() != null) {
|
||||
return List.of(new JpaQueryParsingToken(ctx.NANOSECOND()));
|
||||
} else if (ctx.EPOCH() != null) {
|
||||
return List.of(new JpaQueryParsingToken(ctx.EPOCH()));
|
||||
} else {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JpaQueryParsingToken> visitBinaryLiteral(HqlParser.BinaryLiteralContext ctx) {
|
||||
|
||||
List<JpaQueryParsingToken> tokens = new ArrayList<>();
|
||||
|
||||
if (ctx.BINARY_LITERAL() != null) {
|
||||
tokens.add(new JpaQueryParsingToken(ctx.BINARY_LITERAL()));
|
||||
} else if (ctx.HEXLITERAL() != null) {
|
||||
|
||||
tokens.add(TOKEN_OPEN_BRACE);
|
||||
ctx.HEXLITERAL().forEach(terminalNode -> {
|
||||
tokens.add(new JpaQueryParsingToken(terminalNode));
|
||||
NOSPACE(tokens);
|
||||
tokens.add(TOKEN_COMMA);
|
||||
});
|
||||
CLIP(tokens);
|
||||
tokens.add(TOKEN_CLOSE_BRACE);
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JpaQueryParsingToken> visitPlainPrimaryExpression(HqlParser.PlainPrimaryExpressionContext ctx) {
|
||||
return visit(ctx.primaryExpression());
|
||||
@@ -1177,6 +1229,7 @@ class HqlQueryRenderer extends HqlBaseVisitor<List<JpaQueryParsingToken>> {
|
||||
|
||||
tokens.add(TOKEN_OPEN_PAREN);
|
||||
tokens.addAll(visit(ctx.expression()));
|
||||
NOSPACE(tokens);
|
||||
tokens.add(TOKEN_CLOSE_PAREN);
|
||||
|
||||
return tokens;
|
||||
@@ -1242,6 +1295,29 @@ class HqlQueryRenderer extends HqlBaseVisitor<List<JpaQueryParsingToken>> {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JpaQueryParsingToken> visitToDurationExpression(HqlParser.ToDurationExpressionContext ctx) {
|
||||
|
||||
List<JpaQueryParsingToken> tokens = new ArrayList<>();
|
||||
|
||||
tokens.addAll(visit(ctx.expression()));
|
||||
tokens.addAll(visit(ctx.datetimeField()));
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JpaQueryParsingToken> visitFromDurationExpression(HqlParser.FromDurationExpressionContext ctx) {
|
||||
|
||||
List<JpaQueryParsingToken> tokens = new ArrayList<>();
|
||||
|
||||
tokens.addAll(visit(ctx.expression()));
|
||||
tokens.add(new JpaQueryParsingToken(ctx.BY()));
|
||||
tokens.addAll(visit(ctx.datetimeField()));
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JpaQueryParsingToken> visitCaseExpression(HqlParser.CaseExpressionContext ctx) {
|
||||
return visit(ctx.caseList());
|
||||
|
||||
@@ -48,6 +48,7 @@ class JpaQueryParsingToken {
|
||||
public static final JpaQueryParsingToken TOKEN_CLOSE_SQUARE_BRACKET = new JpaQueryParsingToken("]");
|
||||
public static final JpaQueryParsingToken TOKEN_COLON = new JpaQueryParsingToken(":", false);
|
||||
public static final JpaQueryParsingToken TOKEN_QUESTION_MARK = new JpaQueryParsingToken("?", false);
|
||||
public static final JpaQueryParsingToken TOKEN_OPEN_BRACE = new JpaQueryParsingToken("{", false);
|
||||
public static final JpaQueryParsingToken TOKEN_CLOSE_BRACE = new JpaQueryParsingToken("}");
|
||||
public static final JpaQueryParsingToken TOKEN_CLOSE_SQUARE_BRACKET_BRACE = new JpaQueryParsingToken("]}");
|
||||
public static final JpaQueryParsingToken TOKEN_CLOSE_PAREN_BRACE = new JpaQueryParsingToken(")}");
|
||||
|
||||
@@ -1526,4 +1526,17 @@ class HqlQueryRendererTests {
|
||||
void castFunctionWithFqdnShouldWork() {
|
||||
assertQuery("SELECT o FROM Order o WHERE CAST(:userId AS java.util.UUID) IS NULL OR o.user.id = :userId");
|
||||
}
|
||||
|
||||
@Test // GH-3025
|
||||
void durationLiteralsShouldWork() {
|
||||
assertQuery("SELECT ce.id FROM CalendarEvent ce WHERE (ce.endDate - ce.startDate) > 5 MINUTE");
|
||||
}
|
||||
|
||||
@Test // GH-3025
|
||||
void binaryLiteralsShouldWork() {
|
||||
|
||||
assertQuery("SELECT ce.id FROM CalendarEvent ce WHERE ce.value = {0xDE, 0xAD, 0xBE, 0xEF}");
|
||||
assertQuery("SELECT ce.id FROM CalendarEvent ce WHERE ce.value = X'DEADBEEF'");
|
||||
assertQuery("SELECT ce.id FROM CalendarEvent ce WHERE ce.value = x'deadbeef'");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user