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

Added support to countAll and NotNull keywords for the query name methods #523

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 0 additions & 21 deletions .github/workflows/tck-runner.yml

This file was deleted.

1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,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

== [1.1.1] - 2023-05-25

Expand Down
5 changes: 3 additions & 2 deletions antlr4/org/eclipse/jnosql/query/grammar/method/Method.g4
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ grammar Method;
select: selectStart where? order? EOF;
deleteBy: 'deleteBy' where? EOF;

selectStart: 'find' limit 'By' | 'findBy'| 'countBy'| 'existsBy';
selectStart: 'find' limit 'By' | 'findBy' | 'countAll' | 'countBy' | 'existsBy';
where: condition (and condition| or condition)* ;
condition: eq | gt | gte | lt | lte | between | in | like | truth | untruth;
condition: eq | gt | gte | lt | lte | between | in | like | truth | untruth | nullable;
order: 'OrderBy' orderName (orderName)*;
orderName: variable | variable asc | variable desc;
limit : 'First' max?;
Expand All @@ -22,6 +22,7 @@ lte: variable not? 'LessThanEqual';
between: variable not? 'Between';
in: variable not? 'In';
like: variable not? 'Like';
nullable: variable not? 'Null';
not: 'Not';
variable: ANY_NAME;
max: INT;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public String toString() {
}

