Use index instead of iterator to map position and map keys for updates.

This commit removes usage of the iterator and replaces map key and positional parameter mappings with an index based token lookup.

Closes #3921
Original pull request: #3930.
This commit is contained in:
Christoph Strobl
2022-01-11 13:06:02 +01:00
committed by Mark Paluch
parent 34a35bd489
commit f00e8ed93c
2 changed files with 70 additions and 22 deletions

View File

@@ -1388,6 +1388,14 @@ public class QueryMapper {
this.currentIndex = 0;
}
String nextToken() {
return pathParts.get(currentIndex+1);
}
boolean hasNexToken() {
return pathParts.size() > currentIndex+1;
}
/**
* Maps the property name while retaining potential positional operator {@literal $}.
*
@@ -1397,31 +1405,25 @@ public class QueryMapper {
protected String mapPropertyName(MongoPersistentProperty property) {
StringBuilder mappedName = new StringBuilder(PropertyToFieldNameConverter.INSTANCE.convert(property));
boolean inspect = iterator.hasNext();
while (inspect) {
String partial = iterator.next();
currentIndex++;
boolean isPositional = isPositionalParameter(partial) && property.isCollectionLike() ;
if(property.isMap() && currentPropertyRoot.equals(partial) && iterator.hasNext()){
partial = iterator.next();
currentIndex++;
}
if (isPositional || property.isMap() && !currentPropertyRoot.equals(partial)) {
mappedName.append(".").append(partial);
}
inspect = isPositional && iterator.hasNext();
if(!hasNexToken()) {
return mappedName.toString();
}
if(currentIndex + 1 < pathParts.size()) {
currentIndex++;
currentPropertyRoot = pathParts.get(currentIndex);
String nextToken = nextToken();
if(isPositionalParameter(nextToken)) {
mappedName.append(".").append(nextToken);
currentIndex+=2;
return mappedName.toString();
}
if(property.isMap()) {
mappedName.append(".").append(nextToken);
currentIndex+=2;
return mappedName.toString();
}
currentIndex++;
return mappedName.toString();
}

View File

@@ -1251,6 +1251,36 @@ class UpdateMapperUnitTests {
assertThat(mappedUpdate).isEqualTo("{\"$set\": {\"intKeyedMap.1a.map.0b\": \"testing\"}}");
}
@Test // GH-3921
void mapNumericKeyInPathHavingComplexMapValyeTypes() {
Update update = new Update().set("testInnerData.testMap.1.intValue", "4");
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
context.getPersistentEntity(TestData.class));
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set",new org.bson.Document("testInnerData.testMap.1.intValue","4")));
}
@Test // GH-3921
void mapNumericKeyInPathNotMatchingExistingProperties() {
Update update = new Update().set("testInnerData.imaginaryMap.1.nonExistingProperty", "4");
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
context.getPersistentEntity(TestData.class));
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set",new org.bson.Document("testInnerData.imaginaryMap.1.noExistingProperty","4")));
}
@Test // GH-3921
void mapNumericKeyInPathPartiallyMatchingExistingProperties() {
Update update = new Update().set("testInnerData.testMap.1.nonExistingProperty.2.someValue", "4");
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
context.getPersistentEntity(TestData.class));
assertThat(mappedUpdate).isEqualTo(new org.bson.Document("$set",new org.bson.Document("testInnerData.testMap.1.nonExistingProperty.2.someValue","4")));
}
static class DomainTypeWrappingConcreteyTypeHavingListOfInterfaceTypeAttributes {
ListModelWrapper concreteTypeWithListAttributeOfInterfaceType;
}
@@ -1621,4 +1651,20 @@ class UpdateMapperUnitTests {
Map<String, Map<String, Map<String, Object>>> levelOne;
}
@Data
private static class TestData {
@Id
private String id;
private TestInnerData testInnerData;
}
@Data
private static class TestInnerData {
private Map<Integer, TestValue> testMap;
}
@Data
private static class TestValue {
private int intValue;
}
}