diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 4473eaabf..3ecd546fd 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -22,6 +22,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.10] - 2025-08-19 diff --git a/jnosql-communication/jnosql-communication-semistructured/src/main/java/org/eclipse/jnosql/communication/semistructured/CriteriaCondition.java b/jnosql-communication/jnosql-communication-semistructured/src/main/java/org/eclipse/jnosql/communication/semistructured/CriteriaCondition.java index 8e6207a88..57a64fd2d 100644 --- a/jnosql-communication/jnosql-communication-semistructured/src/main/java/org/eclipse/jnosql/communication/semistructured/CriteriaCondition.java +++ b/jnosql-communication/jnosql-communication-semistructured/src/main/java/org/eclipse/jnosql/communication/semistructured/CriteriaCondition.java @@ -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); } diff --git a/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/repository/ParamValue.java b/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/repository/ParamValue.java new file mode 100644 index 000000000..c3dc3d4e8 --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/repository/ParamValue.java @@ -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){} \ No newline at end of file diff --git a/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/repository/RepositoryReflectionUtils.java b/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/repository/RepositoryReflectionUtils.java index c67fb0a82..5f39a1a17 100644 --- a/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/repository/RepositoryReflectionUtils.java +++ b/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/repository/RepositoryReflectionUtils.java @@ -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; @@ -68,23 +70,54 @@ public Map getParams(Method method, Object[] args) { * @param args the arguments from the method * @return the {@link Map} from method and its arguments */ - public Map getBy(Method method, Object[] args) { - Map params = new HashMap<>(); + public Map getBy(Method method, Object[] args) { + Map 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 constraint = is.value(); + return getParamValue(value, constraint); + } + + static ParamValue getParamValue(Object value, Class 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 diff --git a/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/repository/RepositoryReflectionUtilsTest.java b/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/repository/RepositoryReflectionUtilsTest.java index 2852ccccf..c821f2fe7 100644 --- a/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/repository/RepositoryReflectionUtilsTest.java +++ b/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/repository/RepositoryReflectionUtilsTest.java @@ -14,11 +14,29 @@ */ 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.Sort; + import jakarta.data.repository.BasicRepository; import jakarta.data.repository.By; 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; @@ -29,6 +47,15 @@ import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; +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; + import static org.junit.jupiter.api.Assertions.assertEquals; class RepositoryReflectionUtilsTest { @@ -68,10 +95,10 @@ void shouldByWithoutSpecialParams() { Method method = Arrays.stream(PersonRepository.class.getDeclaredMethods()).filter(m -> m.getName().equals("query")) .findFirst().orElseThrow(); final Sort SPECIAL_PARAM = Sort.asc(""); - Map params = RepositoryReflectionUtils.INSTANCE.getBy(method, new Object[]{"Ada", SPECIAL_PARAM}); + Map 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 @@ -125,6 +152,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> 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> 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> 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 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 { @Query("FROM Person WHERE name = :name") diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/AbstractSemiStructuredTemplate.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/AbstractSemiStructuredTemplate.java index 44d10a40f..f165b8821 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/AbstractSemiStructuredTemplate.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/AbstractSemiStructuredTemplate.java @@ -39,6 +39,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; @@ -147,6 +148,27 @@ public Iterable insert(Iterable entities, Duration ttl) { .collect(Collectors.toList()); } + @Override + public 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 void delete(Iterable 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"); diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/MapperObserver.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/MapperObserver.java index bda3f973c..00e86ca78 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/MapperObserver.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/MapperObserver.java @@ -81,4 +81,4 @@ private Optional getEntityMetadata(String entity) { } } -} +} \ No newline at end of file diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/AbstractSemiStructuredRepositoryProxy.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/AbstractSemiStructuredRepositoryProxy.java index a1ddd5cfa..196889101 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/AbstractSemiStructuredRepositoryProxy.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/AbstractSemiStructuredRepositoryProxy.java @@ -28,6 +28,7 @@ import org.eclipse.jnosql.communication.semistructured.SelectQuery; 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.core.query.AbstractRepository; import org.eclipse.jnosql.mapping.metadata.EntityMetadata; diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/RestrictionConverter.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/RestrictionConverter.java index 1f084b34e..ced174be3 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/RestrictionConverter.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/RestrictionConverter.java @@ -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; @@ -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); diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredParameterBasedQuery.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredParameterBasedQuery.java index 8f28b580e..9c1f10c2b 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredParameterBasedQuery.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredParameterBasedQuery.java @@ -17,13 +17,21 @@ import jakarta.data.Sort; import jakarta.data.page.PageRequest; import jakarta.enterprise.inject.spi.CDI; +import org.eclipse.jnosql.communication.Condition; import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; + +import org.eclipse.jnosql.communication.semistructured.Element; +import org.eclipse.jnosql.mapping.core.NoSQLPage; +import org.eclipse.jnosql.mapping.core.repository.ParamValue; +import org.eclipse.jnosql.mapping.semistructured.MappingQuery; + import org.eclipse.jnosql.mapping.core.Converters; import org.eclipse.jnosql.mapping.core.NoSQLPage; import org.eclipse.jnosql.mapping.metadata.EntityMetadata; import org.eclipse.jnosql.mapping.metadata.FieldMetadata; import org.eclipse.jnosql.mapping.semistructured.MappingQuery; +import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -32,8 +40,8 @@ import static org.eclipse.jnosql.mapping.core.util.ConverterUtil.getValue; /** - * The ColumnParameterBasedQuery class is responsible for generating Column queries based on a set of parameters. - * It leverages the provided parameters, PageRequest information, and entity metadata to construct a ColumnQuery object + * The ColumnParameterBasedQuery class is responsible for generating Column queries based on a set of parameters. It + * leverages the provided parameters, PageRequest information, and entity metadata to construct a ColumnQuery object * tailored for querying a specific entity'sort columns. */ public enum SemiStructuredParameterBasedQuery { @@ -50,12 +58,12 @@ public enum SemiStructuredParameterBasedQuery { * @param entityMetadata Metadata describing the structure of the entity. * @return A ColumnQuery instance tailored for the specified entity. */ - public org.eclipse.jnosql.communication.semistructured.SelectQuery toQuery(Map params, + public org.eclipse.jnosql.communication.semistructured.SelectQuery toQuery(Map params, List> sorts, EntityMetadata entityMetadata) { var convert = CDI.current().select(Converters.class).get(); List conditions = new ArrayList<>(); - for (Map.Entry entry : params.entrySet()) { + for (Map.Entry entry : params.entrySet()) { conditions.add(condition(convert, entityMetadata, entry)); } @@ -67,16 +75,17 @@ public org.eclipse.jnosql.communication.semistructured.SelectQuery toQuery(Map params, - List> sorts, PageRequest pageRequest, - EntityMetadata entityMetadata) { + List> sorts, PageRequest pageRequest, + EntityMetadata entityMetadata) { List conditions = new ArrayList<>(); for (Map.Entry entry : params.entrySet()) { conditions.add(condition(entityMetadata, entry)); @@ -88,7 +97,7 @@ public org.eclipse.jnosql.communication.semistructured.SelectQuery toQueryNative var entity = entityMetadata.name(); long limit = 0; long skip = 0; - if(pageRequest != null) { + if (pageRequest != null) { limit = pageRequest.size(); skip = NoSQLPage.skip(pageRequest); } @@ -104,15 +113,54 @@ private CriteriaCondition condition(List conditions) { return CriteriaCondition.and(conditions.toArray(TO_ARRAY)); } - private CriteriaCondition condition(Converters convert, EntityMetadata entityMetadata, Map.Entry entry) { - var name = entityMetadata.fieldMapping(entry.getKey()) - .map(FieldMetadata::name) - .orElse(entry.getKey()); - var value = getValue(entry.getValue(), entityMetadata, entry.getKey(), convert); - return CriteriaCondition.eq(name, value); + private CriteriaCondition condition(Converters convert, EntityMetadata entityMetadata,Map.Entry entry) { + var fieldName = resolveFieldName(entityMetadata, entry.getKey()); + var paramValue = entry.getValue(); + var condition = paramValue.condition(); + var value = extractConditionValue(paramValue.value(), condition, entityMetadata, entry.getKey(), convert); + + return paramValue.negate() ? CriteriaCondition.of(Element.of(fieldName, value), condition).negate(): + CriteriaCondition.of(Element.of(fieldName, value), condition); + } + + private String resolveFieldName(EntityMetadata metadata, String key) { + return metadata.fieldMapping(key).map(FieldMetadata::name).orElse(key); + } + + private Object extractConditionValue(Object rawValue, Condition condition, EntityMetadata metadata, + String fieldKey, Converters convert) { + boolean isCollectionParameter = rawValue instanceof Iterable || rawValue != null && rawValue.getClass().isArray(); + + if (Condition.BETWEEN.equals(condition) || Condition.IN.equals(condition)) { + if (!isCollectionParameter) { + throw new IllegalArgumentException("The value for condition " + condition + " must be a Iterable or array, but received: " + rawValue); + } + return extractMultipleValues(rawValue, metadata, fieldKey, convert, condition); + } + if(isCollectionParameter) { + throw new IllegalArgumentException("The value for condition " + condition + " must be a single value, but received: " + rawValue); + } + return getValue(rawValue, metadata, fieldKey, convert); + } + + private List extractMultipleValues(Object rawValue, EntityMetadata metadata, String fieldKey, + Converters convert, Condition condition) { + List values = new ArrayList<>(); + if (rawValue instanceof Iterable iterable) { + iterable.forEach(v -> values.add(getValue(v, metadata, fieldKey, convert))); + } else if (rawValue != null && rawValue.getClass().isArray()) { + for (int i = 0; i < Array.getLength(rawValue); i++) { + Object element = Array.get(rawValue, i); + values.add(getValue(element, metadata, fieldKey, convert)); + } + } + if (Condition.BETWEEN.equals(condition) && values.size() != 2) { + throw new IllegalArgumentException("The value for condition " + condition + " must have exactly two elements, but received: " + values); + } + return values; } - private CriteriaCondition condition( EntityMetadata entityMetadata, Map.Entry entry) { + private CriteriaCondition condition(EntityMetadata entityMetadata, Map.Entry entry) { var name = entityMetadata.fieldMapping(entry.getKey()) .map(FieldMetadata::name) .orElse(entry.getKey()); @@ -126,7 +174,7 @@ private List> getSorts(List> sorts, EntityMetadata entityMetadat var name = entityMetadata.fieldMapping(sort.property()) .map(FieldMetadata::name) .orElse(sort.property()); - updateSorter.add(sort.isAscending()? Sort.asc(name): Sort.desc(name)); + updateSorter.add(sort.isAscending() ? Sort.asc(name) : Sort.desc(name)); } return updateSorter; } diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/DefaultSemiStructuredTemplateTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/DefaultSemiStructuredTemplateTest.java index 8f2658e60..faac5af70 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/DefaultSemiStructuredTemplateTest.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/DefaultSemiStructuredTemplateTest.java @@ -22,9 +22,13 @@ import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; import org.assertj.core.api.SoftAssertions; + +import org.eclipse.jnosql.communication.Configurations; + import org.eclipse.jnosql.communication.Condition; import org.eclipse.jnosql.communication.Configurations; import org.eclipse.jnosql.communication.TypeReference; + import org.eclipse.jnosql.communication.semistructured.CommunicationEntity; import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; import org.eclipse.jnosql.communication.semistructured.DatabaseManager; @@ -40,6 +44,7 @@ import org.eclipse.jnosql.mapping.semistructured.entities.Job; import org.eclipse.jnosql.mapping.semistructured.entities.Person; import org.eclipse.jnosql.mapping.semistructured.entities.inheritance.LargeProject; + import org.jboss.weld.junit5.auto.AddExtensions; import org.jboss.weld.junit5.auto.AddPackages; import org.jboss.weld.junit5.auto.EnableAutoWeld; diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CrudRepositoryProxyIsTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CrudRepositoryProxyIsTest.java new file mode 100644 index 000000000..356c1a9a5 --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CrudRepositoryProxyIsTest.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2022 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.semistructured.query; + +import jakarta.data.constraint.GreaterThan; +import jakarta.data.constraint.In; +import jakarta.data.constraint.LessThan; +import jakarta.data.constraint.NotIn; +import jakarta.data.repository.By; +import jakarta.data.repository.CrudRepository; +import jakarta.data.repository.Find; +import jakarta.data.repository.Is; +import jakarta.inject.Inject; +import org.assertj.core.api.SoftAssertions; +import org.eclipse.jnosql.communication.Condition; +import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; +import org.eclipse.jnosql.communication.semistructured.Element; +import org.eclipse.jnosql.communication.semistructured.SelectQuery; +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; +import org.eclipse.jnosql.mapping.reflection.Reflections; +import org.eclipse.jnosql.mapping.reflection.spi.ReflectionEntityMetadataExtension; +import org.eclipse.jnosql.mapping.semistructured.EntityConverter; +import org.eclipse.jnosql.mapping.semistructured.MockProducer; +import org.eclipse.jnosql.mapping.semistructured.SemiStructuredTemplate; +import org.eclipse.jnosql.mapping.semistructured.entities.Product; +import org.eclipse.jnosql.mapping.semistructured.entities._Product; +import org.jboss.weld.junit5.auto.AddExtensions; +import org.jboss.weld.junit5.auto.AddPackages; +import org.jboss.weld.junit5.auto.EnableAutoWeld; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.lang.reflect.Proxy; +import java.math.BigDecimal; +import java.util.List; +import java.util.stream.Stream; + +import static org.eclipse.jnosql.communication.Condition.EQUALS; +import static org.eclipse.jnosql.communication.Condition.GREATER_THAN; +import static org.eclipse.jnosql.communication.Condition.IN; +import static org.eclipse.jnosql.communication.Condition.LESSER_THAN; +import static org.eclipse.jnosql.communication.Condition.NOT; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@EnableAutoWeld +@AddPackages(value = {Converters.class, EntityConverter.class}) +@AddPackages(MockProducer.class) +@AddPackages(Reflections.class) +@AddExtensions({ReflectionEntityMetadataExtension.class}) +class CrudRepositoryProxyIsTest { + + private SemiStructuredTemplate template; + + @Inject + private EntitiesMetadata entities; + + @Inject + private Converters converters; + + private ProductRepository repository; + + + @BeforeEach + public void setUp() { + this.template = Mockito.mock(SemiStructuredTemplate.class); + + var productHandler = new SemiStructuredRepositoryProxy<>(template, + entities, ProductRepository.class, converters); + + + + repository = (ProductRepository) Proxy.newProxyInstance(ProductRepository.class.getClassLoader(), + new Class[]{ProductRepository.class}, + productHandler); + } + + + @Test + void shouldEquals() { + + when(template.select(any(SelectQuery.class))) + .thenReturn(Stream.of(new Product())); + + repository.equals("Mac"); + ArgumentCaptor captor = ArgumentCaptor.forClass(SelectQuery.class); + verify(template).select(captor.capture()); + SelectQuery query = captor.getValue(); + + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(query.name()).isEqualTo("Product"); + softly.assertThat(query.condition()).isPresent(); + CriteriaCondition condition = query.condition().orElseThrow(); + softly.assertThat(condition).isInstanceOf(CriteriaCondition.class); + softly.assertThat(condition.condition()).isEqualTo(EQUALS); + softly.assertThat(condition.element()).isEqualTo(Element.of(_Product.NAME, "Mac")); + }); + } + + + @Test + void shouldDefaultMethod() { + + when(template.select(any(SelectQuery.class))) + .thenReturn(Stream.of(new Product())); + + repository.defaultMethod("Mac"); + ArgumentCaptor captor = ArgumentCaptor.forClass(SelectQuery.class); + verify(template).select(captor.capture()); + SelectQuery query = captor.getValue(); + + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(query.name()).isEqualTo("Product"); + softly.assertThat(query.condition()).isPresent(); + CriteriaCondition condition = query.condition().orElseThrow(); + softly.assertThat(condition).isInstanceOf(CriteriaCondition.class); + softly.assertThat(condition.condition()).isEqualTo(EQUALS); + softly.assertThat(condition.element()).isEqualTo(Element.of(_Product.NAME, "Mac")); + }); + } + + @Test + void shouldAtLeast() { + + when(template.select(any(SelectQuery.class))) + .thenReturn(Stream.of(new Product())); + + repository.greaterThan(BigDecimal.TEN); + ArgumentCaptor captor = ArgumentCaptor.forClass(SelectQuery.class); + verify(template).select(captor.capture()); + SelectQuery query = captor.getValue(); + + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(query.name()).isEqualTo("Product"); + softly.assertThat(query.condition()).isPresent(); + CriteriaCondition condition = query.condition().orElseThrow(); + softly.assertThat(condition).isInstanceOf(CriteriaCondition.class); + softly.assertThat(condition.condition()).isEqualTo(GREATER_THAN); + softly.assertThat(condition.element()).isEqualTo(Element.of(_Product.PRICE, BigDecimal.TEN)); + }); + } + + @Test + void shouldLesser() { + + when(template.select(any(SelectQuery.class))) + .thenReturn(Stream.of(new Product())); + + repository.lesserThan(BigDecimal.TEN); + ArgumentCaptor captor = ArgumentCaptor.forClass(SelectQuery.class); + verify(template).select(captor.capture()); + SelectQuery query = captor.getValue(); + + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(query.name()).isEqualTo("Product"); + softly.assertThat(query.condition()).isPresent(); + CriteriaCondition condition = query.condition().orElseThrow(); + softly.assertThat(condition).isInstanceOf(CriteriaCondition.class); + softly.assertThat(condition.condition()).isEqualTo(LESSER_THAN); + softly.assertThat(condition.element()).isEqualTo(Element.of(_Product.PRICE, BigDecimal.TEN)); + }); + } + + @Test + void shouldIn() { + + when(template.select(any(SelectQuery.class))) + .thenReturn(Stream.of(new Product())); + + repository.in(List.of("Mac", "Iphone")); + ArgumentCaptor captor = ArgumentCaptor.forClass(SelectQuery.class); + verify(template).select(captor.capture()); + SelectQuery query = captor.getValue(); + + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(query.name()).isEqualTo("Product"); + softly.assertThat(query.condition()).isPresent(); + CriteriaCondition condition = query.condition().orElseThrow(); + softly.assertThat(condition).isInstanceOf(CriteriaCondition.class); + softly.assertThat(condition.condition()).isEqualTo(IN); + softly.assertThat(condition.element()).isEqualTo(Element.of(_Product.NAME, List.of("Mac", "Iphone"))); + }); + } + + @Test + void shouldNotIn() { + + when(template.select(any(SelectQuery.class))) + .thenReturn(Stream.of(new Product())); + + repository.notIn(List.of("Mac", "Iphone")); + ArgumentCaptor captor = ArgumentCaptor.forClass(SelectQuery.class); + verify(template).select(captor.capture()); + SelectQuery query = captor.getValue(); + + SoftAssertions.assertSoftly(softly -> { + softly.assertThat(query.name()).isEqualTo("Product"); + softly.assertThat(query.condition()).isPresent(); + CriteriaCondition condition = query.condition().orElseThrow(); + softly.assertThat(condition).isInstanceOf(CriteriaCondition.class); + softly.assertThat(condition.condition()).isEqualTo(NOT); + var criteriaCondition = condition.element().get(CriteriaCondition.class); + softly.assertThat(criteriaCondition.condition()).isEqualTo(IN); + softly.assertThat(criteriaCondition.element()).isEqualTo(Element.of(_Product.NAME, List.of("Mac", "Iphone"))); + }); + } + + + + public interface ProductRepository extends CrudRepository { + @Find + List defaultMethod(@By(_Product.NAME) String name); + + @Find + List equals(@By(_Product.NAME) @Is String name); + + @Find + List greaterThan(@By(_Product.PRICE) @Is(GreaterThan.class) BigDecimal price); + + @Find + List lesserThan(@By(_Product.PRICE) @Is(LessThan.class) BigDecimal price); + + @Find + List in(@By(_Product.NAME) @Is(In.class) List names); + + @Find + List notIn(@By(_Product.NAME) @Is(NotIn.class) List names); + } + +} diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CrudRepositoryProxyTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CrudRepositoryProxyTest.java index 778203a3d..cfe4e8341 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CrudRepositoryProxyTest.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CrudRepositoryProxyTest.java @@ -14,7 +14,9 @@ */ package org.eclipse.jnosql.mapping.semistructured.query; + import jakarta.data.Order; + import jakarta.data.Sort; import jakarta.data.page.Page; import jakarta.data.page.PageRequest; diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredParameterBasedQueryTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredParameterBasedQueryTest.java index 9667d36fa..16fc635c9 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredParameterBasedQueryTest.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredParameterBasedQueryTest.java @@ -17,12 +17,16 @@ import jakarta.data.Sort; import jakarta.data.page.PageRequest; import jakarta.inject.Inject; +import org.assertj.core.api.Assertions; import org.assertj.core.api.SoftAssertions; import org.eclipse.jnosql.communication.Condition; import org.eclipse.jnosql.communication.TypeReference; import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; import org.eclipse.jnosql.communication.semistructured.Element; import org.eclipse.jnosql.mapping.core.Converters; + +import org.eclipse.jnosql.mapping.core.repository.ParamValue; + import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; import org.eclipse.jnosql.mapping.metadata.EntityMetadata; import org.eclipse.jnosql.mapping.reflection.Reflections; @@ -35,6 +39,8 @@ import org.jboss.weld.junit5.auto.EnableAutoWeld; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; import java.util.Collections; import java.util.List; @@ -60,7 +66,7 @@ void setUp() { @Test void shouldCreateQuerySingleParameter() { - Map params = Map.of("name", "Ada"); + Map params = Map.of("name", new ParamValue(Condition.EQUALS, "Ada", false)); var query = SemiStructuredParameterBasedQuery.INSTANCE.toQuery(params, Collections.emptyList(), metadata); SoftAssertions.assertSoftly(soft -> { @@ -69,13 +75,136 @@ void shouldCreateQuerySingleParameter() { soft.assertThat(query.name()).isEqualTo("Person"); soft.assertThat(query.sorts()).isEmpty(); soft.assertThat(query.condition()).isNotEmpty(); + var condition = query.condition().orElseThrow(); + soft.assertThat(condition.condition()).isEqualTo(Condition.EQUALS); soft.assertThat(query.condition()).get().isEqualTo(CriteriaCondition.eq(Element.of("name", "Ada"))); }); } + @Test + void shouldCreateQueryGreaterThan() { + Map params = Map.of("name", new ParamValue(Condition.GREATER_THAN, "Ada", false)); + var query = SemiStructuredParameterBasedQuery.INSTANCE.toQuery(params, Collections.emptyList(), metadata); + + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(query.limit()).isEqualTo(0L); + soft.assertThat(query.skip()).isEqualTo(0L); + soft.assertThat(query.name()).isEqualTo("Person"); + soft.assertThat(query.sorts()).isEmpty(); + soft.assertThat(query.condition()).isNotEmpty(); + var condition = query.condition().orElseThrow(); + soft.assertThat(condition.condition()).isEqualTo(Condition.GREATER_THAN); + soft.assertThat(condition.element()).isEqualTo(Element.of("name","Ada")); + }); + } + + @ParameterizedTest(name = "Executing parameter query: {index} - {0}") + @EnumSource(value = Condition.class, names = {"IN", "BETWEEN", "OR", "AND", "NOT"}, mode = EnumSource.Mode.EXCLUDE) + void shouldUpdateParameterBasedOnSimpleQuery(Condition condition) { + Map params = Map.of("name", new ParamValue(condition,"Ada", false)); + var query = SemiStructuredParameterBasedQuery.INSTANCE.toQuery(params, Collections.emptyList(), metadata); + + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(query.limit()).isEqualTo(0L); + soft.assertThat(query.skip()).isEqualTo(0L); + soft.assertThat(query.name()).isEqualTo("Person"); + soft.assertThat(query.sorts()).isEmpty(); + soft.assertThat(query.condition()).isNotEmpty(); + var criteriaCondition = query.condition().orElseThrow(); + soft.assertThat(criteriaCondition.condition()).isEqualTo(condition); + soft.assertThat(criteriaCondition.element()).isEqualTo(Element.of("name", "Ada")); + }); + } + + @ParameterizedTest(name = "Executing invalid iterable to parameter query: {index} - {0}") + @EnumSource(value = Condition.class, names = {"IN", "BETWEEN", "OR", "AND", "NOT"}, mode = EnumSource.Mode.EXCLUDE) + void shouldNotAllowIterableOnSimpleQuery(Condition condition) { + Map params = Map.of("name", new ParamValue(condition,List.of("Ada"), false)); + Assertions.assertThatThrownBy(() -> SemiStructuredParameterBasedQuery.INSTANCE.toQuery(params, Collections.emptyList(), metadata)) + .isInstanceOf(IllegalArgumentException.class); + } + + @ParameterizedTest(name = "Executing invalid array to parameter query: {index} - {0}") + @EnumSource(value = Condition.class, names = {"IN", "BETWEEN", "OR", "AND", "NOT"}, mode = EnumSource.Mode.EXCLUDE) + void shouldNotAllowArrayOnSimpleQuery(Condition condition) { + Map params = Map.of("name", new ParamValue(condition, new String[] {"Ada"}, false)); + Assertions.assertThatThrownBy(() -> SemiStructuredParameterBasedQuery.INSTANCE.toQuery(params, Collections.emptyList(), metadata)) + .isInstanceOf(IllegalArgumentException.class); + } + + @ParameterizedTest(name = "Executing invalid iterable to parameter query: {index} - {0}") + @EnumSource(value = Condition.class, names = {"IN", "BETWEEN"}, mode = EnumSource.Mode.INCLUDE) + void shouldNotAllowNotArrayAndIterable(Condition condition) { + Map params = Map.of("name", new ParamValue(condition,"Ada", false)); + Assertions.assertThatThrownBy(() -> SemiStructuredParameterBasedQuery.INSTANCE.toQuery(params, Collections.emptyList(), metadata)) + .isInstanceOf(IllegalArgumentException.class); + } + + @ParameterizedTest(name = "Executing parameter query: {index} - {0}") + @EnumSource(value = Condition.class, names = {"IN", "BETWEEN"}, mode = EnumSource.Mode.INCLUDE) + void shouldUpdateParameterBasedOnQueryThatNeedsIterable(Condition condition) { + Map params = Map.of("age", new ParamValue(condition, List.of(10, 20), false)); + var query = SemiStructuredParameterBasedQuery.INSTANCE.toQuery(params, Collections.emptyList(), metadata); + + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(query.limit()).isEqualTo(0L); + soft.assertThat(query.skip()).isEqualTo(0L); + soft.assertThat(query.name()).isEqualTo("Person"); + soft.assertThat(query.sorts()).isEmpty(); + soft.assertThat(query.condition()).isNotEmpty(); + var criteriaCondition = query.condition().orElseThrow(); + soft.assertThat(criteriaCondition.condition()).isEqualTo(condition); + soft.assertThat(criteriaCondition.element()).isEqualTo(Element.of("age", List.of(10, 20))); + }); + } + + @Test + void shouldNotAllowBetweenWithSingleValue() { + Map params = Map.of("age", new ParamValue(Condition.BETWEEN, List.of(10), false)); + Assertions.assertThatThrownBy(() -> SemiStructuredParameterBasedQuery.INSTANCE.toQuery(params, Collections.emptyList(), metadata)) + .isInstanceOf(IllegalArgumentException.class); + } + + @ParameterizedTest(name = "Executing parameter query: {index} - {0}") + @EnumSource(value = Condition.class, names = {"IN", "BETWEEN"}, mode = EnumSource.Mode.INCLUDE) + void shouldUpdateParameterBasedOnQueryThatNeedsArray(Condition condition) { + Map params = Map.of("age", new ParamValue(condition, new int[]{10, 20}, false)); + var query = SemiStructuredParameterBasedQuery.INSTANCE.toQuery(params, Collections.emptyList(), metadata); + + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(query.limit()).isEqualTo(0L); + soft.assertThat(query.skip()).isEqualTo(0L); + soft.assertThat(query.name()).isEqualTo("Person"); + soft.assertThat(query.sorts()).isEmpty(); + soft.assertThat(query.condition()).isNotEmpty(); + var criteriaCondition = query.condition().orElseThrow(); + soft.assertThat(criteriaCondition.condition()).isEqualTo(condition); + soft.assertThat(criteriaCondition.element()).isEqualTo(Element.of("age", List.of(10, 20))); + }); + } + + @Test + void shouldCreateQuerySingleParameterWithNot() { + Map params = Map.of("name", new ParamValue(Condition.EQUALS, "Ada", true)); + var query = SemiStructuredParameterBasedQuery.INSTANCE.toQuery(params, Collections.emptyList(), metadata); + + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(query.limit()).isEqualTo(0L); + soft.assertThat(query.skip()).isEqualTo(0L); + soft.assertThat(query.name()).isEqualTo("Person"); + soft.assertThat(query.sorts()).isEmpty(); + soft.assertThat(query.condition()).isNotEmpty(); + var condition = query.condition().orElseThrow(); + soft.assertThat(condition.condition()).isEqualTo(Condition.NOT); + var criteriaCondition = condition.element().get(CriteriaCondition.class); + soft.assertThat(criteriaCondition).isEqualTo(CriteriaCondition.eq(Element.of("name", "Ada"))); + }); + } + @Test void shouldCreateQueryMultipleParams() { - Map params = Map.of("name", "Ada", "age", 10); + Map params = Map.of("name", new ParamValue(Condition.EQUALS, "Ada", false), + "age", new ParamValue(Condition.EQUALS, 10, false)); var query = SemiStructuredParameterBasedQuery.INSTANCE.toQuery(params, Collections.emptyList(), metadata); SoftAssertions.assertSoftly(soft -> { @@ -95,7 +224,7 @@ void shouldCreateQueryMultipleParams() { @Test void shouldCreateQueryEmptyParams() { - Map params = Collections.emptyMap(); + Map params = Collections.emptyMap(); var query = SemiStructuredParameterBasedQuery.INSTANCE.toQuery(params, Collections.emptyList(), metadata); SoftAssertions.assertSoftly(soft -> { @@ -109,7 +238,7 @@ void shouldCreateQueryEmptyParams() { @Test void shouldAddSort() { - Map params = Collections.emptyMap(); + Map params = Collections.emptyMap(); var query = SemiStructuredParameterBasedQuery.INSTANCE.toQuery(params, List.of(Sort.asc("name")), metadata); SoftAssertions.assertSoftly(soft -> { diff --git a/pom.xml b/pom.xml index 4247b40be..d32b4fa44 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 3.0.1 2.1.3 1.1.0-SNAPSHOT - 1.0.1 + 1.0.2-SNAPSHOT 3.1.1 3.11.1 3.3.1