DATAMONGO-812 - Add support for $push $each since $pushAll is deprecated.
$pushAll has been deprecated in MongoDB 2.4. Instead of calling pushAll one can use push in combination with each. The abstraction for pushAll will remain in code for now but may be removed in a subsequent version. Original pull request: #112.
This commit is contained in:
committed by
Oliver Gierke
parent
8e93b844c7
commit
49eee40f7e
@@ -56,6 +56,7 @@ import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
@@ -71,6 +72,7 @@ import com.mongodb.DBRef;
|
||||
* @author Jon Brisbin
|
||||
* @author Patrik Wasik
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
|
||||
|
||||
@@ -942,13 +944,24 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
}
|
||||
|
||||
public BasicDBList maybeConvertList(Iterable<?> source) {
|
||||
|
||||
BasicDBList newDbl = new BasicDBList();
|
||||
for (Object element : source) {
|
||||
newDbl.add(convertToMongoType(element));
|
||||
Object convertedTypeDdo = convertToMongoType(element);
|
||||
if (!isSimpleOrCollectionType(element.getClass())) {
|
||||
this.getTypeMapper().writeType(element.getClass(), (DBObject) convertedTypeDdo);
|
||||
}
|
||||
newDbl.add(convertedTypeDdo);
|
||||
}
|
||||
|
||||
return newDbl;
|
||||
}
|
||||
|
||||
private boolean isSimpleOrCollectionType(Class<?> type) {
|
||||
return this.conversions.isSimpleType(type) || type.getClass().isArray()
|
||||
|| ClassUtils.isAssignable(Collection.class, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the type information from the conversion result.
|
||||
*
|
||||
|
||||
@@ -47,6 +47,7 @@ import com.mongodb.DBRef;
|
||||
* @author Oliver Gierke
|
||||
* @author Patryk Wasik
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class QueryMapper {
|
||||
|
||||
@@ -109,17 +110,29 @@ public class QueryMapper {
|
||||
Object rawValue = query.get(key);
|
||||
String newKey = field.getMappedKey();
|
||||
|
||||
if (isNestedKeyword(rawValue) && !field.isIdField()) {
|
||||
Keyword keyword = new Keyword((DBObject) rawValue);
|
||||
result.put(newKey, getMappedKeyword(field, keyword));
|
||||
} else {
|
||||
result.put(newKey, getMappedValue(field, rawValue));
|
||||
}
|
||||
result.put(newKey, getMappedObjectForField(field, rawValue));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the mapped object value for given field out of rawValue taking nested {@link Keyword}s into account
|
||||
*
|
||||
* @param field
|
||||
* @param rawValue
|
||||
* @return
|
||||
*/
|
||||
protected Object getMappedObjectForField(Field field, Object rawValue) {
|
||||
|
||||
if (isNestedKeyword(rawValue) && !field.isIdField()) {
|
||||
Keyword keyword = new Keyword((DBObject) rawValue);
|
||||
return getMappedKeyword(field, keyword);
|
||||
}
|
||||
|
||||
return getMappedValue(field, rawValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entity
|
||||
* @param key
|
||||
@@ -138,7 +151,7 @@ public class QueryMapper {
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
private DBObject getMappedKeyword(Keyword keyword, MongoPersistentEntity<?> entity) {
|
||||
protected DBObject getMappedKeyword(Keyword keyword, MongoPersistentEntity<?> entity) {
|
||||
|
||||
// $or/$nor
|
||||
if (keyword.isOrOrNor() || keyword.hasIterableValue()) {
|
||||
@@ -164,7 +177,7 @@ public class QueryMapper {
|
||||
* @param keyword
|
||||
* @return
|
||||
*/
|
||||
private DBObject getMappedKeyword(Field property, Keyword keyword) {
|
||||
protected DBObject getMappedKeyword(Field property, Keyword keyword) {
|
||||
|
||||
boolean needsAssociationConversion = property.isAssociation() && !keyword.isExists();
|
||||
Object value = keyword.getValue();
|
||||
@@ -184,7 +197,7 @@ public class QueryMapper {
|
||||
* @param newKey the key the value will be bound to eventually
|
||||
* @return
|
||||
*/
|
||||
private Object getMappedValue(Field documentField, Object value) {
|
||||
protected Object getMappedValue(Field documentField, Object value) {
|
||||
|
||||
if (documentField.isIdField()) {
|
||||
|
||||
@@ -360,7 +373,7 @@ public class QueryMapper {
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class Keyword {
|
||||
static class Keyword {
|
||||
|
||||
private static final String N_OR_PATTERN = "\\$.*or";
|
||||
|
||||
|
||||
@@ -23,17 +23,23 @@ import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty.PropertyToFieldNameConverter;
|
||||
import org.springframework.data.mongodb.core.query.Update.Modifier;
|
||||
import org.springframework.data.mongodb.core.query.Update.Modifiers;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* A subclass of {@link QueryMapper} that retains type information on the mongo types.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class UpdateMapper extends QueryMapper {
|
||||
|
||||
private final MongoWriter<?> converter;
|
||||
private final MongoConverter converter;
|
||||
|
||||
/**
|
||||
* Creates a new {@link UpdateMapper} using the given {@link MongoConverter}.
|
||||
@@ -59,6 +65,40 @@ public class UpdateMapper extends QueryMapper {
|
||||
entity.getTypeInformation());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.QueryMapper#getMappedObjectForField(org.springframework.data.mongodb.core.convert.QueryMapper.Field, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
protected Object getMappedObjectForField(Field field, Object rawValue) {
|
||||
|
||||
if (!isUpdateModifier(rawValue)) {
|
||||
return super.getMappedObjectForField(field, rawValue);
|
||||
}
|
||||
|
||||
if (rawValue instanceof Modifier) {
|
||||
return getMappedValue((Modifier) rawValue);
|
||||
} else if (rawValue instanceof Modifiers) {
|
||||
|
||||
DBObject modificationOperations = new BasicDBObject();
|
||||
for (Modifier modifier : ((Modifiers) rawValue).getModifiers()) {
|
||||
modificationOperations.putAll(getMappedValue(modifier).toMap());
|
||||
}
|
||||
|
||||
return modificationOperations;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Unable to map value of type '%s'!", rawValue.getClass()));
|
||||
}
|
||||
|
||||
private boolean isUpdateModifier(Object value) {
|
||||
return (value instanceof Modifier || value instanceof Modifiers);
|
||||
}
|
||||
|
||||
private DBObject getMappedValue(Modifier modifier) {
|
||||
return new BasicDBObject(modifier.getKey(), this.converter.convertToMongoType(modifier.getValue()));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.QueryMapper#createPropertyField(org.springframework.data.mongodb.core.mapping.MongoPersistentEntity, java.lang.String, org.springframework.data.mapping.context.MappingContext)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2013 the original author or authors.
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,9 +16,12 @@
|
||||
package org.springframework.data.mongodb.core.query;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
|
||||
@@ -32,6 +35,7 @@ import com.mongodb.DBObject;
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Becca Gaspard
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class Update {
|
||||
|
||||
@@ -39,7 +43,8 @@ public class Update {
|
||||
LAST, FIRST
|
||||
}
|
||||
|
||||
private HashMap<String, Object> modifierOps = new LinkedHashMap<String, Object>();
|
||||
private Map<String, Object> modifierOps = new LinkedHashMap<String, Object>();
|
||||
private Map<String, PushOperatorBuilder> pushCommandBuilders = new LinkedHashMap<String, PushOperatorBuilder>(1);
|
||||
|
||||
/**
|
||||
* Static factory method to create an Update using the provided key
|
||||
@@ -139,9 +144,27 @@ public class Update {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update using the $pushAll update modifier
|
||||
* Update using {@code $push} modifier. <br/>
|
||||
* Allows creation of {@code $push} command for single or multiple (using {@code $each}) values.
|
||||
*
|
||||
* @param key
|
||||
* @return {@link PushOperatorBuilder} for given key
|
||||
*/
|
||||
public PushOperatorBuilder push(String key) {
|
||||
|
||||
if (!pushCommandBuilders.containsKey(key)) {
|
||||
pushCommandBuilders.put(key, new PushOperatorBuilder(key));
|
||||
}
|
||||
return pushCommandBuilders.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update using the {@code $pushAll} update modifier. <br>
|
||||
* <b>Note</b>: In mongodb 2.4 the usage of {@code $pushAll} has been deprecated in favor of {@code $push $each}.
|
||||
* {@link #push(String)}) returns a builder that can be used to populate the {@code $each} object.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/operator/update/pushAll/
|
||||
* @param key
|
||||
* @param values
|
||||
* @return
|
||||
*/
|
||||
@@ -249,4 +272,124 @@ public class Update {
|
||||
|
||||
keyValueMap.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifiers holds a distinct collection of {@link Modifier}
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Modifiers {
|
||||
|
||||
private HashMap<String, Modifier> modifiers;
|
||||
|
||||
public Modifiers() {
|
||||
this.modifiers = new LinkedHashMap<String, Modifier>(1);
|
||||
}
|
||||
|
||||
public Collection<Modifier> getModifiers() {
|
||||
return Collections.unmodifiableCollection(this.modifiers.values());
|
||||
}
|
||||
|
||||
public void addModifier(Modifier modifier) {
|
||||
this.modifiers.put(modifier.getKey(), modifier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marker interface of nested commands.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static interface Modifier {
|
||||
|
||||
/**
|
||||
* @return the command to send eg. {@code $push}
|
||||
*/
|
||||
String getKey();
|
||||
|
||||
/**
|
||||
* @return value to be sent with command
|
||||
*/
|
||||
Object getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of {@link Modifier} representing {@code $each}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
private static class Each implements Modifier {
|
||||
|
||||
private Object[] values;
|
||||
|
||||
public Each(Object... values) {
|
||||
this.values = extractValues(values);
|
||||
}
|
||||
|
||||
private Object[] extractValues(Object[] values) {
|
||||
|
||||
if (values == null || values.length == 0) {
|
||||
return values;
|
||||
}
|
||||
|
||||
if (values.length == 1 && values[0] instanceof Collection) {
|
||||
return ((Collection<?>) values[0]).toArray();
|
||||
}
|
||||
|
||||
Object[] convertedValues = new Object[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
convertedValues[i] = values[i];
|
||||
}
|
||||
|
||||
return convertedValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return "$each";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return this.values;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for creating {@code $push} modifiers
|
||||
*
|
||||
* @author Christop Strobl
|
||||
*/
|
||||
public class PushOperatorBuilder {
|
||||
|
||||
private final String key;
|
||||
private final Modifiers modifiers;
|
||||
|
||||
PushOperatorBuilder(String key) {
|
||||
this.key = key;
|
||||
this.modifiers = new Modifiers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagates {@code $each} to {@code $push}
|
||||
*
|
||||
* @param values
|
||||
* @return
|
||||
*/
|
||||
public Update each(Object... values) {
|
||||
|
||||
this.modifiers.addModifier(new Each(values));
|
||||
return Update.this.push(key, this.modifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagates {@link #value(Object)} to {@code $push}
|
||||
*
|
||||
* @param values
|
||||
* @return
|
||||
*/
|
||||
public Update value(Object value) {
|
||||
return Update.this.push(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public abstract class DBObjectTestUtils {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T getTypedValue(DBObject source, String key, Class<T> type) {
|
||||
public static <T> T getTypedValue(DBObject source, String key, Class<T> type) {
|
||||
|
||||
Object value = source.get(key);
|
||||
assertThat(value, is(notNullValue()));
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assume.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||
import static org.springframework.data.mongodb.core.query.Query.*;
|
||||
@@ -35,7 +36,6 @@ import org.bson.types.ObjectId;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -168,6 +168,7 @@ public class MongoTemplateTests {
|
||||
template.dropCollection(BaseDoc.class);
|
||||
template.dropCollection(ObjectWithEnumValue.class);
|
||||
template.dropCollection(DocumentWithCollection.class);
|
||||
template.dropCollection(DocumentWithCollectionOfSimpleType.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -887,7 +888,7 @@ public class MongoTemplateTests {
|
||||
l2.add(31);
|
||||
Query q3 = new Query(Criteria.where("age").in(l1, l2));
|
||||
template.find(q3, PersonWithIdPropertyOfTypeObjectId.class);
|
||||
Assert.fail("Should have trown an InvalidDocumentStoreApiUsageException");
|
||||
fail("Should have trown an InvalidDocumentStoreApiUsageException");
|
||||
} catch (InvalidMongoDbApiUsageException e) {}
|
||||
}
|
||||
|
||||
@@ -2202,8 +2203,8 @@ public class MongoTemplateTests {
|
||||
template.findAndModify(query, update, Document.class);
|
||||
|
||||
Document retrieved = template.findOne(query, Document.class);
|
||||
Assert.assertThat(retrieved.model, instanceOf(ModelA.class));
|
||||
Assert.assertThat(retrieved.model.value(), equalTo("value2"));
|
||||
assertThat(retrieved.model, instanceOf(ModelA.class));
|
||||
assertThat(retrieved.model.value(), equalTo("value2"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2234,10 +2235,56 @@ public class MongoTemplateTests {
|
||||
assertThat(result.model.get(0).value(), is(newModelValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-812
|
||||
*/
|
||||
@Test
|
||||
public void updateMultiShouldAddValuesCorrectlyWhenUsingPushEachWithComplexTypes() {
|
||||
|
||||
DocumentWithCollection document = new DocumentWithCollection(new ModelA("model-a"));
|
||||
template.save(document);
|
||||
Query query = query(where("id").is(document.id));
|
||||
assumeThat(template.findOne(query, DocumentWithCollection.class).model, hasSize(1));
|
||||
|
||||
Update update = new Update().push("model").each(new ModelA("model-b"), new ModelA("model-c"));
|
||||
template.updateMulti(query, update, DocumentWithCollection.class);
|
||||
|
||||
assertThat(template.findOne(query, DocumentWithCollection.class).model, hasSize(3));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-812
|
||||
*/
|
||||
@Test
|
||||
public void updateMultiShouldAddValuesCorrectlyWhenUsingPushEachWithSimpleTypes() {
|
||||
|
||||
DocumentWithCollectionOfSimpleType document = new DocumentWithCollectionOfSimpleType();
|
||||
document.values = Arrays.asList("spring");
|
||||
template.save(document);
|
||||
|
||||
Query query = query(where("id").is(document.id));
|
||||
assumeThat(template.findOne(query, DocumentWithCollectionOfSimpleType.class).values, hasSize(1));
|
||||
|
||||
Update update = new Update().push("values").each("data", "mongodb");
|
||||
template.updateMulti(query, update, DocumentWithCollectionOfSimpleType.class);
|
||||
|
||||
assertThat(template.findOne(query, DocumentWithCollectionOfSimpleType.class).values, hasSize(3));
|
||||
}
|
||||
|
||||
static class DocumentWithCollection {
|
||||
|
||||
@Id public String id;
|
||||
public List<Model> model;
|
||||
|
||||
DocumentWithCollection(Model... models) {
|
||||
this.model = Arrays.asList(models);
|
||||
}
|
||||
}
|
||||
|
||||
static class DocumentWithCollectionOfSimpleType {
|
||||
|
||||
@Id String id;
|
||||
List<String> values;
|
||||
}
|
||||
|
||||
static interface Model {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2013 the original author or authors.
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.mongodb.core.convert;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.mongodb.core.DBObjectTestUtils.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
@@ -72,6 +73,7 @@ import com.mongodb.util.JSON;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Patrik Wasik
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class MappingMongoConverterUnitTests {
|
||||
@@ -1026,7 +1028,7 @@ public class MappingMongoConverterUnitTests {
|
||||
|
||||
Set<?> readResult = converter.read(Set.class, (BasicDBList) result);
|
||||
assertThat(readResult.size(), is(1));
|
||||
assertThat(readResult.iterator().next(), is(instanceOf(Map.class)));
|
||||
assertThat(readResult.iterator().next(), is(instanceOf(Address.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1381,6 +1383,62 @@ public class MappingMongoConverterUnitTests {
|
||||
assertThat(aValue.get("c"), is((Object) "C"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertsListToBasicDBListAndRetainsTypeInformationForComplexObjects() {
|
||||
|
||||
Address address = new Address();
|
||||
address.city = "London";
|
||||
address.street = "Foo";
|
||||
|
||||
Object result = converter.convertToMongoType(Collections.singletonList(address));
|
||||
|
||||
assertThat(result, is(instanceOf(BasicDBList.class)));
|
||||
|
||||
BasicDBList dbList = (BasicDBList) result;
|
||||
assertThat(dbList, hasSize(1));
|
||||
assertThat(getTypedValue(getAsDBObject(dbList, 0), ("_class"), String.class), equalTo(Address.class.getName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertsListToBasicDBListWithoutTypeInformationForSimpleTypes() {
|
||||
|
||||
Object result = converter.convertToMongoType(Collections.singletonList("foo"));
|
||||
|
||||
assertThat(result, is(instanceOf(BasicDBList.class)));
|
||||
|
||||
BasicDBList dbList = (BasicDBList) result;
|
||||
assertThat(dbList, hasSize(1));
|
||||
assertThat(dbList.get(0), instanceOf(String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertsArrayToBasicDBListAndRetainsTypeInformationForComplexObjects() {
|
||||
|
||||
Address address = new Address();
|
||||
address.city = "London";
|
||||
address.street = "Foo";
|
||||
|
||||
Object result = converter.convertToMongoType(new Address[] { address });
|
||||
|
||||
assertThat(result, is(instanceOf(BasicDBList.class)));
|
||||
|
||||
BasicDBList dbList = (BasicDBList) result;
|
||||
assertThat(dbList, hasSize(1));
|
||||
assertThat(getTypedValue(getAsDBObject(dbList, 0), ("_class"), String.class), equalTo(Address.class.getName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertsArrayToBasicDBListWithoutTypeInformationForSimpleTypes() {
|
||||
|
||||
Object result = converter.convertToMongoType(new String[] { "foo" });
|
||||
|
||||
assertThat(result, is(instanceOf(BasicDBList.class)));
|
||||
|
||||
BasicDBList dbList = (BasicDBList) result;
|
||||
assertThat(dbList, hasSize(1));
|
||||
assertThat(dbList.get(0), instanceOf(String.class));
|
||||
}
|
||||
|
||||
static class GenericType<T> {
|
||||
T content;
|
||||
}
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.collection.IsMapContaining.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.mongodb.core.DBObjectTestUtils.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -31,6 +34,7 @@ import org.springframework.data.mongodb.core.mapping.Field;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.query.Update;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
@@ -38,6 +42,7 @@ import com.mongodb.DBObject;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class UpdateMapperUnitTests {
|
||||
@@ -45,12 +50,14 @@ public class UpdateMapperUnitTests {
|
||||
@Mock MongoDbFactory factory;
|
||||
MappingMongoConverter converter;
|
||||
MongoMappingContext context;
|
||||
UpdateMapper mapper;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
this.context = new MongoMappingContext();
|
||||
this.converter = new MappingMongoConverter(new DefaultDbRefResolver(factory), context);
|
||||
this.mapper = new UpdateMapper(converter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,7 +67,6 @@ public class UpdateMapperUnitTests {
|
||||
public void updateMapperRetainsTypeInformationForCollectionField() {
|
||||
|
||||
Update update = new Update().push("list", new ConcreteChildClass("2", "BAR"));
|
||||
UpdateMapper mapper = new UpdateMapper(converter);
|
||||
|
||||
DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(ParentClass.class));
|
||||
@@ -175,6 +181,91 @@ public class UpdateMapperUnitTests {
|
||||
assertThat(someObject.get("value"), is((Object) "bubu"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-812
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Test
|
||||
public void updateMapperShouldConvertPushCorrectlyWhenCalledWithEachUsingSimpleTypes() {
|
||||
|
||||
Update update = new Update().push("values").each("spring", "data", "mongodb");
|
||||
DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Model.class));
|
||||
|
||||
DBObject push = getAsDBObject(mappedObject, "$push");
|
||||
DBObject values = getAsDBObject(push, "values");
|
||||
BasicDBList each = getAsDBList(values, "$each");
|
||||
|
||||
assertThat(push.get("_class"), nullValue());
|
||||
assertThat(values.get("_class"), nullValue());
|
||||
|
||||
assertThat(each.toMap(), (Matcher) allOf(hasValue("spring"), hasValue("data"), hasValue("mongodb")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-812
|
||||
*/
|
||||
@Test
|
||||
public void updateMapperShouldConvertPushWhithoutAddingClassInformationWhenUsedWithEvery() {
|
||||
|
||||
Update update = new Update().push("values").each("spring", "data", "mongodb");
|
||||
|
||||
DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Model.class));
|
||||
DBObject push = getAsDBObject(mappedObject, "$push");
|
||||
DBObject values = getAsDBObject(push, "values");
|
||||
|
||||
assertThat(push.get("_class"), nullValue());
|
||||
assertThat(values.get("_class"), nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-812
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Test
|
||||
public void updateMapperShouldConvertPushCorrectlyWhenCalledWithEachUsingCustomTypes() {
|
||||
|
||||
Update update = new Update().push("models").each(new ListModel("spring", "data", "mongodb"));
|
||||
DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(ModelWrapper.class));
|
||||
|
||||
DBObject push = getAsDBObject(mappedObject, "$push");
|
||||
DBObject model = getAsDBObject(push, "models");
|
||||
BasicDBList each = getAsDBList(model, "$each");
|
||||
BasicDBList values = getAsDBList((DBObject) each.get(0), "values");
|
||||
|
||||
assertThat(values.toMap(), (Matcher) allOf(hasValue("spring"), hasValue("data"), hasValue("mongodb")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-812
|
||||
*/
|
||||
@Test
|
||||
public void updateMapperShouldRetainClassInformationForPushCorrectlyWhenCalledWithEachUsingCustomTypes() {
|
||||
|
||||
Update update = new Update().push("models").each(new ListModel("spring", "data", "mongodb"));
|
||||
DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(ModelWrapper.class));
|
||||
|
||||
DBObject push = getAsDBObject(mappedObject, "$push");
|
||||
DBObject model = getAsDBObject(push, "models");
|
||||
BasicDBList each = getAsDBList(model, "$each");
|
||||
|
||||
assertThat(((DBObject) each.get(0)).get("_class").toString(), equalTo(ListModel.class.getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-812
|
||||
*/
|
||||
@Test
|
||||
public void testUpdateShouldAllowMultiplePushEachForDifferentFields() {
|
||||
Update update = new Update().push("category").each("spring", "data").push("type").each("mongodb");
|
||||
DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Object.class));
|
||||
|
||||
DBObject push = getAsDBObject(mappedObject, "$push");
|
||||
assertThat(getAsDBObject(push, "category").containsField("$each"), is(true));
|
||||
assertThat(getAsDBObject(push, "type").containsField("$each"), is(true));
|
||||
}
|
||||
|
||||
static interface Model {}
|
||||
|
||||
static class ModelImpl implements Model {
|
||||
@@ -189,6 +280,20 @@ public class UpdateMapperUnitTests {
|
||||
Model model;
|
||||
}
|
||||
|
||||
static class ListModelWrapper {
|
||||
|
||||
List<Model> models;
|
||||
}
|
||||
|
||||
static class ListModel {
|
||||
|
||||
List<String> values;
|
||||
|
||||
public ListModel(String... values) {
|
||||
this.values = Arrays.asList(values);
|
||||
}
|
||||
}
|
||||
|
||||
static class ParentClass {
|
||||
|
||||
String id;
|
||||
|
||||
Reference in New Issue
Block a user