Skip to content

Include Is annotation at Eclipse JNoSQL #606

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

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
761baad
feat: update the code on Restriction Converter to return the proper t…
otaviojava Jun 24, 2025
94b065d
test: generate structure on at Least
otaviojava Jun 25, 2025
d9e587d
feat: update ParamValue to return value
otaviojava Jun 25, 2025
798f6b4
feat: update structure to verson on ParamValue
otaviojava Jun 25, 2025
8fed51e
feat: generate paramvalue to represent param metadata
otaviojava Jun 25, 2025
c6cfaf9
feaet: update structure to paramvalue
otaviojava Jun 25, 2025
fba4e4a
feat: update code scenaion on repository collection
otaviojava Jun 26, 2025
d66b886
test: include scenarion to return
otaviojava Jun 26, 2025
ddd4411
style: include header on ParamValue
otaviojava Jun 26, 2025
b54ace6
style: remove unsed imports at RepositoryReflectionUtils
otaviojava Jun 26, 2025
d6bd444
test: include update repository refletions utils
otaviojava Jun 27, 2025
24d67e1
feat: make method factory at CriteriaCondition public
otaviojava Jun 27, 2025
33a7ee8
feat: include semistructure parameter
otaviojava Jun 30, 2025
9db5dc1
feat: udpate condition structure
otaviojava Jul 1, 2025
4d072b7
feat: update var on semistructure parameter based qusery
otaviojava Jul 1, 2025
3608435
style: remove unsed imports on SemiStructuredParameterBasedQuery
otaviojava Jul 1, 2025
a412086
test: update enable is annotation
otaviojava Jul 1, 2025
0d5fe94
test: create negation condition
otaviojava Jul 2, 2025
6a50ab6
feat: include negate condition
otaviojava Jul 2, 2025
8372ee3
test: update semistructured test paramter
otaviojava Jul 2, 2025
ef08c30
test: include condition to simple query based
otaviojava Jul 2, 2025
3add6a3
test: update test scenario to work with In and between
otaviojava Jul 2, 2025
3b14d0c
feat: include validation to simple query
otaviojava Jul 2, 2025
80d0513
feat: include validation to iterable
otaviojava Jul 2, 2025
5dfa314
test: generate scenarion to not allow arrray and iterable
otaviojava Jul 2, 2025
f62876f
feat: include validation to between
otaviojava Jul 2, 2025
357f9a9
style: remove imports no structure on parameter query
otaviojava Jul 2, 2025
53877b8
style: remove unsed imports
otaviojava Jul 2, 2025
ddb58e8
test: include crud repository proxy
otaviojava Jul 2, 2025
26e77aa
test: update shouldNot in
otaviojava Jul 2, 2025
fb54ddb
docs: update documentation on changelog
otaviojava Jul 2, 2025
75011ce
chore: update snapshot version to 1.0.2
otaviojava Jul 3, 2025
df564af
feat: include new methods from Template
otaviojava Jul 3, 2025
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 @@ -21,6 +21,7 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version

- Include support to Restriction interface
- Include support to record projector
- Include Is annotation support to the Repository


== [1.1.8] - 2025-05-21
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,16 @@ public static CriteriaCondition readOnly(CriteriaCondition condition) {
return new CriteriaCondition(condition.element(), condition.condition(), true);
}

