Skip to content

Commit f359a1d

Browse files
christophstroblodrotbohm
authored andcommitted
DATAMONGO-847 - Allow usage of Query within an Update clause.
In case we detect Query within a value used for an Update value we map the query itself to build the expression to use. This allows to form query statements for e.g. $pull using the same API as for the query itself. Update update = new Update().pull("list", query(where("value").in("foo", "bar"))); Original Pull Request: spring-projects#172.
1 parent 72d645f commit f359a1d

File tree

2 files changed

+53
-3
lines changed

2 files changed

+53
-3
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java

+16-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
2626
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
2727
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty.PropertyToFieldNameConverter;
28+
import org.springframework.data.mongodb.core.query.Query;
2829
import org.springframework.data.mongodb.core.query.Update.Modifier;
2930
import org.springframework.data.mongodb.core.query.Update.Modifiers;
3031
import org.springframework.data.util.ClassTypeInformation;
@@ -79,10 +80,19 @@ protected Entry<String, Object> getMappedObjectForField(Field field, Object rawV
7980
return createMapEntry(field, convertSimpleOrDBObject(rawValue, field.getPropertyEntity()));
8081
}
8182

82-
if (!isUpdateModifier(rawValue)) {
83-
return super.getMappedObjectForField(field, getMappedValue(field, rawValue));
83+
if (isQuery(rawValue)) {
84+
return createMapEntry(field,
85+
super.getMappedObject(((Query) rawValue).getQueryObject(), field.getPropertyEntity()));
8486
}
8587

88+
if (isUpdateModifier(rawValue)) {
89+
return getMappedUpdateModifier(field, rawValue);
90+
}
91+
92+
return super.getMappedObjectForField(field, getMappedValue(field, rawValue));
93+
}
94+
95+
private Entry<String, Object> getMappedUpdateModifier(Field field, Object rawValue) {
8696
Object value = null;
8797

8898
if (rawValue instanceof Modifier) {
@@ -99,7 +109,6 @@ protected Entry<String, Object> getMappedObjectForField(Field field, Object rawV
99109

100110
value = modificationOperations;
101111
} else {
102-
103112
throw new IllegalArgumentException(String.format("Unable to map value of type '%s'!", rawValue.getClass()));
104113
}
105114

@@ -119,6 +128,10 @@ private boolean isUpdateModifier(Object value) {
119128
return value instanceof Modifier || value instanceof Modifiers;
120129
}
121130

131+
private boolean isQuery(Object value) {
132+
return value instanceof Query;
133+
}
134+
122135
private DBObject getMappedValue(Modifier modifier) {
123136

124137
Object value = converter.convertToMongoType(modifier.getValue(), ClassTypeInformation.OBJECT);

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java

+37
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,13 @@
4141
import org.springframework.data.mongodb.core.DBObjectTestUtils;
4242
import org.springframework.data.mongodb.core.mapping.Field;
4343
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
44+
import org.springframework.data.mongodb.core.query.Criteria;
45+
import org.springframework.data.mongodb.core.query.Query;
4446
import org.springframework.data.mongodb.core.query.Update;
4547

4648
import com.mongodb.BasicDBList;
4749
import com.mongodb.BasicDBObject;
50+
import com.mongodb.BasicDBObjectBuilder;
4851
import com.mongodb.DBObject;
4952
import com.mongodb.DBRef;
5053

@@ -471,6 +474,40 @@ public void updateOnDbrefPropertyOfInterfaceTypeWithoutExplicitGetterForIdShould
471474
assertThat(model, allOf(instanceOf(DBRef.class), IsEqual.<Object> equalTo(expectedDBRef)));
472475
}
473476

477+
/**
478+
* @see DATAMONGO-847
479+
*/
480+
@Test
481+
public void updateMapperConvertsNestedQueryCorrectly() {
482+
483+
Update update = new Update().pull("list", Query.query(Criteria.where("value").in("foo", "bar")));
484+
DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
485+
context.getPersistentEntity(ParentClass.class));
486+
487+
DBObject $pull = DBObjectTestUtils.getAsDBObject(mappedUpdate, "$pull");
488+
DBObject list = DBObjectTestUtils.getAsDBObject($pull, "aliased");
489+
DBObject value = DBObjectTestUtils.getAsDBObject(list, "value");
490+
BasicDBList $in = DBObjectTestUtils.getAsDBList(value, "$in");
491+
492+
assertThat($in, IsIterableContainingInOrder.<Object> contains("foo", "bar"));
493+
}
494+
495+
/**
496+
* @see DATAMONGO-847
497+
*/
498+
@Test
499+
public void updateMapperConvertsPullWithNestedQuerfyOnDBRefCorrectly() {
500+
501+
Update update = new Update().pull("dbRefAnnotatedList", Query.query(Criteria.where("id").is("1")));
502+
DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
503+
context.getPersistentEntity(DocumentWithDBRefCollection.class));
504+
505+
DBObject $pull = DBObjectTestUtils.getAsDBObject(mappedUpdate, "$pull");
506+
DBObject list = DBObjectTestUtils.getAsDBObject($pull, "dbRefAnnotatedList");
507+
508+
assertThat(list, equalTo(new BasicDBObjectBuilder().add("_id", "1").get()));
509+
}
510+
474511
@org.springframework.data.mongodb.core.mapping.Document(collection = "DocumentWithReferenceToInterface")
475512
static interface DocumentWithReferenceToInterface {
476513

0 commit comments

Comments
 (0)