Skip to content

Commit

Permalink
FMWK-470 Find by string not in doesn't return entities with null in t…
Browse files Browse the repository at this point in the history
…he relevant field (#757)
  • Loading branch information
agrgr authored Jun 25, 2024
1 parent 2d988d7 commit b015df5
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
import static org.springframework.data.aerospike.util.FilterOperationRegexpBuilder.getStringEquals;
import static org.springframework.data.aerospike.util.Utils.ctxArrToString;
import static org.springframework.data.aerospike.util.Utils.getExpType;
import static org.springframework.data.aerospike.util.Utils.getValueExpOrFail;
import static org.springframework.data.aerospike.util.Utils.getExpValOrFail;

public enum FilterOperation {
/**
Expand Down Expand Up @@ -544,7 +544,10 @@ public Filter sIndexFilter(Map<QualifierKey, Object> qualifierMap) {
@Override
public Exp filterExp(Map<QualifierKey, Object> qualifierMap) {
Exp binIsNull = Exp.not(Exp.binExists(getBinName(qualifierMap)));
return Exp.or(binIsNull, getFilterExpMapValNotEqOrFail(qualifierMap, Exp::ne));
String errMsg = "MAP_VAL_NOTEQ_BY_KEY FilterExpression unsupported type: got " +
getKey(qualifierMap).getClass().getSimpleName();
Exp keyIsNull = mapKeysCountComparedToZero(qualifierMap, Exp::eq, getKey(qualifierMap), errMsg);
return Exp.or(binIsNull, keyIsNull, getFilterExpMapValNotEqOrFail(qualifierMap, Exp::ne));
}

@Override
Expand Down Expand Up @@ -1232,7 +1235,7 @@ public Exp filterExp(Map<QualifierKey, Object> qualifierMap) {
}
String errMsg = "COLLECTION_VAL_CONTAINING FilterExpression unsupported type: got " +
val.getClass().getSimpleName();
Exp value = getValueExpOrFail(val, errMsg);
Exp value = getExpValOrFail(val, errMsg);
return Exp.gt(
ListExp.getByValue(ListReturnType.COUNT, value, Exp.listBin(getBinName(qualifierMap))),
Exp.val(0));
Expand Down Expand Up @@ -1262,7 +1265,7 @@ public Exp filterExp(Map<QualifierKey, Object> qualifierMap) {
}
String errMsg = "COLLECTION_VAL_NOT_CONTAINING FilterExpression unsupported type: got " +
val.getClass().getSimpleName();
Exp value = getValueExpOrFail(val, errMsg);
Exp value = getExpValOrFail(val, errMsg);

Exp binIsNull = Exp.not(Exp.binExists(getBinName(qualifierMap)));
Exp listNotContaining = Exp.eq(
Expand Down Expand Up @@ -1575,7 +1578,7 @@ private static Exp processMetadataFieldNotIn(Map<QualifierKey, Object> qualifier
private static Exp getExpOrFail(Value value, String filterOpName) {
String errMsg = String.format("%s FilterExpression unsupported value type: got %s", filterOpName,
value.getClass().getSimpleName());
return getValueExpOrFail(value, errMsg);
return getExpValOrFail(value, errMsg);
}

private static Collection<?> getValueAsCollectionOrFail(Map<QualifierKey, Object> qualifierMap) {
Expand Down Expand Up @@ -1676,15 +1679,15 @@ private static Exp mapValBetweenByKey(Map<QualifierKey, Object> qualifierMap, CT
private static Exp mapKeysNotContain(Map<QualifierKey, Object> qualifierMap) {
String errMsg = "MAP_KEYS_NOT_CONTAIN FilterExpression unsupported type: got " +
getKey(qualifierMap).getClass().getSimpleName();
Exp mapKeysNotContain = mapKeysCount(qualifierMap, Exp::eq, errMsg);
Exp mapKeysNotContain = mapKeysCountComparedToZero(qualifierMap, Exp::eq, getValue(qualifierMap), errMsg);
Exp binDoesNotExist = Exp.not(Exp.binExists(getBinName(qualifierMap)));
return Exp.or(binDoesNotExist, mapKeysNotContain);
}

private static Exp mapKeysContain(Map<QualifierKey, Object> qualifierMap) {
String errMsg = "MAP_KEYS_CONTAIN FilterExpression unsupported type: got " +
getValue(qualifierMap).getClass().getSimpleName();
return mapKeysCount(qualifierMap, Exp::gt, errMsg);
return mapKeysCountComparedToZero(qualifierMap, Exp::gt, getValue(qualifierMap), errMsg);
}

private static Exp mapValuesNotContain(Map<QualifierKey, Object> qualifierMap) {
Expand All @@ -1702,41 +1705,30 @@ private static Exp mapValuesContain(Map<QualifierKey, Object> qualifierMap) {
}

// operator is Exp::gt to query for mapKeysContain or Exp::eq to query for mapKeysNotContain
private static Exp mapKeysCount(Map<QualifierKey, Object> qualifierMap, BinaryOperator<Exp> operator,
String errMsg) {
Exp key = getValueExpOrFail(getValue(qualifierMap), errMsg);
private static Exp mapKeysCountComparedToZero(Map<QualifierKey, Object> qualifierMap, BinaryOperator<Exp> operator,
Object mapKey, String errMsg) {
Exp key = getExpValOrFail(Value.get(mapKey), errMsg);
Exp map = Exp.mapBin(getBinName(qualifierMap));
Value mapBinKey = getKey(qualifierMap);

if (!mapBinKey.equals(Value.NullValue.INSTANCE)) {
// If map key != null it is a nested query (one level)
String err = "MAP_VAL_NOT_CONTAINING_BY_KEY FilterExpression unsupported type: got " +
mapBinKey.getClass().getSimpleName();
Exp nestedMapKey = getValueExpOrFail(mapBinKey, err);

// locate a Map within its parent bin
map = MapExp.getByKey(MapReturnType.VALUE, Exp.Type.MAP, nestedMapKey,
Exp.mapBin(getBinName(qualifierMap)));
}
CTX[] ctxArr = getCtxArr(qualifierMap);

return operator.apply(
MapExp.getByKey(MapReturnType.COUNT, Exp.Type.INT, key, map),
MapExp.getByKey(MapReturnType.COUNT, Exp.Type.INT, key, map, ctxArr),
Exp.val(0));
}

// operator is Exp::gt to query for mapValuesContain or Exp::eq to query for mapValuesNotContain
private static Exp mapValuesCountComparedToZero(Map<QualifierKey, Object> qualifierMap,
BinaryOperator<Exp> operator,
String errMsg) {
Exp value = getValueExpOrFail(getValue(qualifierMap), errMsg);
Exp value = getExpValOrFail(getValue(qualifierMap), errMsg);
Exp map = Exp.mapBin(getBinName(qualifierMap));
Value mapBinKey = getKey(qualifierMap);

if (!mapBinKey.equals(Value.NullValue.INSTANCE)) {
// If map key != null it means a nested query (one level)
String err = "MAP_VAL_NOT_CONTAINING_BY_KEY FilterExpression unsupported type: got " +
mapBinKey.getClass().getSimpleName();
Exp nestedMapKey = getValueExpOrFail(mapBinKey, err);
Exp nestedMapKey = getExpValOrFail(mapBinKey, err);

// if it is a nested query we need to locate a Map within its parent bin
map = MapExp.getByKey(MapReturnType.VALUE, Exp.Type.MAP, nestedMapKey,
Expand Down Expand Up @@ -1853,11 +1845,11 @@ private static Exp getMapValEq(Map<QualifierKey, Object> qualifierMap, Exp.Type
Exp bin = getBin(getBinName(qualifierMap), getBinType(qualifierMap), "MAP_VAL_EQ");
if (ctxArr != null && ctxArr.length > 0) {
return MapExp.getByKey(MapReturnType.VALUE, expType,
getValueExpOrFail(getKey(qualifierMap), "MAP_VAL_EQ: unsupported type"),
getExpValOrFail(getKey(qualifierMap), "MAP_VAL_EQ: unsupported type"),
bin, ctxArr);
} else {
return MapExp.getByKey(MapReturnType.VALUE, expType,
getValueExpOrFail(getKey(qualifierMap), "MAP_VAL_EQ: unsupported type"),
getExpValOrFail(getKey(qualifierMap), "MAP_VAL_EQ: unsupported type"),
bin);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.util.TypeInformation;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -262,11 +263,18 @@ private Qualifier processMapTwoParams(QueryQualifierBuilder qb, Part part, List<
private Qualifier processMapContaining(QueryQualifierBuilder qb, Part part, String fieldName, FilterOperation keysOp,
FilterOperation valuesOp, FilterOperation byKeyOp) {
FilterOperation op = byKeyOp;
List<String> dotPath = new ArrayList<>();
dotPath.add(part.getProperty().toDotPath());
if (queryParameters.get(0) instanceof AerospikeQueryCriterion queryCriterion) {
switch (queryCriterion) {
case KEY -> {
op = keysOp;
setQualifierBuilderValue(qb, queryParameters.get(1));
// the actual value is irrelevant here,
// the last dotPath element is discarded within AerospikeQueryCreatorUtils.getCtxFromDotPathArray(),
// the elements except the first and the last are converted to CTX,
// the key object (can contain '.') is transferred separately via qualifier builder value
dotPath.add("mapKeyPlaceholder");
}
case VALUE -> {
op = valuesOp;
Expand All @@ -275,7 +283,7 @@ private Qualifier processMapContaining(QueryQualifierBuilder qb, Part part, Stri
default -> throw new UnsupportedOperationException("Unsupported parameter: " + queryCriterion);
}
}
return setQualifier(qb, fieldName, op, part, null, versionSupport);
return setQualifier(qb, fieldName, op, part, dotPath, versionSupport);
}

private Qualifier processMapOtherThanContaining(QueryQualifierBuilder qb, Part part, List<Object> queryParameters,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public static long getObjectsCount(Node node, String namespace, String setName)
* @param errMsg Error message to use
* @return Exp instance
*/
public static Exp getValueExpOrFail(Value value, String errMsg) {
public static Exp getExpValOrFail(Value value, String errMsg) {
return switch (value.getType()) {
case INTEGER -> Exp.val(value.toLong());
case BOOL -> Exp.val((Boolean) value.getObject());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ void findByNestedSimplePropertyNotIn_String() {
assertThat(carter.getAddress().getZipCode()).isEqualTo("C0124");
assertThat(dave.getAddress().getZipCode()).isEqualTo("C0123");
// find all records where address' zipCode is not C0123 or C0125, and all without address.zipCode
assertThat(repository.findByAddressZipCodeNotIn(List.of("C0123", "C0125"))).doesNotContain(dave);
assertThat(repository.findByAddressZipCodeNotIn(List.of("C0123", "C0125")))
.containsOnly(donny, oliver, alicia, boyd, stefan, leroi, leroi2, matias, douglas, carter);
}

@Test
Expand Down

0 comments on commit b015df5

Please sign in to comment.