Skip to content

Commit

Permalink
Merge pull request #532 from eclipse/enhance-map-return
Browse files Browse the repository at this point in the history
Fix queries based on Jakarta Data TCK
  • Loading branch information
otaviojava authored Jul 28, 2024
2 parents fd469d0 + 2e73f56 commit a754f70
Show file tree
Hide file tree
Showing 20 changed files with 872 additions and 474 deletions.
73 changes: 35 additions & 38 deletions antlr4/org/eclipse/jnosql/query/grammar/data/JDQL.g4
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@ from_clause : FROM entity_name;

where_clause : WHERE conditional_expression;

set_clause : SET update_item (',' update_item)*;
update_item : state_field_path_expression '=' (scalar_expression | NULL);
set_clause : SET update_item (COMMA update_item)*;
update_item : state_field_path_expression EQ (scalar_expression | NULL);

select_clause : SELECT select_list;
select_list
: state_field_path_expression (',' state_field_path_expression)*
: state_field_path_expression (COMMA state_field_path_expression)*
| aggregate_expression
;
aggregate_expression : COUNT '(' THIS ')';

orderby_clause : ORDER BY orderby_item (',' orderby_item)*;
orderby_item : state_field_path_expression (ASC | DESC);
orderby_clause : ORDER BY orderby_item (COMMA orderby_item)*;
orderby_item : state_field_path_expression (ASC | DESC)?;

conditional_expression
// highest to lowest precedence
: '(' conditional_expression ')'
: LPAREN conditional_expression RPAREN
| null_comparison_expression
| in_expression
| between_expression
Expand All @@ -36,7 +36,9 @@ conditional_expression
| conditional_expression OR conditional_expression
;

comparison_expression : scalar_expression ('=' | '>' | '>=' | '<' | '<=' | '<>') scalar_expression;
comparison_expression : scalar_expression comparison_operator scalar_expression;
comparison_operator : EQ | GT | GTEQ | LT | LTEQ | NEQ;

between_expression : scalar_expression NOT? BETWEEN scalar_expression AND scalar_expression;
like_expression : scalar_expression NOT? LIKE STRING;

Expand All @@ -47,12 +49,13 @@ null_comparison_expression : state_field_path_expression IS NOT? NULL;

scalar_expression
// highest to lowest precedence
: '(' scalar_expression ')'
: LPAREN scalar_expression RPAREN
| primary_expression
| ('+' | '-') scalar_expression
| scalar_expression ('*' | '/') scalar_expression
| scalar_expression ('+' | '-') scalar_expression
| scalar_expression '||' scalar_expression
| scalar_expression MUL scalar_expression
| scalar_expression DIV scalar_expression
| scalar_expression PLUS scalar_expression
| scalar_expression MINUS scalar_expression
| scalar_expression CONCAT scalar_expression
;

primary_expression
Expand All @@ -65,29 +68,29 @@ primary_expression
;

function_expression
: ABS '(' scalar_expression ')'
| LENGTH '(' scalar_expression ')'
| LOWER '(' scalar_expression ')'
| UPPER '(' scalar_expression ')'
| LEFT '(' scalar_expression ',' scalar_expression ')'
| RIGHT '(' scalar_expression ',' scalar_expression ')'
: ('abs(' | 'ABS(') scalar_expression ')'
| ('length(' | 'LENGTH(') scalar_expression ')'
| ('lower(' | 'LOWER(') scalar_expression ')'
| ('upper(' | 'UPPER(') scalar_expression ')'
| ('left(' | 'LEFT(') scalar_expression ',' scalar_expression ')'
| ('right(' | 'RIGHT(') scalar_expression ',' scalar_expression ')'
;

special_expression
: LOCAL DATE
| LOCAL DATETIME
| LOCAL TIME
| TRUE
| FALSE
: LOCAL_DATE
| LOCAL_DATETIME
| LOCAL_TIME
| TRUE
| FALSE
;

state_field_path_expression : IDENTIFIER ('.' IDENTIFIER)* | FULLY_QUALIFIED_IDENTIFIER;
state_field_path_expression : IDENTIFIER (DOT IDENTIFIER)* | FULLY_QUALIFIED_IDENTIFIER;

entity_name : IDENTIFIER; // no ambiguity

enum_literal : IDENTIFIER ('.' IDENTIFIER)* | FULLY_QUALIFIED_IDENTIFIER; // ambiguity with state_field_path_expression resolvable semantically
enum_literal : IDENTIFIER (DOT IDENTIFIER)* | FULLY_QUALIFIED_IDENTIFIER; // ambiguity with state_field_path_expression resolvable semantically

