Skip to content

Commit

Permalink
Merge pull request #523 from dearrudam/support-count-all-and-notnull-…
Browse files Browse the repository at this point in the history
…query-name-methods

Added support to `countAll` and `NotNull` keywords for the query name methods
  • Loading branch information
otaviojava authored Jun 5, 2024
2 parents 8d42e9c + 9699735 commit 21fc24e
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 36 deletions.
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

0 comments on commit 21fc24e

Please sign in to comment.