Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include support to Eclipse JNoSQL #531

Merged
merged 24 commits into from
Jul 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ad75551
chore: enhance null gramar
otaviojava Jul 26, 2024
3eb395d
docs: include changelog info
otaviojava Jul 26, 2024
b02f48a
feat: include null value type
otaviojava Jul 26, 2024
79d8fd7
feat: create Nullquery value implementation
otaviojava Jul 26, 2024
31a8597
test: create scenario to when is null
otaviojava Jul 26, 2024
3c86215
test: create scenation when is null in the query
otaviojava Jul 26, 2024
d2cfead
feat: fix scenario in the query with negation at null
otaviojava Jul 26, 2024
fd037a1
chore: include Null value at query
otaviojava Jul 26, 2024
e685ac2
test: create scenarios to null and not null value
otaviojava Jul 26, 2024
baa64cf
chore: update ignore case to functions
otaviojava Jul 26, 2024
fc4e7e6
chore: update jql to use ignore case
otaviojava Jul 26, 2024
de332a7
chore: use primary function to ignore case
otaviojava Jul 26, 2024
a95f9a6
test: create scenario to jakarta data query provider
otaviojava Jul 26, 2024
f578874
chore: create and resolve issue at query
otaviojava Jul 26, 2024
a1cf7df
test: create condition test scenario
otaviojava Jul 26, 2024
b8519bb
feat: include not equals condition
otaviojava Jul 26, 2024
c1f528c
test: create test to not equals
otaviojava Jul 26, 2024
35231c7
style: create style scenario at AbstractWhere
otaviojava Jul 26, 2024
4f60c6e
feat: create array repository return
otaviojava Jul 26, 2024
151c120
feat: create and implement array repository return
otaviojava Jul 26, 2024
b5fce47
test: creates scenarios to array repository
otaviojava Jul 26, 2024
45de751
feat: create array repository test
otaviojava Jul 26, 2024
8e0d0da
chore: create repository return as array
otaviojava Jul 26, 2024
986fdb3
style: remove imports at ArrayRepositoryReturn
otaviojava Jul 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version
- Enables custom Repository
- Include the `First` keyword in the method by query in the Repository
- Include the `Null`, `NotNull` and `countAll` keywords in the method by query in the Repository
- Include condition to is NUll and is Not Null in the query

=== Fixed

Expand Down
37 changes: 21 additions & 16 deletions antlr4/org/eclipse/jnosql/query/grammar/data/JDQL.g4
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ 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');
update_item : state_field_path_expression '=' (scalar_expression | NULL);

select_clause : SELECT select_list;
select_list
Expand Down Expand Up @@ -65,27 +65,27 @@ 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 '(' scalar_expression ')'
| LENGTH '(' scalar_expression ')'
| LOWER '(' scalar_expression ')'
| UPPER '(' scalar_expression ')'
| LEFT '(' scalar_expression ',' scalar_expression ')'
| 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)*;
state_field_path_expression : IDENTIFIER ('.' IDENTIFIER)* | FULLY_QUALIFIED_IDENTIFIER;

entity_name : IDENTIFIER; // no ambiguity

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

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

Expand Down Expand Up @@ -123,6 +123,10 @@ LOCAL_TIME : [lL][oO][cC][aA][lL] [tT][iI][mM][eE];
BETWEEN : [bB][eE][tT][wW][eE][eE][nN];
LIKE : [lL][iI][kK][eE];
THIS : [tT][hH][iI][sS];
LOCAL : [lL][oO][cC][aA][lL];
DATE : [dD][aA][tT][eE];
DATETIME : [dD][aA][tT][eE][tT][iI][mM][eE];
TIME : [tT][iI][mM][eE];

