From 4f8ef8befeb753183be0e5d65fab10576a042877 Mon Sep 17 00:00:00 2001 From: agrgr Date: Wed, 11 Oct 2023 18:51:23 +0300 Subject: [PATCH] add support for findByQualifiers() for reactive flow, updates for not setting statement filter if EXCLUDE_FILTER == true and for reusing Qualifiers, cleanup --- .../aerospike/core/AerospikeOperations.java | 8 +- .../core/ReactiveAerospikeOperations.java | 2 +- .../data/aerospike/query/FilterOperation.java | 304 +++++++++--------- .../data/aerospike/query/Qualifier.java | 17 +- .../aerospike/query/StatementBuilder.java | 6 - .../repository/AerospikeRepository.java | 2 +- .../ReactiveAerospikeRepository.java | 2 +- .../query/BaseAerospikePartTreeQuery.java | 57 ---- .../support/SimpleAerospikeRepository.java | 6 +- .../SimpleReactiveAerospikeRepository.java | 5 +- 10 files changed, 173 insertions(+), 236 deletions(-) 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 e9ba3ad99..651c421ce 100644 --- a/src/main/java/org/springframework/data/aerospike/core/AerospikeOperations.java +++ b/src/main/java/org/springframework/data/aerospike/core/AerospikeOperations.java @@ -558,12 +558,12 @@ void createIndex(Class entityClass, String indexName, String binName, boolean indexExists(String indexName); /** - * Find all documents in the given entityClass's set using provided qualifiers. + * Find all documents in the given entityClass's set using provided {@link Qualifier}s. * * @param entityClass The class to extract the Aerospike set from. Must not be {@literal null}. * @param filter Secondary index filter. - * @param qualifiers Qualifiers to build filter expressions from. - * @return Stream of entities + * @param qualifiers Qualifiers to build filter expressions from. Must not be {@literal null}. + * @return Stream of entities. */ - Stream findAllUsingQuery(Class entityClass, Filter filter, Qualifier... qualifiers); + Stream findAllUsingQuery(Class entityClass, Filter filter, Qualifier... qualifiers); } 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 40f07fb3e..a21d2b622 100644 --- a/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeOperations.java +++ b/src/main/java/org/springframework/data/aerospike/core/ReactiveAerospikeOperations.java @@ -525,7 +525,7 @@ Mono createIndex(Class entityClass, String indexName, String binNam * * @param entityClass The class to extract the Aerospike set from. Must not be {@literal null}. * @param filter Secondary index filter. - * @param qualifiers Qualifiers to build filter expressions from. + * @param qualifiers Qualifiers to build filter expressions from. Must not be {@literal null}. * @return Flux of entities. */ Flux findAllUsingQuery(Class entityClass, Filter filter, Qualifier... qualifiers); diff --git a/src/main/java/org/springframework/data/aerospike/query/FilterOperation.java b/src/main/java/org/springframework/data/aerospike/query/FilterOperation.java index a61e049b7..65aef6b53 100644 --- a/src/main/java/org/springframework/data/aerospike/query/FilterOperation.java +++ b/src/main/java/org/springframework/data/aerospike/query/FilterOperation.java @@ -72,23 +72,20 @@ public Filter sIndexFilter(Map qualifierMap) { @Override public Exp filterExp(Map qualifierMap) { // Convert IN to a collection of OR as Aerospike has no direct support for IN query + return getMetadataExp(qualifierMap).orElseGet(() -> { + Value value1 = getValue1AsCollectionOrFail(qualifierMap); + Collection collection = (Collection) value1.getObject(); + Exp[] arrElementsExp = collection.stream().map(item -> + new Qualifier( + new QualifierBuilder() + .setField(getField(qualifierMap)) + .setFilterOperation(FilterOperation.EQ) + .setValue1(Value.get(item)) + ).toFilterExp() + ).toArray(Exp[]::new); - Optional metadataExp; - if ((metadataExp = getMetadataExp(qualifierMap)).isPresent()) return metadataExp.get(); - - Value value1 = getValue1AsCollectionOrFail(qualifierMap); - - Collection collection = (Collection) value1.getObject(); - Exp[] arrElementsExp = collection.stream().map(item -> - new Qualifier( - new QualifierBuilder() - .setField(getField(qualifierMap)) - .setFilterOperation(FilterOperation.EQ) - .setValue1(Value.get(item)) - ).toFilterExp() - ).toArray(Exp[]::new); - - return Exp.or(arrElementsExp); + return Exp.or(arrElementsExp); + }); } @Override @@ -101,22 +98,21 @@ public Filter sIndexFilter(Map qualifierMap) { public Exp filterExp(Map qualifierMap) { // Convert NOT_IN to a collection of AND as Aerospike has no direct support for IN query - Optional metadataExp; - if ((metadataExp = getMetadataExp(qualifierMap)).isPresent()) return metadataExp.get(); + return getMetadataExp(qualifierMap).orElseGet(() -> { + Value value1 = getValue1AsCollectionOrFail(qualifierMap); - Value value1 = getValue1AsCollectionOrFail(qualifierMap); + Collection collection = (Collection) value1.getObject(); + Exp[] arrElementsExp = collection.stream().map(item -> + new Qualifier( + new QualifierBuilder() + .setField(getField(qualifierMap)) + .setFilterOperation(FilterOperation.NOTEQ) + .setValue1(Value.get(item)) + ).toFilterExp() + ).toArray(Exp[]::new); - Collection collection = (Collection) value1.getObject(); - Exp[] arrElementsExp = collection.stream().map(item -> - new Qualifier( - new QualifierBuilder() - .setField(getField(qualifierMap)) - .setFilterOperation(FilterOperation.NOTEQ) - .setValue1(Value.get(item)) - ).toFilterExp() - ).toArray(Exp[]::new); - - return Exp.and(arrElementsExp); + return Exp.and(arrElementsExp); + }); } @Override @@ -127,29 +123,30 @@ public Filter sIndexFilter(Map qualifierMap) { EQ { @Override public Exp filterExp(Map qualifierMap) { - Optional metadataExp; - if ((metadataExp = getMetadataExp(qualifierMap)).isPresent()) return metadataExp.get(); - - Value value = getValue1(qualifierMap); - return switch (value.getType()) { - case INTEGER -> Exp.eq(Exp.intBin(getField(qualifierMap)), Exp.val(value.toLong())); - case STRING -> { - if (ignoreCase(qualifierMap)) { - String equalsRegexp = - QualifierRegexpBuilder.getStringEquals(getValue1(qualifierMap).toString()); - yield Exp.regexCompare(equalsRegexp, RegexFlag.ICASE, Exp.stringBin(getField(qualifierMap))); - } else { - yield Exp.eq(Exp.stringBin(getField(qualifierMap)), Exp.val(value.toString())); + return getMetadataExp(qualifierMap).orElseGet(() -> { + Value value = getValue1(qualifierMap); + return switch (value.getType()) { + case INTEGER -> Exp.eq(Exp.intBin(getField(qualifierMap)), Exp.val(value.toLong())); + case STRING -> { + if (ignoreCase(qualifierMap)) { + String equalsRegexp = + QualifierRegexpBuilder.getStringEquals(getValue1(qualifierMap).toString()); + yield Exp.regexCompare(equalsRegexp, RegexFlag.ICASE, + Exp.stringBin(getField(qualifierMap))); + } else { + yield Exp.eq(Exp.stringBin(getField(qualifierMap)), Exp.val(value.toString())); + } } - } - case BOOL -> Exp.eq(Exp.boolBin(getField(qualifierMap)), Exp.val((Boolean) value.getObject())); - case MAP -> getFilterExp(Exp.val((Map) value.getObject()), getField(qualifierMap), Exp::eq, - Exp::mapBin); - case LIST -> - getFilterExp(Exp.val((List) value.getObject()), getField(qualifierMap), Exp::eq, Exp::listBin); - default -> throw new IllegalArgumentException("EQ FilterExpression unsupported particle type: " + - value.getClass().getSimpleName()); - }; + case BOOL -> Exp.eq(Exp.boolBin(getField(qualifierMap)), Exp.val((Boolean) value.getObject())); + case MAP -> getFilterExp(Exp.val((Map) value.getObject()), getField(qualifierMap), Exp::eq, + Exp::mapBin); + case LIST -> + getFilterExp(Exp.val((List) value.getObject()), getField(qualifierMap), Exp::eq, + Exp::listBin); + default -> throw new IllegalArgumentException("EQ FilterExpression unsupported particle type: " + + value.getClass().getSimpleName()); + }; + }); } @Override @@ -168,39 +165,39 @@ public Filter sIndexFilter(Map qualifierMap) { NOTEQ { @Override public Exp filterExp(Map qualifierMap) { - Optional metadataExp; - if ((metadataExp = getMetadataExp(qualifierMap)).isPresent()) return metadataExp.get(); - - Value value = getValue1(qualifierMap); - return switch (value.getType()) { - // FMWK-175: Exp.ne() does not return null bins, so Exp.not(Exp.binExists()) is added - case INTEGER -> { - Exp ne = Exp.ne(Exp.intBin(getField(qualifierMap)), Exp.val(value.toLong())); - yield Exp.or(Exp.not(Exp.binExists(getField(qualifierMap))), ne); - } - case STRING -> { - if (ignoreCase(qualifierMap)) { - String equalsRegexp = - QualifierRegexpBuilder.getStringEquals(getValue1(qualifierMap).toString()); - Exp regexCompare = Exp.not(Exp.regexCompare(equalsRegexp, RegexFlag.ICASE, - Exp.stringBin(getField(qualifierMap)))); - yield Exp.or(Exp.not(Exp.binExists(getField(qualifierMap))), regexCompare); - } else { - Exp ne = Exp.ne(Exp.stringBin(getField(qualifierMap)), Exp.val(value.toString())); + return getMetadataExp(qualifierMap).orElseGet(() -> { + Value value = getValue1(qualifierMap); + return switch (value.getType()) { + // FMWK-175: Exp.ne() does not return null bins, so Exp.not(Exp.binExists()) is added + case INTEGER -> { + Exp ne = Exp.ne(Exp.intBin(getField(qualifierMap)), Exp.val(value.toLong())); yield Exp.or(Exp.not(Exp.binExists(getField(qualifierMap))), ne); } - } - case BOOL -> { - Exp ne = Exp.ne(Exp.boolBin(getField(qualifierMap)), Exp.val((Boolean) value.getObject())); - yield Exp.or(Exp.not(Exp.binExists(getField(qualifierMap))), ne); - } - case MAP -> getFilterExp(Exp.val((Map) value.getObject()), getField(qualifierMap), Exp::ne, - Exp::mapBin); - case LIST -> - getFilterExp(Exp.val((List) value.getObject()), getField(qualifierMap), Exp::ne, Exp::listBin); - default -> throw new IllegalArgumentException("NOTEQ FilterExpression unsupported particle type: " + - value.getClass().getSimpleName()); - }; + case STRING -> { + if (ignoreCase(qualifierMap)) { + String equalsRegexp = + QualifierRegexpBuilder.getStringEquals(getValue1(qualifierMap).toString()); + Exp regexCompare = Exp.not(Exp.regexCompare(equalsRegexp, RegexFlag.ICASE, + Exp.stringBin(getField(qualifierMap)))); + yield Exp.or(Exp.not(Exp.binExists(getField(qualifierMap))), regexCompare); + } else { + Exp ne = Exp.ne(Exp.stringBin(getField(qualifierMap)), Exp.val(value.toString())); + yield Exp.or(Exp.not(Exp.binExists(getField(qualifierMap))), ne); + } + } + case BOOL -> { + Exp ne = Exp.ne(Exp.boolBin(getField(qualifierMap)), Exp.val((Boolean) value.getObject())); + yield Exp.or(Exp.not(Exp.binExists(getField(qualifierMap))), ne); + } + case MAP -> getFilterExp(Exp.val((Map) value.getObject()), getField(qualifierMap), Exp::ne, + Exp::mapBin); + case LIST -> + getFilterExp(Exp.val((List) value.getObject()), getField(qualifierMap), Exp::ne, + Exp::listBin); + default -> throw new IllegalArgumentException("NOTEQ FilterExpression unsupported particle type: " + + value.getClass().getSimpleName()); + }; + }); } @Override @@ -211,21 +208,22 @@ public Filter sIndexFilter(Map qualifierMap) { GT { @Override public Exp filterExp(Map qualifierMap) { - Optional metadataExp; - if ((metadataExp = getMetadataExp(qualifierMap)).isPresent()) return metadataExp.get(); - - Value value = getValue1(qualifierMap); - return switch (value.getType()) { - case INTEGER -> Exp.gt(Exp.intBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toLong())); - case STRING -> - Exp.gt(Exp.stringBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toString())); - case MAP -> getFilterExp(Exp.val((Map) value.getObject()), getField(qualifierMap), Exp::gt, - Exp::mapBin); - case LIST -> - getFilterExp(Exp.val((List) value.getObject()), getField(qualifierMap), Exp::gt, Exp::listBin); - default -> throw new IllegalArgumentException("GT FilterExpression unsupported particle type: " + - value.getClass().getSimpleName()); - }; + return getMetadataExp(qualifierMap).orElseGet(() -> { + Value value = getValue1(qualifierMap); + return switch (value.getType()) { + case INTEGER -> + Exp.gt(Exp.intBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toLong())); + case STRING -> + Exp.gt(Exp.stringBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toString())); + case MAP -> getFilterExp(Exp.val((Map) value.getObject()), getField(qualifierMap), Exp::gt, + Exp::mapBin); + case LIST -> + getFilterExp(Exp.val((List) value.getObject()), getField(qualifierMap), Exp::gt, + Exp::listBin); + default -> throw new IllegalArgumentException("GT FilterExpression unsupported particle type: " + + value.getClass().getSimpleName()); + }; + }); } @Override @@ -241,21 +239,22 @@ public Filter sIndexFilter(Map qualifierMap) { GTEQ { @Override public Exp filterExp(Map qualifierMap) { - Optional metadataExp; - if ((metadataExp = getMetadataExp(qualifierMap)).isPresent()) return metadataExp.get(); - - Value value = getValue1(qualifierMap); - return switch (value.getType()) { - case INTEGER -> Exp.ge(Exp.intBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toLong())); - case STRING -> - Exp.ge(Exp.stringBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toString())); - case MAP -> getFilterExp(Exp.val((Map) value.getObject()), getField(qualifierMap), Exp::ge, - Exp::mapBin); - case LIST -> - getFilterExp(Exp.val((List) value.getObject()), getField(qualifierMap), Exp::ge, Exp::listBin); - default -> throw new IllegalArgumentException("GTEQ FilterExpression unsupported particle type: " + - value.getClass().getSimpleName()); - }; + return getMetadataExp(qualifierMap).orElseGet(() -> { + Value value = getValue1(qualifierMap); + return switch (value.getType()) { + case INTEGER -> + Exp.ge(Exp.intBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toLong())); + case STRING -> + Exp.ge(Exp.stringBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toString())); + case MAP -> getFilterExp(Exp.val((Map) value.getObject()), getField(qualifierMap), Exp::ge, + Exp::mapBin); + case LIST -> + getFilterExp(Exp.val((List) value.getObject()), getField(qualifierMap), Exp::ge, + Exp::listBin); + default -> throw new IllegalArgumentException("GTEQ FilterExpression unsupported particle type: " + + value.getClass().getSimpleName()); + }; + }); } @Override @@ -269,21 +268,22 @@ public Filter sIndexFilter(Map qualifierMap) { LT { @Override public Exp filterExp(Map qualifierMap) { - Optional metadataExp; - if ((metadataExp = getMetadataExp(qualifierMap)).isPresent()) return metadataExp.get(); - - Value value = getValue1(qualifierMap); - return switch (value.getType()) { - case INTEGER -> Exp.lt(Exp.intBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toLong())); - case STRING -> - Exp.lt(Exp.stringBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toString())); - case MAP -> getFilterExp(Exp.val((Map) value.getObject()), getField(qualifierMap), Exp::lt, - Exp::mapBin); - case LIST -> - getFilterExp(Exp.val((List) value.getObject()), getField(qualifierMap), Exp::lt, Exp::listBin); - default -> throw new IllegalArgumentException("LT FilterExpression unsupported particle type: " + - value.getClass().getSimpleName()); - }; + return getMetadataExp(qualifierMap).orElseGet(() -> { + Value value = getValue1(qualifierMap); + return switch (value.getType()) { + case INTEGER -> + Exp.lt(Exp.intBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toLong())); + case STRING -> + Exp.lt(Exp.stringBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toString())); + case MAP -> getFilterExp(Exp.val((Map) value.getObject()), getField(qualifierMap), Exp::lt, + Exp::mapBin); + case LIST -> + getFilterExp(Exp.val((List) value.getObject()), getField(qualifierMap), Exp::lt, + Exp::listBin); + default -> throw new IllegalArgumentException("LT FilterExpression unsupported particle type: " + + value.getClass().getSimpleName()); + }; + }); } @Override @@ -298,21 +298,22 @@ public Filter sIndexFilter(Map qualifierMap) { LTEQ { @Override public Exp filterExp(Map qualifierMap) { - Optional metadataExp; - if ((metadataExp = getMetadataExp(qualifierMap)).isPresent()) return metadataExp.get(); - - Value value = getValue1(qualifierMap); - return switch (value.getType()) { - case INTEGER -> Exp.le(Exp.intBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toLong())); - case STRING -> - Exp.le(Exp.stringBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toString())); - case MAP -> getFilterExp(Exp.val((Map) value.getObject()), getField(qualifierMap), Exp::le, - Exp::mapBin); - case LIST -> - getFilterExp(Exp.val((List) value.getObject()), getField(qualifierMap), Exp::le, Exp::listBin); - default -> throw new IllegalArgumentException("LTEQ FilterExpression unsupported particle type: " + - value.getClass().getSimpleName()); - }; + return getMetadataExp(qualifierMap).orElseGet(() -> { + Value value = getValue1(qualifierMap); + return switch (value.getType()) { + case INTEGER -> + Exp.le(Exp.intBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toLong())); + case STRING -> + Exp.le(Exp.stringBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toString())); + case MAP -> getFilterExp(Exp.val((Map) value.getObject()), getField(qualifierMap), Exp::le, + Exp::mapBin); + case LIST -> + getFilterExp(Exp.val((List) value.getObject()), getField(qualifierMap), Exp::le, + Exp::listBin); + default -> throw new IllegalArgumentException("LTEQ FilterExpression unsupported particle type: " + + value.getClass().getSimpleName()); + }; + }); } @Override @@ -329,10 +330,7 @@ public Exp filterExp(Map qualifierMap) { validateEquality(getValue1(qualifierMap).getType(), getValue2(qualifierMap).getType(), qualifierMap, "BETWEEN"); - Optional metadataExp; - if ((metadataExp = getMetadataExp(qualifierMap)).isPresent()) return metadataExp.get(); - - return switch (getValue1(qualifierMap).getType()) { + return getMetadataExp(qualifierMap).orElseGet(() -> switch (getValue1(qualifierMap).getType()) { case INTEGER -> Exp.and( Exp.ge(Exp.intBin(getField(qualifierMap)), Exp.val(getValue1(qualifierMap).toLong())), Exp.lt(Exp.intBin(getField(qualifierMap)), Exp.val(getValue2(qualifierMap).toLong())) @@ -356,7 +354,7 @@ public Exp filterExp(Map qualifierMap) { default -> throw new IllegalArgumentException("BETWEEN: unexpected value of type " + getValue1(qualifierMap).getClass() .getSimpleName()); - }; + }); } @Override @@ -1221,7 +1219,6 @@ public Filter sIndexFilter(Map qualifierMap) { }; private static Exp processMetadataFieldInOrNot(Map qualifierMap, boolean notIn) { - String operation = notIn ? "NOT_IN" : "IN"; FilterOperation filterOperation = notIn ? NOTEQ : EQ; Object value1 = getValue1Object(qualifierMap); @@ -1229,6 +1226,7 @@ private static Exp processMetadataFieldInOrNot(Map qualifierMap, try { listOfLongs = (Collection) value1; // previously validated } catch (Exception e) { + String operation = notIn ? "NOT_IN" : "IN"; throw new IllegalStateException("FilterOperation." + operation + " metadata query: expecting value1 with " + "type List"); } @@ -1258,10 +1256,8 @@ private static Value getValue1AsCollectionOrFail(Map qualifierMa value1.getObject().getClass().getSimpleName(); if (value1.getType() != LIST) { throw new IllegalArgumentException(errMsg); - } else { - if (!(value1.getObject() instanceof Collection)) { - throw new IllegalArgumentException(errMsg); - } + } else if (!(value1.getObject() instanceof Collection)) { + throw new IllegalArgumentException(errMsg); } return value1; } @@ -1276,9 +1272,9 @@ private static Value getValue1AsCollectionOrFail(Map qualifierMa private static Optional getMetadataExp(Map qualifierMap) { CriteriaDefinition.AerospikeMetadata metadataField = getMetadataField(qualifierMap); String field = getField(qualifierMap); - FilterOperation operation = getOperation(qualifierMap); if (metadataField != null && (field == null || field.isEmpty())) { + FilterOperation operation = getOperation(qualifierMap); switch (operation) { case EQ, NOTEQ, LT, LTEQ, GT, GTEQ -> { BiFunction operationFunction = mapOperation(operation); diff --git a/src/main/java/org/springframework/data/aerospike/query/Qualifier.java b/src/main/java/org/springframework/data/aerospike/query/Qualifier.java index 45d1edcff..9955e0168 100644 --- a/src/main/java/org/springframework/data/aerospike/query/Qualifier.java +++ b/src/main/java/org/springframework/data/aerospike/query/Qualifier.java @@ -219,10 +219,9 @@ public Set> entrySet() { public String toString() { if (!StringUtils.hasLength(getField()) && StringUtils.hasLength(getMetadataField().toString())) { return String.format("%s:%s:%s:%s", getField(), getOperation(), getValue1(), getValue2()); - } else { - return String.format("(metadata)%s:%s:%s:%s", getMetadataField().toString(), - getOperation(), getValue1(), getValue2()); } + return String.format("(metadata)%s:%s:%s:%s", getMetadataField().toString(), + getOperation(), getValue1(), getValue2()); } public static class QualifierRegexpBuilder { @@ -383,21 +382,21 @@ public Map buildMap() { } } - public static void validateQualifier(Qualifier qualifier) { + public static void validate(Qualifier qualifier) { // metadata query if (qualifier.getMetadataField() != null && qualifier.getField() == null) { FilterOperation operation = qualifier.getOperation(); switch (operation) { - case EQ, NOTEQ, LT, LTEQ, GT, GTEQ -> - Assert.isTrue(qualifier.getValue1AsObj() != null && qualifier.getValue1AsObj() instanceof Long, - operation.name() + ": value1 is expected to be set as Long"); + case EQ, NOTEQ, LT, LTEQ, GT, GTEQ -> Assert.isTrue(qualifier.getValue1AsObj() instanceof Long, + operation.name() + ": value1 is expected to be set as Long"); case BETWEEN -> { - Assert.isTrue(qualifier.getValue1AsObj() != null && qualifier.getValue1AsObj() instanceof Long, + Assert.isTrue(qualifier.getValue1AsObj() instanceof Long, "BETWEEN: value1 is expected to be set as Long"); - Assert.isTrue(qualifier.getValue2AsObj() != null && qualifier.getValue2AsObj() instanceof Long, + Assert.isTrue(qualifier.getValue2AsObj() instanceof Long, "BETWEEN: value2 is expected to be set as Long"); } case NOT_IN, IN -> Assert.isTrue(qualifier.getValue1AsObj() instanceof Collection + && (!((Collection) qualifier.getValue1AsObj()).isEmpty()) && ((Collection) qualifier.getValue1AsObj()).toArray()[0] instanceof Long, operation.name() + ": value1 is expected to be a non-empty Collection"); default -> throw new IllegalArgumentException("Operation " + operation + " cannot be applied to " + diff --git a/src/main/java/org/springframework/data/aerospike/query/StatementBuilder.java b/src/main/java/org/springframework/data/aerospike/query/StatementBuilder.java index f8c57c6b8..d26277c31 100644 --- a/src/main/java/org/springframework/data/aerospike/query/StatementBuilder.java +++ b/src/main/java/org/springframework/data/aerospike/query/StatementBuilder.java @@ -82,12 +82,6 @@ && isIndexedBin(stmt, innerQualifier)) { if (filter != null) { stmt.setFilter(filter); qualifier.setQueryAsFilter(true); - /* If this was the only qualifier, we do not need to do anymore work, just return - * the query iterator. - */ - if (qualifiers.length == 1) { - return; - } break; // the first processed filter becomes statement filter } } diff --git a/src/main/java/org/springframework/data/aerospike/repository/AerospikeRepository.java b/src/main/java/org/springframework/data/aerospike/repository/AerospikeRepository.java index 458cd7089..3083853e1 100644 --- a/src/main/java/org/springframework/data/aerospike/repository/AerospikeRepository.java +++ b/src/main/java/org/springframework/data/aerospike/repository/AerospikeRepository.java @@ -65,7 +65,7 @@ public interface AerospikeRepository extends PagingAndSortingRepository findByQualifiers(Qualifier... qualifiers); diff --git a/src/main/java/org/springframework/data/aerospike/repository/ReactiveAerospikeRepository.java b/src/main/java/org/springframework/data/aerospike/repository/ReactiveAerospikeRepository.java index 91fd8b9c9..6bbcebdb8 100644 --- a/src/main/java/org/springframework/data/aerospike/repository/ReactiveAerospikeRepository.java +++ b/src/main/java/org/springframework/data/aerospike/repository/ReactiveAerospikeRepository.java @@ -36,7 +36,7 @@ public interface ReactiveAerospikeRepository extends ReactiveCrudReposito * Each qualifier itself may contain internal qualifiers and combine them using either {@link FilterOperation#AND} * or {@link FilterOperation#OR}. * - * @param qualifiers One or more qualifiers representing expressions. + * @param qualifiers One or more qualifiers representing expressions. Must not be {@literal null}. * @return Flux of entities. */ Flux findByQualifiers(Qualifier... qualifiers); 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 36d536dd3..d507d5395 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 @@ -15,11 +15,7 @@ */ package org.springframework.data.aerospike.repository.query; -import lombok.Getter; -import lombok.NonNull; -import lombok.Setter; import org.springframework.beans.BeanUtils; -import org.springframework.data.aerospike.query.FilterOperation; import org.springframework.data.aerospike.query.Qualifier; import org.springframework.data.repository.query.ParameterAccessor; import org.springframework.data.repository.query.ParametersParameterAccessor; @@ -33,11 +29,8 @@ import org.springframework.util.ClassUtils; import java.lang.reflect.Constructor; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.Objects; -import java.util.Optional; /** * @author Peter Milne @@ -176,54 +169,4 @@ protected Object runIdQuery(Class sourceClass, Class targetClass, Object i abstract Object findByIds(Iterable iterable, Class sourceClass, Class targetClass, Qualifier... qualifiers); - - protected static List getMetadataQueryParameters(@NonNull Object[] parameters) { - List paramsList = new ArrayList<>(); - for (int i = 0; i < parameters.length; i++) { - if (parameters[i] instanceof CriteriaDefinition.AerospikeMetadata && parameters.length > i + 2) { - MetadataQueryParams metadataQueryParams = new MetadataQueryParams(); - getMetadataFieldParameter(parameters[i]).ifPresent(metadataQueryParams::setField); - getOperationParameter(parameters[i + 1]).ifPresent(metadataQueryParams::setOperation); - getValuesParameter(parameters[i + 2]).ifPresent(metadataQueryParams::setValues); - paramsList.add(metadataQueryParams); - i += 2; - } - } - - return paramsList; - } - - protected static Optional getMetadataFieldParameter(@NonNull Object parameter) { - if (parameter instanceof CriteriaDefinition.AerospikeMetadata) { - return Optional.of((CriteriaDefinition.AerospikeMetadata) parameter); - } - return Optional.empty(); - } - - protected static Optional getOperationParameter(@NonNull Object parameter) { - if (parameter instanceof FilterOperation) { - return Optional.of((FilterOperation) parameter); - } - return Optional.empty(); - } - - protected static Optional> getValuesParameter(@NonNull Object parameter) { - if (parameter instanceof long[]) { - return Optional.of(Arrays.stream((long[]) parameter).boxed().toList()); - } else if (parameter instanceof Long[]) { - return Optional.of(List.of((Long) parameter)); - } else if (parameter instanceof Long) { - return Optional.of(List.of((Long) parameter)); - } - return Optional.empty(); - } - - @Setter - @Getter - public static class MetadataQueryParams { - - CriteriaDefinition.AerospikeMetadata field; - FilterOperation operation; - List values; - } } diff --git a/src/main/java/org/springframework/data/aerospike/repository/support/SimpleAerospikeRepository.java b/src/main/java/org/springframework/data/aerospike/repository/support/SimpleAerospikeRepository.java index aafc0c723..0f9cff7b3 100644 --- a/src/main/java/org/springframework/data/aerospike/repository/support/SimpleAerospikeRepository.java +++ b/src/main/java/org/springframework/data/aerospike/repository/support/SimpleAerospikeRepository.java @@ -163,10 +163,12 @@ public boolean indexExists(String indexName) { @Override public Iterable findByQualifiers(Qualifier... qualifiers) { + Assert.notNull(qualifiers, "Qualifiers must not be null"); + Arrays.stream(qualifiers).forEach(qualifier -> { qualifier.setExcludeFilter(true); - Qualifier.validateQualifier(qualifier); + Qualifier.validate(qualifier); }); - return (Iterable) operations.findAllUsingQuery(entityInformation.getJavaType(), null, qualifiers).toList(); + return operations.findAllUsingQuery(entityInformation.getJavaType(), null, qualifiers).toList(); } } diff --git a/src/main/java/org/springframework/data/aerospike/repository/support/SimpleReactiveAerospikeRepository.java b/src/main/java/org/springframework/data/aerospike/repository/support/SimpleReactiveAerospikeRepository.java index 923e84d57..c45947e0f 100644 --- a/src/main/java/org/springframework/data/aerospike/repository/support/SimpleReactiveAerospikeRepository.java +++ b/src/main/java/org/springframework/data/aerospike/repository/support/SimpleReactiveAerospikeRepository.java @@ -157,7 +157,10 @@ public void deleteIndex(Class domainType, String indexName) { @Override public Flux findByQualifiers(Qualifier... qualifiers) { - Arrays.stream(qualifiers).forEach(Qualifier::validateQualifier); + Assert.notNull(qualifiers, "Qualifiers must not be null"); + + if (qualifiers == null || qualifiers.length == 0) return Flux.empty(); + Arrays.stream(qualifiers).forEach(Qualifier::validate); return operations.findAllUsingQuery(entityInformation.getJavaType(), null, qualifiers); } }