public static DefaultQueryValue of(String text) {
if(text.startsWith(":")) {
if(text != null && text.startsWith(":")) {
return new DefaultQueryValue(text.substring(1));
}
return new DefaultQueryValue(text);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.eclipse.jnosql.communication.query.ParamQueryValue;
import org.eclipse.jnosql.communication.query.QueryCondition;
import org.eclipse.jnosql.communication.query.QueryErrorListener;
import org.eclipse.jnosql.communication.query.StringQueryValue;
import org.eclipse.jnosql.communication.query.Where;
import org.eclipse.jnosql.query.grammar.method.MethodBaseListener;
import org.eclipse.jnosql.query.grammar.method.MethodLexer;
Expand All @@ -37,6 +38,7 @@
import java.util.function.Function;
import java.util.stream.Stream;

import static java.util.stream.Collectors.joining;
import static org.eclipse.jnosql.communication.Condition.AND;
import static org.eclipse.jnosql.communication.Condition.BETWEEN;
import static org.eclipse.jnosql.communication.Condition.EQUALS;
Expand All @@ -48,7 +50,6 @@
import static org.eclipse.jnosql.communication.Condition.LIKE;
import static org.eclipse.jnosql.communication.Condition.NOT;
import static org.eclipse.jnosql.communication.Condition.OR;
import static java.util.stream.Collectors.joining;

abstract class AbstractMethodQueryProvider extends MethodBaseListener {

Expand All @@ -59,6 +60,8 @@ abstract class AbstractMethodQueryProvider extends MethodBaseListener {

protected boolean and = true;

protected boolean shouldCount = false;

protected void runQuery(String query) {

CharStream stream = CharStreams.fromString(query);
Expand All @@ -81,6 +84,11 @@ protected void runQuery(String query) {

abstract Function<MethodParser, ParseTree> getParserTree();

@Override
public void exitSelectStart(MethodParser.SelectStartContext ctx) {
this.shouldCount = ctx.getText().startsWith("count");
}

@Override
public void exitEq(MethodParser.EqContext ctx) {
Condition operator = EQUALS;
Expand Down Expand Up @@ -158,6 +166,13 @@ public void exitBetween(MethodParser.BetweenContext ctx) {
checkCondition(new MethodCondition(variable, operator, value), hasNot);
}

@Override
public void exitNullable(MethodParser.NullableContext ctx) {
boolean hasNot = Objects.nonNull(ctx.not());
String variable = getVariable(ctx.variable());
checkCondition(new MethodCondition(variable, EQUALS, StringQueryValue.of(null)), hasNot);
}

@Override
public void exitAnd(MethodParser.AndContext ctx) {
this.and = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
public final class MethodQuery implements Supplier<String> {

private final String value;
private static final Pattern PATTERN = Pattern.compile("findBy|deleteBy|countBy|existsBy|"
private static final Pattern PATTERN = Pattern.compile("findBy|deleteBy|countAll|countBy|existsBy|"
+ "OrderBy|First(?=\\d+By)|(?<=First\\d{1,})By|"
+ "And|Or(?!der)|Not|Equals|GreaterThanEqual|True|False|" +
+ "And|Or(?!der)|Null|Not|Equals|GreaterThanEqual|True|False|" +
"LessThanEqual|GreaterThan|LessThan|Between|In|Like|Asc|Desc");
private static final Map<String, String> CACHE = Collections.synchronizedMap(new WeakHashMap<>());
private MethodQuery(String value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@ final class MethodSelectQuery implements SelectQuery {

private final long limit;

MethodSelectQuery(String entity, List<Sort<?>> sorts, Where where, long limit) {
private final boolean count;

MethodSelectQuery(String entity, List<Sort<?>> sorts, Where where, long limit, boolean count) {
this.entity = entity;
this.sorts = sorts;
this.where = where;
this.limit = limit;
this.count = count;
}


Expand Down Expand Up @@ -70,7 +73,7 @@ public List<Sort<?>> orderBy() {

@Override
public boolean isCount() {
return false;
return count;
}

public boolean equals(Object o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public SelectQuery apply(String query, String entity) {
Objects.requireNonNull(query, " query is required");
Objects.requireNonNull(entity, " entity is required");
runQuery(MethodQuery.of(query).get());
return new MethodSelectQuery(entity, sorts, where, limit);
return new MethodSelectQuery(entity, sorts, where, limit, shouldCount);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
*/
package org.eclipse.jnosql.communication.query.method;

import org.eclipse.jnosql.communication.Condition;
import jakarta.data.Sort;
import jakarta.data.Direction;
import jakarta.data.Sort;
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.ParamQueryValue;
import org.eclipse.jnosql.communication.query.QueryCondition;
import org.eclipse.jnosql.communication.query.QueryValue;
import org.eclipse.jnosql.communication.query.SelectQuery;
import org.eclipse.jnosql.communication.query.StringQueryValue;
import org.eclipse.jnosql.communication.query.Where;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
Expand All @@ -32,6 +33,7 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

class SelectMethodQueryProviderTest {
Expand All @@ -40,20 +42,38 @@ class SelectMethodQueryProviderTest {


@ParameterizedTest(name = "Should parser the query {0}")
@ValueSource(strings = {"findBy", "countBy", "existsBy"})
@ValueSource(strings = {"findBy", "existsBy"})
void shouldReturnParserQuery(String query) {
String entity = "entity";
SelectQuery selectQuery = queryProvider.apply(query, entity);
assertNotNull(selectQuery);
assertEquals(entity, selectQuery.entity());
assertTrue(selectQuery.fields().isEmpty());
assertTrue(selectQuery.orderBy().isEmpty());
assertFalse(selectQuery.isCount());
assertEquals(0, selectQuery.limit());
assertEquals(0, selectQuery.skip());
Optional<Where> where = selectQuery.where();
assertFalse(where.isPresent());
}

@ParameterizedTest(name = "Should parser the query {0}")
@ValueSource(strings = {"countBy", "countAll"})
void shouldReturnParsedCountableQuery(String query) {
String entity = "entity";
SelectQuery selectQuery = queryProvider.apply(query, entity);
assertNotNull(selectQuery);
assertEquals(entity, selectQuery.entity());
assertTrue(selectQuery.fields().isEmpty());
assertTrue(selectQuery.orderBy().isEmpty());
assertTrue(selectQuery.isCount());
assertEquals(0, selectQuery.limit());
assertEquals(0, selectQuery.skip());
Optional<Where> where = selectQuery.where();
assertFalse(where.isPresent());
}


@ParameterizedTest(name = "Should parser the query {0}")
@ValueSource(strings = {"findFirst10By"})
void shouldFindFirstLimit(String query) {
Expand Down Expand Up @@ -470,6 +490,53 @@ void shouldReturnParserQuery35(String query) {
checkNotCondition(query, Condition.EQUALS, "name");
}

@ParameterizedTest(name = "Should parser the query {0}")
@ValueSource(strings = {"findByNameNotNull", "countByNameNotNull", "existsByNameNotNull"})
void shouldReturnParserQuery36(String query) {
String entity = "entity";
SelectQuery selectQuery = queryProvider.apply(query, entity);
assertNotNull(selectQuery);
assertEquals(entity, selectQuery.entity());
assertTrue(selectQuery.fields().isEmpty());
assertTrue(selectQuery.orderBy().isEmpty());
assertEquals(0, selectQuery.limit());
assertEquals(0, selectQuery.skip());
Optional<Where> where = selectQuery.where();
assertTrue(where.isPresent());
QueryCondition condition = where.get().condition();
QueryValue<?> value = condition.value();
assertEquals(Condition.NOT, condition.condition());


assertEquals("_NOT", condition.name());
assertTrue(value instanceof ConditionQueryValue);
QueryCondition condition1 = ConditionQueryValue.class.cast(value).get().get(0);

assertEquals("name", condition1.name());
assertEquals(Condition.EQUALS, condition1.condition());
var param = condition1.value();
assertNull(StringQueryValue.class.cast(param).get());

}

@ParameterizedTest(name = "Should parser the query {0}")
@ValueSource(strings = {"findByNameNull", "countByNameNull", "existsByNameNull"})
void shouldReturnParserQuery37(String query) {
String entity = "entity";
SelectQuery selectQuery = queryProvider.apply(query, entity);
assertNotNull(selectQuery);
assertEquals(entity, selectQuery.entity());
assertTrue(selectQuery.fields().isEmpty());
assertTrue(selectQuery.orderBy().isEmpty());
assertEquals(0, selectQuery.limit());
assertEquals(0, selectQuery.skip());
Optional<Where> where = selectQuery.where();
assertTrue(where.isPresent());
QueryCondition condition = where.get().condition();
assertEquals("name", condition.name());
assertEquals(Condition.EQUALS, condition.condition());
assertNull(condition.value().get());
}

private void checkOrderBy(String query, Direction direction, Direction direction2) {
String entity = "entity";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public Object invoke(Object instance, Method method, Object[] params) throws Thr
case FIND_BY -> {
return unwrapInvocationTargetException(() -> executeFindByQuery(instance, method, params));
}
case COUNT_BY -> {
case COUNT_ALL, COUNT_BY -> {
return unwrapInvocationTargetException(() -> executeCountByQuery(instance, method, params));
}
case EXISTS_BY -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ public enum RepositoryType {
*/
FIND_ALL("findAll"),
/**
* Count projection returning a numeric result. It starts and ends with "countAll" keyword
*/
COUNT_ALL("countAll"),/**
* Count projection returning a numeric result. It starts with "countBy" keyword
*/
COUNT_BY("countBy"),
Expand Down Expand Up @@ -115,7 +118,7 @@ public enum RepositoryType {
.or(Predicate.isEqual(BasicRepository.class))
.or(Predicate.isEqual(NoSQLRepository.class));

private static final Set<RepositoryType> KEY_WORLD_METHODS = EnumSet.of(FIND_BY, DELETE_BY, COUNT_BY, EXISTS_BY);
private static final Set<RepositoryType> KEY_WORLD_METHODS = EnumSet.of(FIND_BY, DELETE_BY, COUNT_ALL, COUNT_BY, EXISTS_BY);

private static final Set<RepositoryType> OPERATION_ANNOTATIONS = EnumSet.of(INSERT, SAVE, DELETE, UPDATE, QUERY, PARAMETER_BASED);
private final String keyword;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ void shouldReturnCountBy() throws NoSuchMethodException {
Assertions.assertEquals(RepositoryType.COUNT_BY, RepositoryType.of(getMethod(DevRepository.class, "countByName"), CrudRepository.class));
}

@Test
void shouldReturnCountAll() throws NoSuchMethodException {
Assertions.assertEquals(RepositoryType.COUNT_ALL, RepositoryType.of(getMethod(DevRepository.class, "countAll"), CrudRepository.class));
}

@Test
void shouldReturnExistsBy() throws NoSuchMethodException {
Assertions.assertEquals(RepositoryType.EXISTS_BY, RepositoryType.of(getMethod(DevRepository.class, "existsByName"), CrudRepository.class));
Expand Down Expand Up @@ -229,6 +234,8 @@ interface DevRepository extends CrudRepository, Calculate {

Long countByName(String name);

Long countAll();

Long existsByName(String name);

void nope();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public Object invoke(Object instance, Method method, Object[] params) throws Thr
return unwrapInvocationTargetException(() -> repository(method).invoke(instance, method, params));

}
case DELETE_BY, COUNT_BY, EXISTS_BY ->
case DELETE_BY, COUNT_ALL, COUNT_BY, EXISTS_BY ->
throw new UnsupportedOperationException("The custom repository does not support the method " + method);
default -> {
return Void.class;
Expand Down