diff --git a/src/main/java/org/springframework/data/aerospike/core/AerospikeOperations.java b/src/main/java/org/springframework/data/aerospike/core/AerospikeOperations.java index b2d0b1b61..2e86fc1dd 100644 --- a/src/main/java/org/springframework/data/aerospike/core/AerospikeOperations.java +++ b/src/main/java/org/springframework/data/aerospike/core/AerospikeOperations.java @@ -413,6 +413,45 @@ public interface AerospikeOperations { */ boolean delete(T document, String setName); + /** + * Delete records using a query using the set associated with the given entityClass. + * + * @param query The query to check if any matching records exist. Must not be {@literal null}. + * @param entityClass The class to extract set name from. Must not be {@literal null}. + */ + void delete(Query query, Class entityClass); + + /** + * Delete records using a query within the given set. + * + * @param query The query to check if any matching records exist. Must not be {@literal null}. + * @param entityClass The class to translate to returned records into. Must not be {@literal null}. + * @param setName Set name to use. Must not be {@literal null}. + */ + void delete(Query query, Class entityClass, String setName); + + /** + * Count existing records by ids and a query using the given entityClass. + *

+ * The records will be mapped to the given entityClass. + * + * @param ids The ids of the documents to find. Must not be {@literal null}. + * @param entityClass The class to extract set name from. Must not be {@literal null}. + * @param query The {@link Query} to filter results. Optional argument (null if no filtering required). + */ + void deleteByIdsUsingQuery(Collection ids, Class entityClass, @Nullable Query query); + + /** + * Count existing records by ids and a query using the given entityClass within the set. + *

+ * The records will be mapped to the given entityClass. + * + * @param ids The ids of the documents to find. Must not be {@literal null}. + * @param entityClass The class to extract set name from. Must not be {@literal null}. + * @param setName Set name to use. Must not be {@literal null}. + * @param query The {@link Query} to filter results. Optional argument (null if no filtering required). + */ + void deleteByIdsUsingQuery(Collection ids, Class entityClass, String setName, @Nullable Query query); /** * Delete multiple records in one batch request. The policies are analogous to {@link #delete(Object)}. @@ -1026,17 +1065,40 @@ List findByIdsUsingQuery(Collection ids, Class entityClass, Clas * @param entityClass The class to extract set name from. Must not be {@literal null}. * @return whether any matching records exist. */ - boolean existsByQuery(Query query, Class entityClass); + boolean exists(Query query, Class entityClass); /** * Check using a query if any matching records exist within the given set. * - * @param query The query to check if any matching records exist. Must not be {@literal null}. - * @param entityClass The class to translate to returned records into. Must not be {@literal null}. - * @param setName Set name to use. Must not be {@literal null}. + * @param query The query to check if any matching records exist. Must not be {@literal null}. + * @param setName Set name to use. Must not be {@literal null}. * @return whether any matching records exist. */ - boolean existsByQuery(Query query, Class entityClass, String setName); + boolean exists(Query query, String setName); + + /** + * Find if there are existing records by ids and a query using the given entityClass. + *

+ * The records will not be mapped to the given entityClass. The results are not processed (no pagination). + * + * @param ids The ids of the documents to find. Must not be {@literal null}. + * @param entityClass The class to extract set name from. Must not be {@literal null}. + * @param query The {@link Query} to filter results. Optional argument (null if no filtering required). + * @return True if matching records exist, otherwise false. + */ + boolean existsByIdsUsingQuery(Collection ids, Class entityClass, @Nullable Query query); + + /** + * Find if there are existing records by ids and a query using the given entityClass within the set. + *

+ * The records will not be mapped to a Java class. The results are not processed (no pagination). + * + * @param ids The ids of the documents to find. Must not be {@literal null}. + * @param setName Set name to use. Must not be {@literal null}. + * @param query The {@link Query} to filter results. Optional argument (null if no filtering required). + * @return True if matching records exist, otherwise false. + */ + boolean existsByIdsUsingQuery(Collection ids, String setName, @Nullable Query query); /** * Return the amount of records in the set determined by the given entityClass. @@ -1072,6 +1134,30 @@ List findByIdsUsingQuery(Collection ids, Class entityClass, Clas */ long count(Query query, String setName); + /** + * Count existing records by ids and a query using the given entityClass. + *

+ * The records will not be mapped to the given entityClass. The results are not processed (no pagination). + * + * @param ids The ids of the documents to find. Must not be {@literal null}. + * @param entityClass The class to extract set name from. Must not be {@literal null}. + * @param query The {@link Query} to filter results. Optional argument (null if no filtering required). + * @return quantity of matching records. + */ + long countByIdsUsingQuery(Collection ids, Class entityClass, @Nullable Query query); + + /** + * Count existing records by ids and a query using the given entityClass within the set. + *

+ * The records will not be mapped to a Java class. The results are not processed (no pagination). + * + * @param ids The ids of the documents to find. Must not be {@literal null}. + * @param setName Set name to use. Must not be {@literal null}. + * @param query The {@link Query} to filter results. Optional argument (null if no filtering required). + * @return quantity of matching records. + */ + long countByIdsUsingQuery(Collection ids, String setName, @Nullable Query query); + /** * Execute query, apply statement's aggregation function, and return result iterator. * diff --git a/src/main/java/org/springframework/data/aerospike/core/AerospikeTemplate.java b/src/main/java/org/springframework/data/aerospike/core/AerospikeTemplate.java index b900c4b24..647728978 100644 --- a/src/main/java/org/springframework/data/aerospike/core/AerospikeTemplate.java +++ b/src/main/java/org/springframework/data/aerospike/core/AerospikeTemplate.java @@ -48,6 +48,7 @@ import org.springframework.data.aerospike.util.Utils; import org.springframework.data.domain.Sort; import org.springframework.data.util.StreamUtils; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import java.time.Instant; @@ -59,6 +60,7 @@ import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.regex.Matcher; @@ -452,6 +454,52 @@ public boolean deleteById(Object id, String setName) { } } + public void delete(Query query, Class entityClass, String setName) { + Assert.notNull(query, "Query must not be null!"); + Assert.notNull(entityClass, "Entity class must not be null!"); + Assert.notNull(setName, "Set name must not be null!"); + + List findQueryResults = find(query, entityClass, setName).filter(Objects::nonNull).toList(); + + if (!findQueryResults.isEmpty()) { + if (serverVersionSupport.isBatchWriteSupported()) { + deleteAll(findQueryResults); + } else { + findQueryResults.forEach(this::delete); + } + } + } + + @Override + public void delete(Query query, Class entityClass) { + Assert.notNull(query, "Query passed in to exist can't be null"); + Assert.notNull(entityClass, "Class must not be null!"); + + delete(query, entityClass, getSetName(entityClass)); + } + + @Override + public void deleteByIdsUsingQuery(Collection ids, Class entityClass, @Nullable Query query) { + deleteByIdsUsingQuery(ids, entityClass, getSetName(entityClass), query); + } + + @Override + public void deleteByIdsUsingQuery(Collection ids, Class entityClass, String setName, + @Nullable Query query) { + List findQueryResults = findByIdsUsingQuery(ids, entityClass, entityClass, setName, query) + .stream() + .filter(Objects::nonNull) + .collect(Collectors.toUnmodifiableList()); + + if (!findQueryResults.isEmpty()) { + if (serverVersionSupport.isBatchWriteSupported()) { + deleteAll(findQueryResults); + } else { + findQueryResults.forEach(this::delete); + } + } + } + @Override public void deleteAll(Iterable documents) { String setName = getSetName(documents.iterator().next()); @@ -981,10 +1029,36 @@ public List findByIdsUsingQuery(Collection ids, Class entityClas target = entityClass; } - return IntStream.range(0, keys.length) + Stream results = IntStream.range(0, keys.length) .filter(index -> aeroRecords[index] != null) - .mapToObj(index -> mapToEntity(keys[index], target, aeroRecords[index])) - .collect(Collectors.toList()); + .mapToObj(index -> mapToEntity(keys[index], target, aeroRecords[index])); + + return applyPostProcessingOnResults(results, query).collect(Collectors.toList()); + } catch (AerospikeException e) { + throw translateError(e); + } + } + + public IntStream findByIdsUsingQueryWithoutMapping(Collection ids, String setName, Query query) { + Assert.notNull(setName, "Set name must not be null!"); + + try { + Key[] keys; + if (ids == null || ids.isEmpty()) { + keys = new Key[0]; + } else { + keys = ids.stream() + .map(id -> getKey(id, setName)) + .toArray(Key[]::new); + } + + BatchPolicy policy = getBatchPolicyFilterExp(query); + + Record[] aeroRecords; + aeroRecords = getAerospikeClient().get(policy, keys); + + return IntStream.range(0, keys.length) + .filter(index -> aeroRecords[index] != null); } catch (AerospikeException e) { throw translateError(e); } @@ -1122,19 +1196,31 @@ public boolean exists(Object id, String setName) { } @Override - public boolean existsByQuery(Query query, Class entityClass) { + public boolean exists(Query query, Class entityClass) { Assert.notNull(query, "Query passed in to exist can't be null"); Assert.notNull(entityClass, "Class must not be null!"); - return existsByQuery(query, entityClass, getSetName(entityClass)); + return exists(query, getSetName(entityClass)); } @Override - public boolean existsByQuery(Query query, Class entityClass, String setName) { + public boolean exists(Query query, String setName) { Assert.notNull(query, "Query passed in to exist can't be null"); - Assert.notNull(entityClass, "Class must not be null!"); Assert.notNull(setName, "Set name must not be null!"); - return find(query, entityClass, setName).findAny().isPresent(); + return findKeyRecordsUsingQuery(setName, query).findAny().isPresent(); + } + + @Override + public boolean existsByIdsUsingQuery(Collection ids, Class entityClass, @Nullable Query query) { + return existsByIdsUsingQuery(ids, getSetName(entityClass), query); + } + + @Override + public boolean existsByIdsUsingQuery(Collection ids, String setName, @Nullable Query query) { + long findQueryResults = findByIdsUsingQueryWithoutMapping(ids, setName, query) + .filter(Objects::nonNull) + .count(); + return findQueryResults > 0; } @Override @@ -1169,11 +1255,10 @@ public long count(Query query, Class entityClass) { @Override public long count(Query query, String setName) { - Stream results = countRecordsUsingQuery(setName, query); - return results.count(); + return findKeyRecordsUsingQuery(setName, query).count(); } - private Stream countRecordsUsingQuery(String setName, Query query) { + private Stream findKeyRecordsUsingQuery(String setName, Query query) { Assert.notNull(setName, "Set name must not be null!"); Qualifier qualifier = queryCriteriaIsNotNull(query) ? query.getCriteriaObject() : null; @@ -1198,6 +1283,18 @@ private Stream countRecordsUsingQuery(String setName, Query query) { }); } + @Override + public long countByIdsUsingQuery(Collection ids, Class entityClass, @Nullable Query query) { + return countByIdsUsingQuery(ids, getSetName(entityClass), query); + } + + @Override + public long countByIdsUsingQuery(Collection ids, String setName, @Nullable Query query) { + return findByIdsUsingQueryWithoutMapping(ids, setName, query) + .filter(Objects::nonNull) + .count(); + } + @Override public ResultSet aggregate(Filter filter, Class entityClass, String module, String function, List arguments) { @@ -1387,15 +1484,17 @@ private Stream findWithPostProcessing(String setName, Class targetClas } private Stream applyPostProcessingOnResults(Stream results, Query query) { - if (query.getSort() != null && query.getSort().isSorted()) { - Comparator comparator = getComparator(query); - results = results.sorted(comparator); - } - if (query.hasOffset()) { - results = results.skip(query.getOffset()); - } - if (query.hasRows()) { - results = results.limit(query.getRows()); + if (query != null) { + if (query.getSort() != null && query.getSort().isSorted()) { + Comparator comparator = getComparator(query); + results = results.sorted(comparator); + } + if (query.hasOffset()) { + results = results.skip(query.getOffset()); + } + if (query.hasRows()) { + results = results.limit(query.getRows()); + } } return results; diff --git a/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeOperations.java b/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeOperations.java index b9323853d..cbc4e221d 100644 --- a/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeOperations.java +++ b/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeOperations.java @@ -398,6 +398,47 @@ public interface ReactiveAerospikeOperations { */ Mono delete(T document, String setName); + /** + * Delete records using a query using the set associated with the given entityClass. + * + * @param query The query to check if any matching records exist. Must not be {@literal null}. + * @param entityClass The class to extract set name from. Must not be {@literal null}. + */ + Mono delete(Query query, Class entityClass); + + /** + * Delete records using a query within the given set. + * + * @param query The query to check if any matching records exist. Must not be {@literal null}. + * @param entityClass The class to translate to returned records into. Must not be {@literal null}. + * @param setName Set name to use. Must not be {@literal null}. + */ + Mono delete(Query query, Class entityClass, String setName); + + /** + * Count existing records by ids and a query using the given entityClass. + *

+ * The records will be mapped to the given entityClass. + * + * @param ids The ids of the documents to find. Must not be {@literal null}. + * @param entityClass The class to extract set name from. Must not be {@literal null}. + * @param query The {@link Query} to filter results. Optional argument (null if no filtering required). + */ + Mono deleteByIdsUsingQuery(Collection ids, Class entityClass, @Nullable Query query); + + /** + * Count existing records by ids and a query using the given entityClass within the set. + *

+ * The records will be mapped to the given entityClass. + * + * @param ids The ids of the documents to find. Must not be {@literal null}. + * @param entityClass The class to extract set name from. Must not be {@literal null}. + * @param setName Set name to use. Must not be {@literal null}. + * @param query The {@link Query} to filter results. Optional argument (null if no filtering required). + */ + Mono deleteByIdsUsingQuery(Collection ids, Class entityClass, String setName, + @Nullable Query query); + /** * Reactively delete multiple records in one batch request. The policies are analogous to {@link #delete(Object)}. *

@@ -1005,17 +1046,40 @@ Flux findByIdsUsingQuery(Collection ids, Class entityClass, Clas * @param entityClass The class to extract set name from. Must not be {@literal null}. * @return A Mono of whether matching records exist. */ - Mono existsByQuery(Query query, Class entityClass); + Mono exists(Query query, Class entityClass); /** * Reactively check using a query if any matching records exist within the given set. * - * @param query The query to check if any matching records exist. Must not be {@literal null}. - * @param entityClass The class to translate to returned records into. Must not be {@literal null}. - * @param setName Set name to use. Must not be {@literal null}. + * @param query The query to check if any matching records exist. Must not be {@literal null}. + * @param setName Set name to use. Must not be {@literal null}. * @return A Mono of whether matching records exist. */ - Mono existsByQuery(Query query, Class entityClass, String setName); + Mono exists(Query query, String setName); + + /** + * Find if there are existing records by ids and a query using the given entityClass. + *

+ * The records will not be mapped to the given entityClass. The results are not processed (no pagination). + * + * @param ids The ids of the documents to find. Must not be {@literal null}. + * @param entityClass The class to extract set name from. Must not be {@literal null}. + * @param query The {@link Query} to filter results. Optional argument (null if no filtering required). + * @return True if matching records exist, otherwise false. + */ + Mono existsByIdsUsingQuery(Collection ids, Class entityClass, @Nullable Query query); + + /** + * Find if there are existing records by ids and a query using the given entityClass within the set. + *

+ * The records will not be mapped to a Java class. The results are not processed (no pagination). + * + * @param ids The ids of the documents to find. Must not be {@literal null}. + * @param setName Set name to use. Must not be {@literal null}. + * @param query The {@link Query} to filter results. Optional argument (null if no filtering required). + * @return True if matching records exist, otherwise false. + */ + Mono existsByIdsUsingQuery(Collection ids, String setName, @Nullable Query query); /** * Reactively return the amount of records in the set determined by the given entityClass. @@ -1051,6 +1115,30 @@ Flux findByIdsUsingQuery(Collection ids, Class entityClass, Clas */ Mono count(Query query, String setName); + /** + * Count existing records by ids and a query using the given entityClass. + *

+ * The records will not be mapped to the given entityClass. The results are not processed (no pagination). + * + * @param ids The ids of the documents to find. Must not be {@literal null}. + * @param entityClass The class to extract set name from. Must not be {@literal null}. + * @param query The {@link Query} to filter results. Optional argument (null if no filtering required). + * @return Quantity of matching queries. + */ + Mono countByIdsUsingQuery(Collection ids, Class entityClass, @Nullable Query query); + + /** + * Count existing records by ids and a query using the given entityClass within the set. + *

+ * The records will not be mapped to a Java class. The results are not processed (no pagination). + * + * @param ids The ids of the documents to find. Must not be {@literal null}. + * @param setName Set name to use. Must not be {@literal null}. + * @param query The {@link Query} to filter results. Optional argument (null if no filtering required). + * @return Quantity of matching queries. + */ + Mono countByIdsUsingQuery(Collection ids, String setName, @Nullable Query query); + /** * Reactively create an index with the specified name in Aerospike. * diff --git a/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeTemplate.java b/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeTemplate.java index cc5f3ed2c..f8f342493 100644 --- a/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeTemplate.java +++ b/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeTemplate.java @@ -53,6 +53,7 @@ import org.springframework.data.domain.Sort; import org.springframework.data.keyvalue.core.IterableConverter; import org.springframework.data.mapping.PropertyHandler; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -438,6 +439,63 @@ public Mono delete(T document, String setName) { .onErrorMap(this::translateError); } + public Mono delete(Query query, Class entityClass, String setName) { + Assert.notNull(query, "Query must not be null!"); + Assert.notNull(entityClass, "Entity class must not be null!"); + Assert.notNull(setName, "Set name must not be null!"); + + Mono> findQueryResults = find(query, entityClass, setName) + .filter(Objects::nonNull) + .collect(Collectors.toUnmodifiableList()); + + return findQueryResults.flatMap(list -> { + if (!list.isEmpty()) { + if (serverVersionSupport.isBatchWriteSupported()) { + return deleteAll(list); + } else { + list.forEach(this::delete); + return Mono.empty(); + } + } + return Mono.empty(); + } + ); + } + + @Override + public Mono delete(Query query, Class entityClass) { + Assert.notNull(query, "Query passed in to exist can't be null"); + Assert.notNull(entityClass, "Class must not be null!"); + + return delete(query, entityClass, getSetName(entityClass)); + } + + @Override + public Mono deleteByIdsUsingQuery(Collection ids, Class entityClass, @Nullable Query query) { + return deleteByIdsUsingQuery(ids, entityClass, getSetName(entityClass), query); + } + + @Override + public Mono deleteByIdsUsingQuery(Collection ids, Class entityClass, String setName, + @Nullable Query query) { + Mono> findQueryResults = findByIdsUsingQuery(ids, entityClass, entityClass, setName, query) + .filter(Objects::nonNull) + .collect(Collectors.toUnmodifiableList()); + + return findQueryResults.flatMap(list -> { + if (!list.isEmpty()) { + if (serverVersionSupport.isBatchWriteSupported()) { + return deleteAll(list); + } else { + list.forEach(this::delete); + return Mono.empty(); + } + } + return Mono.empty(); + } + ); + } + @Override public Mono deleteById(Object id, Class entityClass) { Assert.notNull(id, "Id must not be null!"); @@ -895,13 +953,13 @@ public Mono findByIdUsingQuery(Object id, Class entityClass, Class< @Override public Flux findByIdsUsingQuery(Collection ids, Class entityClass, Class targetClass, - Query query) { + @Nullable Query query) { return findByIdsUsingQuery(ids, entityClass, targetClass, getSetName(entityClass), query); } @Override public Flux findByIdsUsingQuery(Collection ids, Class entityClass, Class targetClass, - String setName, Query query) { + String setName, @Nullable Query query) { Assert.notNull(ids, "Ids must not be null!"); Assert.notNull(entityClass, "Entity class must not be null!"); Assert.notNull(setName, "Set name must not be null!"); @@ -919,11 +977,29 @@ public Flux findByIdsUsingQuery(Collection ids, Class entityClas target = entityClass; } - return Flux.fromIterable(ids) + Flux results = Flux.fromIterable(ids) .map(id -> getKey(id, setName)) .flatMap(key -> getFromClient(policy, key, targetClass)) .filter(keyRecord -> nonNull(keyRecord.record)) .map(keyRecord -> mapToEntity(keyRecord.key, target, keyRecord.record)); + + return applyPostProcessingOnResults(results, query); + } + + private Flux findByIdsUsingQueryWithoutMapping(Collection ids, String setName, Query query) { + Assert.notNull(ids, "Ids must not be null!"); + Assert.notNull(setName, "Set name must not be null!"); + + if (ids.isEmpty()) { + return Flux.empty(); + } + + BatchPolicy policy = getBatchPolicyFilterExp(query); + + return Flux.fromIterable(ids) + .map(id -> getKey(id, setName)) + .flatMap(key -> getFromClient(policy, key, null)) + .filter(keyRecord -> nonNull(keyRecord.record)); } @Override @@ -1055,18 +1131,29 @@ public Mono exists(Object id, String setName) { } @Override - public Mono existsByQuery(Query query, Class entityClass) { + public Mono exists(Query query, Class entityClass) { Assert.notNull(query, "Query passed in to exist can't be null"); Assert.notNull(entityClass, "Class must not be null!"); - return existsByQuery(query, entityClass, getSetName(entityClass)); + return exists(query, getSetName(entityClass)); } @Override - public Mono existsByQuery(Query query, Class entityClass, String setName) { + public Mono exists(Query query, String setName) { Assert.notNull(query, "Query passed in to exist can't be null"); - Assert.notNull(entityClass, "Class must not be null!"); Assert.notNull(setName, "Set name must not be null!"); - return find(query, entityClass, setName).hasElements(); + return findKeyRecordsUsingQuery(setName, query).hasElements(); + } + + @Override + public Mono existsByIdsUsingQuery(Collection ids, Class entityClass, @Nullable Query query) { + return existsByIdsUsingQuery(ids, getSetName(entityClass), query); + } + + @Override + public Mono existsByIdsUsingQuery(Collection ids, String setName, @Nullable Query query) { + return findByIdsUsingQueryWithoutMapping(ids, setName, query) + .filter(Objects::nonNull) + .hasElements(); } @Override @@ -1087,6 +1174,18 @@ public Mono count(String setName) { } } + @Override + public Mono countByIdsUsingQuery(Collection ids, Class entityClass, @Nullable Query query) { + return countByIdsUsingQuery(ids, getSetName(entityClass), query); + } + + @Override + public Mono countByIdsUsingQuery(Collection ids, String setName, @Nullable Query query) { + return findByIdsUsingQueryWithoutMapping(ids, setName, query) + .filter(Objects::nonNull) + .count(); + } + private long countSet(String setName) { Node[] nodes = reactorClient.getAerospikeClient().getNodes(); @@ -1110,10 +1209,10 @@ public Mono count(Query query, Class entityClass) { public Mono count(Query query, String setName) { Assert.notNull(setName, "Set for count must not be null!"); - return countRecordsUsingQuery(setName, query).count(); + return findKeyRecordsUsingQuery(setName, query).count(); } - private Flux countRecordsUsingQuery(String setName, Query query) { + private Flux findKeyRecordsUsingQuery(String setName, Query query) { Assert.notNull(setName, "Set name must not be null!"); Qualifier qualifier = queryCriteriaIsNotNull(query) ? query.getCriteriaObject() : null; @@ -1358,16 +1457,18 @@ private void verifyUnsortedWithOffset(Sort sort, long offset) { } private Flux applyPostProcessingOnResults(Flux results, Query query) { - if (query.getSort() != null && query.getSort().isSorted()) { - Comparator comparator = getComparator(query); - results = results.sort(comparator); - } + if (query != null) { + if (query.getSort() != null && query.getSort().isSorted()) { + Comparator comparator = getComparator(query); + results = results.sort(comparator); + } - if (query.hasOffset()) { - results = results.skip(query.getOffset()); - } - if (query.hasRows()) { - results = results.take(query.getRows()); + if (query.hasOffset()) { + results = results.skip(query.getOffset()); + } + if (query.hasRows()) { + results = results.take(query.getRows()); + } } return results; } diff --git a/src/main/java/org/springframework/data/aerospike/repository/query/AerospikePartTreeQuery.java b/src/main/java/org/springframework/data/aerospike/repository/query/AerospikePartTreeQuery.java index ce749c2f0..606d6c40e 100644 --- a/src/main/java/org/springframework/data/aerospike/repository/query/AerospikePartTreeQuery.java +++ b/src/main/java/org/springframework/data/aerospike/repository/query/AerospikePartTreeQuery.java @@ -28,6 +28,7 @@ import org.springframework.data.repository.query.parser.AbstractQueryCreator; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -62,21 +63,25 @@ public Object execute(Object[] parameters) { // queries that include id have their own processing flow if (parameters != null && parameters.length > 0) { Qualifier criteria = query.getCriteriaObject(); - List ids; if (criteria.hasSingleId()) { - ids = getIdValue(criteria); - return operations.findByIdsUsingQuery(ids, entityClass, targetClass, null); + return runQueryWithIds(targetClass, getIdValue(criteria), null); } else { Qualifier idQualifier; if ((idQualifier = getIdQualifier(criteria)) != null) { - ids = getIdValue(idQualifier); - return operations.findByIdsUsingQuery(ids, entityClass, targetClass, + return runQueryWithIds(targetClass, getIdValue(idQualifier), new Query(excludeIdQualifier(criteria))); } } } - if (queryMethod.isPageQuery() || queryMethod.isSliceQuery()) { + if (isExistsQuery(queryMethod)) { + return operations.exists(query, queryMethod.getEntityInformation().getJavaType()); + } else if (isCountQuery(queryMethod)) { + return operations.count(query, queryMethod.getEntityInformation().getJavaType()); + } else if (isDeleteQuery(queryMethod)) { + operations.delete(query, queryMethod.getEntityInformation().getJavaType()); + return Optional.empty(); + } else if (queryMethod.isPageQuery() || queryMethod.isSliceQuery()) { return processPaginatedQuery(targetClass, accessor.getPageable(), query); } else if (queryMethod.isStreamQuery()) { return findByQuery(query, targetClass); @@ -90,6 +95,19 @@ public Object execute(Object[] parameters) { "supported"); } + protected Object runQueryWithIds(Class targetClass, List ids, Query query) { + if (isExistsQuery(queryMethod)) { + return operations.existsByIdsUsingQuery(ids, entityClass, query); + } else if (isCountQuery(queryMethod)) { + return operations.countByIdsUsingQuery(ids, entityClass, query); + } else if (isDeleteQuery(queryMethod)) { + operations.deleteByIdsUsingQuery(ids, entityClass, query); + return Optional.empty(); + } else { + return operations.findByIdsUsingQuery(ids, entityClass, targetClass, query); + } + } + private Object processPaginatedQuery(Class targetClass, Pageable pageable, Query query) { Stream unprocessedResultsStream = operations.findUsingQueryWithoutPostProcessing(entityClass, targetClass, query); diff --git a/src/main/java/org/springframework/data/aerospike/repository/query/BaseAerospikePartTreeQuery.java b/src/main/java/org/springframework/data/aerospike/repository/query/BaseAerospikePartTreeQuery.java index e0288a3d5..7f860a333 100644 --- a/src/main/java/org/springframework/data/aerospike/repository/query/BaseAerospikePartTreeQuery.java +++ b/src/main/java/org/springframework/data/aerospike/repository/query/BaseAerospikePartTreeQuery.java @@ -35,6 +35,7 @@ import java.lang.reflect.Constructor; import java.util.Comparator; +import java.util.List; import java.util.stream.Stream; /** @@ -155,4 +156,18 @@ private Comparator getPropertyComparator(Sort.Order order) { boolean ascending = order.getDirection().isAscending(); return new PropertyComparator<>(order.getProperty(), ignoreCase, ascending); } + + protected abstract Object runQueryWithIds(Class targetClass, List ids, Query query); + + protected boolean isExistsQuery(QueryMethod queryMethod) { + return queryMethod.getName().startsWith("existsBy"); + } + + protected boolean isCountQuery(QueryMethod queryMethod) { + return queryMethod.getName().startsWith("countBy"); + } + + protected boolean isDeleteQuery(QueryMethod queryMethod) { + return queryMethod.getName().startsWith("deleteBy") || queryMethod.getName().startsWith("removeBy"); + } } diff --git a/src/main/java/org/springframework/data/aerospike/repository/query/ReactiveAerospikePartTreeQuery.java b/src/main/java/org/springframework/data/aerospike/repository/query/ReactiveAerospikePartTreeQuery.java index 55927f411..3cef62916 100644 --- a/src/main/java/org/springframework/data/aerospike/repository/query/ReactiveAerospikePartTreeQuery.java +++ b/src/main/java/org/springframework/data/aerospike/repository/query/ReactiveAerospikePartTreeQuery.java @@ -31,6 +31,7 @@ import java.util.Comparator; import java.util.List; +import java.util.Optional; import java.util.stream.Stream; import static org.springframework.data.aerospike.core.TemplateUtils.excludeIdQualifier; @@ -62,21 +63,25 @@ public Object execute(Object[] parameters) { // queries that include id have their own processing flow if (parameters != null && parameters.length > 0) { Qualifier criteria = query.getCriteriaObject(); - List ids; if (criteria.hasSingleId()) { - ids = getIdValue(criteria); - return operations.findByIdsUsingQuery(ids, entityClass, targetClass, null); + return runQueryWithIds(targetClass, getIdValue(criteria), null); } else { Qualifier idQualifier; if ((idQualifier = getIdQualifier(criteria)) != null) { - ids = getIdValue(idQualifier); - return operations.findByIdsUsingQuery(ids, entityClass, targetClass, + return runQueryWithIds(targetClass, getIdValue(idQualifier), new Query(excludeIdQualifier(criteria))); } } } - if (queryMethod.isPageQuery() || queryMethod.isSliceQuery()) { + if (isExistsQuery(queryMethod)) { + return operations.exists(query, queryMethod.getEntityInformation().getJavaType()); + } else if (isCountQuery(queryMethod)) { + return operations.count(query, queryMethod.getEntityInformation().getJavaType()); + } else if (isDeleteQuery(queryMethod)) { + operations.delete(query, queryMethod.getEntityInformation().getJavaType()); + return Optional.empty(); + } else if (queryMethod.isPageQuery() || queryMethod.isSliceQuery()) { Pageable pageable = accessor.getPageable(); Flux unprocessedResults = operations.findUsingQueryWithoutPostProcessing(entityClass, targetClass, query); @@ -96,10 +101,21 @@ public Object execute(Object[] parameters) { return getPage(unprocessedResults, size, pageable, query); }); } - return findByQuery(query, targetClass); } + protected Object runQueryWithIds(Class targetClass, List ids, Query query) { + if (isExistsQuery(queryMethod)) { + return operations.existsByIdsUsingQuery(ids, entityClass, query); + } else if (isCountQuery(queryMethod)) { + return operations.countByIdsUsingQuery(ids, entityClass, query); + } else if (isDeleteQuery(queryMethod)) { + return operations.deleteByIdsUsingQuery(ids, entityClass, query); + } else { + return operations.findByIdsUsingQuery(ids, entityClass, targetClass, query); + } + } + public Object getPage(List unprocessedResults, long overallSize, Pageable pageable, Query query) { if (queryMethod.isSliceQuery()) { return processSliceQuery(unprocessedResults, overallSize, pageable, query); diff --git a/src/test/java/org/springframework/data/aerospike/core/sync/AerospikeTemplateDeleteTests.java b/src/test/java/org/springframework/data/aerospike/core/sync/AerospikeTemplateDeleteTests.java index 9ff2c8d29..b6bb06a8e 100644 --- a/src/test/java/org/springframework/data/aerospike/core/sync/AerospikeTemplateDeleteTests.java +++ b/src/test/java/org/springframework/data/aerospike/core/sync/AerospikeTemplateDeleteTests.java @@ -24,6 +24,8 @@ import org.springframework.data.aerospike.BaseBlockingIntegrationTests; import org.springframework.data.aerospike.core.model.GroupedKeys; import org.springframework.data.aerospike.query.FilterOperation; +import org.springframework.data.aerospike.query.qualifier.Qualifier; +import org.springframework.data.aerospike.repository.query.Query; import org.springframework.data.aerospike.sample.Customer; import org.springframework.data.aerospike.sample.Person; import org.springframework.data.aerospike.sample.SampleClasses.CollectionOfObjects; @@ -31,6 +33,7 @@ import org.springframework.data.aerospike.sample.SampleClasses.DocumentWithExpiration; import org.springframework.data.aerospike.sample.SampleClasses.VersionedClass; import org.springframework.data.aerospike.util.AwaitilityUtils; +import org.springframework.data.domain.Sort; import java.time.Instant; import java.util.Arrays; @@ -429,4 +432,34 @@ public void deleteAll_VersionsMismatch() { .hasMessageContaining("Failed to delete the record with ID 'id2' due to versions mismatch"); } } + + @Test + public void deleteByIdsUsingQuery_Paginated() { + Person person1 = new Person("id1", "Alicia", 100); + Person person2 = new Person("id2", "Jenny", 100); + template.save(person1); + template.save(person2); + List ids = List.of(person1.getId(), person2.getId()); + + Qualifier ageEq100 = Qualifier.builder() + // custom bin name has been set to "email" via @Field annotation + .setPath("age") + .setFilterOperation(FilterOperation.EQ) + .setValue(100) + .build(); + Query ageEq100Query = new Query(ageEq100); + + assertThat(template.findByIdsUsingQuery(ids, Person.class, Person.class, ageEq100Query)).hasSize(2); + + // creating another query, we are going to add de facto pagination + Query ageEq100QueryPaginated = new Query(ageEq100); + ageEq100QueryPaginated.setSort(Sort.by("firstName")); // sorting + ageEq100QueryPaginated.setOffset(1); // start with index 1 + ageEq100QueryPaginated.limit(1); // page length is 1 + + template.deleteByIdsUsingQuery(ids, Person.class, ageEq100QueryPaginated); + + // only one record was deleted + assertThat(template.findByIdsUsingQuery(ids, Person.class, Person.class, ageEq100Query)).hasSize(1); + } } diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/countBy/AfterTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/countBy/AfterTests.java new file mode 100644 index 000000000..b716c6918 --- /dev/null +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/countBy/AfterTests.java @@ -0,0 +1,32 @@ +package org.springframework.data.aerospike.repository.query.blocking.noindex.countBy; + +import org.junit.jupiter.api.Test; +import org.springframework.data.aerospike.repository.query.blocking.noindex.PersonRepositoryQueryTests; + +import java.util.Date; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for the "Is after" repository query. Keywords: After, IsAfter. + */ +public class AfterTests extends PersonRepositoryQueryTests { + + @Test + void countByDateSimplePropertyAfter() { + dave.setDateOfBirth(new Date()); + repository.save(dave); + + long result = repository.countByDateOfBirthAfter(new Date(126230400)); + assertThat(result).isEqualTo(1); + + dave.setDateOfBirth(null); + repository.save(dave); + } + + @Test + void countByDateSimplePropertyAfter_NoMatchingRecords() { + long result = repository.countByDateOfBirthAfter(new Date()); + assertThat(result).isZero(); + } +} diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/countBy/BetweenTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/countBy/BetweenTests.java new file mode 100644 index 000000000..7616bc37e --- /dev/null +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/countBy/BetweenTests.java @@ -0,0 +1,121 @@ +package org.springframework.data.aerospike.repository.query.blocking.noindex.countBy; + +import org.junit.jupiter.api.Test; +import org.springframework.data.aerospike.repository.query.blocking.noindex.PersonRepositoryQueryTests; +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; + +/** + * Tests for the "Is between" repository query. Keywords: Between, IsBetween. + */ +public class BetweenTests extends PersonRepositoryQueryTests { + + @Test + void countBySimplePropertyBetween_Integer() { + assertThat(dave.getAge()).isBetween(40, 46); + long result = repository.countByAgeBetween(40, 46); + assertThat(result).isGreaterThan(0); + } + + @Test + void countBySimplePropertyBetween_String() { + long result = repository.countByFirstNameBetween("Dave", "David"); + assertThat(result).isGreaterThan(0); + } + + @Test + void countByNestedSimplePropertyBetween_Integer() { + oliver.setFriend(alicia); + repository.save(oliver); + dave.setFriend(oliver); + repository.save(dave); + carter.setFriend(dave); + repository.save(carter); + + long result = repository.countByFriendAgeBetween(40, 45); + assertThat(result).isGreaterThan(0); + + TestUtils.setFriendsToNull(repository, oliver, dave, carter); + } + + @Test + void countByNestedSimplePropertyBetween_String() { + assertThat(carter.getAddress().getZipCode()).isEqualTo("C0124"); + assertThat(dave.getAddress().getZipCode()).isEqualTo("C0123"); + assertThat(repository.countByAddressZipCodeBetween("C0123", "C0124")).isGreaterThan(0); + } + + /** + * 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 countByCollectionBetween_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 + long persons = repository.countByIntSetBetween(Set.of(0), setToCompareWith); + assertThat(persons).isZero(); + + Set setToCompareWith2 = new TreeSet<>(Comparator.reverseOrder()); + setToCompareWith2.addAll(Set.of(3, 1, 2, 4, 0)); // gets sorted using Comparator: 4, 3, 2, 1, 0 + long persons2 = repository.countByIntSetBetween(Set.of(0), setToCompareWith2); + assertThat(persons2).isGreaterThan(0); + + List listToCompareWith = List.of(0, 4, 3, 1, 2); // the insertion order is preserved + long persons3 = repository.countByIntSetBetween(Set.of(0), listToCompareWith); + assertThat(persons3).isZero(); + + // gets sorted using natural order + PriorityQueue queueToCompareWith = new PriorityQueue<>(Set.of(3, 1, 2, 4, 0)); + long persons4 = repository.countByIntSetBetween(Set.of(0), queueToCompareWith); + assertThat(persons4).isZero(); + + PriorityQueue queueToCompareWith2 = new PriorityQueue<>(Comparator.reverseOrder()); + queueToCompareWith2.addAll(Set.of(3, 1, 2, 4, 0)); // gets sorted using Comparator: 4, 3, 2, 1, 0 + long persons5 = repository.countByIntSetBetween(Set.of(0), queueToCompareWith2); + assertThat(persons5).isGreaterThan(0); + } + } + + @Test + void countByCollectionBetween_IntegerList() { + List list1 = List.of(100, 200, 300); + List list2 = List.of(1000, 2000, 3000); + + long persons = repository.countByIntsBetween(list1, list2); + assertThat(persons).isGreaterThan(0); + } + + @Test + void countByCollectionBetween_NegativeTest() { + assertThatThrownBy(() -> negativeTestsRepository.countByIntsBetween()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Person.ints BETWEEN: invalid number of arguments, expecting two"); + + assertThatThrownBy(() -> negativeTestsRepository.countByIntsBetween(100)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Person.ints BETWEEN: invalid number of arguments, expecting two"); + + assertThatThrownBy(() -> negativeTestsRepository.countByIntsBetween(Map.of(100, 200), Map.of(300, 400))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Person.ints BETWEEN: invalid argument type, expecting Collection"); + } +} diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/countBy/EqualsTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/countBy/EqualsTests.java new file mode 100644 index 000000000..3ab8b4985 --- /dev/null +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/countBy/EqualsTests.java @@ -0,0 +1,47 @@ +package org.springframework.data.aerospike.repository.query.blocking.noindex.countBy; + +import org.junit.jupiter.api.Test; +import org.springframework.data.aerospike.query.QueryParam; +import org.springframework.data.aerospike.repository.query.blocking.noindex.PersonRepositoryQueryTests; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.data.aerospike.query.QueryParam.of; + +/** + * Tests for the "Equals" repository query. Keywords: Is, Equals (or no keyword). + */ +public class EqualsTests extends PersonRepositoryQueryTests { + + @Test + void countBySimplePropertyEquals_String() { + long result = repository.countByFirstName("Leroi"); + assertThat(result).isEqualTo(2); + + long result1 = repository.countByFirstNameIgnoreCase("lEroi"); + assertThat(result1).isEqualTo(2); + + long result2 = repository.countByFirstNameIs("lEroi"); // another way to call the query method + assertThat(result2).isZero(); + } + + @Test + void countPersonById_AND_simpleProperty() { + QueryParam ids = of(dave.getId()); + QueryParam name = of(carter.getFirstName()); + long persons = repository.countByIdAndFirstName(ids, name); + assertThat(persons).isZero(); + + ids = of(dave.getId()); + name = of(dave.getFirstName()); + persons = repository.countByIdAndFirstName(ids, name); + assertThat(persons).isEqualTo(1); + + ids = of(List.of(leroi.getId(), leroi2.getId(), carter.getId())); + QueryParam firstName = of(leroi.getFirstName()); + QueryParam age = of(stefan.getAge()); + long persons4 = repository.countByIdAndFirstNameOrAge(ids, firstName, age); + assertThat(persons4).isEqualTo(2); + } +} diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/deleteBy/AfterTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/deleteBy/AfterTests.java new file mode 100644 index 000000000..6721b5d9b --- /dev/null +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/deleteBy/AfterTests.java @@ -0,0 +1,40 @@ +package org.springframework.data.aerospike.repository.query.blocking.noindex.deleteBy; + +import org.junit.jupiter.api.Test; +import org.springframework.data.aerospike.repository.query.blocking.noindex.PersonRepositoryQueryTests; + +import java.util.Date; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for the "Is after" repository query. Keywords: After, IsAfter. + */ +public class AfterTests extends PersonRepositoryQueryTests { + + @Test + void deleteByDateSimplePropertyAfter() { + dave.setDateOfBirth(new Date()); + repository.save(dave); + + Date date = new Date(126230400); + assertThat(repository.findByDateOfBirthAfter(date)).isNotEmpty(); + + repository.deleteByDateOfBirthAfter(date); + + assertThat(repository.findByDateOfBirthAfter(date)).isEmpty(); + + dave.setDateOfBirth(null); + repository.save(dave); + } + + @Test + void deleteByDateSimplePropertyAfter_NoMatchingRecords() { + Date date = new Date(); + assertThat(repository.findByDateOfBirthAfter(date)).isEmpty(); + + repository.deleteByDateOfBirthAfter(date); + + assertThat(repository.findByDateOfBirthAfter(date)).isEmpty(); + } +} diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/deleteBy/BetweenTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/deleteBy/BetweenTests.java new file mode 100644 index 000000000..e10b29346 --- /dev/null +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/deleteBy/BetweenTests.java @@ -0,0 +1,127 @@ +package org.springframework.data.aerospike.repository.query.blocking.noindex.deleteBy; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.data.aerospike.repository.query.blocking.noindex.PersonRepositoryQueryTests; +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.Set; +import java.util.TreeSet; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +/** + * Tests for the "Is between" repository query. Keywords: Between, IsBetween. + */ +public class BetweenTests extends PersonRepositoryQueryTests { + + @BeforeEach + public void beforeEach() { + additionalAerospikeTestOperations.deleteAllAndVerify(Person.class); + additionalAerospikeTestOperations.saveAll(repository, allPersons); + } + + @Test + void deleteBySimplePropertyBetween_Integer() { + assertThat(dave.getAge()).isBetween(40, 46); + assertThat(repository.findByAgeBetween(40, 46)).isNotEmpty(); + + repository.deleteByAgeBetween(40, 46); + assertThat(repository.findByAgeBetween(40, 46)).isEmpty(); + } + + @Test + void deleteBySimplePropertyBetween_String() { + assertThat(repository.findByFirstNameBetween("Dave", "David")).isNotEmpty(); + + repository.deleteByFirstNameBetween("Dave", "David"); + assertThat(repository.findByFirstNameBetween("Dave", "David")).isEmpty(); + } + + @Test + void deleteByNestedSimplePropertyBetween_Integer() { + oliver.setFriend(alicia); + repository.save(oliver); + dave.setFriend(oliver); + repository.save(dave); + carter.setFriend(dave); + repository.save(carter); + assertThat(repository.findByFriendAgeBetween(40, 45)).isNotEmpty(); + + repository.deleteByFriendAgeBetween(40, 45); + assertThat(repository.findByFriendAgeBetween(40, 45)).isEmpty(); + + TestUtils.setFriendsToNull(repository, oliver, dave, carter); + } + + @Test + void deleteByNestedSimplePropertyBetween_String() { + assertThat(carter.getAddress().getZipCode()).isEqualTo("C0124"); + assertThat(dave.getAddress().getZipCode()).isEqualTo("C0123"); + assertThat(repository.findByAddressZipCodeBetween("C0123", "C0124")).isNotEmpty(); + + repository.deleteByAddressZipCodeBetween("C0123", "C0124"); + assertThat(repository.findByAddressZipCodeBetween("C0123", "C0124")).isEmpty(); + } + + /** + * 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 which preserves the order of elements, + * such Collections can be consistently compared to a List saved in DB. + */ + @Test + void deleteByCollectionBetween_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 + assertThat(repository.findByIntSetBetween(Set.of(0), setToCompareWith)).isEmpty(); + + repository.deleteByIntSetBetween(Set.of(0), setToCompareWith); + assertThat(repository.findByIntSetBetween(Set.of(0), setToCompareWith)).isEmpty(); + + Set setToCompareWith2 = new TreeSet<>(Comparator.reverseOrder()); + setToCompareWith2.addAll(Set.of(3, 1, 2, 4, 0)); // gets sorted using Comparator: 4, 3, 2, 1, 0 + assertThat(repository.findByIntSetBetween(Set.of(0), setToCompareWith2)).isNotEmpty(); + + repository.deleteByIntSetBetween(Set.of(0), setToCompareWith2); + assertThat(repository.findByIntSetBetween(Set.of(0), setToCompareWith2)).isEmpty(); + } + } + + @Test + void deleteByCollectionBetween_IntegerList() { + List list1 = List.of(100, 200, 300); + List list2 = List.of(1000, 2000, 3000); + assertThat(repository.findByIntsBetween(list1, list2)).isNotEmpty(); + + repository.deleteByIntsBetween(list1, list2); + assertThat(repository.findByIntsBetween(list1, list2)).isEmpty(); + } + + @Test + void deleteByCollectionBetween_NegativeTest() { + assertThatThrownBy(() -> negativeTestsRepository.deleteByIntsBetween()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Person.ints BETWEEN: invalid number of arguments, expecting two"); + + assertThatThrownBy(() -> negativeTestsRepository.deleteByIntsBetween(100)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Person.ints BETWEEN: invalid number of arguments, expecting two"); + + assertThatThrownBy(() -> negativeTestsRepository.deleteByIntsBetween(Map.of(100, 200), Map.of(300, 400))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Person.ints BETWEEN: invalid argument type, expecting Collection"); + } +} diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/deleteBy/EqualsTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/deleteBy/EqualsTests.java new file mode 100644 index 000000000..ddea013d4 --- /dev/null +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/deleteBy/EqualsTests.java @@ -0,0 +1,42 @@ +package org.springframework.data.aerospike.repository.query.blocking.noindex.deleteBy; + +import org.junit.jupiter.api.Test; +import org.springframework.data.aerospike.repository.query.blocking.noindex.PersonRepositoryQueryTests; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for the "Equals" repository query. Keywords: Is, Equals (or no keyword). + */ +public class EqualsTests extends PersonRepositoryQueryTests { + + @Test + void deleteBySimplePropertyEquals_String() { + assertThat(repository.findByFirstName("Leroi")).isNotEmpty(); + repository.deleteByFirstName("Leroi"); + assertThat(repository.findByFirstName("Leroi")).isEmpty(); + + repository.save(leroi); + assertThat(repository.findByFirstNameIgnoreCase("lEroi")).isNotEmpty(); + repository.deleteByFirstNameIgnoreCase("lEroi"); + assertThat(repository.findByFirstNameIgnoreCase("lEroi")).isEmpty(); + } + + @Test + void deletePersonById_AND_simpleProperty() { +// QueryParam ids = of(dave.getId()); +// QueryParam name = of(carter.getFirstName()); +// repository.deleteByIdAndFirstName(ids, name); +// assertThat(repository.findByIdAndFirstName(ids, name)).isEmpty(); +// +// ids = of(dave.getId()); +// name = of(dave.getFirstName()); +// assertThat(repository.findByIdAndFirstName(ids, name)).isNotEmpty(); +// repository.deleteByIdAndFirstName(ids, name); +// assertThat(repository.findByIdAndFirstName(ids, name)).isEmpty(); + + repository.deleteAllById(List.of(dave.getId(), carter.getId())); + } +} diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/deleteBy/GreaterThanTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/deleteBy/GreaterThanTests.java new file mode 100644 index 000000000..4a2c0c54f --- /dev/null +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/deleteBy/GreaterThanTests.java @@ -0,0 +1,32 @@ +package org.springframework.data.aerospike.repository.query.blocking.noindex.deleteBy; + +import org.junit.jupiter.api.Test; +import org.springframework.data.aerospike.repository.query.blocking.noindex.PersonRepositoryQueryTests; +import org.springframework.data.aerospike.sample.Person; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for the "Is greater than" repository query. Keywords: GreaterThan, IsGreaterThan. + */ +public class GreaterThanTests extends PersonRepositoryQueryTests { + + @Test + void deleteBySimpleProperty_Integer_Paginated() { + List findQueryResults = repository.findByAgeGreaterThan(40); + assertThat(findQueryResults).isNotEmpty(); + + repository.deleteByAgeGreaterThan(40, PageRequest.of(0, 1)); + List findQueryResultsAfterDelete = repository.findByAgeGreaterThan(40); + assertThat(findQueryResultsAfterDelete.size()).isNotZero().isLessThan(findQueryResults.size()); + + // Query to delete results from a non-existing page, no records must be deleted + repository.deleteByAgeGreaterThan(40, PageRequest.of(10, 1, Sort.by("firstName"))); + List findQueryResultsAfterDelete2 = repository.findByAgeGreaterThan(40); + assertThat(findQueryResultsAfterDelete2).containsExactlyInAnyOrderElementsOf(findQueryResultsAfterDelete); + } +} diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/existsBy/AfterTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/existsBy/AfterTests.java new file mode 100644 index 000000000..9f108bfff --- /dev/null +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/existsBy/AfterTests.java @@ -0,0 +1,32 @@ +package org.springframework.data.aerospike.repository.query.blocking.noindex.existsBy; + +import org.junit.jupiter.api.Test; +import org.springframework.data.aerospike.repository.query.blocking.noindex.PersonRepositoryQueryTests; + +import java.util.Date; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for the "Is after" repository query. Keywords: After, IsAfter. + */ +public class AfterTests extends PersonRepositoryQueryTests { + + @Test + void existsByDateSimplePropertyAfter() { + dave.setDateOfBirth(new Date()); + repository.save(dave); + + boolean result = repository.existsByDateOfBirthAfter(new Date(126230400)); + assertThat(result).isTrue(); + + dave.setDateOfBirth(null); + repository.save(dave); + } + + @Test + void existsByDateSimplePropertyAfter_NoMatchingRecords() { + boolean result = repository.existsByDateOfBirthAfter(new Date()); + assertThat(result).isFalse(); + } +} diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/existsBy/BetweenTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/existsBy/BetweenTests.java new file mode 100644 index 000000000..24f0682ad --- /dev/null +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/existsBy/BetweenTests.java @@ -0,0 +1,121 @@ +package org.springframework.data.aerospike.repository.query.blocking.noindex.existsBy; + +import org.junit.jupiter.api.Test; +import org.springframework.data.aerospike.repository.query.blocking.noindex.PersonRepositoryQueryTests; +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; + +/** + * Tests for the "Is between" repository query. Keywords: Between, IsBetween. + */ +public class BetweenTests extends PersonRepositoryQueryTests { + + @Test + void existsBySimplePropertyBetween_Integer() { + assertThat(dave.getAge()).isBetween(40, 46); + boolean result = repository.existsByAgeBetween(40, 46); + assertThat(result).isTrue(); + } + + @Test + void existsBySimplePropertyBetween_String() { + boolean result = repository.existsByFirstNameBetween("Dave", "David"); + assertThat(result).isTrue(); + } + + @Test + void existsByNestedSimplePropertyBetween_Integer() { + oliver.setFriend(alicia); + repository.save(oliver); + dave.setFriend(oliver); + repository.save(dave); + carter.setFriend(dave); + repository.save(carter); + + boolean result = repository.existsByFriendAgeBetween(40, 45); + assertThat(result).isTrue(); + + TestUtils.setFriendsToNull(repository, oliver, dave, carter); + } + + @Test + void existsByNestedSimplePropertyBetween_String() { + assertThat(carter.getAddress().getZipCode()).isEqualTo("C0124"); + assertThat(dave.getAddress().getZipCode()).isEqualTo("C0123"); + assertThat(repository.existsByAddressZipCodeBetween("C0123", "C0124")).isTrue(); + } + + /** + * 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 existsByCollectionBetween_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 + boolean persons = repository.existsByIntSetBetween(Set.of(0), setToCompareWith); + assertThat(persons).isFalse(); + + Set setToCompareWith2 = new TreeSet<>(Comparator.reverseOrder()); + setToCompareWith2.addAll(Set.of(3, 1, 2, 4, 0)); // gets sorted using Comparator: 4, 3, 2, 1, 0 + boolean persons2 = repository.existsByIntSetBetween(Set.of(0), setToCompareWith2); + assertThat(persons2).isTrue(); + + List listToCompareWith = List.of(0, 4, 3, 1, 2); // the insertion order is preserved + boolean persons3 = repository.existsByIntSetBetween(Set.of(0), listToCompareWith); + assertThat(persons3).isFalse(); + + // gets sorted using natural order + PriorityQueue queueToCompareWith = new PriorityQueue<>(Set.of(3, 1, 2, 4, 0)); + boolean persons4 = repository.existsByIntSetBetween(Set.of(0), queueToCompareWith); + assertThat(persons4).isFalse(); + + PriorityQueue queueToCompareWith2 = new PriorityQueue<>(Comparator.reverseOrder()); + queueToCompareWith2.addAll(Set.of(3, 1, 2, 4, 0)); // gets sorted using Comparator: 4, 3, 2, 1, 0 + boolean persons5 = repository.existsByIntSetBetween(Set.of(0), queueToCompareWith2); + assertThat(persons5).isTrue(); + } + } + + @Test + void existsByCollectionBetween_IntegerList() { + List list1 = List.of(100, 200, 300); + List list2 = List.of(1000, 2000, 3000); + + boolean persons = repository.existsByIntsBetween(list1, list2); + assertThat(persons).isTrue(); + } + + @Test + void existsByCollectionBetween_NegativeTest() { + assertThatThrownBy(() -> negativeTestsRepository.existsByIntsBetween()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Person.ints BETWEEN: invalid number of arguments, expecting two"); + + assertThatThrownBy(() -> negativeTestsRepository.existsByIntsBetween(100)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Person.ints BETWEEN: invalid number of arguments, expecting two"); + + assertThatThrownBy(() -> negativeTestsRepository.existsByIntsBetween(Map.of(100, 200), Map.of(300, 400))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Person.ints BETWEEN: invalid argument type, expecting Collection"); + } +} diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/existsBy/EqualsTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/existsBy/EqualsTests.java new file mode 100644 index 000000000..722459794 --- /dev/null +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/existsBy/EqualsTests.java @@ -0,0 +1,47 @@ +package org.springframework.data.aerospike.repository.query.blocking.noindex.existsBy; + +import org.junit.jupiter.api.Test; +import org.springframework.data.aerospike.query.QueryParam; +import org.springframework.data.aerospike.repository.query.blocking.noindex.PersonRepositoryQueryTests; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.data.aerospike.query.QueryParam.of; + +/** + * Tests for the "Equals" repository query. Keywords: Is, Equals (or no keyword). + */ +public class EqualsTests extends PersonRepositoryQueryTests { + + @Test + void existsBySimplePropertyEquals_String() { + boolean result = repository.existsByFirstName("Leroi"); + assertThat(result).isTrue(); + + boolean result1 = repository.existsByFirstNameIgnoreCase("lEroi"); + assertThat(result1).isTrue(); + + boolean result2 = repository.existsByFirstNameIs("lEroi"); // another way to call the query method + assertThat(result2).isFalse(); + } + + @Test + void existsPersonById_AND_simpleProperty() { + QueryParam ids = of(dave.getId()); + QueryParam name = of(carter.getFirstName()); + boolean result = repository.existsByIdAndFirstName(ids, name); + assertThat(result).isFalse(); + + ids = of(dave.getId()); + name = of(dave.getFirstName()); + result = repository.existsByIdAndFirstName(ids, name); + assertThat(result).isTrue(); + + ids = of(List.of(leroi.getId(), leroi2.getId(), carter.getId())); + QueryParam firstName = of(leroi.getFirstName()); + QueryParam age = of(stefan.getAge()); + boolean result2 = repository.existsByIdAndFirstNameOrAge(ids, firstName, age); + assertThat(result2).isTrue(); + } +} diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/CustomQueriesTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/CustomQueriesTests.java index 9aab25ab1..cfba09714 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/CustomQueriesTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/CustomQueriesTests.java @@ -53,13 +53,13 @@ void findBySimplePropertyEquals_String() { alicia.setEmailAddress(email); repository.save(alicia); - Qualifier genderEqFemale = Qualifier.builder() - // custom bin name has been set to "email" via @Field annotation + Qualifier emailEquals = Qualifier.builder() + // custom bin name has been set to "email " via @Field annotation .setPath("email") .setFilterOperation(FilterOperation.EQ) .setValue(email) .build(); - assertThat(repository.findUsingQuery(new Query(genderEqFemale))).containsOnly(alicia); + assertThat(repository.findUsingQuery(new Query(emailEquals))).containsOnly(alicia); } @Test diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/EqualsTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/EqualsTests.java index f0854617d..6acecfe6a 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/EqualsTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/EqualsTests.java @@ -125,42 +125,65 @@ void findBySimplePropertyEquals_Boolean_NegativeTest() { @Test void findPersonById_AND_simpleProperty() { - QueryParam ids = of(List.of(dave.getId(), boyd.getId())); - QueryParam names = of(carter.getFirstName()); - List persons = repository.findByIdAndFirstName(ids, names); + QueryParam ids = of(dave.getId()); + QueryParam name = of(carter.getFirstName()); + List persons = repository.findByIdAndFirstName(ids, name); assertThat(persons).isEmpty(); + ids = of(dave.getId()); + name = of(dave.getFirstName()); + persons = repository.findByIdAndFirstName(ids, name); + assertThat(persons).containsOnly(dave); + ids = of(List.of(boyd.getId(), dave.getId(), carter.getId())); - names = of(dave.getFirstName()); - persons = repository.findByIdAndFirstName(ids, names); + name = of(dave.getFirstName()); + // when in a combined query, "findById" part can receive multiple ids wrapped in QueryParam + persons = repository.findByIdAndFirstName(ids, name); assertThat(persons).containsOnly(dave); ids = of(List.of(leroi.getId(), leroi2.getId(), carter.getId())); - QueryParam firstNames = of(leroi.getFirstName()); - QueryParam ages = of(leroi2.getAge()); - List persons2 = repository.findByIdAndFirstNameAndAge(ids, firstNames, ages); + QueryParam firstName = of(leroi.getFirstName()); + QueryParam age = of(leroi2.getAge()); + List persons2 = repository.findByIdAndFirstNameAndAge(ids, firstName, age); 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 - 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); + ids = of(List.of(leroi.getId(), leroi2.getId(), carter.getId())); + firstName = of(leroi.getFirstName()); + age = of(leroi2.getAge()); + List persons3 = repository.findByIdAndFirstNameOrAge(ids, firstName, age); assertThat(persons3).containsOnly(leroi, leroi2); - 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); + ids = of(List.of(leroi.getId(), leroi2.getId(), carter.getId())); + firstName = of(leroi.getFirstName()); + age = of(stefan.getAge()); + List persons4 = repository.findByIdAndFirstNameOrAge(ids, firstName, age); assertThat(persons4).containsOnly(leroi, leroi2); } @Test - void findById_dynamicProjection() { + void findAllByIds() { + Iterable result = repository.findAllById(List.of(dave.getId(), carter.getId())); + assertThat(result).containsExactlyInAnyOrder(dave, carter); + } + + @Test + void findAllPersonByIds_AND_simpleProperty() { + QueryParam ids1 = of(List.of(dave.getId(), boyd.getId())); + QueryParam name1 = of(dave.getFirstName()); + List persons1 = repository.findAllByIdAndFirstName(ids1, name1); + assertThat(persons1).contains(dave); + + QueryParam ids2 = of(List.of(dave.getId(), boyd.getId())); + QueryParam name2 = of(carter.getFirstName()); + List persons2 = repository.findAllByIdAndFirstName(ids2, name2); + assertThat(persons2).isEmpty(); + } + + @Test + void findByIds_dynamicProjection() { List result = repository.findById(dave.getId(), PersonSomeFields.class); assertThat(result).containsOnly(dave.toPersonSomeFields()); } @@ -174,32 +197,32 @@ void findBySimpleProperty_String_projection() { @Test void findById_AND_simpleProperty_dynamicProjection() { QueryParam ids = of(List.of(boyd.getId(), dave.getId(), carter.getId())); - QueryParam lastNames = of(carter.getLastName()); - List result = repository.findByIdAndLastName(ids, lastNames, PersonSomeFields.class); + QueryParam lastName = of(carter.getLastName()); + List result = repository.findByIdAndLastName(ids, lastName, PersonSomeFields.class); assertThat(result).containsOnly(carter.toPersonSomeFields()); } @Test void findById_AND_simpleProperty_DynamicProjection_EmptyResult() { QueryParam ids = of(List.of(carter.getId(), boyd.getId())); - QueryParam lastNames = of(dave.getLastName()); - List result = repository.findByIdAndLastName(ids, lastNames, PersonSomeFields.class); + QueryParam lastName = of(dave.getLastName()); + List result = repository.findByIdAndLastName(ids, lastName, PersonSomeFields.class); assertThat(result).isEmpty(); } @Test void findBySimpleProperty_AND_id_dynamicProjection() { - QueryParam ids = of(dave.getId()); - QueryParam lastNames = of(dave.getLastName()); - List result = repository.findByLastNameAndId(lastNames, ids, PersonSomeFields.class); + QueryParam id = of(dave.getId()); + QueryParam lastName = of(dave.getLastName()); + List result = repository.findByLastNameAndId(lastName, id, PersonSomeFields.class); assertThat(result).containsOnly(dave.toPersonSomeFields()); } @Test void findBySimpleProperty_AND_simpleProperty_DynamicProjection() { - QueryParam firstNames = of(carter.getFirstName()); - QueryParam lastNames = of(carter.getLastName()); - List result = repository.findByFirstNameAndLastName(firstNames, lastNames, + QueryParam firstName = of(carter.getFirstName()); + QueryParam lastName = of(carter.getLastName()); + List result = repository.findByFirstNameAndLastName(firstName, lastName, PersonSomeFields.class); assertThat(result).containsOnly(carter.toPersonSomeFields()); } diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/findByKeywordSynonymsTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/findByKeywordSynonymsTests.java new file mode 100644 index 000000000..498552591 --- /dev/null +++ b/src/test/java/org/springframework/data/aerospike/repository/query/blocking/noindex/findBy/findByKeywordSynonymsTests.java @@ -0,0 +1,34 @@ +package org.springframework.data.aerospike.repository.query.blocking.noindex.findBy; + +import org.junit.jupiter.api.Test; +import org.springframework.data.aerospike.repository.query.blocking.noindex.PersonRepositoryQueryTests; +import org.springframework.data.aerospike.sample.Person; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class findByKeywordSynonymsTests extends PersonRepositoryQueryTests { + + @Test + void findBySimplePropertyEquals_String() { + List resultFind = repository.findByFirstName("Leroi"); + assertThat(resultFind).containsOnly(leroi, leroi2); + + List resultRead = repository.readByFirstName("Leroi"); + assertThat(resultRead).containsExactlyInAnyOrderElementsOf(resultFind); + + List resultGet = repository.getByFirstName("Leroi"); + assertThat(resultGet).containsExactlyInAnyOrderElementsOf(resultFind); + + List resultQuery = repository.queryByFirstName("Leroi"); + assertThat(resultQuery).containsExactlyInAnyOrderElementsOf(resultFind); + + List resultSearch = repository.searchByFirstName("Leroi"); + assertThat(resultSearch).containsExactlyInAnyOrderElementsOf(resultFind); + + List resultStream = repository.streamByFirstName("Leroi"); + assertThat(resultStream).containsExactlyInAnyOrderElementsOf(resultFind); + } + +} diff --git a/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryCountRelatedTests.java b/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryCountRelatedTests.java new file mode 100644 index 000000000..47cf87507 --- /dev/null +++ b/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryCountRelatedTests.java @@ -0,0 +1,49 @@ +package org.springframework.data.aerospike.repository.reactive; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.aerospike.BaseReactiveIntegrationTests; +import org.springframework.data.aerospike.query.QueryParam; +import org.springframework.data.aerospike.sample.Customer; +import org.springframework.data.aerospike.sample.ReactiveCustomerRepository; +import reactor.core.publisher.Flux; +import reactor.test.StepVerifier; + +import java.util.List; + +public class ReactiveAerospikeRepositoryCountRelatedTests extends BaseReactiveIntegrationTests { + + @Autowired + ReactiveCustomerRepository customerRepo; + + private Customer customer1, customer2; + + @BeforeEach + public void setUp() { + customer1 = Customer.builder().id(nextId()).firstName("Philip J.").lastName("Fry").age(1029).build(); + customer2 = Customer.builder().id(nextId()).firstName("Leela").lastName("Turanga").age(29).build(); + StepVerifier.create(customerRepo.saveAll(Flux.just(customer1, customer2))).expectNextCount(2).verifyComplete(); + } + + @Test + public void countByAgeBetween() { + StepVerifier.create(customerRepo.countByAgeBetween(20, 1100)) + .expectNextMatches(result -> result >= 2) + .verifyComplete(); + } + + @Test + public void countByIdAndFirstNameIn() { + QueryParam ids = QueryParam.of(List.of(customer1.getId(), customer2.getId())); + QueryParam firstNames = QueryParam.of(List.of(customer1.getFirstName(), customer2.getFirstName(), "FirstName")); + StepVerifier.create(customerRepo.countByIdAndFirstNameIn(ids, firstNames)) + .expectNext(2L) + .verifyComplete(); + + firstNames = QueryParam.of(List.of("FirstName")); + StepVerifier.create(customerRepo.countByIdAndFirstNameIn(ids, firstNames)) + .expectNext(0L) + .verifyComplete(); + } +} diff --git a/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryDeleteRelatedTests.java b/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryDeleteRelatedTests.java index ccdd1eb11..41647bbdf 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryDeleteRelatedTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryDeleteRelatedTests.java @@ -6,6 +6,7 @@ import org.reactivestreams.Publisher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.aerospike.BaseReactiveIntegrationTests; +import org.springframework.data.aerospike.query.QueryParam; import org.springframework.data.aerospike.sample.Customer; import org.springframework.data.aerospike.sample.ReactiveCustomerRepository; import reactor.core.publisher.Flux; @@ -170,4 +171,38 @@ public void deleteAll_ShouldDelete() { StepVerifier.create(customerRepo.findById(customer1.getId())).expectNextCount(0).verifyComplete(); StepVerifier.create(customerRepo.findById(customer2.getId())).expectNextCount(0).verifyComplete(); } + + @Test + public void deleteByIdAndFirstNameIn() { + StepVerifier.create(customerRepo.saveAll(Flux.just(customer1, customer2))) + .expectNextCount(2) + .verifyComplete(); + + StepVerifier.create(customerRepo.findAllById(List.of(customer1.getId(), customer2.getId())).collectList()) + .expectNextMatches(list -> list.size() == 2 && list.contains(customer1) && list.contains(customer2)) + .verifyComplete(); + + QueryParam ids = QueryParam.of(List.of(customer1.getId(), customer2.getId())); + QueryParam firstNames = QueryParam.of(List.of("FirstName")); + // no records satisfying the condition + StepVerifier.create(customerRepo.deleteByIdAndFirstNameIn(ids, firstNames)) + .expectComplete() + .verify(); + + // no records get deleted + StepVerifier.create(customerRepo.findAllById(List.of(customer1.getId(), customer2.getId())).collectList()) + .expectNextMatches(list -> list.size() == 2 && list.contains(customer1) && list.contains(customer2)) + .verifyComplete(); + + // 2 records satisfying the condition + firstNames = QueryParam.of(List.of(customer1.getFirstName(), customer2.getFirstName(), "FirstName")); + StepVerifier.create(customerRepo.deleteByIdAndFirstNameIn(ids, firstNames)) + .expectComplete() + .verify(); + + // 2 records get deleted + StepVerifier.create(customerRepo.findAllById(List.of(customer1.getId(), customer2.getId())).collectList()) + .expectNextMatches(List::isEmpty) + .verifyComplete(); + } } diff --git a/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryExistRelatedTests.java b/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryExistRelatedTests.java index 759ca1f3f..6c9a3df54 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryExistRelatedTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/reactive/ReactiveAerospikeRepositoryExistRelatedTests.java @@ -4,12 +4,15 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.aerospike.BaseReactiveIntegrationTests; +import org.springframework.data.aerospike.query.QueryParam; import org.springframework.data.aerospike.sample.Customer; import org.springframework.data.aerospike.sample.ReactiveCustomerRepository; import reactor.core.publisher.Flux; import reactor.core.scheduler.Schedulers; import reactor.test.StepVerifier; +import java.util.List; + /** * @author Igor Ermolenko */ @@ -57,4 +60,18 @@ public void existsByIdPublisher_ShouldCheckOnlyFirstElement() { .subscribeOn(Schedulers.parallel())) .expectNext(true).verifyComplete(); } + + @Test + public void existsByIdAndFirstNameIn() { + QueryParam ids = QueryParam.of(List.of(customer1.getId(), customer2.getId())); + QueryParam firstNames = QueryParam.of(List.of(customer1.getFirstName(), customer2.getFirstName(), "FirstName")); + StepVerifier.create(customerRepo.existsByIdAndFirstNameIn(ids, firstNames)) + .expectNext(true) + .verifyComplete(); + + firstNames = QueryParam.of(List.of("FirstName")); + StepVerifier.create(customerRepo.existsByIdAndFirstNameIn(ids, firstNames)) + .expectNext(false) + .verifyComplete(); + } } 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 e4fe11020..aef3bc012 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 @@ -15,6 +15,7 @@ import org.springframework.data.domain.Sort; import reactor.core.publisher.Flux; import reactor.core.scheduler.Schedulers; +import reactor.test.StepVerifier; import java.util.List; @@ -299,4 +300,47 @@ public void findByGroup() { assertThat(results).containsOnly(customer2, customer3); } + + @Test + public void findByIdAndFirstNameIn() { + QueryParam ids = QueryParam.of(List.of(customer1.getId(), customer2.getId())); + QueryParam firstNames = QueryParam.of(List.of(customer1.getFirstName(), customer2.getFirstName(), "FirstName")); + StepVerifier.create(customerRepo.findByIdAndFirstNameIn(ids, firstNames).collectList()) + .expectNextMatches(list -> list.size() == 2 && list.contains(customer1) && list.contains(customer2)) + .verifyComplete(); + + firstNames = QueryParam.of(List.of("FirstName")); + StepVerifier.create(customerRepo.findByIdAndFirstNameIn(ids, firstNames)) + .expectComplete() + .verify(); + } + + @Test + public void findByIdAndFirstNameIn_Synonyms() { + QueryParam ids = QueryParam.of(List.of(customer1.getId(), customer2.getId())); + QueryParam firstNames = QueryParam.of(List.of(customer1.getFirstName(), customer2.getFirstName(), "FirstName")); + StepVerifier.create(customerRepo.readByIdAndFirstNameIn(ids, firstNames).collectList()) + .expectNextMatches(list -> list.size() == 2 && list.contains(customer1) && list.contains(customer2)) + .verifyComplete(); + + StepVerifier.create(customerRepo.readByIdAndFirstNameIn(ids, firstNames).collectList()) + .expectNextMatches(list -> list.size() == 2 && list.contains(customer1) && list.contains(customer2)) + .verifyComplete(); + + StepVerifier.create(customerRepo.getByIdAndFirstNameIn(ids, firstNames).collectList()) + .expectNextMatches(list -> list.size() == 2 && list.contains(customer1) && list.contains(customer2)) + .verifyComplete(); + + StepVerifier.create(customerRepo.queryByIdAndFirstNameIn(ids, firstNames).collectList()) + .expectNextMatches(list -> list.size() == 2 && list.contains(customer1) && list.contains(customer2)) + .verifyComplete(); + + StepVerifier.create(customerRepo.searchByIdAndFirstNameIn(ids, firstNames).collectList()) + .expectNextMatches(list -> list.size() == 2 && list.contains(customer1) && list.contains(customer2)) + .verifyComplete(); + + StepVerifier.create(customerRepo.streamByIdAndFirstNameIn(ids, firstNames).collectList()) + .expectNextMatches(list -> list.size() == 2 && list.contains(customer1) && list.contains(customer2)) + .verifyComplete(); + } } 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 d27a5e811..9e1046ab1 100644 --- a/src/test/java/org/springframework/data/aerospike/sample/PersonNegativeTestsRepository.java +++ b/src/test/java/org/springframework/data/aerospike/sample/PersonNegativeTestsRepository.java @@ -254,16 +254,66 @@ List

findByIntMapContaining(CriteriaDefinition.AerospikeQueryCriterion criter */ List

findByIntsBetween(); + /** + * Invalid number of arguments: expecting two + */ + boolean existsByIntsBetween(); + + /** + * Invalid number of arguments: expecting two + */ + long countByIntsBetween(); + + /** + * Invalid number of arguments: expecting two + */ + void deleteByIntsBetween(); + /** * Invalid number of arguments: expecting two */ List

findByIntsBetween(int number1); + /** + * Invalid number of arguments: expecting two + */ + boolean existsByIntsBetween(int number1); + + /** + * Invalid number of arguments: expecting two + */ + long countByIntsBetween(int number1); + + /** + * Invalid number of arguments: expecting two + */ + void deleteByIntsBetween(int number1); + /** * Type mismatch, expecting one of the following types: Number, Collection */ List

findByIntsBetween(Map map1, Map map2); + /** + * Type mismatch, expecting one of the following types: Number, Collection + */ + boolean existsByIntsBetween(Map map1, Map map2); + + /** + * Type mismatch, expecting one of the following types: Number, Collection + */ + long countByIntsBetween(Map map1, Map map2); + + /** + * Type mismatch, expecting one of the following types: Number, Collection + */ + long existsBycountByIntsBetween(Map map1, Map map2); + + /** + * Type mismatch, expecting one of the following types: Number, Collection + */ + void deleteByIntsBetween(Map map1, Map map2); + /** * Invalid number of arguments: expecting one POJO */ 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 67033b8fc..e3d0efb9a 100644 --- a/src/test/java/org/springframework/data/aerospike/sample/PersonRepository.java +++ b/src/test/java/org/springframework/data/aerospike/sample/PersonRepository.java @@ -75,6 +75,42 @@ public interface PersonRepository

extends AerospikeRepository< */ List

findByIdAndFirstName(QueryParam ids, QueryParam firstName); + /** + * Find if there are entities that satisfy the condition "have primary key in the given list and first name equal to + * the specified string". + * + * @param ids List of primary keys + * @param firstName String to compare with + */ + boolean existsByIdAndFirstName(QueryParam ids, QueryParam firstName); + + /** + * Count all entities that satisfy the condition "have primary key in the given list and first name equal to the + * specified string". + * + * @param ids List of primary keys + * @param firstName String to compare with + */ + long countByIdAndFirstName(QueryParam ids, QueryParam firstName); + + /** + * Delete all entities that satisfy the condition "have primary key in the given list and first name equal to the + * specified string". + * + * @param ids List of primary keys + * @param firstName String to compare with + */ + void deleteByIdAndFirstName(QueryParam ids, QueryParam firstName); + + /** + * Find all entities that satisfy the condition "have primary key in the given list and first name equal to the + * specified string". + * + * @param ids List of primary keys + * @param firstName String to compare with + */ + List

findAllByIdAndFirstName(QueryParam ids, QueryParam firstName); + /** * Find all entities that satisfy the condition "have primary key in the given list and either first name equal to * the specified string or age equal to the specified integer". @@ -87,6 +123,10 @@ public interface PersonRepository

extends AerospikeRepository< List

findByIdAndFirstNameOrAge(QueryParam ids, QueryParam firstName, QueryParam age); + boolean existsByIdAndFirstNameOrAge(QueryParam ids, QueryParam firstName, QueryParam age); + + long countByIdAndFirstNameOrAge(QueryParam ids, QueryParam firstName, QueryParam age); + Page

findByLastNameStartsWithOrderByAgeAsc(String prefix, Pageable pageable); List

findByLastNameEndsWith(String postfix); @@ -153,6 +193,30 @@ public interface PersonRepository

extends AerospikeRepository< */ List

findByAgeBetween(int from, int to); + /** + * Find if there are existing entities that satisfy the condition "have age in the given range" + * + * @param from lower limit, inclusive + * @param to upper limit, exclusive + */ + boolean existsByAgeBetween(int from, int to); + + /** + * Count existing entities that satisfy the condition "have age in the given range" + * + * @param from lower limit, inclusive + * @param to upper limit, exclusive + */ + long countByAgeBetween(int from, int to); + + /** + * Delete entities that satisfy the condition "have age in the given range" + * + * @param from lower limit, inclusive + * @param to upper limit, exclusive + */ + void deleteByAgeBetween(int from, int to); + /** * Find all entities that satisfy the condition "have the first name in the given range" *

@@ -163,6 +227,36 @@ public interface PersonRepository

extends AerospikeRepository< */ List

findByFirstNameBetween(String from, String to); + /** + * Find if there are existing entities that satisfy the condition "have the first name in the given range" + *

+ * Information about ordering + * + * @param from lower limit for the map value, inclusive + * @param to upper limit for the map value, exclusive + */ + boolean existsByFirstNameBetween(String from, String to); + + /** + * Count existing entities that satisfy the condition "have the first name in the given range" + *

+ * Information about ordering + * + * @param from lower limit for the map value, inclusive + * @param to upper limit for the map value, exclusive + */ + long countByFirstNameBetween(String from, String to); + + /** + * Delete entities that satisfy the condition "have the first name in the given range" + *

+ * Information about ordering + * + * @param from lower limit for the map value, inclusive + * @param to upper limit for the map value, exclusive + */ + void deleteByFirstNameBetween(String from, String to); + List

findByIntsExists(); List

findByIntMapExists(); @@ -234,6 +328,12 @@ List

findByAgeOrLastNameLikeAndFirstNameLike(QueryParam age, QueryParam lastN List

findByDateOfBirthAfter(Date date); + boolean existsByDateOfBirthAfter(Date date); + + long countByDateOfBirthAfter(Date date); + + void deleteByDateOfBirthAfter(Date date); + List

findByRegDate(LocalDate date); List

findByRegDateBefore(LocalDate date); @@ -261,12 +361,14 @@ List

findByAgeOrLastNameLikeAndFirstNameLike(QueryParam age, QueryParam lastN @SuppressWarnings("UnusedReturnValue") long countByLastName(String lastName); - int countByFirstName(String firstName); - long someCountQuery(String lastName); List

findByFirstNameIgnoreCase(String firstName); + long countByFirstNameIgnoreCase(String firstName); + + void deleteByFirstNameIgnoreCase(String firstName); + List

findByFirstNameNotIgnoreCase(String firstName); List

findByFirstNameStartingWithIgnoreCase(String string); @@ -294,6 +396,14 @@ List

findByAgeOrLastNameLikeAndFirstNameLike(QueryParam age, QueryParam lastN */ Slice

findByAgeGreaterThan(int age, Pageable pageable); + /** + * Delete entities with age greater than the given numeric parameter + * + * @param age integer to compare with + * @param pageable Pageable + */ + Slice deleteByAgeGreaterThan(int age, Pageable pageable); + /** * Find all entities with age less than the given numeric parameter * @@ -327,7 +437,8 @@ List

findByAgeOrLastNameLikeAndFirstNameLike(QueryParam age, QueryParam lastN List

findByStringsEquals(Collection strings); /** - * Find all entities that satisfy the condition "have strings list equal to 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 strings Collection to compare strings with, subsequently gets converted to a List */ @@ -351,8 +462,8 @@ List

findByAgeOrLastNameLikeAndFirstNameLike(QueryParam age, QueryParam lastN List

findByStringsLessThan(Collection strings); /** - * 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). + * 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 * @@ -547,8 +658,8 @@ 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) + * 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 */ @@ -606,6 +717,31 @@ List

findByAgeOrLastNameLikeAndFirstNameLike(QueryParam age, QueryParam lastN */ List

findByFriendAgeBetween(int from, int to); + /** + * Find if there are entities that satisfy the condition "have a friend with the age in the given range" (find by + * POJO field) + * + * @param from lower limit, inclusive + * @param to upper limit, exclusive + */ + boolean existsByFriendAgeBetween(int from, int to); + + /** + * Count entities that satisfy the condition "have a friend with the age in the given range" (find by POJO field) + * + * @param from lower limit, inclusive + * @param to upper limit, exclusive + */ + long countByFriendAgeBetween(int from, int to); + + /** + * Delete entities that satisfy the condition "have a friend with the age in the given range" (find by POJO field) + * + * @param from lower limit, inclusive + * @param to upper limit, exclusive + */ + void deleteByFriendAgeBetween(int from, int to); + /** * Find all entities that satisfy the condition "have address with zipCode (find by nested simple property)" */ @@ -697,6 +833,39 @@ List

findByAgeOrLastNameLikeAndFirstNameLike(QueryParam age, QueryParam lastN */ List

findByAddressZipCodeBetween(String lowerLimit, String upperLimit); + /** + * Find if there are entities that satisfy the condition "have address with zipCode between the given arguments" + * (find by nested simple property) + *

+ * Information about ordering + * + * @param lowerLimit - lower limit, inclusive + * @param upperLimit - upper limit, exclusive + */ + boolean existsByAddressZipCodeBetween(String lowerLimit, String upperLimit); + + /** + * Count entities that satisfy the condition "have address with zipCode between the given arguments" (find by nested + * simple property) + *

+ * Information about ordering + * + * @param lowerLimit - lower limit, inclusive + * @param upperLimit - upper limit, exclusive + */ + long countByAddressZipCodeBetween(String lowerLimit, String upperLimit); + + /** + * Delete entities that satisfy the condition "have address with zipCode between the given arguments" (find by + * nested simple property) + *

+ * Information about ordering + * + * @param lowerLimit - lower limit, inclusive + * @param upperLimit - upper limit, exclusive + */ + void deleteByAddressZipCodeBetween(String lowerLimit, String upperLimit); + /** * Find all entities that satisfy the condition "have address with zipCode equal to one of the values in the given * list" (find by nested simple property) @@ -1210,8 +1379,8 @@ 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) + * 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 */ @@ -1294,6 +1463,36 @@ List

findByFriendStringMapNotContaining(AerospikeQueryCriterion criterion, */ List

findByIntSetBetween(Collection from, Collection to); + /** + * Find if there are entities that satisfy the condition "have intSet in the given range" + *

+ * 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 + */ + boolean existsByIntSetBetween(Collection from, Collection to); + + /** + * Count entities that satisfy the condition "have intSet in the given range" + *

+ * 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 + */ + long countByIntSetBetween(Collection from, Collection to); + + /** + * Find all entities that satisfy the condition "have intSet in the given range" + *

+ * 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 + */ + void deleteByIntSetBetween(Collection from, Collection to); + /** * Find all entities that satisfy the condition "have ints list in the given range" *

@@ -1304,6 +1503,36 @@ List

findByFriendStringMapNotContaining(AerospikeQueryCriterion criterion, */ List

findByIntsBetween(Collection from, Collection to); + /** + * Find if there are entities that satisfy the condition "have ints list in the given range" + *

+ * 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 + */ + boolean existsByIntsBetween(Collection from, Collection to); + + /** + * Count entities that satisfy the condition "have ints list in the given range" + *

+ * 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 + */ + long countByIntsBetween(Collection from, Collection to); + + /** + * Delete entities that satisfy the condition "have ints list in the given range" + *

+ * 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 + */ + void deleteByIntsBetween(Collection from, Collection to); + /** * Find all entities that satisfy the condition "have strings list in the given range" *

@@ -1326,12 +1555,34 @@ List

findByFriendStringMapNotContaining(AerospikeQueryCriterion criterion, List

findByFirstName(String name); + boolean existsByFirstName(String name); + + boolean existsByFirstNameIgnoreCase(String name); + + long countByFirstName(String name); + + void deleteByFirstName(String name); + + List

readByFirstName(String name); + + List

getByFirstName(String name); + + List

queryByFirstName(String name); + + List

searchByFirstName(String name); + + List

streamByFirstName(String name); + List

findByGender(Person.Gender gender); List

findByGenderIn(List list); List

findByFirstNameIs(String name); + boolean existsByFirstNameIs(String name); + + long countByFirstNameIs(String name); + List

findByFirstNameEquals(String name); List

findByFirstNameNot(String name); 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 7d0e7afc7..52bd89334 100644 --- a/src/test/java/org/springframework/data/aerospike/sample/ReactiveCustomerRepository.java +++ b/src/test/java/org/springframework/data/aerospike/sample/ReactiveCustomerRepository.java @@ -64,6 +64,8 @@ public interface ReactiveCustomerRepository extends ReactiveAerospikeRepository< Flux findByAgeBetween(long from, long to); + Mono countByAgeBetween(long from, long to); + Flux findByFirstNameContains(String firstName); Flux findByFirstNameContainingIgnoreCase(String firstName); @@ -73,4 +75,22 @@ public interface ReactiveCustomerRepository extends ReactiveAerospikeRepository< Flux findByAgeBetweenOrderByFirstNameDesc(long i, long j); Flux findByGroup(char group); + + Flux findByIdAndFirstNameIn(QueryParam ids, QueryParam firstNames); + + Flux readByIdAndFirstNameIn(QueryParam ids, QueryParam firstNames); + + Flux getByIdAndFirstNameIn(QueryParam ids, QueryParam firstNames); + + Flux queryByIdAndFirstNameIn(QueryParam ids, QueryParam firstNames); + + Flux searchByIdAndFirstNameIn(QueryParam ids, QueryParam firstNames); + + Flux streamByIdAndFirstNameIn(QueryParam ids, QueryParam firstNames); + + Mono existsByIdAndFirstNameIn(QueryParam ids, QueryParam firstNames); + + Mono countByIdAndFirstNameIn(QueryParam ids, QueryParam firstNames); + + Mono deleteByIdAndFirstNameIn(QueryParam ids, QueryParam firstNames); }