static CriteriaCondition of(Element element, Condition condition) {

/**
* Creates a new {@link CriteriaCondition} with the specified element and condition.
*
* @param element the element representing the data to match
* @param condition the condition to apply
* @return a new {@link CriteriaCondition}
* @throws NullPointerException when the element or condition is null
*/
public static CriteriaCondition of(Element element, Condition condition) {
return new CriteriaCondition(Objects.requireNonNull(element, "Column is required"), condition);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2025 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.mapping.core.repository;

import org.eclipse.jnosql.communication.Condition;

/**
* Represents a parameter value with its condition that can be used in repository queries that has the {@link jakarta.data.repository.Find} annotation at method.
* It will get the {@link jakarta.data.repository.Param} to each parameter value and combine it with {@link jakarta.data.repository.Is}
* by default value is {@link Condition#EQUALS}
*/
public record ParamValue(Condition condition, Object value, boolean negate){}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
package org.eclipse.jnosql.mapping.core.repository;



import jakarta.data.constraint.Constraint;
import jakarta.data.repository.By;
import jakarta.data.repository.Is;
import jakarta.data.repository.Param;
import jakarta.data.repository.Query;
import org.eclipse.jnosql.communication.Condition;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
Expand Down Expand Up @@ -68,23 +70,54 @@ public Map<String, Object> getParams(Method method, Object[] args) {
* @param args the arguments from the method
* @return the {@link Map} from method and its arguments
*/
public Map<String, Object> getBy(Method method, Object[] args) {
Map<String, Object> params = new HashMap<>();
public Map<String, ParamValue> getBy(Method method, Object[] args) {
Map<String, ParamValue> params = new HashMap<>();

Parameter[] parameters = method.getParameters();
for (int index = 0; index < parameters.length; index++) {
Parameter parameter = parameters[index];
boolean isNotSpecialParameter = SpecialParameters.isNotSpecialParameter(parameter.getType());
By by = parameter.getAnnotation(By.class);
Is is = parameter.getAnnotation(Is.class);
if (Objects.nonNull(by)) {
params.put(by.value(), args[index]);
params.put(by.value(), condition(is, args[index]));
} else if(parameter.isNamePresent() && isNotSpecialParameter) {
params.put(parameter.getName(), args[index]);
params.put(parameter.getName(), condition(is,args[index]));
}
}
return params;
}

public ParamValue condition(Is is, Object value) {
if (Objects.isNull(is)) {
return new ParamValue(Condition.EQUALS, value, false);
}
Class<? extends Constraint> constraint = is.value();
return getParamValue(value, constraint);
}

static ParamValue getParamValue(Object value, Class<? extends Constraint> constraint) {
return switch (constraint.getName()) {
case "jakarta.data.constraint.AtLeast" -> new ParamValue(Condition.GREATER_EQUALS_THAN, value, false);
case "jakarta.data.constraint.AtMost" -> new ParamValue(Condition.LESSER_EQUALS_THAN, value, false);
case "jakarta.data.constraint.GreaterThan" -> new ParamValue(Condition.GREATER_THAN, value, false);
case "jakarta.data.constraint.LessThan" -> new ParamValue(Condition.LESSER_THAN, value, false);
case "jakarta.data.constraint.Between" -> new ParamValue(Condition.BETWEEN, value, false);
case "jakarta.data.constraint.EqualTo" -> new ParamValue(Condition.EQUALS, value, false);
case "jakarta.data.constraint.Like" -> new ParamValue(Condition.LIKE, value, false);
case "jakarta.data.constraint.In" -> new ParamValue(Condition.IN, value, false);
// Negate conditions
case "jakarta.data.constraint.NotBetween" -> new ParamValue(Condition.BETWEEN, value, true);
case "jakarta.data.constraint.NotEqualTo" -> new ParamValue(Condition.EQUALS, value, true);
case "jakarta.data.constraint.NotIn" -> new ParamValue(Condition.IN, value, true);
case "jakarta.data.constraint.NotLike" -> new ParamValue(Condition.LIKE, value, true);
default ->
throw new UnsupportedOperationException("The FindBy annotation does not support this constraint: " + constraint.getName()
+ " at the Is annotation, please use one of the following: "
+ "AtLeast, AtMost, GreaterThan, LesserThan, Between, EqualTo, Like, In, NotBetween, NotEquals, NotIn or NotLike");
};
}


/**
* Returns the query value from the {@link Query} annotation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,25 @@
*/
package org.eclipse.jnosql.mapping.core.repository;

import jakarta.data.constraint.AtLeast;
import jakarta.data.constraint.AtMost;
import jakarta.data.constraint.Between;
import jakarta.data.constraint.Constraint;
import jakarta.data.constraint.EqualTo;
import jakarta.data.constraint.GreaterThan;
import jakarta.data.constraint.In;
import jakarta.data.constraint.LessThan;
import jakarta.data.constraint.Like;
import jakarta.data.constraint.NotBetween;
import jakarta.data.constraint.NotEqualTo;
import jakarta.data.constraint.NotIn;
import jakarta.data.constraint.NotLike;
import jakarta.data.repository.By;
import jakarta.data.repository.BasicRepository;
import jakarta.data.repository.Param;
import jakarta.data.repository.Query;
import org.assertj.core.api.SoftAssertions;
import org.eclipse.jnosql.communication.Condition;
import org.eclipse.jnosql.mapping.core.entities.Person;
import org.junit.jupiter.api.Test;

Expand All @@ -31,6 +46,11 @@
import static org.junit.jupiter.api.Assertions.*;

import jakarta.data.Sort;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.junit.jupiter.params.provider.ValueSources;

class RepositoryReflectionUtilsTest {

Expand Down Expand Up @@ -69,10 +89,10 @@ void shouldByWithoutSpecialParams() {
Method method = Arrays.stream(PersonRepository.class.getDeclaredMethods()).filter(m -> m.getName().equals("query"))
.findFirst().orElseThrow();
final Sort<Object> SPECIAL_PARAM = Sort.asc("");
Map<String, Object> params = RepositoryReflectionUtils.INSTANCE.getBy(method, new Object[]{"Ada", SPECIAL_PARAM});
Map<String, ParamValue> params = RepositoryReflectionUtils.INSTANCE.getBy(method, new Object[]{"Ada", SPECIAL_PARAM});
assertThat(params)
.hasSize(1)
.containsEntry("name", "Ada");
.containsEntry("name", new ParamValue(Condition.EQUALS, "Ada", false));
}

@Test
Expand Down Expand Up @@ -126,6 +146,60 @@ void shouldFindByAgeAndNameWithParams() {
.containsEntry("name", "Ada");
}


@ParameterizedTest(name = "Testing positive {index} - {0}")
@ValueSource(classes = {AtLeast.class, AtMost.class, GreaterThan.class, LessThan.class, Between.class,
EqualTo.class, Like.class, In.class})
void shouldGetParamValueByPositive(Class<? extends Constraint<?>> constraint) {
ParamValue paramValue = RepositoryReflectionUtils.getParamValue("name", constraint);

SoftAssertions.assertSoftly(softly -> {
softly.assertThat(paramValue.value()).isEqualTo("name");
softly.assertThat(paramValue.negate()).isFalse();
});
}

@ParameterizedTest(name = "Negative positive {index} - {0}")
@ValueSource(classes = {NotBetween.class, NotEqualTo.class, NotIn.class, NotLike.class})
void shouldGetParamValueByNegative(Class<? extends Constraint<?>> constraint) {
ParamValue paramValue = RepositoryReflectionUtils.getParamValue("name", constraint);

SoftAssertions.assertSoftly(softly -> {
softly.assertThat(paramValue.value()).isEqualTo("name");
softly.assertThat(paramValue.negate()).isTrue();
});
}


@ParameterizedTest(name = "Testing condition {index} - {0}")
@MethodSource("conditions")
void shouldReturnParam(Class<? extends Constraint<?>> constraint, boolean isNegate, Condition condition) {
ParamValue paramValue = RepositoryReflectionUtils.getParamValue("name", constraint);

SoftAssertions.assertSoftly(softly -> {
softly.assertThat(paramValue.condition()).isEqualTo(condition);
softly.assertThat(paramValue.negate()).isEqualTo(isNegate);
softly.assertThat(paramValue.value()).isEqualTo("name");
});
}

public static Stream<Arguments> conditions() {
return Stream.of(
Arguments.of(AtLeast.class, false, Condition.GREATER_EQUALS_THAN),
Arguments.of(AtMost.class, false, Condition.LESSER_EQUALS_THAN),
Arguments.of(GreaterThan.class, false, Condition.GREATER_THAN),
Arguments.of(LessThan.class, false, Condition.LESSER_THAN),
Arguments.of(Between.class, false, Condition.BETWEEN),
Arguments.of(EqualTo.class, false, Condition.EQUALS),
Arguments.of(Like.class, false, Condition.LIKE),
Arguments.of(In.class, false, Condition.IN),
Arguments.of(NotBetween.class, true, Condition.BETWEEN),
Arguments.of(NotEqualTo.class, true, Condition.EQUALS),
Arguments.of(NotIn.class, true, Condition.IN),
Arguments.of(NotLike.class, true, Condition.LIKE)
);
}

interface PersonRepository extends BasicRepository<Person, String> {

@Query("FROM Person WHERE name = :name")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.time.Duration;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
Expand Down Expand Up @@ -148,6 +149,27 @@ public <T> Iterable<T> insert(Iterable<T> entities, Duration ttl) {
.collect(Collectors.toList());
}

@Override
public <T> void delete(T entity) {
Objects.requireNonNull(entity, "entity is required");
EntityMetadata metadata = entities().get(entity.getClass());
FieldMetadata idField = metadata.id()
.orElseThrow(() -> IdNotFoundException.newInstance(metadata.type()));

var idValue = idField.read(entity);
LOGGER.fine("Deleting entity: " + entity.getClass() + " with id: " + idValue);
DeleteQuery query = DeleteQuery.delete().from(metadata.name())
.where(idField.name()).eq(idValue).build();
manager().delete(query);
}

@Override
public <T> void delete(Iterable<? extends T> iterable) {
Objects.requireNonNull(iterable, "iterable is required");
StreamSupport.stream(iterable.spliterator(), false)
.forEach(this::delete);
}

@Override
public void delete(DeleteQuery query) {
requireNonNull(query, "query is required");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.eclipse.jnosql.communication.semistructured.QueryType;
import org.eclipse.jnosql.mapping.core.repository.DynamicQueryMethodReturn;
import org.eclipse.jnosql.mapping.core.repository.DynamicReturn;
import org.eclipse.jnosql.mapping.core.repository.ParamValue;
import org.eclipse.jnosql.mapping.core.repository.RepositoryReflectionUtils;
import org.eclipse.jnosql.mapping.metadata.EntityMetadata;
import org.eclipse.jnosql.mapping.semistructured.MappingDeleteQuery;
Expand Down Expand Up @@ -165,7 +166,7 @@ protected Object executeFindByQuery(Object instance, Method method, Object[] par
@Override
protected Object executeParameterBased(Object instance, Method method, Object[] params) {
Class<?> type = entityMetadata().type();
Map<String, Object> parameters = RepositoryReflectionUtils.INSTANCE.getBy(method, params);
Map<String, ParamValue> parameters = RepositoryReflectionUtils.INSTANCE.getBy(method, params);
var query = SemiStructuredParameterBasedQuery.INSTANCE.toQuery(parameters, getSorts(method, entityMetadata()), entityMetadata());
return executeFindByQuery(method, params, type, updateQueryDynamically(params, query));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
*/
package org.eclipse.jnosql.mapping.semistructured.query;

import jakarta.data.constraint.AtLeast;
import jakarta.data.constraint.AtMost;
import jakarta.data.constraint.Between;
import jakarta.data.constraint.Constraint;
import jakarta.data.constraint.EqualTo;
import jakarta.data.constraint.GreaterThan;
import jakarta.data.constraint.GreaterThanOrEqual;
import jakarta.data.constraint.In;
import jakarta.data.constraint.LessThan;
import jakarta.data.constraint.LessThanOrEqual;
import jakarta.data.constraint.Like;
import jakarta.data.constraint.NotBetween;
import jakarta.data.constraint.NotEqualTo;
Expand Down Expand Up @@ -152,13 +152,13 @@ private CriteriaCondition condition(BasicAttribute<?, ?> basicAttribute, Constra
return gt(name, value);
}

case GreaterThanOrEqual<?> greaterThanOrEqual -> {
case AtLeast<?> greaterThanOrEqual -> {
var value = ValueConverter.of(greaterThanOrEqual::bound, basicAttribute, converters,
converter.orElse(null), fieldMetadata.orElse(null));
return gte(name, value);
}

case LessThanOrEqual<?> lesserThanOrEqual -> {
case AtMost<?> lesserThanOrEqual -> {
var value = ValueConverter.of(lesserThanOrEqual::bound, basicAttribute, converters,
converter.orElse(null), fieldMetadata.orElse(null));
return lte(name, value);
Expand Down
Loading
Loading