Skip to content

Commit

Permalink
FMWK-635 Use correct secondary index filter in containing queries wit…
Browse files Browse the repository at this point in the history
…h nested map values (#814)
  • Loading branch information
agrgr authored Jan 1, 2025
1 parent d6b9317 commit c619bb7
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@
import static com.aerospike.client.command.ParticleType.MAP;
import static com.aerospike.client.command.ParticleType.STRING;
import static org.springframework.data.aerospike.query.qualifier.QualifierKey.*;
import static org.springframework.data.aerospike.repository.query.AerospikeQueryCreatorUtils.convertToStringListExclStart;
import static org.springframework.data.aerospike.repository.query.AerospikeQueryCreatorUtils.getDotPathArray;
import static org.springframework.data.aerospike.repository.query.AerospikeQueryCreatorUtils.resolveCtxList;
import static org.springframework.data.aerospike.util.FilterOperationRegexpBuilder.getContaining;
import static org.springframework.data.aerospike.util.FilterOperationRegexpBuilder.getEndsWith;
import static org.springframework.data.aerospike.util.FilterOperationRegexpBuilder.getNotContaining;
Expand Down Expand Up @@ -1082,7 +1084,7 @@ public Exp filterExp(Map<QualifierKey, Object> qualifierMap) {

@Override
public Filter sIndexFilter(Map<QualifierKey, Object> qualifierMap) {
return collectionContains(IndexCollectionType.MAPKEYS, qualifierMap);
return cdtContains(IndexCollectionType.MAPKEYS, qualifierMap);
}
},
/**
Expand Down Expand Up @@ -1118,7 +1120,7 @@ public Exp filterExp(Map<QualifierKey, Object> qualifierMap) {

@Override
public Filter sIndexFilter(Map<QualifierKey, Object> qualifierMap) {
return collectionContains(IndexCollectionType.MAPVALUES, qualifierMap);
return cdtContains(IndexCollectionType.MAPVALUES, qualifierMap);
}
},
/**
Expand Down Expand Up @@ -1255,7 +1257,7 @@ public Filter sIndexFilter(Map<QualifierKey, Object> qualifierMap) {
return null;
}

return collectionContains(IndexCollectionType.LIST, qualifierMap);
return cdtContains(IndexCollectionType.LIST, qualifierMap);
}
},
/**
Expand Down Expand Up @@ -1937,10 +1939,6 @@ protected static Value getKey(Map<QualifierKey, Object> qualifierMap) {
return Value.get(qualifierMap.get(KEY));
}

protected static String getKeyAsString(Map<QualifierKey, Object> qualifierMap) {
return (String) qualifierMap.get(KEY);
}

protected static Value getNestedKey(Map<QualifierKey, Object> qualifierMap) {
return Value.get(qualifierMap.get(NESTED_KEY));
}
Expand Down Expand Up @@ -1977,9 +1975,14 @@ protected static ServerVersionSupport getServerVersionSupport(Map<QualifierKey,

public abstract Filter sIndexFilter(Map<QualifierKey, Object> qualifierMap);

protected Filter collectionContains(IndexCollectionType collectionType, Map<QualifierKey, Object> qualifierMap) {
protected Filter cdtContains(IndexCollectionType collectionType, Map<QualifierKey, Object> qualifierMap) {
Value val = getValue(qualifierMap);
int valType = val.getType();
String[] dotPathArray = getDotPathArray(getDotPath(qualifierMap));
if (dotPathArray != null && dotPathArray.length > 1) {
List<String> ctxList = convertToStringListExclStart(dotPathArray);
qualifierMap.put(CTX_ARRAY, resolveCtxList(ctxList));
}
return switch (valType) {
// TODO: Add Bytes and Double Support (will fail on old mode - no results)
case INTEGER -> Filter.contains(getBinName(qualifierMap), collectionType, val.toLong(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ protected static Qualifier setQualifier(QueryQualifierBuilder qb, String binName
qb.setDotPath(dotPath);
String[] dotPathArr = getDotPathArray(dotPath);
if (dotPathArr != null && dotPathArr.length > 2) {
List<String> ctxList = getCtxFromDotPathArray(dotPathArr);
List<String> ctxList = convertToStringListExclStartAndEnd(dotPathArr);
qb.setCtxArray(resolveCtxList(ctxList));
}
}
qb.setServerVersionSupport(versionSupport);
return qb.build();
}

private static CTX[] resolveCtxList(List<String> ctxList) {
public static CTX[] resolveCtxList(List<String> ctxList) {
return ctxList.stream()
.filter(not(String::isEmpty))
.map(AerospikeContextDslResolverUtils::toCtx)
Expand All @@ -69,10 +69,29 @@ public static String[] getDotPathArray(List<String> dotPathList) {
return null;
}

protected static List<String> getCtxFromDotPathArray(@NonNull String[] dotPathArr) {
return Arrays.stream(dotPathArr)
/**
* Convert a String array into String List excluding the first and the last elements
*
* @param array String array
* @return String List
*/
protected static List<String> convertToStringListExclStartAndEnd(@NonNull String[] array) {
return Arrays.stream(array)
.skip(1) // first element is bin name
.limit(array.length - 2L) // last element is the key we already have
.collect(Collectors.toList());
}

/**
* Convert a String array into String List excluding the first element
*
* @param array String array
* @return String List
*/
public static List<String> convertToStringListExclStart(@NonNull String[] array) {
return Arrays.stream(array)
.skip(1) // first element is bin name
.limit(dotPathArr.length - 2L) // last element is the key we already have
.limit(array.length - 1L)
.collect(Collectors.toList());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ public void setUp() {
template.save(thirdPerson);

// Create index
additionalAerospikeTestOperations.createIndex(Person.class,
"person_age_index", "age", IndexType.NUMERIC);
additionalAerospikeTestOperations.createIndex(Person.class, "person_age_index", "age", IndexType.NUMERIC);
}

@AfterAll
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,18 @@ void findByCollectionContainingPOJO() {
repository.save(leroi2);
}

@Test
void findByNestedCollectionContainingList() {
if (serverVersionSupport.isFindByCDTSupported()) {
List<List<Integer>> listOfLists1 = List.of(List.of(100));
stefan.setListOfIntLists(listOfLists1);
repository.save(stefan);

List<Person> persons = repository.findByListOfIntListsContaining(List.of(100));
assertThat(persons).contains(stefan);
}
}

@Test
void findByMapKeysContainingString() {
assertThat(donny.getStringMap()).containsKey("key1");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1420,7 +1420,12 @@ List<P> findByFriendStringMapNotContaining(AerospikeQueryCriterion criterion,
/**
* Find all entities that satisfy the condition "have the list of lists which is greater than the given list".
* <p>
* ListOfIntLists is the name of the list of lists
* ListOfIntLists is the name of the list of lists.
* <br><br>
* Note: only the upper level ListOfLists will be compared even if the parameter has different number of levels.
* So findByListOfListsGreaterThan(List.of(1)) and findByListOfListsGreaterThan(List.of(List.of(List.of(1))))
* will compare with the given parameter only the upper level ListOfLists itself
*
* </p>
* <p>
* <a href="https://docs.aerospike.com/server/guide/data-types/cdt-ordering#list">Information about ordering</a>
Expand All @@ -1429,6 +1434,13 @@ List<P> findByFriendStringMapNotContaining(AerospikeQueryCriterion criterion,
*/
List<P> findByListOfIntListsGreaterThan(List<List<Integer>> list);

/**
* Find all entities that satisfy the condition "contain the given list".
* <p>
* @param list List to contain
*/
List<P> findByListOfIntListsContaining(List<Integer> list);

/**
* Find all entities that satisfy the condition "have map in the given range"
* <p>
Expand Down

0 comments on commit c619bb7

Please sign in to comment.