input_parameter : ':' IDENTIFIER | '?' INTEGER;
input_parameter : COLON IDENTIFIER | QUESTION INTEGER;

literal : STRING | INTEGER | DOUBLE;

Expand All @@ -111,12 +114,6 @@ ASC : [aA][sS][cC];
DESC : [dD][eE][sS][cC];
AND : [aA][nN][dD];
OR : [oO][rR];
ABS : [aA][bB][sS];
LENGTH : [lL][eE][nN][gG][tT][hH];
LOWER : [lL][oO][wW][eE][rR];
UPPER : [uU][pP][pP][eE][rR];
LEFT : [lL][eE][fF][tT];
RIGHT : [rR][iI][gG][hH][tT];
LOCAL_DATE : [lL][oO][cC][aA][lL] [dD][aA][tT][eE];
LOCAL_DATETIME : [lL][oO][cC][aA][lL] [dD][aA][tT][eE][tT][iI][mM][eE];
LOCAL_TIME : [lL][oO][cC][aA][lL] [tT][iI][mM][eE];
Expand Down Expand Up @@ -150,12 +147,12 @@ COLON : ':';
QUESTION : '?';

// Identifier and literals
FULLY_QUALIFIED_IDENTIFIER : [a-zA-Z_][a-zA-Z0-9_]*('.'[a-zA-Z_][a-zA-Z0-9_]*)+;
IDENTIFIER : [a-zA-Z_][a-zA-Z0-9_]*;
STRING : '"' ( ~["\\] | '\\' . )* '"' // double quoted strings
| '\'' ( ~['\\] | '\\' . )* '\''; // single quoted strings
INTEGER : '-'?[0-9]+;
DOUBLE : '-'?[0-9]+'.'[0-9]* | '-'?'.'[0-9]+;
FULLY_QUALIFIED_IDENTIFIER : [a-zA-Z_][a-zA-Z0-9_]* (DOT [a-zA-Z_][a-zA-Z0-9_]*)+;
IDENTIFIER : [a-zA-Z_][a-zA-Z0-9_]*;
STRING : '\'' ( ~('\'' | '\\') | '\\' . | '\'\'' )* '\'' // single quoted strings with embedded single quotes handled
| '"' ( ~["\\] | '\\' . )* '"' ; // double quoted strings
INTEGER : '-'?[0-9]+;
DOUBLE : '-'?[0-9]+'.'[0-9]* | '-'?'.'[0-9]+;
// Whitespace and Comments
WS : [ \t\r\n]+ -> skip ;
Expand Down
6 changes: 4 additions & 2 deletions antlr4/org/eclipse/jnosql/query/grammar/method/Method.g4
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ where: condition (and condition| or condition)* ;
condition: eq | gt | gte | lt | lte | between | in | like | truth | untruth | nullable | contains | endsWith | startsWith;
order: 'OrderBy' orderName (orderName)*;
orderName: variable | variable asc | variable desc;
limit : 'First' max?;
limit: firstLimit | firstOne;
firstLimit : 'First' limitNumber;
firstOne: 'First';
and: 'And';
or: 'Or';
asc: 'Asc';
Expand All @@ -29,7 +31,7 @@ nullable: variable ignoreCase? not? 'Null';
ignoreCase: 'IgnoreCase';
not: 'Not';
variable: ANY_NAME;
max: INT;
limitNumber: INT;
ANY_NAME: [a-zA-Z_.][a-zA-Z_.0-9-]*;
WS: [ \t\r\n]+ -> skip ;
INT: [0-9]+;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ public void exitComparison_expression(JDQLParser.Comparison_expressionContext ct
and = andCondition;
}

@Override
public void exitConditional_expression(JDQLParser.Conditional_expressionContext ctx) {
super.exitConditional_expression(ctx);
if(Objects.nonNull(ctx.LPAREN()) || Objects.nonNull(ctx.RPAREN())) {
throw new UnsupportedOperationException("Eclipse JNoSQL does not support parenthesis is not supported in the query: " + ctx.getText());
}
}

@Override
public void exitNull_comparison_expression(JDQLParser.Null_comparison_expressionContext ctx) {
super.exitNull_comparison_expression(ctx);
Expand Down Expand Up @@ -180,17 +188,18 @@ public void exitFunction_expression(JDQLParser.Function_expressionContext ctx) {
}

private Condition getCondition(JDQLParser.Comparison_expressionContext ctx) {
if (ctx.EQ() != null) {
var context = ctx.comparison_operator();
if (context.EQ() != null) {
return EQUALS;
} else if (ctx.LT() != null) {
} else if (context.LT() != null) {
return Condition.LESSER_THAN;
} else if (ctx.LTEQ() != null) {
} else if (context.LTEQ() != null) {
return Condition.LESSER_EQUALS_THAN;
} else if (ctx.GT() != null) {
} else if (context.GT() != null) {
return Condition.GREATER_THAN;
} else if (ctx.GTEQ() != null) {
} else if (context.GTEQ() != null) {
return Condition.GREATER_EQUALS_THAN;
} else if (ctx.NEQ() != null) {
} else if (context.NEQ() != null) {
return NOT;
}
throw new UnsupportedOperationException("The operation does not support: " + ctx.getText());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,33 @@ public Enum<?> apply(String text) {
var lastDotIndex = text.lastIndexOf('.');
var enumClassName = text.substring(0, lastDotIndex);
var enumValueName = text.substring(lastDotIndex + 1);
Class<?> enumClass = Class.forName(enumClassName);
if (enumClass.isEnum()) {
Class<? extends Enum> enumType = enumClass.asSubclass(Enum.class);
return Enum.valueOf(enumType, enumValueName);
} else {
throw new QueryException("There is an issue to load class because it is not an enum: " + enumClassName);

// Try loading the class directly
try {
return getEnumValue(enumClassName, enumValueName);
} catch (ClassNotFoundException e) {
// Replace last '.' with '$' for inner classes and try again
int secondLastDotIndex = enumClassName.lastIndexOf('.');
if (secondLastDotIndex != -1) {
enumClassName = enumClassName.substring(0, secondLastDotIndex) + '$' + enumClassName.substring(secondLastDotIndex + 1);
return getEnumValue(enumClassName, enumValueName);
} else {
throw e;
}
}
} catch (ClassNotFoundException | IllegalArgumentException exp) {
throw new QueryException("There is an issue to load class because: " + text, exp);
}
}

@SuppressWarnings({"unchecked", "rawtypes"})
private Enum<?> getEnumValue(String enumClassName, String enumValueName) throws ClassNotFoundException {
Class<?> enumClass = Class.forName(enumClassName);
if (enumClass.isEnum()) {
Class<? extends Enum> enumType = enumClass.asSubclass(Enum.class);
return Enum.valueOf(enumType, enumValueName);
} else {
throw new QueryException("There is an issue to load class because it is not an enum: " + enumClassName);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,20 @@ public void exitUpdate_item(JDQLParser.Update_itemContext ctx) {
super.exitUpdate_item(ctx);
String name = ctx.state_field_path_expression().getText();
var scalarContext = ctx.scalar_expression();
if(isArithmeticOperation(scalarContext)) {
throw new UnsupportedOperationException("Eclipse JNoSQL does not support arithmetic operations in the UPDATE clause: " + scalarContext.getText());
}
if(hasParenthesis(scalarContext)) {
throw new UnsupportedOperationException("Eclipse JNoSQL does not support parenthesis in the UPDATE clause: " + scalarContext.getText());
}
var primaryExpression = scalarContext.primary_expression();
var value = PrimaryFunction.INSTANCE.apply(primaryExpression);
items.add(JDQLUpdateItem.of(name, value));

}



@Override
public void exitEntity_name(JDQLParser.Entity_nameContext ctx) {
super.exitEntity_name(ctx);
Expand All @@ -65,4 +73,16 @@ public void exitEntity_name(JDQLParser.Entity_nameContext ctx) {
ParserRuleContext getTree(JDQLParser parser) {
return parser.update_statement();
}

private static boolean isArithmeticOperation(JDQLParser.Scalar_expressionContext scalarContext) {
return Objects.nonNull(scalarContext.MUL())
|| Objects.nonNull(scalarContext.DIV())
|| Objects.nonNull(scalarContext.PLUS())
|| Objects.nonNull(scalarContext.MINUS())
|| Objects.nonNull(scalarContext.CONCAT());
}
private boolean hasParenthesis(JDQLParser.Scalar_expressionContext scalarContext) {
return Objects.nonNull(scalarContext.LPAREN()) || Objects.nonNull(scalarContext.RPAREN());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public final class DeleteByMethodQueryProvider extends AbstractMethodQueryProvid
public DeleteQuery apply(String query, String entity) {
Objects.requireNonNull(query, " query is required");
Objects.requireNonNull(entity, " entity is required");
runQuery(MethodQuery.of(query).get());
runQuery(QueryTokenizer.of(query).get());
return DeleteQuery.of(entity, where);
}

Expand Down

This file was deleted.

Loading

0 comments on commit a754f70

Please sign in to comment.