diff --git a/src/main/java/org/springframework/data/aerospike/query/CombinedQueryParam.java b/src/main/java/org/springframework/data/aerospike/query/CombinedQueryParam.java new file mode 100644 index 000000000..65d3f0606 --- /dev/null +++ b/src/main/java/org/springframework/data/aerospike/query/CombinedQueryParam.java @@ -0,0 +1,19 @@ +package org.springframework.data.aerospike.query; + +import lombok.Getter; + +/** + * This class stores arguments passed to each part of a combined repository query, + * e.g., repository.findByNameAndEmail(CombinedQueryParam.of("John"), CombinedQueryParam.of("john@email.com")) + */ +public record CombinedQueryParam(@Getter Object[] arguments) { + + /** + * This method is required to pass arguments to each part of a combined query + * @param arguments necessary objects + * @return instance of {@link CombinedQueryParam} + */ + public static CombinedQueryParam of(Object... arguments) { + return new CombinedQueryParam(arguments); + } +} 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 d1bb4ec47..47200d928 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 @@ -21,6 +21,7 @@ import org.springframework.data.aerospike.convert.MappingAerospikeConverter; import org.springframework.data.aerospike.mapping.AerospikeMappingContext; import org.springframework.data.aerospike.mapping.AerospikePersistentProperty; +import org.springframework.data.aerospike.query.CombinedQueryParam; import org.springframework.data.aerospike.query.FilterOperation; import org.springframework.data.aerospike.query.Qualifier; import org.springframework.data.aerospike.repository.query.CriteriaDefinition.AerospikeMapQueryCriteria; @@ -62,12 +63,14 @@ public class AerospikeQueryCreator extends AbstractQueryCreator 1; } @Override @@ -75,7 +78,17 @@ protected CriteriaDefinition create(Part part, Iterator iterator) { PersistentPropertyPath path = context.getPersistentPropertyPath(part.getProperty()); AerospikePersistentProperty property = path.getLeafProperty(); - return create(part, property, iterator); + + Iterator paramIterator = iterator; + if (isCombinedQuery && iterator.hasNext()) { + Object nextParam = iterator.next(); + if (!(nextParam instanceof CombinedQueryParam)) { + throw new IllegalArgumentException(part.getProperty() + ": expected CombinedQueryParam, instead got " + nextParam.getClass() + .getSimpleName()); + } + paramIterator = Arrays.stream(((CombinedQueryParam) nextParam).getArguments()).iterator(); + } + return create(part, property, paramIterator); } private CriteriaDefinition create(Part part, AerospikePersistentProperty property, Iterator parameters) { @@ -140,7 +153,7 @@ public CriteriaDefinition getCriteria(Part part, AerospikePersistentProperty pro qualifier = processCollection(part, value1, value2, parametersIterator, op, fieldName); } else if (property.isMap()) { qualifier = processMap(part, value1, value2, parametersIterator, op, fieldName); - } else { // if it is neither a collection nor a map + } else { qualifier = processOther(part, value1, value2, property, op, fieldName); } @@ -210,7 +223,7 @@ private Qualifier processCollection(Part part, Object value1, Object value2, Ite List params = new ArrayList<>(); parametersIterator.forEachRemaining(params::add); - validateCollectionQuery(op, value1, value2, params); + validateCollectionQuery(op, value1, value2, params, part.getProperty()); Qualifier.QualifierBuilder qb = Qualifier.builder(); if (!params.isEmpty()) { @@ -231,32 +244,39 @@ private Object convertNullParameter(Object value) { return (value == NULL) ? null : value; } - private void validateCollectionQuery(FilterOperation op, Object value1, Object value2, List params) { + private void validateCollectionQuery(FilterOperation op, Object value1, Object value2, List params, + PropertyPath property) { + String queryPartDescription = String.join(" ", property.toString(), op.toString()); switch (op) { - case CONTAINING, NOT_CONTAINING -> validateCollectionQueryContaining(value1, params); - case EQ, NOTEQ, GT, GTEQ, LT, LTEQ -> validateCollectionQueryComparison(value1, params); - case BETWEEN -> validateCollectionQueryBetween(value1, value2, params); + case CONTAINING, NOT_CONTAINING -> validateCollectionQueryContaining(value1, params, queryPartDescription); + case EQ, NOTEQ, GT, GTEQ, LT, LTEQ -> validateCollectionQueryComparison(value1, params, + queryPartDescription); + case BETWEEN -> validateCollectionQueryBetween(value1, value2, params, queryPartDescription); + default -> throw new UnsupportedOperationException( + String.format("Unsupported operation: %s applied to %s", op, property)); } } - private void validateCollectionQueryComparison(Object value1, List params) { + private void validateCollectionQueryComparison(Object value1, List params, String queryPartDescription) { // Other than 1 argument if (getArgumentsSize(value1, params) != 1) { - throw new IllegalArgumentException("Invalid number of arguments: expecting one"); + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, expecting one"); } } - private void validateCollectionQueryContaining(Object value1, List params) { + private void validateCollectionQueryContaining(Object value1, List params, String queryPartDescription) { // No arguments if (getArgumentsSize(value1, params) == 0) { - throw new IllegalArgumentException("Invalid number of arguments: expecting at least one"); + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, expecting at " + + "least one"); } } - private void validateCollectionQueryBetween(Object value1, Object value2, List params) { + private void validateCollectionQueryBetween(Object value1, Object value2, List params, + String queryPartDescription) { // No arguments if (getArgumentsSize(value1, value2, params) != 2) { - throw new IllegalArgumentException("Invalid number of arguments: expecting two"); + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, expecting two"); } } @@ -267,7 +287,7 @@ private Qualifier processMap(Part part, Object value1, Object value2, Iterator params) { + private void validateMapQuery(FilterOperation op, Object value1, Object value2, List params, + PropertyPath property) { + String queryPartDescription = String.join(" ", property.toString(), op.toString()); switch (op) { - case CONTAINING, NOT_CONTAINING -> validateMapQueryContaining(value1, params); - case EQ, NOTEQ -> validateMapQueryEquals(value1, params); - case GT, GTEQ, LT, LTEQ -> validateMapQueryComparison(value1, params); - case BETWEEN -> validateMapQueryBetween(value1, value2, params); + case CONTAINING, NOT_CONTAINING -> validateMapQueryContaining(value1, params, queryPartDescription); + case EQ, NOTEQ -> validateMapQueryEquals(value1, params, queryPartDescription); + case GT, GTEQ, LT, LTEQ -> validateMapQueryComparison(value1, params, queryPartDescription); + case BETWEEN -> validateMapQueryBetween(value1, value2, params, queryPartDescription); + case LIKE, STARTS_WITH, ENDS_WITH -> validateMapQueryLike(value1, value2, params, queryPartDescription); + default -> throw new UnsupportedOperationException( + String.format("Unsupported operation: %s applied to %s", op, property)); } } - private void validateMapQueryContaining(Object value1, List params) { + private void validateMapQueryContaining(Object value1, List params, String queryPartDescription) { // Less than two arguments, including a case when value1 intentionally equals null if (params.isEmpty()) { - throw new IllegalArgumentException("Invalid number of arguments: at least two arguments are required"); + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, at least two " + + "arguments are required"); } + // Two or more arguments of type MapCriteria if (value1 instanceof AerospikeMapQueryCriteria && hasMultipleMapCriteria(value1, params)) { - throw new IllegalArgumentException("Invalid combination of arguments: cannot have multiple MapCriteria " + + throw new IllegalArgumentException(queryPartDescription + ": invalid combination of arguments, cannot " + + "have multiple MapCriteria " + "arguments"); } + // Odd number of arguments when none are MapCriteria if (getArgumentsSize(value1, params) % 2 != 0 && !hasMapCriteria(value1, params)) { - throw new IllegalArgumentException("Invalid combination of arguments: " + + throw new IllegalArgumentException(queryPartDescription + ": invalid combination of arguments, " + "one AerospikeMapCriteria argument is required"); } + // Even number of arguments, no MapCriteria, checking for allowed types in odd positions (keys) if (getArgumentsSize(value1, params) % 2 == 0 && !hasMapCriteria(value1, params)) { List list = new ArrayList<>(params); list.add(0, value1); for (int i = 0; i < list.size(); i += 2) { if (!(isAllowedMapKeyType(list.get(i)))) { - throw new IllegalArgumentException("Invalid argument type: expected String, Number or byte[] at " + + throw new IllegalArgumentException(queryPartDescription + ": invalid argument type, expected " + + "String, Number or byte[] at " + "position " + (i + 1)); } } @@ -359,22 +390,25 @@ private boolean hasMultipleMapCriteria(List params) { .count() > 1; } - private void validateMapQueryEquals(Object value1, List params) { + private void validateMapQueryEquals(Object value1, List params, String queryPartDescription) { // Only one argument which is not a Map if (params.isEmpty() && !(value1 instanceof Map)) { - throw new IllegalArgumentException("Invalid combination of arguments: expecting either a Map or a " + + throw new IllegalArgumentException(queryPartDescription + ": invalid combination of arguments, expecting " + + "either a Map or a " + "key-value pair"); } // More than 2 arguments if (getArgumentsSize(value1, params) > 2) { - throw new IllegalArgumentException("Invalid number of arguments: expecting either a Map or a key-value " + + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, expecting " + + "either a Map or a key-value " + "pair"); } // 2 arguments of type Map if (getArgumentsSize(value1, params) == 2 && getArgumentsMapsSize(value1, params) > 1) { - throw new IllegalArgumentException("Invalid combination of arguments: expecting either a Map or a " + + throw new IllegalArgumentException(queryPartDescription + ": invalid combination of arguments, expecting " + + "either a Map or a " + "key-value pair"); } } @@ -386,41 +420,56 @@ private long getArgumentsMapsSize(Object value1, List params) { .count(); } - private void validateMapQueryComparison(Object value1, List params) { - // More than two arguments + private void validateMapQueryComparison(Object value1, List params, String queryPartDescription) { long argumentsSize = getArgumentsSize(value1, params); + + // More than two arguments if (argumentsSize > 2) { - throw new IllegalArgumentException("Invalid number of arguments: expecting one (Map) or two (Map key and " + + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, expecting one " + + "(Map) or two (Map key and " + "value)"); } // One argument not of type Map if (argumentsSize == 1 && !(value1 instanceof Map)) { - throw new IllegalArgumentException("Invalid combination of arguments: expecting one (Map) or two (Map key" + + throw new IllegalArgumentException(queryPartDescription + ": invalid combination of arguments, expecting " + + "one (Map) or two (Map key" + " and value)"); } // Two arguments, checking whether first argument's type is allowed if (argumentsSize == 2 && !isAllowedMapKeyType(value1)) { - throw new IllegalArgumentException("Invalid first argument type: expected String, Number or byte[]"); + throw new IllegalArgumentException(queryPartDescription + ": invalid first argument type, expected " + + "String, Number or byte[]"); } } - private void validateMapQueryBetween(Object value1, Object value2, List params) { + private void validateMapQueryBetween(Object value1, Object value2, List params, + String queryPartDescription) { // Number of arguments is less than two or greater than three long argumentsSize = getArgumentsSize(value1, value2, params); if (argumentsSize < 2 || argumentsSize > 3) { - throw new IllegalArgumentException("Invalid number of arguments: expecting two (Maps) or three (Map key " + - "and two values)"); + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, expecting two " + + "(Maps) or three (Map key and two values)"); } // Two arguments when at least one of them is not a Map if (queryHasOnlyBothValues(value1, value2, params) && (!(value1 instanceof Map) || !(value2 instanceof Map))) { - throw new IllegalArgumentException("Invalid combination of arguments: both must be of type Map"); + throw new IllegalArgumentException(queryPartDescription + ": invalid combination of arguments, both must " + + "be of type Map"); } } + private void validateMapQueryLike(Object value1, Object value2, List params, String queryPartDescription) { + // Number of arguments is not two + if (getArgumentsSize(value1, value2, params) != 2) { + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, " + + "expecting two (a key and an expression to compare with)"); + } + + } + private boolean queryHasOnlyBothValues(Object value1, Object value2, List params) { return params.size() == 0 && value1 != null && value2 != null; } @@ -556,9 +605,9 @@ private Qualifier processOther(Part part, Object value1, Object value2, if (part.getProperty().hasNext()) { // if it is a POJO field (a simple type field or an inner POJO) PropertyPath nestedProperty = getNestedPropertyPath(part.getProperty()); if (isPojo(nestedProperty.getType())) { - validatePojoQuery(op, value1, value2); + validatePojoQuery(op, value1, value2, nestedProperty); } else { - validateSimplePropertyQuery(op, value1, value2); + validateSimplePropertyQuery(op, value1, value2, part.getProperty()); } if (op == FilterOperation.BETWEEN) { @@ -572,14 +621,14 @@ private Qualifier processOther(Part part, Object value1, Object value2, value2 = Value.get(property.getFieldName()); // VALUE2 contains key (field name) dotPath = List.of(part.getProperty().toDotPath()); } else if (isPojo(part.getProperty().getType())) { // if it is a first level POJO - validatePojoQuery(op, value1, value2); + validatePojoQuery(op, value1, value2, part.getProperty()); if (op != FilterOperation.BETWEEN) { // if it is a POJO compared for equality it already has op == FilterOperation.EQ value2 = Value.get(property.getFieldName()); // VALUE2 contains key (field name) } } else { - validateSimplePropertyQuery(op, value1, value2); + validateSimplePropertyQuery(op, value1, value2, part.getProperty()); } return setQualifier(qb, fieldName, op, part, value1, value2, value3, dotPath); @@ -605,50 +654,76 @@ private PropertyPath getNestedPropertyPath(PropertyPath propertyPath) { return result; } - private void validatePojoQuery(FilterOperation op, Object value1, Object value2) { + private void validatePojoQuery(FilterOperation op, Object value1, Object value2, PropertyPath nestedProperty) { + String queryPartDescription = String.join(" ", nestedProperty.toString(), op.toString()); switch (op) { case CONTAINING, NOT_CONTAINING -> throw new UnsupportedOperationException("Unsupported operation, " + "please use queries like 'findByPojoField()' directly addressing the required fields"); - case EQ, NOTEQ -> validatePojoQueryEquals(value1); - case GT, GTEQ, LT, LTEQ -> validatePojoQueryComparison(value1); - case BETWEEN -> validatePojoQueryBetween(value1, value2); + case EQ, NOTEQ -> validatePojoQueryEquals(value1, queryPartDescription); + case GT, GTEQ, LT, LTEQ -> validatePojoQueryComparison(value1, queryPartDescription); + case BETWEEN -> validatePojoQueryBetween(value1, value2, queryPartDescription); + case IN, NOT_IN -> validatePojoQueryIn(value1, value2, queryPartDescription); + case IS_NOT_NULL, IS_NULL -> validatePojoQueryIsNull(value1, value2, queryPartDescription); + default -> throw new UnsupportedOperationException( + String.format("Unsupported operation: %s applied to %s", op, nestedProperty)); } } - private void validateSimplePropertyQuery(FilterOperation op, Object value1, Object value2) { + private void validateSimplePropertyQuery(FilterOperation op, Object value1, Object value2, PropertyPath property) { + String queryPartDescription = String.join(" ", property.toString(), op.toString()); switch (op) { - case CONTAINING, NOT_CONTAINING, GT, GTEQ, LT, LTEQ -> - validateSimplePropertyQueryComparison(value1, value2); - case EQ, NOTEQ -> validateSimplePropertyQueryEquals(value1, value2); - case BETWEEN -> validateSimplePropertyQueryBetween(value1, value2); + case CONTAINING, NOT_CONTAINING, GT, GTEQ, LT, LTEQ, LIKE, STARTS_WITH, ENDS_WITH, IN, NOT_IN -> + validateSimplePropertyQueryComparison(value1, value2, queryPartDescription); + case EQ, NOTEQ -> validateSimplePropertyQueryEquals(value1, value2, queryPartDescription); + case BETWEEN -> validateSimplePropertyQueryBetween(value1, value2, queryPartDescription); + case IS_NOT_NULL, IS_NULL -> validateSimplePropertyQueryIsNull(value1, value2, queryPartDescription); + default -> throw new UnsupportedOperationException( + String.format("Unsupported operation: %s applied to %s", op, property)); } } - private void validateSimplePropertyQueryEquals(Object value1, Object value2) { + private void validateSimplePropertyQueryEquals(Object value1, Object value2, String queryPartDescription) { // No arguments if (getArgumentsSize(value1, value2) == 0) { - throw new IllegalArgumentException("Invalid number of arguments: expecting at least one"); + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, expecting at " + + "least one"); } } - private void validateSimplePropertyQueryComparison(Object value1, Object value2) { + private void validateSimplePropertyQueryComparison(Object value1, Object value2, String queryPartDescription) { // Number of arguments is not one if (getArgumentsSize(value1, value2) != 1) { - throw new IllegalArgumentException("Invalid number of arguments: expecting one"); + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, expecting one"); } } - private void validateSimplePropertyQueryBetween(Object value1, Object value2) { + private void validateSimplePropertyQueryBetween(Object value1, Object value2, String queryPartDescription) { // Number of arguments is not two if (getArgumentsSize(value1, value2) != 2) { - throw new IllegalArgumentException("Invalid number of arguments: expecting two POJOs"); + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, expecting two " + + "POJOs"); } } - private void validatePojoQueryEquals(Object value1) { - // No parameter + private void validateSimplePropertyQueryIn(Object value1, Object value2, String queryPartDescription) { + // Number of arguments is not one + if (getArgumentsSize(value1, value2) != 1) { + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, expecting one"); + } + } + + private void validateSimplePropertyQueryIsNull(Object value1, Object value2, String queryPartDescription) { + // Number of arguments is not zero + if (getArgumentsSize(value1, value2) != 0) { + throw new IllegalArgumentException(queryPartDescription + ": expecting no arguments"); + } + } + + private void validatePojoQueryEquals(Object value1, String queryPartDescription) { + // No arguments if (value1 == null) { - throw new IllegalArgumentException("Invalid number of arguments: expecting one POJO"); + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, expecting one " + + "POJO"); } // Checking whether the argument is of the following type: @@ -656,15 +731,16 @@ private void validatePojoQueryEquals(Object value1) { // a UUID, a URI, a URL, a Locale, or a Class Class class1 = value1.getClass(); if (isSimpleValueType(class1)) { - throw new IllegalArgumentException(String.format("Invalid arguments type: expecting a POJO, instead " + - "got %s", class1.getSimpleName())); + throw new IllegalArgumentException(String.format("%s: invalid arguments type, expecting a POJO, instead " + + "got %s", queryPartDescription, class1.getSimpleName())); } } - private void validatePojoQueryComparison(Object value1) { - // No parameter + private void validatePojoQueryComparison(Object value1, String queryPartDescription) { + // No arguments if (value1 == null) { - throw new IllegalArgumentException("Invalid number of arguments: expecting one POJO"); + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, expecting one " + + "POJO"); } // Checking whether the argument is of the following type: @@ -672,15 +748,16 @@ private void validatePojoQueryComparison(Object value1) { // a UUID, a URI, a URL, a Locale, or a Class Class class1 = value1.getClass(); if (isSimpleValueType(class1)) { - throw new IllegalArgumentException(String.format("Invalid arguments type: expecting a POJO, instead " + - "got %s", class1.getSimpleName())); + throw new IllegalArgumentException(String.format("%s: invalid arguments type: expecting a POJO, instead " + + "got %s", queryPartDescription, class1.getSimpleName())); } } - private void validatePojoQueryBetween(Object value1, Object value2) { + private void validatePojoQueryBetween(Object value1, Object value2, String queryPartDescription) { // Number of arguments is not two if (getArgumentsSize(value1, value2) != 2) { - throw new IllegalArgumentException("Invalid number of arguments: expecting two POJOs"); + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, expecting two " + + "POJOs"); } // Checking whether at least one of the arguments is of the following type: @@ -689,8 +766,22 @@ private void validatePojoQueryBetween(Object value1, Object value2) { Class class1 = value1.getClass(); Class class2 = value2.getClass(); if (isSimpleValueType(class1) || isSimpleValueType(class2)) { - throw new IllegalArgumentException(String.format("Invalid arguments type: expecting two POJOs, instead " + - "got %s and %s", class1.getSimpleName(), class2.getSimpleName())); + throw new IllegalArgumentException(String.format("%s: invalid arguments type, expecting two POJOs, " + + "instead got %s and %s", queryPartDescription, class1.getSimpleName(), class2.getSimpleName())); + } + } + + private void validatePojoQueryIn(Object value1, Object value2, String queryPartDescription) { + // Number of arguments is not one + if (getArgumentsSize(value1, value2) != 1) { + throw new IllegalArgumentException(queryPartDescription + ": invalid number of arguments, expecting one"); + } + } + + private void validatePojoQueryIsNull(Object value1, Object value2, String queryPartDescription) { + // Number of arguments is not zero + if (getArgumentsSize(value1, value2) != 0) { + throw new IllegalArgumentException(queryPartDescription + ": expecting no arguments"); } } @@ -785,25 +876,20 @@ private void setQbValuesForMapByKey(Qualifier.QualifierBuilder qb, Object key, O qb.setValue2(Value.get(key)); // contains key } - private boolean isPojo(Class clazz) { // if it is a first level POJO + private boolean isPojo(Class clazz) { // if it is a first level POJO or a Map TypeInformation type = TypeInformation.of(clazz); - // returns true if it is a POJO or a Map -// return !converter.getCustomConversions().isSimpleType(part.getProperty().getType()) && !type -// .isCollectionLike(); return !Utils.isSimpleValueType(clazz) && !type.isCollectionLike(); } @Override protected CriteriaDefinition and(Part part, CriteriaDefinition base, Iterator iterator) { + CriteriaDefinition criteriaDefinition = create(part, iterator); + if (base == null) { - return create(part, iterator); + return criteriaDefinition; } - PersistentPropertyPath path = - context.getPersistentPropertyPath(part.getProperty()); - AerospikePersistentProperty property = path.getLeafProperty(); - - return Qualifier.and(base.getCriteriaObject(), create(part, property, iterator).getCriteriaObject()); + return Qualifier.and(base.getCriteriaObject(), criteriaDefinition.getCriteriaObject()); } @Override diff --git a/src/test/java/org/springframework/data/aerospike/query/reactive/ReactiveIndexedPersonRepositoryQueryTests.java b/src/test/java/org/springframework/data/aerospike/query/reactive/ReactiveIndexedPersonRepositoryQueryTests.java index a3a176489..4c3948567 100644 --- a/src/test/java/org/springframework/data/aerospike/query/reactive/ReactiveIndexedPersonRepositoryQueryTests.java +++ b/src/test/java/org/springframework/data/aerospike/query/reactive/ReactiveIndexedPersonRepositoryQueryTests.java @@ -8,8 +8,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.aerospike.AsCollections; import org.springframework.data.aerospike.BaseReactiveIntegrationTests; import org.springframework.data.aerospike.ReactiveBlockingAerospikeTestOperations; +import org.springframework.data.aerospike.query.CombinedQueryParam; import org.springframework.data.aerospike.query.FilterOperation; import org.springframework.data.aerospike.query.Qualifier; import org.springframework.data.aerospike.repository.query.CriteriaDefinition; @@ -30,7 +32,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.springframework.data.aerospike.AsCollections.of; import static org.springframework.data.aerospike.repository.query.CriteriaDefinition.AerospikeMapQueryCriteria.VALUE; import static org.springframework.data.aerospike.repository.query.CriteriaDefinition.AerospikeMetadata.SINCE_UPDATE_TIME; @@ -41,19 +42,19 @@ public class ReactiveIndexedPersonRepositoryQueryTests extends BaseReactiveInteg .age(42).strings(Arrays.asList("str1", "str2")) .address(new Address("Foo Street 1", 1, "C0123", "Bar")).build(); static final IndexedPerson luc = IndexedPerson.builder().id(nextId()).firstName("Luc").lastName("Besson").age(39) - .stringMap(of("key1", "val1", "key2", "val2")).address(new Address(null, null, null, null)) + .stringMap(AsCollections.of("key1", "val1", "key2", "val2")).address(new Address(null, null, null, null)) .build(); static final IndexedPerson lilly = IndexedPerson.builder().id(nextId()).firstName("Lilly").lastName("Bertineau") - .age(28).intMap(of("key1", 1, "key2", 2)) + .age(28).intMap(AsCollections.of("key1", 1, "key2", 2)) .address(new Address("Foo Street 2", 2, "C0124", "C0123")).build(); static final IndexedPerson daniel = IndexedPerson.builder().id(nextId()).firstName("Daniel").lastName("Morales") .age(29).ints(Arrays.asList(500, 550, 990)).build(); static final IndexedPerson petra = IndexedPerson.builder().id(nextId()).firstName("Petra") .lastName("Coutant-Kerbalec") - .age(34).stringMap(of("key1", "val1", "key2", "val2", "key3", "val3")).build(); + .age(34).stringMap(AsCollections.of("key1", "val1", "key2", "val2", "key3", "val3")).build(); static final IndexedPerson emilien = IndexedPerson.builder().id(nextId()).firstName("Emilien") .lastName("Coutant-Kerbalec").age(30) - .intMap(of("key1", 0, "key2", 1)).ints(Arrays.asList(450, 550, 990)).build(); + .intMap(AsCollections.of("key1", 0, "key2", 1)).ints(Arrays.asList(450, 550, 990)).build(); public static final List allIndexedPersons = Arrays.asList(alain, luc, lilly, daniel, petra, emilien); @Autowired @@ -230,7 +231,9 @@ void findDistinctByFriendLastNameStartingWith() { @Test public void findPersonsByFirstnameAndByAge() { - List results = reactiveRepository.findByFirstNameAndAge("Lilly", 28) + CombinedQueryParam firstName = CombinedQueryParam.of("Lilly"); + CombinedQueryParam age = CombinedQueryParam.of(28); + List results = reactiveRepository.findByFirstNameAndAge(firstName, age) .subscribeOn(Schedulers.parallel()).collectList().block(); assertThat(results).containsOnly(lilly); diff --git a/src/test/java/org/springframework/data/aerospike/repository/IndexedPersonRepositoryQueryTests.java b/src/test/java/org/springframework/data/aerospike/repository/IndexedPersonRepositoryQueryTests.java index 3b7305e53..f4bbc9691 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/IndexedPersonRepositoryQueryTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/IndexedPersonRepositoryQueryTests.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.TestInstance; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.aerospike.BaseBlockingIntegrationTests; +import org.springframework.data.aerospike.query.CombinedQueryParam; import org.springframework.data.aerospike.query.model.Index; import org.springframework.data.aerospike.repository.query.CriteriaDefinition; import org.springframework.data.aerospike.sample.Address; @@ -233,7 +234,9 @@ public void findsPersonsByFirstName() { @Test public void findsPersonsByActiveAndFirstName() { assertThat(tricia.isActive()).isFalse(); - List result = repository.findByIsActiveAndFirstName(false, "Tricia"); + CombinedQueryParam isActive = CombinedQueryParam.of(false); + CombinedQueryParam firstNames = CombinedQueryParam.of("Tricia"); + List result = repository.findByIsActiveAndFirstName(isActive, firstNames); assertThat(result) .hasSize(1) @@ -310,10 +313,14 @@ public void findByAgeGreaterThan_forEmptyResult() { @Test public void findsPersonsByFirstNameAndByAge() { - List result = repository.findByFirstNameAndAge("Billy", 25); + CombinedQueryParam firstNames = CombinedQueryParam.of("Billy"); + CombinedQueryParam ages = CombinedQueryParam.of(25); + List result = repository.findByFirstNameAndAge(firstNames, ages); assertThat(result).containsOnly(billy); - result = repository.findByFirstNameAndAge("Peter", 41); + firstNames = CombinedQueryParam.of("Peter"); + ages = CombinedQueryParam.of(41); + result = repository.findByFirstNameAndAge(firstNames, ages); assertThat(result).containsOnly(peter); } @@ -331,19 +338,27 @@ public void findsPersonInAgeRangeCorrectlyOrderByLastName() { @Test public void findsPersonInAgeRangeAndNameCorrectly() { - Iterable it = repository.findByAgeBetweenAndLastName(40, 45, "Matthews"); + CombinedQueryParam ageBetween = CombinedQueryParam.of(40, 45); + CombinedQueryParam lastNames = CombinedQueryParam.of("Matthews"); + Iterable it = repository.findByAgeBetweenAndLastName(ageBetween, lastNames); assertThat(it).hasSize(0); - Iterable result = repository.findByAgeBetweenAndLastName(20, 26, "Smith"); + ageBetween = CombinedQueryParam.of(20, 26); + lastNames = CombinedQueryParam.of("Smith"); + Iterable result = repository.findByAgeBetweenAndLastName(ageBetween, lastNames); assertThat(result).hasSize(1).contains(billy); } @Test public void findsPersonInAgeRangeOrNameCorrectly() { - Iterable it = repository.findByAgeBetweenOrLastName(40, 45, "James"); + CombinedQueryParam ageBetween = CombinedQueryParam.of(40, 45); + CombinedQueryParam lastNames = CombinedQueryParam.of("James"); + Iterable it = repository.findByAgeBetweenOrLastName(ageBetween, lastNames); assertThat(it).containsExactlyInAnyOrder(john, peter, tricia); - Iterable result = repository.findByAgeBetweenOrLastName(20, 26, "Macintosh"); + ageBetween = CombinedQueryParam.of(20, 26); + lastNames = CombinedQueryParam.of("Macintosh"); + Iterable result = repository.findByAgeBetweenOrLastName(ageBetween, lastNames); assertThat(result).containsExactlyInAnyOrder(billy, peter); } diff --git a/src/test/java/org/springframework/data/aerospike/repository/PersonRepositoryQueryTests.java b/src/test/java/org/springframework/data/aerospike/repository/PersonRepositoryQueryTests.java index e31e92708..56a33c1a5 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/PersonRepositoryQueryTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/PersonRepositoryQueryTests.java @@ -6,7 +6,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.aerospike.AsCollections; import org.springframework.data.aerospike.BaseBlockingIntegrationTests; +import org.springframework.data.aerospike.query.CombinedQueryParam; import org.springframework.data.aerospike.query.FilterOperation; import org.springframework.data.aerospike.query.Qualifier; import org.springframework.data.aerospike.repository.query.Query; @@ -40,7 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.springframework.data.aerospike.AsCollections.of; +import static org.springframework.data.aerospike.query.CombinedQueryParam.of; import static org.springframework.data.aerospike.repository.query.CriteriaDefinition.AerospikeMapQueryCriteria.KEY; import static org.springframework.data.aerospike.repository.query.CriteriaDefinition.AerospikeMapQueryCriteria.VALUE; import static org.springframework.data.aerospike.repository.query.CriteriaDefinition.AerospikeMapQueryCriteria.VALUE_CONTAINING; @@ -54,16 +56,16 @@ public class PersonRepositoryQueryTests extends BaseBlockingIntegrationTests { .strings(List.of("str0", "str1", "str2")).address(new Address("Foo Street 1", 1, "C0123", "Bar")) .build(); static final Person donny = Person.builder().id(nextId()).firstName("Donny").lastName("Macintire").age(39) - .strings(List.of("str1", "str2", "str3")).stringMap(of("key1", "val1")).build(); + .strings(List.of("str1", "str2", "str3")).stringMap(AsCollections.of("key1", "val1")).build(); static final Person oliver = Person.builder().id(nextId()).firstName("Oliver August").lastName("Matthews").age(14) .ints(List.of(425, 550, 990)).build(); static final Person alicia = Person.builder().id(nextId()).firstName("Alicia").lastName("Keys").age(30) .ints(List.of(550, 600, 990)).build(); static final Person carter = Person.builder().id(nextId()).firstName("Carter").lastName("Beauford").age(49) - .intMap(of("key1", 0, "key2", 1)) + .intMap(AsCollections.of("key1", 0, "key2", 1)) .address(new Address("Foo Street 2", 2, "C0124", "C0123")).build(); static final Person boyd = Person.builder().id(nextId()).firstName("Boyd").lastName("Tinsley").age(45) - .stringMap(of("key1", "val1", "key2", "val2")).address(new Address(null, null, null, null)) + .stringMap(AsCollections.of("key1", "val1", "key2", "val2")).address(new Address(null, null, null, null)) .build(); static final Person stefan = Person.builder().id(nextId()).firstName("Stefan").lastName("Lessard").age(34).build(); static final Person leroi = Person.builder().id(nextId()).firstName("Leroi").lastName("Moore").age(44) @@ -198,11 +200,11 @@ void findByListNotContainingAddress() { void findPersonsByIntsListContainingNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByIntsContaining()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting at least one"); + .hasMessage("Person.ints CONTAINING: invalid number of arguments, expecting at least one"); assertThatThrownBy(() -> negativeTestsRepository.findByIntsNotContaining()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting at least one"); + .hasMessage("Person.ints NOT_CONTAINING: invalid number of arguments, expecting at least one"); } @Test @@ -250,6 +252,13 @@ void findByBoolean() { repository.delete(intBoolBinPerson); } + @Test + void findByBooleanNegativeTest() { + assertThatThrownBy(() -> negativeTestsRepository.findByIsActive()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Person.isActive EQ: invalid number of arguments, expecting at least one"); + } + @Test void findByListValueLessThanOrEqualNumber() { List persons; @@ -438,11 +447,11 @@ void findByStringListInRange() { void findByIntListBetweenNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByIntsBetween()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting two"); + .hasMessage("Person.ints BETWEEN: invalid number of arguments, expecting two"); assertThatThrownBy(() -> negativeTestsRepository.findByIntsBetween(100)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting two"); + .hasMessage("Person.ints BETWEEN: invalid number of arguments, expecting two"); } @Test @@ -546,48 +555,58 @@ void findByStringMapKeyValueEquals() { void findByStringMapContainingNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByStringMapContaining()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: at least two arguments are required"); + .hasMessage("Person.stringMap CONTAINING: invalid number of arguments, at least two arguments are " + + "required"); assertThatThrownBy(() -> negativeTestsRepository.findByStringMapContaining("key1")) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: at least two arguments are required"); + .hasMessage("Person.stringMap CONTAINING: invalid number of arguments, at least two arguments are " + + "required"); assertThatThrownBy(() -> negativeTestsRepository.findByStringMapContaining(1100)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: at least two arguments are required"); + .hasMessage("Person.stringMap CONTAINING: invalid number of arguments, at least two arguments are " + + "required"); assertThatThrownBy(() -> negativeTestsRepository.findByStringMapContaining(KEY, VALUE)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid combination of arguments: cannot have multiple MapCriteria arguments"); + .hasMessage("Person.stringMap CONTAINING: invalid combination of arguments, cannot have multiple " + + "MapCriteria arguments"); assertThatThrownBy(() -> negativeTestsRepository.findByStringMapContaining("key", "value", new Person("id", "firstName"), "value")) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid argument type: expected String, Number or byte[] at position 3"); + .hasMessage("Person.stringMap CONTAINING: invalid argument type, expected String, Number or byte[] at " + + "position 3"); } @Test void findByStringMapNotContainingNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByStringMapNotContaining()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: at least two arguments are required"); + .hasMessage("Person.stringMap NOT_CONTAINING: invalid number of arguments, at least two arguments are " + + "required"); assertThatThrownBy(() -> negativeTestsRepository.findByStringMapNotContaining("key1")) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: at least two arguments are required"); + .hasMessage("Person.stringMap NOT_CONTAINING: invalid number of arguments, at least two arguments are " + + "required"); assertThatThrownBy(() -> negativeTestsRepository.findByStringMapNotContaining(1100)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: at least two arguments are required"); + .hasMessage("Person.stringMap NOT_CONTAINING: invalid number of arguments, at least two arguments are " + + "required"); assertThatThrownBy(() -> negativeTestsRepository.findByStringMapNotContaining(KEY, VALUE)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid combination of arguments: cannot have multiple MapCriteria arguments"); + .hasMessage("Person.stringMap NOT_CONTAINING: invalid combination of arguments, cannot have multiple " + + "MapCriteria arguments"); assertThatThrownBy(() -> negativeTestsRepository.findByStringMapNotContaining("key", "value", new Person("id" , "firstName"), "value")) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid argument type: expected String, Number or byte[] at position 3"); + .hasMessage("Person.stringMap NOT_CONTAINING: invalid argument type, expected String, Number or byte[] at" + + " position 3"); } @Test @@ -696,6 +715,13 @@ void findByExists() { repository.save(stefan); } +// @Test +// void findByExistsNegativeTest() { +// assertThatThrownBy(() -> negativeTestsRepository.findByAddressExists(new Address(null, null, null, null))) +// .isInstanceOf(IllegalArgumentException.class) +// .hasMessage("Expected CombinedQueryParam, instead got String"); +// } + @Test void findByIsNull() { assertThat(stefan.getAddress()).isNull(); @@ -745,20 +771,20 @@ void findByIsNull() { @Test void findByIsNotNull() { -// assertThat(stefan.getAddress()).isNull(); -// assertThat(carter.getAddress()).isNotNull(); -// assertThat(dave.getAddress()).isNotNull(); -// assertThat(repository.findByAddressIsNotNull()).contains(carter, dave).doesNotContain(stefan); -// -// stefan.setAddress(new Address(null, null, "zipCode", null)); -// repository.save(stefan); -// assertThat(repository.findByAddressIsNotNull()).contains(stefan); // Address is not null -// assertThat(repository.findByAddressZipCodeIsNotNull()).contains(stefan); // zipCode is not null -// -// stefan.setAddress(new Address(null, null, null, null)); -// repository.save(stefan); -// assertThat(repository.findByAddressIsNotNull()).contains(stefan); // Address is not null -// assertThat(repository.findByAddressZipCodeIsNotNull()).doesNotContain(stefan); // zipCode is null + assertThat(stefan.getAddress()).isNull(); + assertThat(carter.getAddress()).isNotNull(); + assertThat(dave.getAddress()).isNotNull(); + assertThat(repository.findByAddressIsNotNull()).contains(carter, dave).doesNotContain(stefan); + + stefan.setAddress(new Address(null, null, "zipCode", null)); + repository.save(stefan); + assertThat(repository.findByAddressIsNotNull()).contains(stefan); // Address is not null + assertThat(repository.findByAddressZipCodeIsNotNull()).contains(stefan); // zipCode is not null + + stefan.setAddress(new Address(null, null, null, null)); + repository.save(stefan); + assertThat(repository.findByAddressIsNotNull()).contains(stefan); // Address is not null + assertThat(repository.findByAddressZipCodeIsNotNull()).doesNotContain(stefan); // zipCode is null stefan.setAddress(null); // cleanup repository.save(stefan); @@ -962,15 +988,17 @@ void findByMapKeyValueLessThanOrEqual() { void findByMapComparisonNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByIntMapLessThan(100)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid combination of arguments: expecting one (Map) or two (Map key and value)"); + .hasMessage("Person.intMap LT: invalid combination of arguments, expecting one (Map) or two (Map key and " + + "value)"); assertThatThrownBy(() -> negativeTestsRepository.findByIntMapLessThanEqual(100, 200, 300)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one (Map) or two (Map key and value)"); + .hasMessage("Person.intMap LTEQ: invalid number of arguments, expecting one (Map) or two (Map key and " + + "value)"); assertThatThrownBy(() -> negativeTestsRepository.findByIntMapGreaterThan(new Person("id1", "name1"), 400)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid first argument type: expected String, Number or byte[]"); + .hasMessage("Person.intMap GT: invalid first argument type, expected String, Number or byte[]"); } @Test @@ -1084,23 +1112,26 @@ void findByIntMapBetween() { void findByIntMapBetweenNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByIntMapBetween()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting two (Maps) or three (Map key and two values)"); + .hasMessage("Person.intMap BETWEEN: invalid number of arguments, expecting two (Maps) or three (Map key " + + "and two values)"); assertThatThrownBy(() -> negativeTestsRepository.findByIntMapBetween(100)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting two (Maps) or three (Map key and two values)"); + .hasMessage("Person.intMap BETWEEN: invalid number of arguments, expecting two (Maps) or three (Map key " + + "and two values)"); assertThatThrownBy(() -> negativeTestsRepository.findByIntMapBetween(100, Map.of(200, 300))) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid combination of arguments: both must be of type Map"); + .hasMessage("Person.intMap BETWEEN: invalid combination of arguments, both must be of type Map"); assertThatThrownBy(() -> negativeTestsRepository.findByIntMapBetween(100, 200)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid combination of arguments: both must be of type Map"); + .hasMessage("Person.intMap BETWEEN: invalid combination of arguments, both must be of type Map"); assertThatThrownBy(() -> negativeTestsRepository.findByIntMapBetween(100, 200, 300, 400)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting two (Maps) or three (Map key and two values)"); + .hasMessage("Person.intMap BETWEEN: invalid number of arguments, expecting two (Maps) or three (Map key " + + "and two values)"); } @Test @@ -1347,32 +1378,40 @@ void deleteAllPersonsFromList() { @Test void findPersonByIdsAndFields() { -// List persons = repository.findByIdAndFirstName(List.of(boyd.getId(), dave.getId(), carter.getId()), -// dave.getFirstName()); -// assertThat(persons).containsOnly(dave); + CombinedQueryParam ids = of(List.of(boyd.getId(), dave.getId(), carter.getId())); + CombinedQueryParam names = of(dave.getFirstName()); + List persons = repository.findByIdAndFirstName(ids, names); + assertThat(persons).containsOnly(dave); - List persons2 = repository.findByIdAndFirstNameAndAge(List.of(leroi.getId(), leroi2.getId(), - carter.getId()), leroi.getFirstName(), leroi2.getAge()); + ids = of(List.of(leroi.getId(), leroi2.getId(), carter.getId())); + CombinedQueryParam firstNames = of(leroi.getFirstName()); + CombinedQueryParam ages = of(leroi2.getAge()); + List persons2 = repository.findByIdAndFirstNameAndAge(ids, firstNames, ages); assertThat(persons2).containsOnly(leroi2); // "findByIdOr..." will return empty list because primary keys are used to firstly narrow down the results.parts // In a combined id query "OR" can be put only between the non-id fields like shown below, // and the results are limited by the given ids - List persons3 = repository.findByIdAndFirstNameOrAge(List.of(leroi.getId(), leroi2.getId(), - carter.getId()), - leroi.getFirstName(), leroi2.getAge()); + ids = of(List.of(leroi.getId(), leroi2.getId(), + carter.getId())); + firstNames = of(leroi.getFirstName()); + ages = of(leroi2.getAge()); + List persons3 = repository.findByIdAndFirstNameOrAge(ids, firstNames, ages); assertThat(persons3).containsOnly(leroi, leroi2); - List persons4 = repository.findByIdAndFirstNameOrAge(List.of(leroi.getId(), leroi2.getId(), - carter.getId()), - leroi.getFirstName(), stefan.getAge()); + ids = of(List.of(leroi.getId(), leroi2.getId(), + carter.getId())); + firstNames = of(leroi.getFirstName()); + ages = of(stefan.getAge()); + List persons4 = repository.findByIdAndFirstNameOrAge(ids, firstNames, ages); assertThat(persons4).containsOnly(leroi, leroi2); } @Test void findPersonByIdsAndFirstNameEmptyResult() { - List persons = repository.findByIdAndFirstName(List.of(dave.getId(), boyd.getId()), - carter.getFirstName()); + CombinedQueryParam ids = of(List.of(dave.getId(), boyd.getId())); + CombinedQueryParam names = of(carter.getFirstName()); + List persons = repository.findByIdAndFirstName(ids, names); assertThat(persons).isEmpty(); } @@ -1656,31 +1695,34 @@ void findByIdDynamicProjection() { @Test void findByIdAndLastNameDynamicProjection() { - List result = repository.findByIdAndLastName(List.of(carter.getId(), leroi.getId(), - leroi2.getId()), carter.getLastName(), - PersonSomeFields.class); + CombinedQueryParam ids = of(List.of(boyd.getId(), dave.getId(), carter.getId())); + CombinedQueryParam lastNames = of(carter.getLastName()); + List result = repository.findByIdAndLastName(ids, lastNames, PersonSomeFields.class); assertThat(result).containsOnly(carter.toPersonSomeFields()); } @Test void findByIdAndLastNameDynamicProjectionNullResult() { - List result = repository.findByIdAndLastName(List.of(carter.getId(), boyd.getId()), - dave.getLastName(), - PersonSomeFields.class); + CombinedQueryParam ids = of(List.of(carter.getId(), boyd.getId())); + CombinedQueryParam lastNames = of(dave.getLastName()); + List result = repository.findByIdAndLastName(ids, lastNames, PersonSomeFields.class); assertThat(result).isEmpty(); } @Test void findByLastNameAndIdDynamicProjection() { - List result = repository.findByLastNameAndId(dave.getLastName(), - dave.getId(), PersonSomeFields.class); + CombinedQueryParam ids = of(dave.getId()); + CombinedQueryParam lastNames = of(dave.getLastName()); + List result = repository.findByLastNameAndId(lastNames, ids, PersonSomeFields.class); assertThat(result).containsOnly(dave.toPersonSomeFields()); } @Test void findByFirstNameAndLastNameDynamicProjection() { - List result = repository.findByFirstNameAndLastName(carter.getFirstName(), - carter.getLastName(), PersonSomeFields.class); + CombinedQueryParam firstNames = of(carter.getFirstName()); + CombinedQueryParam lastNames = of(carter.getLastName()); + List result = repository.findByFirstNameAndLastName(firstNames, lastNames, + PersonSomeFields.class); assertThat(result).containsOnly(carter.toPersonSomeFields()); } @@ -2049,13 +2091,29 @@ void findByLastNameStartingWith_limited() { @Test void findPersonsByFirstNameAndByAge() { - List result = repository.findByFirstNameAndAge("Leroi", 25); + CombinedQueryParam firstName = of("Leroi"); + CombinedQueryParam age = of(25); + List result = repository.findByFirstNameAndAge(firstName, age); assertThat(result).containsOnly(leroi2); - result = repository.findByFirstNameAndAge("Leroi", 44); + firstName = of("Leroi"); + age = of(44); + result = repository.findByFirstNameAndAge(firstName, age); assertThat(result).containsOnly(leroi); } + @Test + void findPersonsByFirstNameAndByAgeNegativeTest() { + assertThatThrownBy(() -> negativeTestsRepository.findByFirstNameAndAge("John", 100)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Person.firstName: expected CombinedQueryParam, instead got String"); + + CombinedQueryParam firstName = of("John"); + assertThatThrownBy(() -> negativeTestsRepository.findByFirstNameOrAge(firstName)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Person.age EQ: invalid number of arguments, expecting at least one"); + } + @Test void findPersonsByFirstNameStartsWith() { List result = repository.findByFirstNameStartsWith("D"); @@ -2129,20 +2187,22 @@ void findPersonInRangeCorrectly() { void findByPojoBetweenNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByAddressBetween()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting two POJOs"); + .hasMessage("Person.address BETWEEN: invalid number of arguments, expecting two POJOs"); assertThatThrownBy(() -> negativeTestsRepository.findByAddressBetween(100)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting two POJOs"); + .hasMessage("Person.address BETWEEN: invalid number of arguments, expecting two POJOs"); assertThatThrownBy(() -> negativeTestsRepository.findByAddressBetween(100, 200, 300)) .isInstanceOf(IllegalArgumentException.class) // .hasMessage("Invalid number of arguments: expecting two POJOs"); - .hasMessage("Invalid arguments type: expecting two POJOs, instead got Integer and Integer"); + .hasMessage("Person.address BETWEEN: invalid arguments type, expecting two POJOs, instead got Integer and" + + " Integer"); assertThatThrownBy(() -> negativeTestsRepository.findByAddressBetween(100, 200)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid arguments type: expecting two POJOs, instead got Integer and Integer"); + .hasMessage("Person.address BETWEEN: invalid arguments type, expecting two POJOs, instead got Integer and" + + " Integer"); } @Test @@ -2153,10 +2213,14 @@ void findPersonInAgeRangeCorrectlyOrderByLastName() { @Test void findPersonInAgeRangeAndNameCorrectly() { - Iterable it = repository.findByAgeBetweenAndLastName(40, 45, "Matthews"); + CombinedQueryParam ageBetween = of(40, 45); + CombinedQueryParam lastNames = of("Matthews"); + Iterable it = repository.findByAgeBetweenAndLastName(ageBetween, lastNames); assertThat(it).hasSize(1); - Iterable result = repository.findByAgeBetweenAndLastName(20, 26, "Moore"); + ageBetween = of(20, 26); + lastNames = of("Moore"); + Iterable result = repository.findByAgeBetweenAndLastName(ageBetween, lastNames); assertThat(result).hasSize(1); } @@ -2194,17 +2258,13 @@ void findPersonsByStringsList() { @Test void findPersonsByStringsListEqualsNegativeTest() { -// assertThatThrownBy(() -> negativeTestsRepository.findByStringsEquals(1000)) -// .isInstanceOf(IllegalArgumentException.class) -// .hasMessage("Invalid argument: type mismatch"); -// assertThatThrownBy(() -> negativeTestsRepository.findByStrings()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one"); + .hasMessage("Person.strings EQ: invalid number of arguments, expecting one"); assertThatThrownBy(() -> negativeTestsRepository.findByStringsEquals("string1", "string2")) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one"); + .hasMessage("Person.strings EQ: invalid number of arguments, expecting one"); } @Test @@ -2224,15 +2284,15 @@ void findPersonsByStringsListNotEqual() { void findPersonsByStringsListNotEqualNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByStringsIsNot()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one"); + .hasMessage("Person.strings NOTEQ: invalid number of arguments, expecting one"); assertThatThrownBy(() -> negativeTestsRepository.findByStringsIsNot("string1", "string2")) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one"); + .hasMessage("Person.strings NOTEQ: invalid number of arguments, expecting one"); assertThatThrownBy(() -> negativeTestsRepository.findByStringsIsNot(List.of("string1"), List.of("string2"))) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one"); + .hasMessage("Person.strings NOTEQ: invalid number of arguments, expecting one"); } @Test @@ -2272,16 +2332,16 @@ void findPersonsByStringsListGreaterThanOrEqual() { void findPersonsByStringsListComparisonNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByStringsLessThan()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one"); + .hasMessage("Person.strings LT: invalid number of arguments, expecting one"); assertThatThrownBy(() -> negativeTestsRepository.findByStringsLessThanEqual(List.of("string1"), List.of( "String2"))) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one"); + .hasMessage("Person.strings LTEQ: invalid number of arguments, expecting one"); assertThatThrownBy(() -> negativeTestsRepository.findByStringsGreaterThan("string1", "string2")) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one"); + .hasMessage("Person.strings GT: invalid number of arguments, expecting one"); } @Test @@ -2303,28 +2363,33 @@ void findPersonsByStringMap() { void findPersonsByStringMapEqualsNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByStringMapEquals("map1")) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid combination of arguments: expecting either a Map or a key-value pair"); + .hasMessage("Person.stringMap EQ: invalid combination of arguments, expecting either a Map or a key-value" + + " pair"); assertThatThrownBy(() -> negativeTestsRepository.findByStringMap(100)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid combination of arguments: expecting either a Map or a key-value pair"); + .hasMessage("Person.stringMap EQ: invalid combination of arguments, expecting either a Map or a key-value" + + " pair"); assertThatThrownBy(() -> negativeTestsRepository.findByStringMapEquals(Map.of("key", "value"), Map.of("key", "value"))) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid combination of arguments: expecting either a Map or a key-value pair"); + .hasMessage("Person.stringMap EQ: invalid combination of arguments, expecting either a Map or a key-value" + + " pair"); } @Test void findPersonsByStringMapNotEqualNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByStringMapIsNot("map1")) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid combination of arguments: expecting either a Map or a key-value pair"); + .hasMessage("Person.stringMap NOTEQ: invalid combination of arguments, expecting either a Map or a " + + "key-value pair"); assertThatThrownBy(() -> negativeTestsRepository.findByStringMapIsNot(Map.of("key", "value"), Map.of("key", "value"))) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid combination of arguments: expecting either a Map or a key-value pair"); + .hasMessage("Person.stringMap NOTEQ: invalid combination of arguments, expecting either a Map or a " + + "key-value pair"); } @Test @@ -2343,26 +2408,26 @@ void findPersonsByAddress() { void findByPojoEqualsNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByAddress()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one POJO"); + .hasMessage("Person.address EQ: invalid number of arguments, expecting one POJO"); assertThatThrownBy(() -> negativeTestsRepository.findByAddressEquals()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one POJO"); + .hasMessage("Person.address EQ: invalid number of arguments, expecting one POJO"); assertThatThrownBy(() -> negativeTestsRepository.findByAddress(100)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid arguments type: expecting a POJO, instead got Integer"); + .hasMessage("Person.address EQ: invalid arguments type, expecting a POJO, instead got Integer"); } @Test void findByPojoNotEqualNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByAddressIsNot()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one POJO"); + .hasMessage("Person.address NOTEQ: invalid number of arguments, expecting one POJO"); assertThatThrownBy(() -> negativeTestsRepository.findByAddressIsNot(100)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid arguments type: expecting a POJO, instead got Integer"); + .hasMessage("Person.address NOTEQ: invalid arguments type, expecting a POJO, instead got Integer"); } @Test @@ -2462,26 +2527,26 @@ void findPersonsByFriendAddress() { void findByNestedPojoEqualsNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByFriendAddress()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one POJO"); + .hasMessage("Person.address EQ: invalid number of arguments, expecting one POJO"); assertThatThrownBy(() -> negativeTestsRepository.findByFriendAddressEquals()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one POJO"); + .hasMessage("Person.address EQ: invalid number of arguments, expecting one POJO"); assertThatThrownBy(() -> negativeTestsRepository.findByFriendAddress(100)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid arguments type: expecting a POJO, instead got Integer"); + .hasMessage("Person.address EQ: invalid arguments type, expecting a POJO, instead got Integer"); } @Test void findByNestedPojoNotEqualNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByFriendAddressIsNot()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting one POJO"); + .hasMessage("Person.address NOTEQ: invalid number of arguments, expecting one POJO"); assertThatThrownBy(() -> negativeTestsRepository.findByFriendAddressIsNot(100)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid arguments type: expecting a POJO, instead got Integer"); + .hasMessage("Person.address NOTEQ: invalid arguments type, expecting a POJO, instead got Integer"); } @Test @@ -2507,26 +2572,18 @@ void findPersonsByFriendAddressZipCode() { void findByNestedSimplePropertyEqualsNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByFriendAddressZipCode()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting at least one"); + .hasMessage("Person.friend.address.zipCode EQ: invalid number of arguments, expecting at least one"); assertThatThrownBy(() -> negativeTestsRepository.findByFriendAddressZipCodeEquals()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting at least one"); -// -// assertThatThrownBy(() -> negativeTestsRepository.findByFriendAddressZipCode(100)) -// .isInstanceOf(IllegalArgumentException.class) -// .hasMessage("Invalid argument type: expecting String"); + .hasMessage("Person.friend.address.zipCode EQ: invalid number of arguments, expecting at least one"); } @Test void findByNestedSimplePropertyNotEqualNegativeTest() { assertThatThrownBy(() -> negativeTestsRepository.findByFriendAddressZipCodeIsNot()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Invalid number of arguments: expecting at least one"); -// -// assertThatThrownBy(() -> negativeTestsRepository.findByFriendAddressZipCodeIsNot(100)) -// .isInstanceOf(IllegalArgumentException.class) -// .hasMessage("Invalid argument type: expecting String"); + .hasMessage("Person.friend.address.zipCode NOTEQ: invalid number of arguments, expecting at least one"); } @Test diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUnitTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUnitTests.java index f565c7d6a..f99b65b9f 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUnitTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUnitTests.java @@ -9,10 +9,12 @@ import org.springframework.data.aerospike.convert.AerospikeTypeAliasAccessor; import org.springframework.data.aerospike.convert.MappingAerospikeConverter; import org.springframework.data.aerospike.mapping.AerospikeMappingContext; +import org.springframework.data.aerospike.query.CombinedQueryParam; import org.springframework.data.aerospike.sample.Person; import org.springframework.data.repository.query.parser.PartTree; import java.util.Collections; +import java.util.List; /** * @author Peter Milne @@ -49,11 +51,22 @@ public void createsQueryCorrectly() { @Test public void createQueryByInList() { - PartTree tree = new PartTree("findByFirstNameOrFriend", Person.class); + PartTree tree1 = new PartTree("findByFirstNameInOrFriend", Person.class); + AerospikeQueryCreator creator1 = new AerospikeQueryCreator( + tree1, new StubParameterAccessor( + CombinedQueryParam.of(List.of("Oliver", "Peter")), + CombinedQueryParam.of(new Person("id", "firstName")) + ), context, converter); + creator1.createQuery(); + + PartTree tree2 = new PartTree("findByFirstNameOrFriend", Person.class); + AerospikeQueryCreator creator2 = new AerospikeQueryCreator( + tree2, new StubParameterAccessor( + CombinedQueryParam.of("Oliver", "Peter"), + CombinedQueryParam.of(new Person("id", "firstName")) + ), context, converter); + creator2.createQuery(); - AerospikeQueryCreator creator = new AerospikeQueryCreator( - tree, new StubParameterAccessor("Oliver", "Peter"), context, converter); - Query query = creator.createQuery(); } private MappingAerospikeConverter getMappingAerospikeConverter(AerospikeCustomConversions conversions) { diff --git a/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryFindRelatedTests.java b/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryFindRelatedTests.java index e02ed49f2..216d66cb2 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryFindRelatedTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryFindRelatedTests.java @@ -8,6 +8,7 @@ import org.reactivestreams.Publisher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.aerospike.BaseReactiveIntegrationTests; +import org.springframework.data.aerospike.query.CombinedQueryParam; import org.springframework.data.aerospike.sample.Customer; import org.springframework.data.aerospike.sample.CustomerSomeFields; import org.springframework.data.aerospike.sample.ReactiveCustomerRepository; @@ -19,6 +20,7 @@ import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.data.aerospike.query.CombinedQueryParam.of; import static org.springframework.data.domain.Sort.Order.asc; /** @@ -220,7 +222,9 @@ public void findByFirstnameIn_ShouldWorkProperly() { @Test public void findByFirstnameAndLastname_ShouldWorkProperly() { - List results = customerRepo.findByFirstNameAndLastName("Bart", "Simpson") + CombinedQueryParam firstName = of("Bart"); + CombinedQueryParam lastName = of("Simpson"); + List results = customerRepo.findByFirstNameAndLastName(firstName, lastName) .subscribeOn(Schedulers.parallel()).collectList().block(); assertThat(results).containsOnly(customer3); @@ -228,7 +232,9 @@ public void findByFirstnameAndLastname_ShouldWorkProperly() { @Test public void findOneByFirstnameAndLastname_ShouldWorkProperly() { - Customer result = customerRepo.findByFirstNameAndLastName("Bart", "Simpson") + CombinedQueryParam firstName = of("Bart"); + CombinedQueryParam lastName = of("Simpson"); + Customer result = customerRepo.findByFirstNameAndLastName(firstName, lastName) .subscribeOn(Schedulers.parallel()).blockLast(); assertThat(result).isEqualTo(customer3); @@ -236,7 +242,9 @@ public void findOneByFirstnameAndLastname_ShouldWorkProperly() { @Test public void findByLastnameAndAge_ShouldWorkProperly() { - Customer result = customerRepo.findByLastNameAndAge("Simpson", 15) + CombinedQueryParam lastName = of("Simpson"); + CombinedQueryParam age = of(15); + Customer result = customerRepo.findByLastNameAndAge(lastName, age) .subscribeOn(Schedulers.parallel()).blockLast(); assertThat(result).isEqualTo(customer3); @@ -268,7 +276,9 @@ public void findByFirstnameContainingIgnoreCase_ShouldWorkProperly() { @Test public void findByAgeBetweenAndLastname_ShouldWorkProperly() { - List results = customerRepo.findByAgeBetweenAndLastName(30, 70, "Simpson") + CombinedQueryParam ageBetween = of(30, 70); + CombinedQueryParam lastName = of("Simpson"); + List results = customerRepo.findByAgeBetweenAndLastName(ageBetween, lastName) .subscribeOn(Schedulers.parallel()).collectList().block(); assertThat(results).containsOnly(customer1, customer2); diff --git a/src/test/java/org/springframework/data/aerospike/sample/PersonNegativeTestsRepository.java b/src/test/java/org/springframework/data/aerospike/sample/PersonNegativeTestsRepository.java index 4bdc60e28..6714d901b 100644 --- a/src/test/java/org/springframework/data/aerospike/sample/PersonNegativeTestsRepository.java +++ b/src/test/java/org/springframework/data/aerospike/sample/PersonNegativeTestsRepository.java @@ -15,6 +15,7 @@ */ package org.springframework.data.aerospike.sample; +import org.springframework.data.aerospike.query.CombinedQueryParam; import org.springframework.data.aerospike.repository.AerospikeRepository; import org.springframework.data.aerospike.repository.query.CriteriaDefinition; @@ -271,10 +272,6 @@ List

findByStringMapNotContaining(CriteriaDefinition.AerospikeMapQueryCriteri */ List

findByFriendAddressZipCodeIsNot(); - List

findByFriendAddressZipCode(int number1); - - List

findByFriendAddressZipCodeIsNot(int number1); - /** * Invalid number of arguments: expecting two POJOs */ @@ -294,4 +291,24 @@ List

findByStringMapNotContaining(CriteriaDefinition.AerospikeMapQueryCriteri * Invalid arguments type: expecting two POJOs, instead got Integer and Integer */ List

findByAddressBetween(int number1, int number2, int number3); + + /** + * Expected CombinedQueryParam, instead got String + */ + List

findByFirstNameAndAge(String firstName, int age); + + /** + * Invalid number of arguments, expecting at least one + */ + List

findByFirstNameOrAge(CombinedQueryParam firstName); + + /** + * + */ + List

findByAddressExists(Address address); + + /** + * Invalid number of arguments: expecting at least one + */ + List

findByIsActive(); } 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 cd325ef5e..be8534e62 100644 --- a/src/test/java/org/springframework/data/aerospike/sample/PersonRepository.java +++ b/src/test/java/org/springframework/data/aerospike/sample/PersonRepository.java @@ -16,6 +16,7 @@ package org.springframework.data.aerospike.sample; import jakarta.validation.constraints.NotNull; +import org.springframework.data.aerospike.query.CombinedQueryParam; import org.springframework.data.aerospike.repository.AerospikeRepository; import org.springframework.data.aerospike.repository.query.CriteriaDefinition.AerospikeMapQueryCriteria; import org.springframework.data.aerospike.repository.query.CriteriaDefinition.AerospikeNullQueryCriteria; @@ -57,13 +58,13 @@ public interface PersonRepository

extends AerospikeRepository< List findById(String id, Class type); // Dynamic Projection - List findByIdAndLastName(List ids, String lastName, Class type); + List findByIdAndLastName(CombinedQueryParam ids, CombinedQueryParam lastName, Class type); // Dynamic Projection - List findByLastNameAndId(String lastName, String id, Class type); + List findByLastNameAndId(CombinedQueryParam lastName, CombinedQueryParam id, Class type); // Dynamic Projection - List findByFirstNameAndLastName(String firstName, String lastName, Class type); + List findByFirstNameAndLastName(CombinedQueryParam firstName, CombinedQueryParam lastName, Class type); /** * Find all entities that satisfy the condition "have primary key in the given list and first name equal to the @@ -72,7 +73,7 @@ public interface PersonRepository

extends AerospikeRepository< * @param ids List of primary keys * @param firstName String to compare with */ - List

findByIdAndFirstName(List ids, String firstName); + List

findByIdAndFirstName(CombinedQueryParam ids, CombinedQueryParam firstName); /** * Find all entities that satisfy the condition "have primary key in the given list and either first name equal to @@ -82,9 +83,9 @@ public interface PersonRepository

extends AerospikeRepository< * @param firstName String to compare firstName with * @param age integer to compare age with */ - List

findByIdAndFirstNameAndAge(List ids, String firstName, int age); + List

findByIdAndFirstNameAndAge(CombinedQueryParam ids, CombinedQueryParam firstName, CombinedQueryParam age); - List

findByIdAndFirstNameOrAge(List ids, String firstName, int age); + List

findByIdAndFirstNameOrAge(CombinedQueryParam ids, CombinedQueryParam firstName, CombinedQueryParam age); Page

findByLastNameStartsWithOrderByAgeAsc(String prefix, Pageable pageable); @@ -140,8 +141,6 @@ public interface PersonRepository

extends AerospikeRepository< Stream

findByFirstNameNotIn(Collection firstNames); - List

findByFirstNameAndLastName(String firstName, String lastName); - List

findByAgeBigInteger(BigInteger age); List

findByAgeBigDecimal(BigDecimal age); @@ -237,9 +236,10 @@ public interface PersonRepository

extends AerospikeRepository< List

findByFirstNameNotContaining(String str); - List

findByLastNameLikeAndAgeBetween(String lastName, int from, int to); + List

findByLastNameLikeAndAgeBetween(CombinedQueryParam lastName, CombinedQueryParam ageBetween); - List

findByAgeOrLastNameLikeAndFirstNameLike(int age, String lastName, String firstName); + List

findByAgeOrLastNameLikeAndFirstNameLike(CombinedQueryParam age, CombinedQueryParam lastName, + CombinedQueryParam firstName); // List

findByNamedQuery(String firstName); @@ -275,7 +275,7 @@ public interface PersonRepository

extends AerospikeRepository< List

findByIsActiveFalse(); - List

findByIsActiveAndFirstName(boolean isActive, String firstName); + List

findByIsActiveAndFirstName(CombinedQueryParam isActive, CombinedQueryParam firstName); @SuppressWarnings("UnusedReturnValue") long countByLastName(String lastName); @@ -1131,11 +1131,11 @@ List

findByStringMapContaining(String key1, String value1, String key2, Strin */ List

findByFirstNameGreaterThan(String string); - List

findByFirstNameAndAge(String string, int i); + List

findByFirstNameAndAge(CombinedQueryParam string, CombinedQueryParam age); - Iterable

findByAgeBetweenAndLastName(int from, int to, String lastName); + Iterable

findByAgeBetweenAndLastName(CombinedQueryParam ageBetween, CombinedQueryParam lastName); - Iterable

findByAgeBetweenOrLastName(int from, int to, String lastName); + Iterable

findByAgeBetweenOrLastName(CombinedQueryParam ageBetween, CombinedQueryParam lastName); List

findByFirstNameStartsWith(String string); diff --git a/src/test/java/org/springframework/data/aerospike/sample/ReactiveCustomerRepository.java b/src/test/java/org/springframework/data/aerospike/sample/ReactiveCustomerRepository.java index 597ecd201..1faa3982c 100644 --- a/src/test/java/org/springframework/data/aerospike/sample/ReactiveCustomerRepository.java +++ b/src/test/java/org/springframework/data/aerospike/sample/ReactiveCustomerRepository.java @@ -15,6 +15,7 @@ */ package org.springframework.data.aerospike.sample; +import org.springframework.data.aerospike.query.CombinedQueryParam; import org.springframework.data.aerospike.repository.ReactiveAerospikeRepository; import org.springframework.data.domain.Sort; import reactor.core.publisher.Flux; @@ -55,11 +56,11 @@ public interface ReactiveCustomerRepository extends ReactiveAerospikeRepository< Flux findByFirstNameIn(List firstNames); - Flux findByFirstNameAndLastName(String firstName, String lastName); + Flux findByFirstNameAndLastName(CombinedQueryParam firstName, CombinedQueryParam lastName); - Mono findOneByFirstNameAndLastName(String firstName, String lastName); + Mono findOneByFirstNameAndLastName(CombinedQueryParam firstName, CombinedQueryParam lastName); - Flux findByLastNameAndAge(String lastName, long age); + Flux findByLastNameAndAge(CombinedQueryParam lastName, CombinedQueryParam age); Flux findByAgeBetween(long from, long to); @@ -67,7 +68,7 @@ public interface ReactiveCustomerRepository extends ReactiveAerospikeRepository< Flux findByFirstNameContainingIgnoreCase(String firstName); - Flux findByAgeBetweenAndLastName(long from, long to, String lastName); + Flux findByAgeBetweenAndLastName(CombinedQueryParam ageBetween, CombinedQueryParam lastName); Flux findByAgeBetweenOrderByFirstNameDesc(long i, long j); diff --git a/src/test/java/org/springframework/data/aerospike/sample/ReactiveIndexedPersonRepository.java b/src/test/java/org/springframework/data/aerospike/sample/ReactiveIndexedPersonRepository.java index 5657b8ca7..74abc4a5d 100644 --- a/src/test/java/org/springframework/data/aerospike/sample/ReactiveIndexedPersonRepository.java +++ b/src/test/java/org/springframework/data/aerospike/sample/ReactiveIndexedPersonRepository.java @@ -1,5 +1,6 @@ package org.springframework.data.aerospike.sample; +import org.springframework.data.aerospike.query.CombinedQueryParam; import org.springframework.data.aerospike.repository.ReactiveAerospikeRepository; import org.springframework.data.aerospike.repository.query.CriteriaDefinition; import org.springframework.data.domain.Page; @@ -178,7 +179,7 @@ public interface ReactiveIndexedPersonRepository extends ReactiveAerospikeReposi */ Flux findDistinctByFriendLastNameStartingWith(String string); - Flux findByFirstNameAndAge(String string, int i); + Flux findByFirstNameAndAge(CombinedQueryParam string, CombinedQueryParam i); - Flux findByAgeBetweenAndLastName(int from, int to, String lastName); + Flux findByAgeBetweenAndLastName(CombinedQueryParam ageBetween, CombinedQueryParam lastName); } diff --git a/src/test/resources/bootstrap.properties b/src/test/resources/bootstrap.properties index 6bdee7dc6..8a09d7002 100644 --- a/src/test/resources/bootstrap.properties +++ b/src/test/resources/bootstrap.properties @@ -1,2 +1 @@ -embedded.aerospike.dockerImage=aerospike/aerospike-server:6.1.0.7 -#embedded.aerospike.dockerImage=aerospike/aerospike-server:6.4.0.1 \ No newline at end of file +embedded.aerospike.dockerImage=aerospike/aerospike-server:6.1.0.7 \ No newline at end of file