// Operators
EQ : '=';
Expand All @@ -146,9 +150,10 @@ 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
STRING : '"' ( ~["\\] | '\\' . )* '"' // double quoted strings
| '\'' ( ~['\\] | '\\' . )* '\''; // single quoted strings
INTEGER : '-'?[0-9]+;
DOUBLE : '-'?[0-9]+'.'[0-9]* | '-'?'.'[0-9]+;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2024 Contributors to the Eclipse Foundation
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
* You may elect to redistribute this code under either of these licenses.
* Contributors:
* Otavio Santana
*/
package org.eclipse.jnosql.communication.query;

/**
* A query value that represents a null value.
*/
public enum NullQueryValue implements QueryValue<NullQueryValue> {

INSTANCE;

@Override
public NullQueryValue get() {
return INSTANCE;
}

@Override
public ValueType type() {
return ValueType.NULL;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,11 @@ public enum ValueType {
* type that can have only the values true or false. Used in NoSQL queries to
* handle logical branching and conditional checks.
*/
BOOLEAN
BOOLEAN,
/**
* Represents a null value. Null is a special value in NoSQL databases that
* indicates the absence of a value. Used in queries to handle missing or
* unknown data, or to represent the absence of a value in a specific context.
*/
NULL
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import org.eclipse.jnosql.communication.Condition;
import org.eclipse.jnosql.communication.query.ConditionQueryValue;
import org.eclipse.jnosql.communication.query.NullQueryValue;
import org.eclipse.jnosql.communication.query.QueryCondition;
import org.eclipse.jnosql.communication.query.QueryValue;
import org.eclipse.jnosql.communication.query.StringQueryValue;
Expand Down Expand Up @@ -59,13 +60,18 @@ public void exitComparison_expression(JDQLParser.Comparison_expressionContext ct
super.exitComparison_expression(ctx);
boolean hasNot = false;
boolean andCondition = true;
if(ctx.getParent() instanceof JDQLParser.Conditional_expressionContext ctxParent
&& ctxParent.getParent() instanceof JDQLParser.Conditional_expressionContext grandParent){
if (ctx.getParent() instanceof JDQLParser.Conditional_expressionContext ctxParent
&& ctxParent.getParent() instanceof JDQLParser.Conditional_expressionContext grandParent) {
hasNot = Objects.nonNull(grandParent.NOT());
andCondition = Objects.isNull(grandParent.OR());
}
var contexts = ctx.scalar_expression();
var contextCondition = getCondition(ctx);

if (contextCondition.equals(NOT)) {
contextCondition = EQUALS;
hasNot = !hasNot;
}
var name = contexts.get(0).getText();
var value = contexts.get(1);
var literal = PrimaryFunction.INSTANCE.apply(value.primary_expression());
Expand All @@ -76,23 +82,41 @@ public void exitComparison_expression(JDQLParser.Comparison_expressionContext ct
and = andCondition;
}

@Override
public void exitNull_comparison_expression(JDQLParser.Null_comparison_expressionContext ctx) {
super.exitNull_comparison_expression(ctx);
boolean hasNot = Objects.nonNull(ctx.NOT());
boolean andCondition = true;
if (ctx.getParent() instanceof JDQLParser.Conditional_expressionContext ctxParent
&& ctxParent.getParent() instanceof JDQLParser.Conditional_expressionContext grandParent) {
andCondition = Objects.isNull(grandParent.OR());
}
var stateFieldPathExpressionContext = ctx.state_field_path_expression();
var name = stateFieldPathExpressionContext.getText();
if (this.condition != null && this.condition.value() instanceof ConditionQueryValue) {
and = andCondition;
}
checkCondition(new DefaultQueryCondition(name, EQUALS, NullQueryValue.INSTANCE), hasNot);
and = andCondition;
}

@Override
public void exitLike_expression(JDQLParser.Like_expressionContext ctx) {
super.exitLike_expression(ctx);
boolean hasNot = Objects.nonNull(ctx.NOT());
boolean andCondition = true;

if(ctx.getParent() instanceof JDQLParser.Conditional_expressionContext ctxParent
&& ctxParent.getParent() instanceof JDQLParser.Conditional_expressionContext grandParent){
if (ctx.getParent() instanceof JDQLParser.Conditional_expressionContext ctxParent
&& ctxParent.getParent() instanceof JDQLParser.Conditional_expressionContext grandParent) {
andCondition = Objects.isNull(grandParent.OR());
}

var contexts = ctx.scalar_expression();
var name = contexts.getText();
var contextCondition = Condition.LIKE;
var likeValueIndex = ctx.getChildCount() -1 ;
var likeValueIndex = ctx.getChildCount() - 1;
var likeValue = contexts.getParent().getChild(likeValueIndex).getText();
var literal = StringQueryValue.of(likeValue.substring(1, likeValue.length() -1));
var literal = StringQueryValue.of(likeValue.substring(1, likeValue.length() - 1));
if (this.condition != null && this.condition.value() instanceof ConditionQueryValue) {
and = andCondition;
}
Expand All @@ -106,8 +130,8 @@ public void exitBetween_expression(JDQLParser.Between_expressionContext ctx) {
boolean hasNot = Objects.nonNull(ctx.NOT());
boolean andCondition = true;

if(ctx.getParent() instanceof JDQLParser.Conditional_expressionContext ctxParent
&& ctxParent.getParent() instanceof JDQLParser.Conditional_expressionContext grandParent){
if (ctx.getParent() instanceof JDQLParser.Conditional_expressionContext ctxParent
&& ctxParent.getParent() instanceof JDQLParser.Conditional_expressionContext grandParent) {
andCondition = Objects.isNull(grandParent.OR());
}

Expand All @@ -130,8 +154,8 @@ public void exitIn_expression(JDQLParser.In_expressionContext ctx) {
boolean hasNot = Objects.nonNull(ctx.NOT());
boolean andCondition = true;

if(ctx.getParent() instanceof JDQLParser.Conditional_expressionContext ctxParent
&& ctxParent.getParent() instanceof JDQLParser.Conditional_expressionContext grandParent){
if (ctx.getParent() instanceof JDQLParser.Conditional_expressionContext ctxParent
&& ctxParent.getParent() instanceof JDQLParser.Conditional_expressionContext grandParent) {
andCondition = Objects.isNull(grandParent.OR());
}

Expand Down Expand Up @@ -166,6 +190,8 @@ private Condition getCondition(JDQLParser.Comparison_expressionContext ctx) {
return Condition.GREATER_THAN;
} else if (ctx.GTEQ() != null) {
return Condition.GREATER_EQUALS_THAN;
} else if (ctx.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 @@ -19,6 +19,7 @@
import org.eclipse.jnosql.communication.query.StringQueryValue;
import org.eclipse.jnosql.query.grammar.data.JDQLParser;

import java.util.Locale;
import java.util.function.Function;
import java.util.logging.Logger;

Expand All @@ -44,7 +45,7 @@ public QueryValue<?> apply(JDQLParser.Primary_expressionContext context) {
return DefaultQueryValue.of(context.input_parameter().getText());
} else if (context.special_expression() != null) {
var specialExpression = context.special_expression().getText();
return switch (specialExpression) {
return switch (specialExpression.toUpperCase(Locale.US)) {
case "TRUE" -> BooleanQueryValue.TRUE;
case "FALSE" -> BooleanQueryValue.FALSE;
default ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
import org.assertj.core.api.SoftAssertions;
import org.eclipse.jnosql.communication.Condition;
import org.eclipse.jnosql.communication.query.BooleanQueryValue;
import org.eclipse.jnosql.communication.query.ConditionQueryValue;
import org.eclipse.jnosql.communication.query.EnumQueryValue;
import org.eclipse.jnosql.communication.query.NullQueryValue;
import org.eclipse.jnosql.communication.query.NumberQueryValue;
import org.eclipse.jnosql.communication.query.SelectQuery;
import org.eclipse.jnosql.communication.query.StringQueryValue;
import org.eclipse.jnosql.communication.query.data.DefaultQueryValue;
import org.eclipse.jnosql.communication.query.data.DeleteProvider;
Expand Down Expand Up @@ -268,4 +271,75 @@ void shouldEqUsingEnumLiteral(String query){
});
}

@ParameterizedTest(name = "Should parser the query {0}")
@ValueSource(strings = "DELETE FROM entity WHERE hexadecimal IS NULL")
void shouldQueryIsNull(String query) {
var deleteQuery = deleteProvider.apply(query);

SoftAssertions.assertSoftly(soft -> {
soft.assertThat(deleteQuery.fields()).isEmpty();
soft.assertThat(deleteQuery.entity()).isEqualTo("entity");
var where = deleteQuery.where().orElseThrow();
var condition = where.condition();
soft.assertThat(condition.condition()).isEqualTo(Condition.EQUALS);
soft.assertThat(condition.name()).isEqualTo("hexadecimal");
soft.assertThat(condition.value()).isEqualTo(NullQueryValue.INSTANCE);
});
}

@ParameterizedTest(name = "Should parser the query {0}")
@ValueSource(strings = "DELETE FROM entity WHERE hexadecimal IS NOT NULL")
void shouldQueryIsNotNull(String query) {

var deleteQuery = deleteProvider.apply(query);
SoftAssertions.assertSoftly(soft -> {
soft.assertThat(deleteQuery.fields()).isEmpty();
soft.assertThat(deleteQuery.entity()).isEqualTo("entity");
soft.assertThat(deleteQuery.where()).isNotEmpty();
var where = deleteQuery.where().orElseThrow();
var condition = where.condition();
soft.assertThat(condition.condition()).isEqualTo(Condition.NOT);
var notCondition = (ConditionQueryValue) condition.value();
var queryCondition = notCondition.get().get(0);
soft.assertThat(queryCondition.name()).isEqualTo("hexadecimal");
soft.assertThat(queryCondition.value()).isEqualTo(NullQueryValue.INSTANCE);
});
}

@ParameterizedTest(name = "Should parser the query {0}")
@ValueSource(strings = "DELETE FROM entity WHERE NOT age <> 10")
void shouldUseNotNotEquals(String query) {
var deleteQuery = deleteProvider.apply(query);

SoftAssertions.assertSoftly(soft -> {
soft.assertThat(deleteQuery.fields()).isEmpty();
soft.assertThat(deleteQuery.entity()).isEqualTo("entity");
soft.assertThat(deleteQuery.where()).isNotEmpty();
var where = deleteQuery.where().orElseThrow();
var condition = where.condition();
soft.assertThat(condition.condition()).isEqualTo(Condition.EQUALS);
soft.assertThat(condition.name()).isEqualTo("age");
soft.assertThat(condition.value()).isEqualTo(NumberQueryValue.of(10));
});
}

@ParameterizedTest(name = "Should parser the query {0}")
@ValueSource(strings = "DELETE FROM entity WHERE age <> 10")
void shouldUseNotEquals(String query) {
var deleteQuery = deleteProvider.apply(query);

SoftAssertions.assertSoftly(soft -> {
soft.assertThat(deleteQuery.fields()).isEmpty();
soft.assertThat(deleteQuery.entity()).isEqualTo("entity");
soft.assertThat(deleteQuery.where()).isNotEmpty();
var where = deleteQuery.where().orElseThrow();
var condition = where.condition();
soft.assertThat(condition.condition()).isEqualTo(Condition.NOT);
var notCondition = (ConditionQueryValue) condition.value();
var queryCondition = notCondition.get().get(0);
soft.assertThat(queryCondition.name()).isEqualTo("age");
soft.assertThat(queryCondition.value()).isEqualTo(NumberQueryValue.of(10));
});
}

}
Loading