Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FMWK-635 Use correct sIndex filter in containing queries with nested map values #814

Merged
merged 1 commit into from
Jan 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading