From 7c97e7a34f6fd23c263366932767b92a2f29b53d Mon Sep 17 00:00:00 2001 From: Andrey G Date: Wed, 15 May 2024 15:25:40 +0300 Subject: [PATCH] FMWK-438 Add tests and javadocs for comparing Collections (#740) * Add tests and javadocs for comparing Collection * Add correct validation of types of Map query arguments --- .../query/AerospikeQueryCreator.java | 12 +- .../query/AerospikeQueryCreatorUtils.java | 21 ++- .../query/CollectionQueryCreator.java | 2 +- .../repository/query/MapQueryCreator.java | 28 +++- .../blocking/noindex/findBy/BetweenTests.java | 45 +++++++ .../findBy/GreaterThanOrEqualTests.java | 52 +++++++- .../noindex/findBy/GreaterThanTests.java | 40 ++++++ .../blocking/noindex/findBy/InTests.java | 24 ++++ .../noindex/findBy/LessThanOrEqualTests.java | 69 ++++++++++ .../noindex/findBy/LessThanTests.java | 45 +++++++ .../aerospike/sample/PersonRepository.java | 120 +++++++++++++----- 11 files changed, 406 insertions(+), 52 deletions(-) diff --git a/src/main/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreator.java b/src/main/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreator.java index 6deb74e49..085990496 100644 --- a/src/main/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreator.java +++ b/src/main/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreator.java @@ -116,8 +116,8 @@ protected CriteriaDefinition create(Part part, Iterator iterator) { } private CriteriaDefinition create(Part part, AerospikePersistentProperty property, Iterator parameters) { - List queryParameters = getQueryParameters(parameters); FilterOperation filterOperation = getFilterOperation(part.getType()); + List queryParameters = getQueryParameters(parameters, filterOperation); IAerospikeQueryCreator queryCreator = getQueryCreator(part, property, queryParameters, filterOperation); queryCreator.validate(); @@ -142,10 +142,12 @@ private IAerospikeQueryCreator getQueryCreator(Part part, AerospikePersistentPro } } else if (property.isMap()) { if (part.getProperty().hasNext()) { // a POJO field - queryCreator = new MapQueryCreator(part, property, fieldName, queryParameters, filterOperation, - converter, versionSupport, true); + PropertyPath nestedProperty = getNestedPropertyPath(part.getProperty()); + queryCreator = new MapQueryCreator(part, nestedProperty, property, fieldName, queryParameters, + filterOperation, converter, versionSupport, true); } else { - queryCreator = new MapQueryCreator(part, property, fieldName, queryParameters, filterOperation, + queryCreator = new MapQueryCreator(part, part.getProperty(), property, fieldName, queryParameters, + filterOperation, converter, versionSupport, false); } } else { @@ -193,7 +195,7 @@ private FilterOperation getFilterOperation(Part.Type type) { }; } - private List getQueryParameters(Iterator parametersIterator) { + private List getQueryParameters(Iterator parametersIterator, FilterOperation filterOperation) { List params = new ArrayList<>(); parametersIterator.forEachRemaining(param -> params.add(convertIfNecessary(param, converter))); // null parameters are not allowed, instead AerospikeNullQueryCriteria.NULL_PARAM should be used diff --git a/src/main/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUtils.java b/src/main/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUtils.java index 7b0b9af26..998e69422 100644 --- a/src/main/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUtils.java +++ b/src/main/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUtils.java @@ -145,7 +145,7 @@ protected static void setQbValuesForMapByKey(QualifierBuilder qb, Object key, Ob } protected static Object convertIfNecessary(Object obj, MappingAerospikeConverter converter) { - if (obj == null || obj instanceof AerospikeQueryCriterion || obj instanceof AerospikeNullQueryCriterion) { + if (typeDoesNotRequireConversion(obj)) { return obj; } @@ -154,6 +154,12 @@ protected static Object convertIfNecessary(Object obj, MappingAerospikeConverter return converter.toWritableValue(obj, valueType); } + private static boolean typeDoesNotRequireConversion(Object obj) { + return obj == null + || obj instanceof AerospikeQueryCriterion + || obj instanceof AerospikeNullQueryCriterion; + } + protected static Value getValueOfQueryParameter(Object queryParameter) { return Value.get(convertNullParameter(queryParameter)); } @@ -196,15 +202,15 @@ protected static void validateTypes(MappingAerospikeConverter converter, Propert protected static void validateTypes(MappingAerospikeConverter converter, PropertyPath propertyPath, List queryParameters, FilterOperation op, String queryPartDescription) { - validateTypes(converter, propertyPath.getTypeInformation() - .getType(), queryParameters, op, queryPartDescription); + validateTypes(converter, propertyPath.getTypeInformation().getType(), queryParameters, op, + queryPartDescription); } protected static void validateTypes(MappingAerospikeConverter converter, Class propertyType, List queryParameters, FilterOperation op, String queryPartDescription, String... alternativeTypes) { // Checking versus Number rather than strict type to be able to compare, e.g., integer to a long - if (isAssignable(Number.class, propertyType) && isAssignableValue(Number.class, queryParameters.get(0))) { + if (propertyTypeAndFirstParamAssignableToNumber(propertyType, queryParameters)) { propertyType = Number.class; } @@ -226,6 +232,13 @@ protected static void validateTypes(MappingAerospikeConverter converter, Class propertyType, + List queryParameters) { + return !queryParameters.isEmpty() + && isAssignable(Number.class, propertyType) + && isAssignableValue(Number.class, queryParameters.get(0)); + } + protected static void validateQueryIsNull(List queryParameters, String queryPartDescription) { // Number of arguments is not zero if (!queryParameters.isEmpty()) { diff --git a/src/main/java/org/springframework/data/aerospike/repository/query/CollectionQueryCreator.java b/src/main/java/org/springframework/data/aerospike/repository/query/CollectionQueryCreator.java index bd715012a..78862c256 100644 --- a/src/main/java/org/springframework/data/aerospike/repository/query/CollectionQueryCreator.java +++ b/src/main/java/org/springframework/data/aerospike/repository/query/CollectionQueryCreator.java @@ -87,7 +87,7 @@ private void validateCollectionQueryComparison(List queryParameters, Str } if (queryParameters.get(0) instanceof Collection) { - validateTypes(converter, Collection.class, queryParameters, filterOperation, queryPartDescription); + validateTypes(converter, Collection.class, queryParameters, this.filterOperation, queryPartDescription); } else { throw new IllegalArgumentException(queryPartDescription + ": invalid argument type, expecting Collection"); } diff --git a/src/main/java/org/springframework/data/aerospike/repository/query/MapQueryCreator.java b/src/main/java/org/springframework/data/aerospike/repository/query/MapQueryCreator.java index 7b1a9c884..91fe6e25c 100644 --- a/src/main/java/org/springframework/data/aerospike/repository/query/MapQueryCreator.java +++ b/src/main/java/org/springframework/data/aerospike/repository/query/MapQueryCreator.java @@ -9,6 +9,7 @@ import org.springframework.data.aerospike.query.qualifier.QualifierBuilder; import org.springframework.data.aerospike.repository.query.CriteriaDefinition.AerospikeQueryCriterion; import org.springframework.data.aerospike.server.version.ServerVersionSupport; +import org.springframework.data.mapping.PropertyPath; import org.springframework.data.repository.query.parser.Part; import org.springframework.data.util.TypeInformation; @@ -24,6 +25,7 @@ public class MapQueryCreator implements IAerospikeQueryCreator { private final Part part; private final AerospikePersistentProperty property; + private final PropertyPath propertyPath; private final String fieldName; private final List queryParameters; private final FilterOperation filterOperation; @@ -31,10 +33,11 @@ public class MapQueryCreator implements IAerospikeQueryCreator { private final ServerVersionSupport versionSupport; private final boolean isNested; - public MapQueryCreator(Part part, AerospikePersistentProperty property, String fieldName, + public MapQueryCreator(Part part, PropertyPath propertyPath, AerospikePersistentProperty property, String fieldName, List queryParameters, FilterOperation filterOperation, MappingAerospikeConverter converter, ServerVersionSupport versionSupport, boolean isNested) { this.part = part; + this.propertyPath = propertyPath; this.property = property; this.fieldName = fieldName; this.queryParameters = queryParameters; @@ -46,13 +49,26 @@ public MapQueryCreator(Part part, AerospikePersistentProperty property, String f @Override public void validate() { - String queryPartDescription = String.join(" ", part.getProperty().toString(), filterOperation.toString()); + String queryPartDescription = String.join(" ", propertyPath.toString(), filterOperation.toString()); switch (filterOperation) { + // Types of query arguments for CONTAINING and NOT_CONTAINING are validated within the method case CONTAINING, NOT_CONTAINING -> validateMapQueryContaining(queryPartDescription); - case EQ, NOTEQ, GT, GTEQ, LT, LTEQ -> validateMapQueryComparison(queryPartDescription); - case BETWEEN -> validateMapQueryBetween(queryPartDescription); - case IN, NOT_IN -> validateQueryIn(queryParameters, queryPartDescription); - case IS_NOT_NULL, IS_NULL -> validateQueryIsNull(queryParameters, queryPartDescription); + case EQ, NOTEQ, GT, GTEQ, LT, LTEQ -> { + validateMapQueryComparison(queryPartDescription); + validateTypes(converter, propertyPath, filterOperation, queryParameters); + } + case BETWEEN -> { + validateMapQueryBetween(queryPartDescription); + validateTypes(converter, propertyPath, filterOperation, queryParameters); + } + case IN, NOT_IN -> { + validateQueryIn(queryParameters, queryPartDescription); + validateTypes(converter, propertyPath, filterOperation, queryParameters); + } + case IS_NOT_NULL, IS_NULL -> { + validateQueryIsNull(queryParameters, queryPartDescription); + validateTypes(converter, propertyPath, filterOperation, queryParameters); + } default -> throw new UnsupportedOperationException("Unsupported operation: " + queryPartDescription); } } diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/BetweenTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/BetweenTests.java index 0b8bfd0cd..4b6511336 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/BetweenTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/BetweenTests.java @@ -6,8 +6,12 @@ import org.springframework.data.aerospike.sample.Person; import org.springframework.data.aerospike.util.TestUtils; +import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.PriorityQueue; +import java.util.Set; +import java.util.TreeSet; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -55,6 +59,47 @@ void findByNestedSimplePropertyBetween_String() { .containsExactly(dave); } + /** + * Collections are converted to Lists when saved to AerospikeDB. + *

+ * Argument of type Collection meant to be compared with a List in DB also gets converted to a List. + *

+ * In this test we are providing a SortedSet and a PriorityQueue which preserve the order of elements, + * such Collections can be consistently compared to a List saved in DB. + */ + @Test + void findByCollectionBetween_SortedSet() { + if (serverVersionSupport.isFindByCDTSupported()) { + Set davesIntSet = Set.of(1); + dave.setIntSet(davesIntSet); + repository.save(dave); + assertThat(dave.getIntSet()).isEqualTo(davesIntSet); + + Set setToCompareWith = new TreeSet<>(Set.of(3, 1, 2, 4, 0)); // gets sorted using natural order + List persons = repository.findByIntSetBetween(Set.of(0), setToCompareWith); + assertThat(persons).doesNotContain(dave); + + Set setToCompareWith2 = new TreeSet<>(Comparator.reverseOrder()); + setToCompareWith2.addAll(Set.of(3, 1, 2, 4, 0)); // gets sorted using Comparator: 4, 3, 2, 1, 0 + List persons2 = repository.findByIntSetBetween(Set.of(0), setToCompareWith2); + assertThat(persons2).contains(dave); + + List listToCompareWith = List.of(0, 4, 3, 1, 2); // the insertion order is preserved + List persons3 = repository.findByIntSetBetween(Set.of(0), listToCompareWith); + assertThat(persons3).doesNotContain(dave); + + // gets sorted using natural order + PriorityQueue queueToCompareWith = new PriorityQueue<>(Set.of(3, 1, 2, 4, 0)); + List persons4 = repository.findByIntSetBetween(Set.of(0), queueToCompareWith); + assertThat(persons4).doesNotContain(dave); + + PriorityQueue queueToCompareWith2 = new PriorityQueue<>(Comparator.reverseOrder()); + queueToCompareWith2.addAll(Set.of(3, 1, 2, 4, 0)); // gets sorted using Comparator: 4, 3, 2, 1, 0 + List persons5 = repository.findByIntSetBetween(Set.of(0), queueToCompareWith2); + assertThat(persons5).contains(dave); + } + } + @Test void findByCollectionBetween_IntegerList() { List list1 = List.of(100, 200, 300); diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/GreaterThanOrEqualTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/GreaterThanOrEqualTests.java index 4d12c864c..6579a0612 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/GreaterThanOrEqualTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/GreaterThanOrEqualTests.java @@ -6,9 +6,12 @@ import org.springframework.data.aerospike.sample.Person; import org.springframework.data.aerospike.util.TestUtils; +import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.PriorityQueue; import java.util.Set; +import java.util.TreeSet; import static org.assertj.core.api.Assertions.assertThat; @@ -24,8 +27,19 @@ void findByNestedSimplePropertyGreaterThan_String() { assertThat(repository.findByAddressZipCodeGreaterThanEqual(zipCode)).containsExactly(carter); } + /** + * Collections are converted to Lists when saved to AerospikeDB. + *

+ * Argument of type Collection meant to be compared with a List in DB also gets converted to a List. + *

+ * In this test we are providing an unordered Collection (Set) which means that the order of elements in a resulting + * List cannot be guaranteed. + *

+ * Comparing with an unordered Collection works only for equality (EQ/NOTEQ) operations and not for + * LT/LTEQ/GT/GTEQ/BETWEEN. + */ @Test - void findByCollectionGreaterThanOrEqual_Set() { + void findByCollectionGreaterThanOrEqual_UnorderedSet_Equals_List() { if (serverVersionSupport.isFindByCDTSupported()) { Set setToCompareWith = Set.of(0, 1, 2, 3, 4); dave.setIntSet(setToCompareWith); @@ -37,6 +51,42 @@ void findByCollectionGreaterThanOrEqual_Set() { } } + /** + * Collections are converted to Lists when saved to AerospikeDB. + *

+ * Argument of type Collection meant to be compared with a List in DB also gets converted to a List. + *

+ * In this test we are providing a SortedSet and a PriorityQueue which preserve the order of elements, such + * Collections can be consistently compared to a List saved in DB. + */ + @Test + void findByCollectionGreaterThanOrEqual_SortedSet() { + if (serverVersionSupport.isFindByCDTSupported()) { + Set davesIntSet = Set.of(1); + dave.setIntSet(davesIntSet); + repository.save(dave); + assertThat(dave.getIntSet()).isEqualTo(davesIntSet); + + Set setToCompareWith = new TreeSet<>(Set.of(0, 1, 2, 3, 4)); // natural order + List persons = repository.findByIntSetGreaterThanEqual(setToCompareWith); + assertThat(persons).contains(dave); + + Set setToCompareWith2 = new TreeSet<>(Comparator.comparingInt(Integer::intValue)); + setToCompareWith2.addAll(Set.of(3, 1, 2, 4, 0)); // gets sorted using Comparator + List persons2 = repository.findByIntSetGreaterThanEqual(setToCompareWith2); + assertThat(persons2).contains(dave); + + List listToCompareWith = List.of(3, 1, 2, 0, 4); // the insertion order is preserved + List persons3 = repository.findByIntSetGreaterThanEqual(listToCompareWith); + assertThat(persons3).doesNotContain(dave); + + // gets sorted using natural order + PriorityQueue queueToCompareWith = new PriorityQueue<>(Set.of(3, 1, 2, 4, 0)); + List persons4 = repository.findByIntSetGreaterThanEqual(queueToCompareWith); + assertThat(persons4).contains(dave); + } + } + @Test void findByCollectionGreaterThanOrEqual_List() { if (serverVersionSupport.isFindByCDTSupported()) { diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/GreaterThanTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/GreaterThanTests.java index 61287192c..82b469707 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/GreaterThanTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/GreaterThanTests.java @@ -11,8 +11,12 @@ import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; +import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.PriorityQueue; +import java.util.Set; +import java.util.TreeSet; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -134,6 +138,42 @@ void findByNestedSimplePropertyGreaterThan_Integer() { TestUtils.setFriendsToNull(repository, alicia, dave, carter, leroi); } + /** + * Collections are converted to Lists when saved to AerospikeDB. + *

+ * Argument of type Collection meant to be compared with a List in DB also gets converted to a List. + *

+ * In this test we are providing a SortedSet and a PriorityQueue which preserve the order of elements, such + * Collections can be consistently compared to a List saved in DB. + */ + @Test + void findByCollectionGreaterThan_SortedSet() { + if (serverVersionSupport.isFindByCDTSupported()) { + Set davesIntSet = Set.of(1); + dave.setIntSet(davesIntSet); + repository.save(dave); + assertThat(dave.getIntSet()).isEqualTo(davesIntSet); + + Set setToCompareWith = new TreeSet<>(Set.of(0, 1, 2, 3, 4)); // natural order + List persons = repository.findByIntSetGreaterThan(setToCompareWith); + assertThat(persons).contains(dave); + + Set setToCompareWith2 = new TreeSet<>(Comparator.comparingInt(Integer::intValue)); + setToCompareWith2.addAll(Set.of(3, 1, 2, 4, 0)); // gets sorted using Comparator + List persons2 = repository.findByIntSetGreaterThan(setToCompareWith2); + assertThat(persons2).contains(dave); + + List listToCompareWith = List.of(3, 1, 2, 0, 4); // the insertion order is preserved + List persons3 = repository.findByIntSetGreaterThan(listToCompareWith); + assertThat(persons3).doesNotContain(dave); + + // gets sorted using natural order + PriorityQueue queueToCompareWith = new PriorityQueue<>(Set.of(3, 1, 2, 4, 0)); + List persons4 = repository.findByIntSetGreaterThan(queueToCompareWith); + assertThat(persons4).contains(dave); + } + } + @Test void findByCollectionGreaterThan() { List listToCompare1 = List.of(100, 200, 300, 400); diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/InTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/InTests.java index fa79b2cc1..620a58078 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/InTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/InTests.java @@ -35,6 +35,18 @@ void findByNestedSimplePropertyIn_String() { .containsExactlyInAnyOrder(dave, carter); } + @Test + void findByCollectionIn() { + if (serverVersionSupport.isFindByCDTSupported()) { + dave.setInts(List.of(1, 2, 3, 4)); + repository.save(dave); + + List result = repository.findByIntsIn(List.of(List.of(0, 1, 2, 3, 4, 5, 6, 7), + List.of(1, 2, 3), List.of(1, 2, 3, 4))); + assertThat(result).contains(dave); + } + } + @Test void findByNestedCollectionIn() { if (serverVersionSupport.isFindByCDTSupported()) { @@ -52,6 +64,18 @@ void findByNestedCollectionIn() { } } + @Test + void findByMapIn() { + if (serverVersionSupport.isFindByCDTSupported()) { + dave.setIntMap(Map.of("1", 2, "3", 4)); + repository.save(dave); + + List result = repository.findByIntMapIn(List.of(Map.of("0", 1, "2", 3, "4", 5, "6", 7), + Map.of("1", 2, "3", 4567), Map.of("1", 2, "3", 4))); + assertThat(result).contains(dave); + } + } + @Test void findByNestedMapIn() { if (serverVersionSupport.isFindByCDTSupported()) { diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/LessThanOrEqualTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/LessThanOrEqualTests.java index ce42483df..b43a54d22 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/LessThanOrEqualTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/LessThanOrEqualTests.java @@ -6,8 +6,12 @@ import org.springframework.data.aerospike.sample.Person; import org.springframework.data.aerospike.util.TestUtils; +import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.PriorityQueue; +import java.util.Set; +import java.util.TreeSet; import static org.assertj.core.api.Assertions.assertThat; @@ -40,6 +44,71 @@ void findByNestedSimplePropertyGreaterThan_String() { assertThat(repository.findByAddressZipCodeLessThanEqual("C0125")).containsExactlyInAnyOrder(carter, dave); } + /** + * Collections are converted to Lists when saved to AerospikeDB. + *

+ * Argument of type Collection meant to be compared with a List in DB also gets converted to a List. + *

+ * In this test we are providing an unordered Collection (Set) which means that the order of elements in a resulting + * List cannot be guaranteed. + *

+ * Comparing with an unordered Collection works only for equality (EQ/NOTEQ) operations and not for + * LT/LTEQ/GT/GTEQ/BETWEEN. + */ + @Test + void findByCollectionLessThanOrEqual_UnorderedSet_Equals_List() { + if (serverVersionSupport.isFindByCDTSupported()) { + Set setToCompareWith = Set.of(0, 1, 2, 3, 4); + dave.setIntSet(setToCompareWith); + repository.save(dave); + assertThat(dave.getIntSet()).isEqualTo(setToCompareWith); + + List persons = repository.findByIntSetLessThanEqual(setToCompareWith); + assertThat(persons).contains(dave); + } + } + + /** + * Collections are converted to Lists when saved to AerospikeDB. + *

+ * Argument of type Collection meant to be compared with a List in DB also gets converted to a List. + *

+ * In this test we are providing a SortedSet and a PriorityQueue which preserve the order of elements, such + * Collections can be consistently compared to a List saved in DB. + */ + @Test + void findByCollectionLessThanOrEqual_SortedSet() { + if (serverVersionSupport.isFindByCDTSupported()) { + Set davesIntSet = Set.of(1); + dave.setIntSet(davesIntSet); + repository.save(dave); + assertThat(dave.getIntSet()).isEqualTo(davesIntSet); + + Set setToCompareWith = new TreeSet<>(Set.of(3, 1, 2, 4, 0)); // gets sorted using natural order + List persons = repository.findByIntSetLessThanEqual(setToCompareWith); + assertThat(persons).doesNotContain(dave); + + Set setToCompareWith2 = new TreeSet<>(Comparator.reverseOrder()); + setToCompareWith2.addAll(Set.of(3, 1, 2, 4, 0)); // gets sorted using Comparator: 4, 3, 2, 1, 0 + List persons2 = repository.findByIntSetLessThanEqual(setToCompareWith2); + assertThat(persons2).contains(dave); + + List listToCompareWith = List.of(0, 4, 3, 1, 2); // the insertion order is preserved + List persons3 = repository.findByIntSetLessThanEqual(listToCompareWith); + assertThat(persons3).doesNotContain(dave); + + // gets sorted using natural order + PriorityQueue queueToCompareWith = new PriorityQueue<>(Set.of(3, 1, 2, 4, 0)); + List persons4 = repository.findByIntSetLessThanEqual(queueToCompareWith); + assertThat(persons4).doesNotContain(dave); + + PriorityQueue queueToCompareWith2 = new PriorityQueue<>(Comparator.reverseOrder()); + queueToCompareWith2.addAll(Set.of(3, 1, 2, 4, 0)); // gets sorted using Comparator: 4, 3, 2, 1, 0 + List persons5 = repository.findByIntSetLessThanEqual(queueToCompareWith2); + assertThat(persons5).contains(dave); + } + } + @Test void findByNestedCollectionLessThanOrEqual() { if (serverVersionSupport.isFindByCDTSupported()) { diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/LessThanTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/LessThanTests.java index bb74db1fb..0debfcf35 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/LessThanTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/LessThanTests.java @@ -8,8 +8,12 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.PriorityQueue; +import java.util.Set; +import java.util.TreeSet; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -36,6 +40,47 @@ void findByNestedSimplePropertyGreaterThan_String() { assertThat(repository.findByAddressZipCodeLessThan("C0124")).containsExactly(dave); } + /** + * Collections are converted to Lists when saved to AerospikeDB. + *

+ * Argument of type Collection meant to be compared with a List in DB also gets converted to a List. + *

+ * In this test we are providing a SortedSet and a PriorityQueue which preserve the order of elements, such + * Collections can be consistently compared to a List saved in DB. + */ + @Test + void findByCollectionLessThan_SortedSet() { + if (serverVersionSupport.isFindByCDTSupported()) { + Set davesIntSet = Set.of(1); + dave.setIntSet(davesIntSet); + repository.save(dave); + assertThat(dave.getIntSet()).isEqualTo(davesIntSet); + + Set setToCompareWith = new TreeSet<>(Set.of(3, 1, 2, 4, 0)); // gets sorted using natural order + List persons = repository.findByIntSetLessThan(setToCompareWith); + assertThat(persons).doesNotContain(dave); + + Set setToCompareWith2 = new TreeSet<>(Comparator.reverseOrder()); + setToCompareWith2.addAll(Set.of(3, 1, 2, 4, 0)); // gets sorted using Comparator: 4, 3, 2, 1, 0 + List persons2 = repository.findByIntSetLessThan(setToCompareWith2); + assertThat(persons2).contains(dave); + + List listToCompareWith = List.of(0, 4, 3, 1, 2); // the insertion order is preserved + List persons3 = repository.findByIntSetLessThan(listToCompareWith); + assertThat(persons3).doesNotContain(dave); + + // gets sorted using natural order + PriorityQueue queueToCompareWith = new PriorityQueue<>(Set.of(3, 1, 2, 4, 0)); + List persons4 = repository.findByIntSetLessThan(queueToCompareWith); + assertThat(persons4).doesNotContain(dave); + + PriorityQueue queueToCompareWith2 = new PriorityQueue<>(Comparator.reverseOrder()); + queueToCompareWith2.addAll(Set.of(3, 1, 2, 4, 0)); // gets sorted using Comparator: 4, 3, 2, 1, 0 + List persons5 = repository.findByIntSetLessThan(queueToCompareWith2); + assertThat(persons5).contains(dave); + } + } + @Test void findByCollectionLessThan() { if (serverVersionSupport.isFindByCDTSupported()) { diff --git a/src/test/java/org/springframework/data/aerospike/sample/PersonRepository.java b/src/test/java/org/springframework/data/aerospike/sample/PersonRepository.java index e57d946d3..1ede5bb2d 100644 --- a/src/test/java/org/springframework/data/aerospike/sample/PersonRepository.java +++ b/src/test/java/org/springframework/data/aerospike/sample/PersonRepository.java @@ -320,18 +320,18 @@ List

findByAgeOrLastNameLikeAndFirstNameLike(QueryParam age, QueryParam lastN Page

findByAddressIn(List

address, Pageable page); /** - * Find all entities that satisfy the condition "have strings the same as the given argument" (find by collection) + * Find all entities that satisfy the condition "have strings the same as the given argument" (find by Collection) * - * @param list List to compare strings with + * @param strings Collection to compare strings with, subsequently gets converted to a List */ - List

findByStringsEquals(List list); + List

findByStringsEquals(Collection strings); /** - * Find all entities that satisfy the condition "have strings the same as the given argument" (find by collection) + * Find all entities that satisfy the condition "have strings list equal to the given argument" (find by Collection) * - * @param collection Collection to compare strings with + * @param strings Collection to compare strings with, subsequently gets converted to a List */ - List

findByStrings(Collection collection); + List

findByStrings(Collection strings); /** * Find all entities with existing strings list not equal to the given argument @@ -342,41 +342,71 @@ List

findByAgeOrLastNameLikeAndFirstNameLike(QueryParam age, QueryParam lastN /** * Find all entities that satisfy the condition "have strings list with fewer elements or with a corresponding - * element lower in ordering than in the given argument" (find by list). + * element lower in ordering than in the given argument" (find by Collection). *

* Information about ordering * - * @param list - List to compare with + * @param strings - Collection to compare with, subsequently gets converted to a List */ - List

findByStringsLessThan(List list); + List

findByStringsLessThan(Collection strings); /** - * Find all entities that satisfy the condition "have integers list with more elements or with a corresponding - * element higher in ordering than in the given argument" (find by list). + * Find all entities that satisfy the condition "have ints list with more elements or with a corresponding + * element higher in ordering than in the given argument" (find by Collection). *

* Information about ordering * - * @param list - List to compare with + * @param ints - Collection to compare with, subsequently gets converted to a List */ - List

findByIntsGreaterThan(List list); + List

findByIntsGreaterThan(Collection ints); /** - * Find all entities that satisfy the condition "have strings set with more elements or with a corresponding element - * higher in ordering than in the given argument" (find by collection). + * Find all entities that satisfy the condition "have intSet with fewer elements or with a corresponding element + * lower in ordering than in the given argument" (find by Collection). *

* Information about ordering * - * @param collection - Collection to compare with + * @param collection - Collection to compare with, subsequently gets converted to a List + */ + List

findByIntSetLessThan(Collection collection); + + /** + * Find all entities that satisfy the condition "have intSet with fewer elements or with a corresponding element + * lower in ordering than in the given argument, or equal to the given argument" (find by Collection). + *

+ * Information about ordering + * + * @param collection - Collection to compare with, subsequently gets converted to a List + */ + List

findByIntSetLessThanEqual(Collection collection); + + /** + * Find all entities that satisfy the condition "have intSet with more elements or with a corresponding element + * higher in ordering than in the given argument" (find by Collection). + *

+ * Information about ordering + * + * @param collection - Collection to compare with, subsequently gets converted to a List + */ + List

findByIntSetGreaterThan(Collection collection); + + /** + * Find all entities that satisfy the condition "have intSet with more elements or with a corresponding element + * higher in ordering than in the given argument, or equal to the given argument" (find by Collection). + *

+ * Information about ordering + * + * @param collection - Collection to compare with, subsequently gets converted to a List */ List

findByIntSetGreaterThanEqual(Collection collection); /** - * Find all entities that satisfy the condition "have strings set with more elements or with a corresponding element - * higher in ordering than in the given argument" (find by collection). + * Find all entities that satisfy the condition "have ints list with more elements or with a corresponding element + * higher in ordering than in the given argument, or equal to the given argument" (find by Collection). *

* Information about ordering * - * @param collection - Collection to compare with + * @param collection - Collection to compare with, subsequently gets converted to a List */ List

findByIntsGreaterThanEqual(Collection collection); @@ -457,14 +487,14 @@ List

findByAgeOrLastNameLikeAndFirstNameLike(QueryParam age, QueryParam lastN List

findByAddressesMapContaining(AerospikeQueryCriterion criterionPair, String key, Address value); /** - * Find all entities that satisfy the condition "have stringMap the same as the given argument" (find by map) + * Find all entities that satisfy the condition "have stringMap the same as the given argument" (find by Map) * * @param map Map to compare stringMap with */ List

findByStringMapEquals(Map map); /** - * Find all entities that satisfy the condition "have stringMap the same as the given argument" (find by map) + * Find all entities that satisfy the condition "have stringMap the same as the given argument" (find by Map) * * @param map Map to compare stringMap with */ @@ -472,7 +502,7 @@ List

findByAgeOrLastNameLikeAndFirstNameLike(QueryParam age, QueryParam lastN /** * Find all entities that satisfy the condition "have stringMap with more elements or with a corresponding key-value - * higher in ordering than in the given argument" (find by map). + * higher in ordering than in the given argument" (find by Map). *

* Information about ordering * @@ -516,6 +546,14 @@ List

findByAgeOrLastNameLikeAndFirstNameLike(QueryParam age, QueryParam lastN */ List

findByIntMapBetween(Map from, Map to); + /** + * Find all entities that satisfy the condition "have intMap equal to one of the values in the given list" + * (find by Map) + * + * @param list - list of possible values + */ + List

findByIntMapIn(List> list); + /** * Find all entities that satisfy the condition "have a bestFriend who has a friend with address apartment value in * the range between the given integers (deeply nested)" @@ -1171,6 +1209,14 @@ List

findByFriendStringMapNotContaining(AerospikeQueryCriterion criterion, */ List

findByIntsContaining(int integer); + /** + * Find all entities that satisfy the condition "have ints list equal to one of the values in the given list" + * (find by Collection) + * + * @param list - list of possible values, each of them subsequently gets converted to a List + */ + List

findByIntsIn(List> list); + /** * Find all entities that satisfy the condition "have the array which contains the given integer" *

@@ -1239,30 +1285,34 @@ List

findByFriendStringMapNotContaining(AerospikeQueryCriterion criterion, List

findByIntsLessThanEqual(long value); /** - * Find all entities that satisfy the condition "have list in the given range" - *

- * List name in this case is Ints - *

+ * Find all entities that satisfy the condition "have intSet in the given range" *

* Information about ordering * - * @param from lower limit, inclusive - * @param to upper limit, exclusive + * @param from lower limit, inclusive, subsequently gets converted to a List + * @param to upper limit, exclusive, subsequently gets converted to a List */ - List

findByIntsBetween(List from, List to); + List

findByIntSetBetween(Collection from, Collection to); /** - * Find all entities that satisfy the condition "have list in the given range" + * Find all entities that satisfy the condition "have ints list in the given range" *

- * List name in this case is Strings - *

+ * Information about ordering + * + * @param from lower limit, inclusive, subsequently gets converted to a List + * @param to upper limit, exclusive, subsequently gets converted to a List + */ + List

findByIntsBetween(Collection from, Collection to); + + /** + * Find all entities that satisfy the condition "have strings list in the given range" *

* Information about ordering * - * @param from lower limit, inclusive - * @param to upper limit, exclusive + * @param from lower limit, inclusive, subsequently gets converted to a List + * @param to upper limit, exclusive, subsequently gets converted to a List */ - List

findByStringsBetween(List from, List to); + List

findByStringsBetween(Collection from, Collection to); P findFirstByLastNameStartingWith(String lastName, Sort sort);