/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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.*;
import static org.springframework.data.mongodb.core.query.Update.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.bson.types.ObjectId;
import org.joda.time.DateTime;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.annotation.Version;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.LazyLoadingProxy;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.index.Index;
import org.springframework.data.mongodb.core.index.Index.Duplicates;
import org.springframework.data.mongodb.core.index.IndexField;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.StringUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.CommandResult;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.DBRef;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
import com.mongodb.ReadPreference;
import com.mongodb.WriteConcern;
import com.mongodb.WriteResult;
/**
* Integration test for {@link MongoTemplate}.
*
* @author Oliver Gierke
* @author Thomas Risberg
* @author Amol Nayak
* @author Patryk Wasik
* @author Thomas Darimont
* @author Komi Innocent
* @author Christoph Strobl
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:infrastructure.xml")
public class MongoTemplateTests {
private static final org.springframework.data.util.Version TWO_DOT_FOUR = org.springframework.data.util.Version
.parse("2.4");
@Autowired MongoTemplate template;
@Autowired MongoDbFactory factory;
MongoTemplate mappingTemplate;
org.springframework.data.util.Version mongoVersion;
@Rule public ExpectedException thrown = ExpectedException.none();
@Autowired
@SuppressWarnings("unchecked")
public void setMongo(Mongo mongo) throws Exception {
CustomConversions conversions = new CustomConversions(Arrays.asList(DateToDateTimeConverter.INSTANCE,
DateTimeToDateConverter.INSTANCE));
MongoMappingContext mappingContext = new MongoMappingContext();
mappingContext.setInitialEntitySet(new HashSet<Class<?>>(Arrays.asList(PersonWith_idPropertyOfTypeObjectId.class,
PersonWith_idPropertyOfTypeString.class, PersonWithIdPropertyOfTypeObjectId.class,
PersonWithIdPropertyOfTypeString.class, PersonWithIdPropertyOfTypeInteger.class,
PersonWithIdPropertyOfTypeBigInteger.class, PersonWithIdPropertyOfPrimitiveInt.class,
PersonWithIdPropertyOfTypeLong.class, PersonWithIdPropertyOfPrimitiveLong.class)));
mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
mappingContext.initialize();
DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, mappingContext);
mappingConverter.setCustomConversions(conversions);
mappingConverter.afterPropertiesSet();
this.mappingTemplate = new MongoTemplate(factory, mappingConverter);
}
@Before
public void setUp() {
cleanDb();
queryMongoVersionIfNecessary();
}
@After
public void cleanUp() {
cleanDb();
}
private void queryMongoVersionIfNecessary() {
if (mongoVersion == null) {
CommandResult result = template.executeCommand("{ buildInfo: 1 }");
mongoVersion = org.springframework.data.util.Version.parse(result.get("version").toString());
}
}
protected void cleanDb() {
template.dropCollection(Person.class);
template.dropCollection(PersonWithAList.class);
template.dropCollection(PersonWith_idPropertyOfTypeObjectId.class);
template.dropCollection(PersonWith_idPropertyOfTypeString.class);
template.dropCollection(PersonWithIdPropertyOfTypeObjectId.class);
template.dropCollection(PersonWithIdPropertyOfTypeString.class);
template.dropCollection(PersonWithIdPropertyOfTypeInteger.class);
template.dropCollection(PersonWithIdPropertyOfTypeBigInteger.class);
template.dropCollection(PersonWithIdPropertyOfPrimitiveInt.class);
template.dropCollection(PersonWithIdPropertyOfTypeLong.class);
template.dropCollection(PersonWithIdPropertyOfPrimitiveLong.class);
template.dropCollection(PersonWithVersionPropertyOfTypeInteger.class);
template.dropCollection(TestClass.class);
template.dropCollection(Sample.class);
template.dropCollection(MyPerson.class);
template.dropCollection(TypeWithFieldAnnotation.class);
template.dropCollection(TypeWithDate.class);
template.dropCollection("collection");
template.dropCollection("personX");
template.dropCollection(Document.class);
template.dropCollection(ObjectWith3AliasedFields.class);
template.dropCollection(ObjectWith3AliasedFieldsAndNestedAddress.class);
template.dropCollection(BaseDoc.class);
template.dropCollection(ObjectWithEnumValue.class);
template.dropCollection(DocumentWithCollection.class);
template.dropCollection(DocumentWithCollectionOfSimpleType.class);
template.dropCollection(DocumentWithMultipleCollections.class);
template.dropCollection(DocumentWithDBRefCollection.class);
template.dropCollection(SomeContent.class);
template.dropCollection(SomeTemplate.class);
}
@Test
public void insertsSimpleEntityCorrectly() throws Exception {
Person person = new Person("Oliver");
person.setAge(25);
template.insert(person);
List<Person> result = template.find(new Query(Criteria.where("_id").is(person.getId())), Person.class);
assertThat(result.size(), is(1));
assertThat(result, hasItem(person));
}
@Test
public void bogusUpdateDoesNotTriggerException() throws Exception {
MongoTemplate mongoTemplate = new MongoTemplate(factory);
mongoTemplate.setWriteResultChecking(WriteResultChecking.EXCEPTION);
Person person = new Person("Oliver2");
person.setAge(25);
mongoTemplate.insert(person);
Query q = new Query(Criteria.where("BOGUS").gt(22));
Update u = new Update().set("firstName", "Sven");
mongoTemplate.updateFirst(q, u, Person.class);
}
/**
* @see DATAMONGO-480
*/
@Test
public void throwsExceptionForDuplicateIds() {
MongoTemplate template = new MongoTemplate(factory);
template.setWriteResultChecking(WriteResultChecking.EXCEPTION);
Person person = new Person(new ObjectId(), "Amol");
person.setAge(28);
template.insert(person);
try {
template.insert(person);
fail("Expected DataIntegrityViolationException!");
} catch (DataIntegrityViolationException e) {
assertThat(e.getMessage(), containsString("E11000 duplicate key error index: database.person.$_id_ dup key:"));
}
}
/**
* @see DATAMONGO-480
* @see DATAMONGO-799
*/
@Test
public void throwsExceptionForUpdateWithInvalidPushOperator() {
MongoTemplate template = new MongoTemplate(factory);
template.setWriteResultChecking(WriteResultChecking.EXCEPTION);
ObjectId id = new ObjectId();
Person person = new Person(id, "Amol");
person.setAge(28);
template.insert(person);
thrown.expect(DataIntegrityViolationException.class);
thrown.expectMessage("Execution");
thrown.expectMessage("UPDATE");
thrown.expectMessage("array");
thrown.expectMessage("firstName");
thrown.expectMessage("failed");
Query query = new Query(Criteria.where("firstName").is("Amol"));
Update upd = new Update().push("age", 29);
template.updateFirst(query, upd, Person.class);
}
/**
* @see DATAMONGO-480
*/
@Test
public void throwsExceptionForIndexViolationIfConfigured() {
MongoTemplate template = new MongoTemplate(factory);
template.setWriteResultChecking(WriteResultChecking.EXCEPTION);
template.indexOps(Person.class).ensureIndex(new Index().on("firstName", Direction.DESC).unique());
Person person = new Person(new ObjectId(), "Amol");
person.setAge(28);
template.save(person);
person = new Person(new ObjectId(), "Amol");
person.setAge(28);
try {
template.save(person);
fail("Expected DataIntegrityViolationException!");
} catch (DataIntegrityViolationException e) {
assertThat(e.getMessage(),
containsString("E11000 duplicate key error index: database.person.$firstName_-1 dup key:"));
}
}
/**
* @see DATAMONGO-480
*/
@Test
public void rejectsDuplicateIdInInsertAll() {
thrown.expect(DataIntegrityViolationException.class);
thrown.expectMessage("E11000 duplicate key error index: database.person.$_id_");
MongoTemplate template = new MongoTemplate(factory);
template.setWriteResultChecking(WriteResultChecking.EXCEPTION);
ObjectId id = new ObjectId();
Person person = new Person(id, "Amol");
person.setAge(28);
List<Person> records = new ArrayList<Person>();
records.add(person);
records.add(person);
template.insertAll(records);
}
@Test
public void testEnsureIndex() throws Exception {
Person p1 = new Person("Oliver");
p1.setAge(25);
template.insert(p1);
Person p2 = new Person("Sven");
p2.setAge(40);
template.insert(p2);
template.indexOps(Person.class).ensureIndex(new Index().on("age", Direction.DESC).unique(Duplicates.DROP));
DBCollection coll = template.getCollection(template.getCollectionName(Person.class));
List<DBObject> indexInfo = coll.getIndexInfo();
assertThat(indexInfo.size(), is(2));
String indexKey = null;
boolean unique = false;
boolean dropDupes = false;
for (DBObject ix : indexInfo) {
if ("age_-1".equals(ix.get("name"))) {
indexKey = ix.get("key").toString();
unique = (Boolean) ix.get("unique");
dropDupes = (Boolean) ix.get("dropDups");
}
}
assertThat(indexKey, is("{ \"age\" : -1}"));
assertThat(unique, is(true));
assertThat(dropDupes, is(true));
List<IndexInfo> indexInfoList = template.indexOps(Person.class).getIndexInfo();
assertThat(indexInfoList.size(), is(2));
IndexInfo ii = indexInfoList.get(1);
assertThat(ii.isUnique(), is(true));
assertThat(ii.isDropDuplicates(), is(true));
assertThat(ii.isSparse(), is(false));
List<IndexField> indexFields = ii.getIndexFields();
IndexField field = indexFields.get(0);
assertThat(field, is(IndexField.create("age", Direction.DESC)));
}
/**
* @see DATAMONGO-746
*/
@Test
public void testReadIndexInfoForIndicesCreatedViaMongoShellCommands() throws Exception {
String command = "db." + template.getCollectionName(Person.class)
+ ".ensureIndex({'age':-1}, {'unique':true, 'sparse':true})";
template.indexOps(Person.class).dropAllIndexes();
assertThat(template.indexOps(Person.class).getIndexInfo().isEmpty(), is(true));
factory.getDb().eval(command);
List<DBObject> indexInfo = template.getCollection(template.getCollectionName(Person.class)).getIndexInfo();
String indexKey = null;
boolean unique = false;
for (DBObject ix : indexInfo) {
if ("age_-1".equals(ix.get("name"))) {
indexKey = ix.get("key").toString();
unique = (Boolean) ix.get("unique");
}
}
assertThat(indexKey, is("{ \"age\" : -1.0}"));
assertThat(unique, is(true));
IndexInfo info = template.indexOps(Person.class).getIndexInfo().get(1);
assertThat(info.isUnique(), is(true));
assertThat(info.isSparse(), is(true));
List<IndexField> indexFields = info.getIndexFields();
IndexField field = indexFields.get(0);
assertThat(field, is(IndexField.create("age", Direction.DESC)));
}
@Test
public void testProperHandlingOfDifferentIdTypesWithMappingMongoConverter() throws Exception {
testProperHandlingOfDifferentIdTypes(this.mappingTemplate);
}
private void testProperHandlingOfDifferentIdTypes(MongoTemplate mongoTemplate) throws Exception {
// String id - generated
PersonWithIdPropertyOfTypeString p1 = new PersonWithIdPropertyOfTypeString();
p1.setFirstName("Sven_1");
p1.setAge(22);
// insert
mongoTemplate.insert(p1);
// also try save
mongoTemplate.save(p1);
assertThat(p1.getId(), notNullValue());
PersonWithIdPropertyOfTypeString p1q = mongoTemplate.findOne(new Query(where("id").is(p1.getId())),
PersonWithIdPropertyOfTypeString.class);
assertThat(p1q, notNullValue());
assertThat(p1q.getId(), is(p1.getId()));
checkCollectionContents(PersonWithIdPropertyOfTypeString.class, 1);
// String id - provided
PersonWithIdPropertyOfTypeString p2 = new PersonWithIdPropertyOfTypeString();
p2.setFirstName("Sven_2");
p2.setAge(22);
p2.setId("TWO");
// insert
mongoTemplate.insert(p2);
// also try save
mongoTemplate.save(p2);
assertThat(p2.getId(), notNullValue());
PersonWithIdPropertyOfTypeString p2q = mongoTemplate.findOne(new Query(where("id").is(p2.getId())),
PersonWithIdPropertyOfTypeString.class);
assertThat(p2q, notNullValue());
assertThat(p2q.getId(), is(p2.getId()));
checkCollectionContents(PersonWithIdPropertyOfTypeString.class, 2);
// String _id - generated
PersonWith_idPropertyOfTypeString p3 = new PersonWith_idPropertyOfTypeString();
p3.setFirstName("Sven_3");
p3.setAge(22);
// insert
mongoTemplate.insert(p3);
// also try save
mongoTemplate.save(p3);
assertThat(p3.get_id(), notNullValue());
PersonWith_idPropertyOfTypeString p3q = mongoTemplate.findOne(new Query(where("_id").is(p3.get_id())),
PersonWith_idPropertyOfTypeString.class);
assertThat(p3q, notNullValue());
assertThat(p3q.get_id(), is(p3.get_id()));
checkCollectionContents(PersonWith_idPropertyOfTypeString.class, 1);
// String _id - provided
PersonWith_idPropertyOfTypeString p4 = new PersonWith_idPropertyOfTypeString();
p4.setFirstName("Sven_4");
p4.setAge(22);
p4.set_id("FOUR");
// insert
mongoTemplate.insert(p4);
// also try save
mongoTemplate.save(p4);
assertThat(p4.get_id(), notNullValue());
PersonWith_idPropertyOfTypeString p4q = mongoTemplate.findOne(new Query(where("_id").is(p4.get_id())),
PersonWith_idPropertyOfTypeString.class);
assertThat(p4q, notNullValue());
assertThat(p4q.get_id(), is(p4.get_id()));
checkCollectionContents(PersonWith_idPropertyOfTypeString.class, 2);
// ObjectId id - generated
PersonWithIdPropertyOfTypeObjectId p5 = new PersonWithIdPropertyOfTypeObjectId();
p5.setFirstName("Sven_5");
p5.setAge(22);
// insert
mongoTemplate.insert(p5);
// also try save
mongoTemplate.save(p5);
assertThat(p5.getId(), notNullValue());
PersonWithIdPropertyOfTypeObjectId p5q = mongoTemplate.findOne(new Query(where("id").is(p5.getId())),
PersonWithIdPropertyOfTypeObjectId.class);
assertThat(p5q, notNullValue());
assertThat(p5q.getId(), is(p5.getId()));
checkCollectionContents(PersonWithIdPropertyOfTypeObjectId.class, 1);
// ObjectId id - provided
PersonWithIdPropertyOfTypeObjectId p6 = new PersonWithIdPropertyOfTypeObjectId();
p6.setFirstName("Sven_6");
p6.setAge(22);
p6.setId(new ObjectId());
// insert
mongoTemplate.insert(p6);
// also try save
mongoTemplate.save(p6);
assertThat(p6.getId(), notNullValue());
PersonWithIdPropertyOfTypeObjectId p6q = mongoTemplate.findOne(new Query(where("id").is(p6.getId())),
PersonWithIdPropertyOfTypeObjectId.class);
assertThat(p6q, notNullValue());
assertThat(p6q.getId(), is(p6.getId()));
checkCollectionContents(PersonWithIdPropertyOfTypeObjectId.class, 2);
// ObjectId _id - generated
PersonWith_idPropertyOfTypeObjectId p7 = new PersonWith_idPropertyOfTypeObjectId();
p7.setFirstName("Sven_7");
p7.setAge(22);
// insert
mongoTemplate.insert(p7);
// also try save
mongoTemplate.save(p7);
assertThat(p7.get_id(), notNullValue());
PersonWith_idPropertyOfTypeObjectId p7q = mongoTemplate.findOne(new Query(where("_id").is(p7.get_id())),
PersonWith_idPropertyOfTypeObjectId.class);
assertThat(p7q, notNullValue());
assertThat(p7q.get_id(), is(p7.get_id()));
checkCollectionContents(PersonWith_idPropertyOfTypeObjectId.class, 1);
// ObjectId _id - provided
PersonWith_idPropertyOfTypeObjectId p8 = new PersonWith_idPropertyOfTypeObjectId();
p8.setFirstName("Sven_8");
p8.setAge(22);
p8.set_id(new ObjectId());
// insert
mongoTemplate.insert(p8);
// also try save
mongoTemplate.save(p8);
assertThat(p8.get_id(), notNullValue());
PersonWith_idPropertyOfTypeObjectId p8q = mongoTemplate.findOne(new Query(where("_id").is(p8.get_id())),
PersonWith_idPropertyOfTypeObjectId.class);
assertThat(p8q, notNullValue());
assertThat(p8q.get_id(), is(p8.get_id()));
checkCollectionContents(PersonWith_idPropertyOfTypeObjectId.class, 2);
// Integer id - provided
PersonWithIdPropertyOfTypeInteger p9 = new PersonWithIdPropertyOfTypeInteger();
p9.setFirstName("Sven_9");
p9.setAge(22);
p9.setId(Integer.valueOf(12345));
// insert
mongoTemplate.insert(p9);
// also try save
mongoTemplate.save(p9);
assertThat(p9.getId(), notNullValue());
PersonWithIdPropertyOfTypeInteger p9q = mongoTemplate.findOne(new Query(where("id").in(p9.getId())),
PersonWithIdPropertyOfTypeInteger.class);
assertThat(p9q, notNullValue());
assertThat(p9q.getId(), is(p9.getId()));
checkCollectionContents(PersonWithIdPropertyOfTypeInteger.class, 1);
/*
* @see DATAMONGO-602
*/
// BigInteger id - provided
PersonWithIdPropertyOfTypeBigInteger p9bi = new PersonWithIdPropertyOfTypeBigInteger();
p9bi.setFirstName("Sven_9bi");
p9bi.setAge(22);
p9bi.setId(BigInteger.valueOf(12345));
// insert
mongoTemplate.insert(p9bi);
// also try save
mongoTemplate.save(p9bi);
assertThat(p9bi.getId(), notNullValue());
PersonWithIdPropertyOfTypeBigInteger p9qbi = mongoTemplate.findOne(new Query(where("id").in(p9bi.getId())),
PersonWithIdPropertyOfTypeBigInteger.class);
assertThat(p9qbi, notNullValue());
assertThat(p9qbi.getId(), is(p9bi.getId()));
checkCollectionContents(PersonWithIdPropertyOfTypeBigInteger.class, 1);
// int id - provided
PersonWithIdPropertyOfPrimitiveInt p10 = new PersonWithIdPropertyOfPrimitiveInt();
p10.setFirstName("Sven_10");
p10.setAge(22);
p10.setId(12345);
// insert
mongoTemplate.insert(p10);
// also try save
mongoTemplate.save(p10);
assertThat(p10.getId(), notNullValue());
PersonWithIdPropertyOfPrimitiveInt p10q = mongoTemplate.findOne(new Query(where("id").in(p10.getId())),
PersonWithIdPropertyOfPrimitiveInt.class);
assertThat(p10q, notNullValue());
assertThat(p10q.getId(), is(p10.getId()));
checkCollectionContents(PersonWithIdPropertyOfPrimitiveInt.class, 1);
// Long id - provided
PersonWithIdPropertyOfTypeLong p11 = new PersonWithIdPropertyOfTypeLong();
p11.setFirstName("Sven_9");
p11.setAge(22);
p11.setId(Long.valueOf(12345L));
// insert
mongoTemplate.insert(p11);
// also try save
mongoTemplate.save(p11);
assertThat(p11.getId(), notNullValue());
PersonWithIdPropertyOfTypeLong p11q = mongoTemplate.findOne(new Query(where("id").in(p11.getId())),
PersonWithIdPropertyOfTypeLong.class);
assertThat(p11q, notNullValue());
assertThat(p11q.getId(), is(p11.getId()));
checkCollectionContents(PersonWithIdPropertyOfTypeLong.class, 1);
// long id - provided
PersonWithIdPropertyOfPrimitiveLong p12 = new PersonWithIdPropertyOfPrimitiveLong();
p12.setFirstName("Sven_10");
p12.setAge(22);
p12.setId(12345L);
// insert
mongoTemplate.insert(p12);
// also try save
mongoTemplate.save(p12);
assertThat(p12.getId(), notNullValue());
PersonWithIdPropertyOfPrimitiveLong p12q = mongoTemplate.findOne(new Query(where("id").in(p12.getId())),
PersonWithIdPropertyOfPrimitiveLong.class);
assertThat(p12q, notNullValue());
assertThat(p12q.getId(), is(p12.getId()));
checkCollectionContents(PersonWithIdPropertyOfPrimitiveLong.class, 1);
}
private void checkCollectionContents(Class<?> entityClass, int count) {
assertThat(template.findAll(entityClass).size(), is(count));
}
/**
* @see DATAMONGO-234
*/
@Test
public void testFindAndUpdate() {
template.insert(new Person("Tom", 21));
template.insert(new Person("Dick", 22));
template.insert(new Person("Harry", 23));
Query query = new Query(Criteria.where("firstName").is("Harry"));
Update update = new Update().inc("age", 1);
Person p = template.findAndModify(query, update, Person.class); // return old
assertThat(p.getFirstName(), is("Harry"));
assertThat(p.getAge(), is(23));
p = template.findOne(query, Person.class);
assertThat(p.getAge(), is(24));
p = template.findAndModify(query, update, Person.class, "person");
assertThat(p.getAge(), is(24));
p = template.findOne(query, Person.class);
assertThat(p.getAge(), is(25));
p = template.findAndModify(query, update, new FindAndModifyOptions().returnNew(true), Person.class);
assertThat(p.getAge(), is(26));
p = template.findAndModify(query, update, null, Person.class, "person");
assertThat(p.getAge(), is(26));
p = template.findOne(query, Person.class);
assertThat(p.getAge(), is(27));
Query query2 = new Query(Criteria.where("firstName").is("Mary"));
p = template.findAndModify(query2, update, new FindAndModifyOptions().returnNew(true).upsert(true), Person.class);
assertThat(p.getFirstName(), is("Mary"));
assertThat(p.getAge(), is(1));
}
@Test
public void testFindAndUpdateUpsert() {
template.insert(new Person("Tom", 21));
template.insert(new Person("Dick", 22));
Query query = new Query(Criteria.where("firstName").is("Harry"));
Update update = new Update().set("age", 23);
Person p = template.findAndModify(query, update, new FindAndModifyOptions().upsert(true).returnNew(true),
Person.class);
assertThat(p.getFirstName(), is("Harry"));
assertThat(p.getAge(), is(23));
}
@Test
public void testFindAndRemove() throws Exception {
Message m1 = new Message("Hello Spring");
template.insert(m1);
Message m2 = new Message("Hello Mongo");
template.insert(m2);
Query q = new Query(Criteria.where("text").regex("^Hello.*"));
Message found1 = template.findAndRemove(q, Message.class);
Message found2 = template.findAndRemove(q, Message.class);
// Message notFound = template.findAndRemove(q, Message.class);
DBObject notFound = template.getCollection("").findAndRemove(q.getQueryObject());
assertThat(found1, notNullValue());
assertThat(found2, notNullValue());
assertThat(notFound, nullValue());
}
@Test
public void testUsingAnInQueryWithObjectId() throws Exception {
template.remove(new Query(), PersonWithIdPropertyOfTypeObjectId.class);
PersonWithIdPropertyOfTypeObjectId p1 = new PersonWithIdPropertyOfTypeObjectId();
p1.setFirstName("Sven");
p1.setAge(11);
template.insert(p1);
PersonWithIdPropertyOfTypeObjectId p2 = new PersonWithIdPropertyOfTypeObjectId();
p2.setFirstName("Mary");
p2.setAge(21);
template.insert(p2);
PersonWithIdPropertyOfTypeObjectId p3 = new PersonWithIdPropertyOfTypeObjectId();
p3.setFirstName("Ann");
p3.setAge(31);
template.insert(p3);
PersonWithIdPropertyOfTypeObjectId p4 = new PersonWithIdPropertyOfTypeObjectId();
p4.setFirstName("John");
p4.setAge(41);
template.insert(p4);
Query q1 = new Query(Criteria.where("age").in(11, 21, 41));
List<PersonWithIdPropertyOfTypeObjectId> results1 = template.find(q1, PersonWithIdPropertyOfTypeObjectId.class);
Query q2 = new Query(Criteria.where("firstName").in("Ann", "Mary"));
List<PersonWithIdPropertyOfTypeObjectId> results2 = template.find(q2, PersonWithIdPropertyOfTypeObjectId.class);
Query q3 = new Query(Criteria.where("id").in(p3.getId()));
List<PersonWithIdPropertyOfTypeObjectId> results3 = template.find(q3, PersonWithIdPropertyOfTypeObjectId.class);
assertThat(results1.size(), is(3));
assertThat(results2.size(), is(2));
assertThat(results3.size(), is(1));
}
@Test
public void testUsingAnInQueryWithStringId() throws Exception {
template.remove(new Query(), PersonWithIdPropertyOfTypeString.class);
PersonWithIdPropertyOfTypeString p1 = new PersonWithIdPropertyOfTypeString();
p1.setFirstName("Sven");
p1.setAge(11);
template.insert(p1);
PersonWithIdPropertyOfTypeString p2 = new PersonWithIdPropertyOfTypeString();
p2.setFirstName("Mary");
p2.setAge(21);
template.insert(p2);
PersonWithIdPropertyOfTypeString p3 = new PersonWithIdPropertyOfTypeString();
p3.setFirstName("Ann");
p3.setAge(31);
template.insert(p3);
PersonWithIdPropertyOfTypeString p4 = new PersonWithIdPropertyOfTypeString();
p4.setFirstName("John");
p4.setAge(41);
template.insert(p4);
Query q1 = new Query(Criteria.where("age").in(11, 21, 41));
List<PersonWithIdPropertyOfTypeString> results1 = template.find(q1, PersonWithIdPropertyOfTypeString.class);
Query q2 = new Query(Criteria.where("firstName").in("Ann", "Mary"));
List<PersonWithIdPropertyOfTypeString> results2 = template.find(q2, PersonWithIdPropertyOfTypeString.class);
Query q3 = new Query(Criteria.where("id").in(p3.getId(), p4.getId()));
List<PersonWithIdPropertyOfTypeString> results3 = template.find(q3, PersonWithIdPropertyOfTypeString.class);
assertThat(results1.size(), is(3));
assertThat(results2.size(), is(2));
assertThat(results3.size(), is(2));
}
@Test
public void testUsingAnInQueryWithLongId() throws Exception {
template.remove(new Query(), PersonWithIdPropertyOfTypeLong.class);
PersonWithIdPropertyOfTypeLong p1 = new PersonWithIdPropertyOfTypeLong();
p1.setFirstName("Sven");
p1.setAge(11);
p1.setId(1001L);
template.insert(p1);
PersonWithIdPropertyOfTypeLong p2 = new PersonWithIdPropertyOfTypeLong();
p2.setFirstName("Mary");
p2.setAge(21);
p2.setId(1002L);
template.insert(p2);
PersonWithIdPropertyOfTypeLong p3 = new PersonWithIdPropertyOfTypeLong();
p3.setFirstName("Ann");
p3.setAge(31);
p3.setId(1003L);
template.insert(p3);
PersonWithIdPropertyOfTypeLong p4 = new PersonWithIdPropertyOfTypeLong();
p4.setFirstName("John");
p4.setAge(41);
p4.setId(1004L);
template.insert(p4);
Query q1 = new Query(Criteria.where("age").in(11, 21, 41));
List<PersonWithIdPropertyOfTypeLong> results1 = template.find(q1, PersonWithIdPropertyOfTypeLong.class);
Query q2 = new Query(Criteria.where("firstName").in("Ann", "Mary"));
List<PersonWithIdPropertyOfTypeLong> results2 = template.find(q2, PersonWithIdPropertyOfTypeLong.class);
Query q3 = new Query(Criteria.where("id").in(1001L, 1004L));
List<PersonWithIdPropertyOfTypeLong> results3 = template.find(q3, PersonWithIdPropertyOfTypeLong.class);
assertThat(results1.size(), is(3));
assertThat(results2.size(), is(2));
assertThat(results3.size(), is(2));
}
/**
* @see DATAMONGO-602
*/
@Test
public void testUsingAnInQueryWithBigIntegerId() throws Exception {
template.remove(new Query(), PersonWithIdPropertyOfTypeBigInteger.class);
PersonWithIdPropertyOfTypeBigInteger p1 = new PersonWithIdPropertyOfTypeBigInteger();
p1.setFirstName("Sven");
p1.setAge(11);
p1.setId(new BigInteger("2666666666666666665069473312490162649510603601"));
template.insert(p1);
PersonWithIdPropertyOfTypeBigInteger p2 = new PersonWithIdPropertyOfTypeBigInteger();
p2.setFirstName("Mary");
p2.setAge(21);
p2.setId(new BigInteger("2666666666666666665069473312490162649510603602"));
template.insert(p2);
PersonWithIdPropertyOfTypeBigInteger p3 = new PersonWithIdPropertyOfTypeBigInteger();
p3.setFirstName("Ann");
p3.setAge(31);
p3.setId(new BigInteger("2666666666666666665069473312490162649510603603"));
template.insert(p3);
PersonWithIdPropertyOfTypeBigInteger p4 = new PersonWithIdPropertyOfTypeBigInteger();
p4.setFirstName("John");
p4.setAge(41);
p4.setId(new BigInteger("2666666666666666665069473312490162649510603604"));
template.insert(p4);
Query q1 = new Query(Criteria.where("age").in(11, 21, 41));
List<PersonWithIdPropertyOfTypeBigInteger> results1 = template.find(q1, PersonWithIdPropertyOfTypeBigInteger.class);
Query q2 = new Query(Criteria.where("firstName").in("Ann", "Mary"));
List<PersonWithIdPropertyOfTypeBigInteger> results2 = template.find(q2, PersonWithIdPropertyOfTypeBigInteger.class);
Query q3 = new Query(Criteria.where("id").in(new BigInteger("2666666666666666665069473312490162649510603601"),
new BigInteger("2666666666666666665069473312490162649510603604")));
List<PersonWithIdPropertyOfTypeBigInteger> results3 = template.find(q3, PersonWithIdPropertyOfTypeBigInteger.class);
assertThat(results1.size(), is(3));
assertThat(results2.size(), is(2));
assertThat(results3.size(), is(2));
}
@Test
public void testUsingAnInQueryWithPrimitiveIntId() throws Exception {
template.remove(new Query(), PersonWithIdPropertyOfPrimitiveInt.class);
PersonWithIdPropertyOfPrimitiveInt p1 = new PersonWithIdPropertyOfPrimitiveInt();
p1.setFirstName("Sven");
p1.setAge(11);
p1.setId(1001);
template.insert(p1);
PersonWithIdPropertyOfPrimitiveInt p2 = new PersonWithIdPropertyOfPrimitiveInt();
p2.setFirstName("Mary");
p2.setAge(21);
p2.setId(1002);
template.insert(p2);
PersonWithIdPropertyOfPrimitiveInt p3 = new PersonWithIdPropertyOfPrimitiveInt();
p3.setFirstName("Ann");
p3.setAge(31);
p3.setId(1003);
template.insert(p3);
PersonWithIdPropertyOfPrimitiveInt p4 = new PersonWithIdPropertyOfPrimitiveInt();
p4.setFirstName("John");
p4.setAge(41);
p4.setId(1004);
template.insert(p4);
Query q1 = new Query(Criteria.where("age").in(11, 21, 41));
List<PersonWithIdPropertyOfPrimitiveInt> results1 = template.find(q1, PersonWithIdPropertyOfPrimitiveInt.class);
Query q2 = new Query(Criteria.where("firstName").in("Ann", "Mary"));
List<PersonWithIdPropertyOfPrimitiveInt> results2 = template.find(q2, PersonWithIdPropertyOfPrimitiveInt.class);
Query q3 = new Query(Criteria.where("id").in(1001, 1003));
List<PersonWithIdPropertyOfPrimitiveInt> results3 = template.find(q3, PersonWithIdPropertyOfPrimitiveInt.class);
assertThat(results1.size(), is(3));
assertThat(results2.size(), is(2));
assertThat(results3.size(), is(2));
}
@Test
public void testUsingInQueryWithList() throws Exception {
template.remove(new Query(), PersonWithIdPropertyOfTypeObjectId.class);
PersonWithIdPropertyOfTypeObjectId p1 = new PersonWithIdPropertyOfTypeObjectId();
p1.setFirstName("Sven");
p1.setAge(11);
template.insert(p1);
PersonWithIdPropertyOfTypeObjectId p2 = new PersonWithIdPropertyOfTypeObjectId();
p2.setFirstName("Mary");
p2.setAge(21);
template.insert(p2);
PersonWithIdPropertyOfTypeObjectId p3 = new PersonWithIdPropertyOfTypeObjectId();
p3.setFirstName("Ann");
p3.setAge(31);
template.insert(p3);
PersonWithIdPropertyOfTypeObjectId p4 = new PersonWithIdPropertyOfTypeObjectId();
p4.setFirstName("John");
p4.setAge(41);
template.insert(p4);
List<Integer> l1 = new ArrayList<Integer>();
l1.add(11);
l1.add(21);
l1.add(41);
Query q1 = new Query(Criteria.where("age").in(l1));
List<PersonWithIdPropertyOfTypeObjectId> results1 = template.find(q1, PersonWithIdPropertyOfTypeObjectId.class);
Query q2 = new Query(Criteria.where("age").in(l1.toArray()));
List<PersonWithIdPropertyOfTypeObjectId> results2 = template.find(q2, PersonWithIdPropertyOfTypeObjectId.class);
assertThat(results1.size(), is(3));
assertThat(results2.size(), is(3));
try {
List<Integer> l2 = new ArrayList<Integer>();
l2.add(31);
Query q3 = new Query(Criteria.where("age").in(l1, l2));
template.find(q3, PersonWithIdPropertyOfTypeObjectId.class);
fail("Should have trown an InvalidDocumentStoreApiUsageException");
} catch (InvalidMongoDbApiUsageException e) {}
}
@Test
public void testUsingRegexQueryWithOptions() throws Exception {
template.remove(new Query(), PersonWithIdPropertyOfTypeObjectId.class);
PersonWithIdPropertyOfTypeObjectId p1 = new PersonWithIdPropertyOfTypeObjectId();
p1.setFirstName("Sven");
p1.setAge(11);
template.insert(p1);
PersonWithIdPropertyOfTypeObjectId p2 = new PersonWithIdPropertyOfTypeObjectId();
p2.setFirstName("Mary");
p2.setAge(21);
template.insert(p2);
PersonWithIdPropertyOfTypeObjectId p3 = new PersonWithIdPropertyOfTypeObjectId();
p3.setFirstName("Ann");
p3.setAge(31);
template.insert(p3);
PersonWithIdPropertyOfTypeObjectId p4 = new PersonWithIdPropertyOfTypeObjectId();
p4.setFirstName("samantha");
p4.setAge(41);
template.insert(p4);
Query q1 = new Query(Criteria.where("firstName").regex("S.*"));
List<PersonWithIdPropertyOfTypeObjectId> results1 = template.find(q1, PersonWithIdPropertyOfTypeObjectId.class);
Query q2 = new Query(Criteria.where("firstName").regex("S.*", "i"));
List<PersonWithIdPropertyOfTypeObjectId> results2 = template.find(q2, PersonWithIdPropertyOfTypeObjectId.class);
assertThat(results1.size(), is(1));
assertThat(results2.size(), is(2));
}
@Test
public void testUsingAnOrQuery() throws Exception {
template.remove(new Query(), PersonWithIdPropertyOfTypeObjectId.class);
PersonWithIdPropertyOfTypeObjectId p1 = new PersonWithIdPropertyOfTypeObjectId();
p1.setFirstName("Sven");
p1.setAge(11);
template.insert(p1);
PersonWithIdPropertyOfTypeObjectId p2 = new PersonWithIdPropertyOfTypeObjectId();
p2.setFirstName("Mary");
p2.setAge(21);
template.insert(p2);
PersonWithIdPropertyOfTypeObjectId p3 = new PersonWithIdPropertyOfTypeObjectId();
p3.setFirstName("Ann");
p3.setAge(31);
template.insert(p3);
PersonWithIdPropertyOfTypeObjectId p4 = new PersonWithIdPropertyOfTypeObjectId();
p4.setFirstName("John");
p4.setAge(41);
template.insert(p4);
Query orQuery = new Query(new Criteria().orOperator(where("age").in(11, 21), where("age").is(31)));
List<PersonWithIdPropertyOfTypeObjectId> results = template.find(orQuery, PersonWithIdPropertyOfTypeObjectId.class);
assertThat(results.size(), is(3));
for (PersonWithIdPropertyOfTypeObjectId p : results) {
assertThat(p.getAge(), isOneOf(11, 21, 31));
}
}
@Test
public void testUsingUpdateWithMultipleSet() throws Exception {
template.remove(new Query(), PersonWithIdPropertyOfTypeObjectId.class);
PersonWithIdPropertyOfTypeObjectId p1 = new PersonWithIdPropertyOfTypeObjectId();
p1.setFirstName("Sven");
p1.setAge(11);
template.insert(p1);
PersonWithIdPropertyOfTypeObjectId p2 = new PersonWithIdPropertyOfTypeObjectId();
p2.setFirstName("Mary");
p2.setAge(21);
template.insert(p2);
Update u = new Update().set("firstName", "Bob").set("age", 10);
WriteResult wr = template.updateMulti(new Query(), u, PersonWithIdPropertyOfTypeObjectId.class);
assertThat(wr.getN(), is(2));
Query q1 = new Query(Criteria.where("age").in(11, 21));
List<PersonWithIdPropertyOfTypeObjectId> r1 = template.find(q1, PersonWithIdPropertyOfTypeObjectId.class);
assertThat(r1.size(), is(0));
Query q2 = new Query(Criteria.where("age").is(10));
List<PersonWithIdPropertyOfTypeObjectId> r2 = template.find(q2, PersonWithIdPropertyOfTypeObjectId.class);
assertThat(r2.size(), is(2));
for (PersonWithIdPropertyOfTypeObjectId p : r2) {
assertThat(p.getAge(), is(10));
assertThat(p.getFirstName(), is("Bob"));
}
}
@Test
public void testRemovingDocument() throws Exception {
PersonWithIdPropertyOfTypeObjectId p1 = new PersonWithIdPropertyOfTypeObjectId();
p1.setFirstName("Sven_to_be_removed");
p1.setAge(51);
template.insert(p1);
Query q1 = new Query(Criteria.where("id").is(p1.getId()));
PersonWithIdPropertyOfTypeObjectId found1 = template.findOne(q1, PersonWithIdPropertyOfTypeObjectId.class);
assertThat(found1, notNullValue());
Query _q = new Query(Criteria.where("_id").is(p1.getId()));
template.remove(_q, PersonWithIdPropertyOfTypeObjectId.class);
PersonWithIdPropertyOfTypeObjectId notFound1 = template.findOne(q1, PersonWithIdPropertyOfTypeObjectId.class);
assertThat(notFound1, nullValue());
PersonWithIdPropertyOfTypeObjectId p2 = new PersonWithIdPropertyOfTypeObjectId();
p2.setFirstName("Bubba_to_be_removed");
p2.setAge(51);
template.insert(p2);
Query q2 = new Query(Criteria.where("id").is(p2.getId()));
PersonWithIdPropertyOfTypeObjectId found2 = template.findOne(q2, PersonWithIdPropertyOfTypeObjectId.class);
assertThat(found2, notNullValue());
template.remove(q2, PersonWithIdPropertyOfTypeObjectId.class);
PersonWithIdPropertyOfTypeObjectId notFound2 = template.findOne(q2, PersonWithIdPropertyOfTypeObjectId.class);
assertThat(notFound2, nullValue());
}
@Test
public void testAddingToList() {
PersonWithAList p = new PersonWithAList();
p.setFirstName("Sven");
p.setAge(22);
template.insert(p);
Query q1 = new Query(Criteria.where("id").is(p.getId()));
PersonWithAList p2 = template.findOne(q1, PersonWithAList.class);
assertThat(p2, notNullValue());
assertThat(p2.getWishList().size(), is(0));
p2.addToWishList("please work!");
template.save(p2);
PersonWithAList p3 = template.findOne(q1, PersonWithAList.class);
assertThat(p3, notNullValue());
assertThat(p3.getWishList().size(), is(1));
Friend f = new Friend();
p.setFirstName("Erik");
p.setAge(21);
p3.addFriend(f);
template.save(p3);
PersonWithAList p4 = template.findOne(q1, PersonWithAList.class);
assertThat(p4, notNullValue());
assertThat(p4.getWishList().size(), is(1));
assertThat(p4.getFriends().size(), is(1));
}
@Test
public void testFindOneWithSort() {
PersonWithAList p = new PersonWithAList();
p.setFirstName("Sven");
p.setAge(22);
template.insert(p);
PersonWithAList p2 = new PersonWithAList();
p2.setFirstName("Erik");
p2.setAge(21);
template.insert(p2);
PersonWithAList p3 = new PersonWithAList();
p3.setFirstName("Mark");
p3.setAge(40);
template.insert(p3);
// test query with a sort
Query q2 = new Query(Criteria.where("age").gt(10));
q2.with(new Sort(Direction.DESC, "age"));
PersonWithAList p5 = template.findOne(q2, PersonWithAList.class);
assertThat(p5.getFirstName(), is("Mark"));
}
@Test
@SuppressWarnings("deprecation")
public void testUsingReadPreference() throws Exception {
this.template.execute("readPref", new CollectionCallback<Object>() {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
assertThat(collection.getOptions(), is(0));
assertThat(collection.getDB().getOptions(), is(0));
return null;
}
});
MongoTemplate slaveTemplate = new MongoTemplate(factory);
slaveTemplate.setReadPreference(ReadPreference.SECONDARY);
slaveTemplate.execute("readPref", new CollectionCallback<Object>() {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
assertThat(collection.getReadPreference(), is(ReadPreference.SECONDARY));
assertThat(collection.getDB().getOptions(), is(0));
return null;
}
});
}
/**
* @see DATADOC-166
*/
@Test
public void removingNullIsANoOp() {
template.remove(null);
}
/**
* @see DATADOC-240, DATADOC-212
*/
@Test
public void updatesObjectIdsCorrectly() {
PersonWithIdPropertyOfTypeObjectId person = new PersonWithIdPropertyOfTypeObjectId();
person.setId(new ObjectId());
person.setFirstName("Dave");
template.save(person);
template.updateFirst(query(where("id").is(person.getId())), update("firstName", "Carter"),
PersonWithIdPropertyOfTypeObjectId.class);
PersonWithIdPropertyOfTypeObjectId result = template.findById(person.getId(),
PersonWithIdPropertyOfTypeObjectId.class);
assertThat(result, is(notNullValue()));
assertThat(result.getId(), is(person.getId()));
assertThat(result.getFirstName(), is("Carter"));
}
@Test
public void testWriteConcernResolver() {
PersonWithIdPropertyOfTypeObjectId person = new PersonWithIdPropertyOfTypeObjectId();
person.setId(new ObjectId());
person.setFirstName("Dave");
template.setWriteConcern(WriteConcern.NONE);
template.save(person);
WriteResult result = template.updateFirst(query(where("id").is(person.getId())), update("firstName", "Carter"),
PersonWithIdPropertyOfTypeObjectId.class);
WriteConcern lastWriteConcern = result.getLastConcern();
assertThat(lastWriteConcern, equalTo(WriteConcern.NONE));
FsyncSafeWriteConcernResolver resolver = new FsyncSafeWriteConcernResolver();
template.setWriteConcernResolver(resolver);
Query q = query(where("_id").is(person.getId()));
Update u = update("firstName", "Carter");
result = template.updateFirst(q, u, PersonWithIdPropertyOfTypeObjectId.class);
lastWriteConcern = result.getLastConcern();
assertThat(lastWriteConcern, equalTo(WriteConcern.FSYNC_SAFE));
MongoAction lastMongoAction = resolver.getMongoAction();
assertThat(lastMongoAction.getCollectionName(), is("personWithIdPropertyOfTypeObjectId"));
assertThat(lastMongoAction.getDefaultWriteConcern(), equalTo(WriteConcern.NONE));
assertThat(lastMongoAction.getDocument(), notNullValue());
assertThat(lastMongoAction.getEntityType().toString(), is(PersonWithIdPropertyOfTypeObjectId.class.toString()));
assertThat(lastMongoAction.getMongoActionOperation(), is(MongoActionOperation.UPDATE));
assertThat(lastMongoAction.getQuery(), equalTo(q.getQueryObject()));
}
private class FsyncSafeWriteConcernResolver implements WriteConcernResolver {
private MongoAction mongoAction;
public WriteConcern resolve(MongoAction action) {
this.mongoAction = action;
return WriteConcern.FSYNC_SAFE;
}
public MongoAction getMongoAction() {
return mongoAction;
}
}
/**
* @see DATADOC-246
*/
@Test
public void updatesDBRefsCorrectly() {
DBRef first = new DBRef(factory.getDb(), "foo", new ObjectId());
DBRef second = new DBRef(factory.getDb(), "bar", new ObjectId());
template.updateFirst(null, update("dbRefs", Arrays.asList(first, second)), ClassWithDBRefs.class);
}
class ClassWithDBRefs {
List<DBRef> dbrefs;
}
/**
* @see DATADOC-202
*/
@Test
public void executeDocument() {
template.insert(new Person("Tom"));
template.insert(new Person("Dick"));
template.insert(new Person("Harry"));
final List<String> names = new ArrayList<String>();
template.executeQuery(new Query(), template.getCollectionName(Person.class), new DocumentCallbackHandler() {
public void processDocument(DBObject dbObject) {
String name = (String) dbObject.get("firstName");
if (name != null) {
names.add(name);
}
}
});
assertEquals(3, names.size());
// template.remove(new Query(), Person.class);
}
/**
* @see DATADOC-202
*/
@Test
public void executeDocumentWithCursorPreparer() {
template.insert(new Person("Tom"));
template.insert(new Person("Dick"));
template.insert(new Person("Harry"));
final List<String> names = new ArrayList<String>();
template.executeQuery(new Query(), template.getCollectionName(Person.class), new DocumentCallbackHandler() {
public void processDocument(DBObject dbObject) {
String name = (String) dbObject.get("firstName");
if (name != null) {
names.add(name);
}
}
}, new CursorPreparer() {
public DBCursor prepare(DBCursor cursor) {
cursor.limit(1);
return cursor;
}
});
assertEquals(1, names.size());
// template.remove(new Query(), Person.class);
}
/**
* @see DATADOC-183
*/
@Test
public void countsDocumentsCorrectly() {
assertThat(template.count(new Query(), Person.class), is(0L));
Person dave = new Person("Dave");
Person carter = new Person("Carter");
template.save(dave);
template.save(carter);
assertThat(template.count(null, Person.class), is(2L));
assertThat(template.count(query(where("firstName").is("Carter")), Person.class), is(1L));
}
/**
* @see DATADOC-183
*/
@Test(expected = IllegalArgumentException.class)
public void countRejectsNullEntityClass() {
template.count(null, (Class<?>) null);
}
/**
* @see DATADOC-183
*/
@Test(expected = IllegalArgumentException.class)
public void countRejectsEmptyCollectionName() {
template.count(null, "");
}
/**
* @see DATADOC-183
*/
@Test(expected = IllegalArgumentException.class)
public void countRejectsNullCollectionName() {
template.count(null, (String) null);
}
@Test
public void returnsEntityWhenQueryingForDateTime() {
DateTime dateTime = new DateTime(2011, 3, 3, 12, 0, 0, 0);
TestClass testClass = new TestClass(dateTime);
mappingTemplate.save(testClass);
List<TestClass> testClassList = mappingTemplate.find(new Query(Criteria.where("myDate").is(dateTime.toDate())),
TestClass.class);
assertThat(testClassList.size(), is(1));
assertThat(testClassList.get(0).myDate, is(testClass.myDate));
}
/**
* @see DATADOC-230
*/
@Test
public void removesEntityFromCollection() {
template.remove(new Query(), "mycollection");
Person person = new Person("Dave");
template.save(person, "mycollection");
assertThat(template.findAll(TestClass.class, "mycollection").size(), is(1));
template.remove(person, "mycollection");
assertThat(template.findAll(Person.class, "mycollection").isEmpty(), is(true));
}
/**
* @see DATADOC-349
*/
@Test
public void removesEntityWithAnnotatedIdIfIdNeedsMassaging() {
String id = new ObjectId().toString();
Sample sample = new Sample();
sample.id = id;
template.save(sample);
assertThat(template.findOne(query(where("id").is(id)), Sample.class).id, is(id));
template.remove(sample);
assertThat(template.findOne(query(where("id").is(id)), Sample.class), is(nullValue()));
}
/**
* @see DATAMONGO-423
*/
@Test
public void executesQueryWithNegatedRegexCorrectly() {
Sample first = new Sample();
first.field = "Matthews";
Sample second = new Sample();
second.field = "Beauford";
template.save(first);
template.save(second);
Query query = query(where("field").not().regex("Matthews"));
List<Sample> result = template.find(query, Sample.class);
assertThat(result.size(), is(1));
assertThat(result.get(0).field, is("Beauford"));
}
/**
* @see DATAMONGO-447
*/
@Test
public void storesAndRemovesTypeWithComplexId() {
MyId id = new MyId();
id.first = "foo";
id.second = "bar";
TypeWithMyId source = new TypeWithMyId();
source.id = id;
template.save(source);
template.remove(query(where("id").is(id)), TypeWithMyId.class);
}
/**
* @see DATAMONGO-506
*/
@Test
public void exceutesBasicQueryCorrectly() {
Address address = new Address();
address.state = "PA";
address.city = "Philadelphia";
MyPerson person = new MyPerson();
person.name = "Oleg";
person.address = address;
template.save(person);
Query query = new BasicQuery("{'name' : 'Oleg'}");
List<MyPerson> result = template.find(query, MyPerson.class);
assertThat(result, hasSize(1));
assertThat(result.get(0), hasProperty("name", is("Oleg")));
query = new BasicQuery("{'address.state' : 'PA' }");
result = template.find(query, MyPerson.class);
assertThat(result, hasSize(1));
assertThat(result.get(0), hasProperty("name", is("Oleg")));
}
/**
* @see DATAMONGO-279
*/
@Test(expected = OptimisticLockingFailureException.class)
public void optimisticLockingHandling() {
// Init version
PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger();
person.age = 29;
person.firstName = "Patryk";
template.save(person);
List<PersonWithVersionPropertyOfTypeInteger> result = template
.findAll(PersonWithVersionPropertyOfTypeInteger.class);
assertThat(result, hasSize(1));
assertThat(result.get(0).version, is(0));
// Version change
person = result.get(0);
person.firstName = "Patryk2";
template.save(person);
assertThat(person.version, is(1));
result = mappingTemplate.findAll(PersonWithVersionPropertyOfTypeInteger.class);
assertThat(result, hasSize(1));
assertThat(result.get(0).version, is(1));
// Optimistic lock exception
person.version = 0;
person.firstName = "Patryk3";
template.save(person);
}
/**
* @see DATAMONGO-562
*/
@Test
public void optimisticLockingHandlingWithExistingId() {
PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger();
person.id = new ObjectId().toString();
person.age = 29;
person.firstName = "Patryk";
template.save(person);
}
/**
* @see DATAMONGO-617
*/
@Test
public void doesNotFailOnVersionInitForUnversionedEntity() {
DBObject dbObject = new BasicDBObject();
dbObject.put("firstName", "Oliver");
template.insert(dbObject, template.determineCollectionName(PersonWithVersionPropertyOfTypeInteger.class));
}
/**
* @see DATAMONGO-539
*/
@Test
public void removesObjectFromExplicitCollection() {
String collectionName = "explicit";
template.remove(new Query(), collectionName);
PersonWithConvertedId person = new PersonWithConvertedId();
person.name = "Dave";
template.save(person, collectionName);
assertThat(template.findAll(PersonWithConvertedId.class, collectionName).isEmpty(), is(false));
template.remove(person, collectionName);
assertThat(template.findAll(PersonWithConvertedId.class, collectionName).isEmpty(), is(true));
}
/**
* @see DATAMONGO-549
*/
public void savesMapCorrectly() {
Map<String, String> map = new HashMap<String, String>();
map.put("key", "value");
template.save(map, "maps");
}
/**
* @see DATAMONGO-549
*/
@Test(expected = MappingException.class)
public void savesMongoPrimitiveObjectCorrectly() {
template.save(new Object(), "collection");
}
/**
* @see DATAMONGO-549
*/
@Test(expected = IllegalArgumentException.class)
public void rejectsNullObjectToBeSaved() {
template.save(null);
}
/**
* @see DATAMONGO-550
*/
@Test
public void savesPlainDbObjectCorrectly() {
DBObject dbObject = new BasicDBObject("foo", "bar");
template.save(dbObject, "collection");
assertThat(dbObject.containsField("_id"), is(true));
}
/**
* @see DATAMONGO-550
*/
@Test(expected = InvalidDataAccessApiUsageException.class)
public void rejectsPlainObjectWithOutExplicitCollection() {
DBObject dbObject = new BasicDBObject("foo", "bar");
template.save(dbObject, "collection");
template.findById(dbObject.get("_id"), DBObject.class);
}
/**
* @see DATAMONGO-550
*/
@Test
public void readsPlainDbObjectById() {
DBObject dbObject = new BasicDBObject("foo", "bar");
template.save(dbObject, "collection");
DBObject result = template.findById(dbObject.get("_id"), DBObject.class, "collection");
assertThat(result.get("foo"), is(dbObject.get("foo")));
assertThat(result.get("_id"), is(dbObject.get("_id")));
}
/**
* @see DATAMONGO-551
*/
@Test
public void writesPlainString() {
template.save("{ 'foo' : 'bar' }", "collection");
}
/**
* @see DATAMONGO-551
*/
@Test(expected = MappingException.class)
public void rejectsNonJsonStringForSave() {
template.save("Foobar!", "collection");
}
/**
* @see DATAMONGO-588
*/
@Test
public void initializesVersionOnInsert() {
PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger();
person.firstName = "Dave";
template.insert(person);
assertThat(person.version, is(0));
}
/**
* @see DATAMONGO-588
*/
@Test
public void initializesVersionOnBatchInsert() {
PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger();
person.firstName = "Dave";
template.insertAll(Arrays.asList(person));
assertThat(person.version, is(0));
}
/**
* @see DATAMONGO-568
*/
@Test
public void queryCantBeNull() {
List<PersonWithIdPropertyOfTypeObjectId> result = template.findAll(PersonWithIdPropertyOfTypeObjectId.class);
assertThat(template.find(null, PersonWithIdPropertyOfTypeObjectId.class), is(result));
}
/**
* @see DATAMONGO-620
*/
@Test
public void versionsObjectIntoDedicatedCollection() {
PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger();
person.firstName = "Dave";
template.save(person, "personX");
assertThat(person.version, is(0));
template.save(person, "personX");
assertThat(person.version, is(1));
}
/**
* @see DATAMONGO-621
*/
@Test
public void correctlySetsLongVersionProperty() {
PersonWithVersionPropertyOfTypeLong person = new PersonWithVersionPropertyOfTypeLong();
person.firstName = "Dave";
template.save(person);
assertThat(person.version, is(0L));
}
/**
* @see DATAMONGO-622
*/
@Test(expected = DuplicateKeyException.class)
public void preventsDuplicateInsert() {
template.setWriteConcern(WriteConcern.SAFE);
PersonWithVersionPropertyOfTypeInteger person = new PersonWithVersionPropertyOfTypeInteger();
person.firstName = "Dave";
template.save(person);
assertThat(person.version, is(0));
person.version = null;
template.save(person);
}
/**
* @see DATAMONGO-629
*/
@Test
public void countAndFindWithoutTypeInformation() {
Person person = new Person();
template.save(person);
Query query = query(where("_id").is(person.getId()));
String collectionName = template.getCollectionName(Person.class);
assertThat(template.find(query, HashMap.class, collectionName), hasSize(1));
assertThat(template.count(query, collectionName), is(1L));
}
/**
* @see DATAMONGO-571
*/
@Test
public void nullsPropertiesForVersionObjectUpdates() {
VersionedPerson person = new VersionedPerson();
person.firstname = "Dave";
person.lastname = "Matthews";
template.save(person);
assertThat(person.id, is(notNullValue()));
person.lastname = null;
template.save(person);
person = template.findOne(query(where("id").is(person.id)), VersionedPerson.class);
assertThat(person.lastname, is(nullValue()));
}
/**
* @see DATAMONGO-571
*/
@Test
public void nullsValuesForUpdatesOfUnversionedEntity() {
Person person = new Person("Dave");
template.save(person);
person.setFirstName(null);
template.save(person);
person = template.findOne(query(where("id").is(person.getId())), Person.class);
assertThat(person.getFirstName(), is(nullValue()));
}
/**
* @see DATAMONGO-651
*/
@Test
public void throwsMongoSpecificExceptionForDataIntegrityViolations() {
WriteResult result = mock(WriteResult.class);
when(result.getError()).thenReturn("ERROR");
MongoActionOperation operation = MongoActionOperation.INSERT;
MongoTemplate mongoTemplate = new MongoTemplate(factory);
mongoTemplate.setWriteResultChecking(WriteResultChecking.EXCEPTION);
try {
mongoTemplate.handleAnyWriteResultErrors(result, null, operation);
fail("Expected MonogoDataIntegrityViolationException!");
} catch (MongoDataIntegrityViolationException o_O) {
assertThat(o_O.getActionOperation(), is(operation));
assertThat(o_O.getWriteResult(), is(result));
}
}
/**
* @see DATAMONGO-679
*/
@Test
public void savesJsonStringCorrectly() {
DBObject dbObject = new BasicDBObject().append("first", "first").append("second", "second");
template.save(dbObject.toString(), "collection");
List<DBObject> result = template.findAll(DBObject.class, "collection");
assertThat(result.size(), is(1));
assertThat(result.get(0).containsField("first"), is(true));
}
@Test
public void executesExistsCorrectly() {
Sample sample = new Sample();
template.save(sample);
Query query = query(where("id").is(sample.id));
assertThat(template.exists(query, Sample.class), is(true));
assertThat(template.exists(query(where("_id").is(sample.id)), template.getCollectionName(Sample.class)), is(true));
assertThat(template.exists(query, Sample.class, template.getCollectionName(Sample.class)), is(true));
}
/**
* @see DATAMONGO-675
*/
@Test
public void updateConsidersMappingAnnotations() {
TypeWithFieldAnnotation entity = new TypeWithFieldAnnotation();
entity.emailAddress = "old";
template.save(entity);
Query query = query(where("_id").is(entity.id));
Update update = Update.update("emailAddress", "new");
FindAndModifyOptions options = new FindAndModifyOptions().returnNew(true);
TypeWithFieldAnnotation result = template.findAndModify(query, update, options, TypeWithFieldAnnotation.class);
assertThat(result.emailAddress, is("new"));
}
/**
* @see DATAMONGO-671
*/
@Test
public void findsEntityByDateReference() {
TypeWithDate entity = new TypeWithDate();
entity.date = new Date(System.currentTimeMillis() - 10);
template.save(entity);
Query query = query(where("date").lt(new Date()));
List<TypeWithDate> result = template.find(query, TypeWithDate.class);
assertThat(result, hasSize(1));
assertThat(result.get(0).date, is(notNullValue()));
}
/**
* @see DATAMONGO-540
*/
@Test
public void findOneAfterUpsertForNonExistingObjectReturnsTheInsertedObject() {
String idValue = "4711";
Query query = new Query(Criteria.where("id").is(idValue));
String fieldValue = "bubu";
Update update = Update.update("field", fieldValue);
template.upsert(query, update, Sample.class);
Sample result = template.findOne(query, Sample.class);
assertThat(result, is(notNullValue()));
assertThat(result.field, is(fieldValue));
assertThat(result.id, is(idValue));
}
/**
* @see DATAMONGO-392
*/
@Test
public void updatesShouldRetainTypeInformation() {
Document doc = new Document();
doc.id = "4711";
doc.model = new ModelA("foo");
template.insert(doc);
Query query = new Query(Criteria.where("id").is(doc.id));
String newModelValue = "bar";
Update update = Update.update("model", new ModelA(newModelValue));
template.updateFirst(query, update, Document.class);
Document result = template.findOne(query, Document.class);
assertThat(result, is(notNullValue()));
assertThat(result.id, is(doc.id));
assertThat(result.model, is(notNullValue()));
assertThat(result.model.value(), is(newModelValue));
}
/**
* @see DATAMONGO-702
*/
@Test
public void queryShouldSupportRealAndAliasedPropertyNamesForFieldInclusions() {
ObjectWith3AliasedFields obj = new ObjectWith3AliasedFields();
obj.id = "4711";
obj.property1 = "P1";
obj.property2 = "P2";
obj.property3 = "P3";
template.insert(obj);
Query query = new Query(Criteria.where("id").is(obj.id));
query.fields() //
.include("property2") // real property name
.include("prop3"); // aliased property name
ObjectWith3AliasedFields result = template.findOne(query, ObjectWith3AliasedFields.class);
assertThat(result.id, is(obj.id));
assertThat(result.property1, is(nullValue()));
assertThat(result.property2, is(obj.property2));
assertThat(result.property3, is(obj.property3));
}
/**
* @see DATAMONGO-702
*/
@Test
public void queryShouldSupportRealAndAliasedPropertyNamesForFieldExclusions() {
ObjectWith3AliasedFields obj = new ObjectWith3AliasedFields();
obj.id = "4711";
obj.property1 = "P1";
obj.property2 = "P2";
obj.property3 = "P3";
template.insert(obj);
Query query = new Query(Criteria.where("id").is(obj.id));
query.fields() //
.exclude("property2") // real property name
.exclude("prop3"); // aliased property name
ObjectWith3AliasedFields result = template.findOne(query, ObjectWith3AliasedFields.class);
assertThat(result.id, is(obj.id));
assertThat(result.property1, is(obj.property1));
assertThat(result.property2, is(nullValue()));
assertThat(result.property3, is(nullValue()));
}
/**
* @see DATAMONGO-702
*/
@Test
public void findMultipleWithQueryShouldSupportRealAndAliasedPropertyNamesForFieldExclusions() {
ObjectWith3AliasedFields obj0 = new ObjectWith3AliasedFields();
obj0.id = "4711";
obj0.property1 = "P10";
obj0.property2 = "P20";
obj0.property3 = "P30";
ObjectWith3AliasedFields obj1 = new ObjectWith3AliasedFields();
obj1.id = "4712";
obj1.property1 = "P11";
obj1.property2 = "P21";
obj1.property3 = "P31";
template.insert(obj0);
template.insert(obj1);
Query query = new Query(Criteria.where("id").in(obj0.id, obj1.id));
query.fields() //
.exclude("property2") // real property name
.exclude("prop3"); // aliased property name
List<ObjectWith3AliasedFields> results = template.find(query, ObjectWith3AliasedFields.class);
assertThat(results, is(notNullValue()));
assertThat(results.size(), is(2));
ObjectWith3AliasedFields result0 = results.get(0);
assertThat(result0, is(notNullValue()));
assertThat(result0.id, is(obj0.id));
assertThat(result0.property1, is(obj0.property1));
assertThat(result0.property2, is(nullValue()));
assertThat(result0.property3, is(nullValue()));
ObjectWith3AliasedFields result1 = results.get(1);
assertThat(result1, is(notNullValue()));
assertThat(result1.id, is(obj1.id));
assertThat(result1.property1, is(obj1.property1));
assertThat(result1.property2, is(nullValue()));
assertThat(result1.property3, is(nullValue()));
}
/**
* @see DATAMONGO-702
*/
@Test
public void queryShouldSupportNestedPropertyNamesForFieldInclusions() {
ObjectWith3AliasedFieldsAndNestedAddress obj = new ObjectWith3AliasedFieldsAndNestedAddress();
obj.id = "4711";
obj.property1 = "P1";
obj.property2 = "P2";
obj.property3 = "P3";
Address address = new Address();
String stateValue = "WA";
address.state = stateValue;
address.city = "Washington";
obj.address = address;
template.insert(obj);
Query query = new Query(Criteria.where("id").is(obj.id));
query.fields() //
.include("property2") // real property name
.include("address.state"); // aliased property name
ObjectWith3AliasedFieldsAndNestedAddress result = template.findOne(query,
ObjectWith3AliasedFieldsAndNestedAddress.class);
assertThat(result.id, is(obj.id));
assertThat(result.property1, is(nullValue()));
assertThat(result.property2, is(obj.property2));
assertThat(result.property3, is(nullValue()));
assertThat(result.address, is(notNullValue()));
assertThat(result.address.city, is(nullValue()));
assertThat(result.address.state, is(stateValue));
}
/**
* @see DATAMONGO-709
*/
@Test
public void aQueryRestrictedWithOneRestrictedResultTypeShouldReturnOnlyInstancesOfTheRestrictedType() {
BaseDoc doc0 = new BaseDoc();
doc0.value = "foo";
SpecialDoc doc1 = new SpecialDoc();
doc1.value = "foo";
doc1.specialValue = "specialfoo";
VerySpecialDoc doc2 = new VerySpecialDoc();
doc2.value = "foo";
doc2.specialValue = "specialfoo";
doc2.verySpecialValue = 4711;
String collectionName = template.getCollectionName(BaseDoc.class);
template.insert(doc0, collectionName);
template.insert(doc1, collectionName);
template.insert(doc2, collectionName);
Query query = Query.query(where("value").is("foo")).restrict(SpecialDoc.class);
List<BaseDoc> result = template.find(query, BaseDoc.class);
assertThat(result, is(notNullValue()));
assertThat(result.size(), is(1));
assertThat(result.get(0), is(instanceOf(SpecialDoc.class)));
}
/**
* @see DATAMONGO-709
*/
@Test
public void aQueryRestrictedWithMultipleRestrictedResultTypesShouldReturnOnlyInstancesOfTheRestrictedTypes() {
BaseDoc doc0 = new BaseDoc();
doc0.value = "foo";
SpecialDoc doc1 = new SpecialDoc();
doc1.value = "foo";
doc1.specialValue = "specialfoo";
VerySpecialDoc doc2 = new VerySpecialDoc();
doc2.value = "foo";
doc2.specialValue = "specialfoo";
doc2.verySpecialValue = 4711;
String collectionName = template.getCollectionName(BaseDoc.class);
template.insert(doc0, collectionName);
template.insert(doc1, collectionName);
template.insert(doc2, collectionName);
Query query = Query.query(where("value").is("foo")).restrict(BaseDoc.class, VerySpecialDoc.class);
List<BaseDoc> result = template.find(query, BaseDoc.class);
assertThat(result, is(notNullValue()));
assertThat(result.size(), is(2));
assertThat(result.get(0).getClass(), is((Object) BaseDoc.class));
assertThat(result.get(1).getClass(), is((Object) VerySpecialDoc.class));
}
/**
* @see DATAMONGO-709
*/
@Test
public void aQueryWithNoRestrictedResultTypesShouldReturnAllInstancesWithinTheGivenCollection() {
BaseDoc doc0 = new BaseDoc();
doc0.value = "foo";
SpecialDoc doc1 = new SpecialDoc();
doc1.value = "foo";
doc1.specialValue = "specialfoo";
VerySpecialDoc doc2 = new VerySpecialDoc();
doc2.value = "foo";
doc2.specialValue = "specialfoo";
doc2.verySpecialValue = 4711;
String collectionName = template.getCollectionName(BaseDoc.class);
template.insert(doc0, collectionName);
template.insert(doc1, collectionName);
template.insert(doc2, collectionName);
Query query = Query.query(where("value").is("foo"));
List<BaseDoc> result = template.find(query, BaseDoc.class);
assertThat(result, is(notNullValue()));
assertThat(result.size(), is(3));
assertThat(result.get(0).getClass(), is((Object) BaseDoc.class));
assertThat(result.get(1).getClass(), is((Object) SpecialDoc.class));
assertThat(result.get(2).getClass(), is((Object) VerySpecialDoc.class));
}
/**
* @see DATAMONGO-771
*/
@Test
public void allowInsertWithPlainJsonString() {
String id = "4711";
String value = "bubu";
String json = String.format("{_id:%s, field: '%s'}", id, value);
template.insert(json, "sample");
List<Sample> result = template.findAll(Sample.class);
assertThat(result.size(), is(1));
assertThat(result.get(0).id, is(id));
assertThat(result.get(0).field, is(value));
}
/**
* @see DATAMONGO-816
*/
@Test
public void shouldExecuteQueryShouldMapQueryBeforeQueryExecution() {
ObjectWithEnumValue o = new ObjectWithEnumValue();
o.value = EnumValue.VALUE2;
template.save(o);
Query q = Query.query(Criteria.where("value").in(EnumValue.VALUE2));
template.executeQuery(q, StringUtils.uncapitalize(ObjectWithEnumValue.class.getSimpleName()),
new DocumentCallbackHandler() {
@Override
public void processDocument(DBObject dbObject) throws MongoException, DataAccessException {
assertThat(dbObject, is(notNullValue()));
ObjectWithEnumValue result = template.getConverter().read(ObjectWithEnumValue.class, dbObject);
assertThat(result.value, is(EnumValue.VALUE2));
}
});
}
/**
* @see DATAMONGO-811
*/
@Test
public void updateFirstShouldIncreaseVersionForVersionedEntity() {
VersionedPerson person = new VersionedPerson();
person.firstname = "Dave";
person.lastname = "Matthews";
template.save(person);
assertThat(person.id, is(notNullValue()));
Query qry = query(where("id").is(person.id));
VersionedPerson personAfterFirstSave = template.findOne(qry, VersionedPerson.class);
assertThat(personAfterFirstSave.version, is(0L));
template.updateFirst(qry, Update.update("lastname", "Bubu"), VersionedPerson.class);
VersionedPerson personAfterUpdateFirst = template.findOne(qry, VersionedPerson.class);
assertThat(personAfterUpdateFirst.version, is(1L));
assertThat(personAfterUpdateFirst.lastname, is("Bubu"));
}
/**
* @see DATAMONGO-811
*/
@Test
public void updateFirstShouldIncreaseVersionOnlyForFirstMatchingEntity() {
VersionedPerson person1 = new VersionedPerson();
person1.firstname = "Dave";
VersionedPerson person2 = new VersionedPerson();
person2.firstname = "Dave";
template.save(person1);
template.save(person2);
Query q = query(where("id").in(person1.id, person2.id));
template.updateFirst(q, Update.update("lastname", "Metthews"), VersionedPerson.class);
for (VersionedPerson p : template.find(q, VersionedPerson.class)) {
if ("Metthews".equals(p.lastname)) {
assertThat(p.version, equalTo(Long.valueOf(1)));
} else {
assertThat(p.version, equalTo(Long.valueOf(0)));
}
}
}
/**
* @see DATAMONGO-811
*/
@Test
public void updateMultiShouldIncreaseVersionOfAllUpdatedEntities() {
VersionedPerson person1 = new VersionedPerson();
person1.firstname = "Dave";
VersionedPerson person2 = new VersionedPerson();
person2.firstname = "Dave";
template.save(person1);
template.save(person2);
Query q = query(where("id").in(person1.id, person2.id));
template.updateMulti(q, Update.update("lastname", "Metthews"), VersionedPerson.class);
for (VersionedPerson p : template.find(q, VersionedPerson.class)) {
assertThat(p.version, equalTo(Long.valueOf(1)));
}
}
/**
* @see DATAMONGO-686
*/
@Test
public void itShouldBePossibleToReuseAnExistingQuery() {
Sample sample = new Sample();
sample.id = "42";
sample.field = "A";
template.save(sample);
Query query = new Query();
query.addCriteria(where("_id").in("42", "43"));
assertThat(template.count(query, Sample.class), is(1L));
query.with(new PageRequest(0, 10));
query.with(new Sort("field"));
assertThat(template.find(query, Sample.class), is(not(empty())));
}
/**
* @see DATAMONGO-807
*/
@Test
public void findAndModifyShouldRetrainTypeInformationWithinUpdatedType() {
Document document = new Document();
document.model = new ModelA("value1");
template.save(document);
Query query = query(where("id").is(document.id));
Update update = Update.update("model", new ModelA("value2"));
template.findAndModify(query, update, Document.class);
Document retrieved = template.findOne(query, Document.class);
assertThat(retrieved.model, instanceOf(ModelA.class));
assertThat(retrieved.model.value(), equalTo("value2"));
}
/**
* @see DATAMONGO-407
*/
@Test
public void updatesShouldRetainTypeInformationEvenForCollections() {
List<Model> models = Arrays.<Model> asList(new ModelA("foo"));
DocumentWithCollection doc = new DocumentWithCollection(models);
doc.id = "4711";
template.insert(doc);
Query query = new Query(Criteria.where("id").is(doc.id));
query.addCriteria(where("models.value").is("foo"));
String newModelValue = "bar";
Update update = Update.update("models.$", new ModelA(newModelValue));
template.updateFirst(query, update, DocumentWithCollection.class);
Query findQuery = new Query(Criteria.where("id").is(doc.id));
DocumentWithCollection result = template.findOne(findQuery, DocumentWithCollection.class);
assertThat(result, is(notNullValue()));
assertThat(result.id, is(doc.id));
assertThat(result.models, is(notNullValue()));
assertThat(result.models, hasSize(1));
assertThat(result.models.get(0).value(), is(newModelValue));
}
/**
* @see DATAMONGO-812
*/
@Test
public void updateMultiShouldAddValuesCorrectlyWhenUsingPushEachWithComplexTypes() {
assumeThat(mongoVersion.isGreaterThanOrEqualTo(TWO_DOT_FOUR), is(true));
DocumentWithCollection document = new DocumentWithCollection(Collections.<Model> emptyList());
template.save(document);
Query query = query(where("id").is(document.id));
assumeThat(template.findOne(query, DocumentWithCollection.class).models, hasSize(1));
Update update = new Update().push("models").each(new ModelA("model-b"), new ModelA("model-c"));
template.updateMulti(query, update, DocumentWithCollection.class);
assertThat(template.findOne(query, DocumentWithCollection.class).models, hasSize(3));
}
/**
* @see DATAMONGO-812
*/
@Test
public void updateMultiShouldAddValuesCorrectlyWhenUsingPushEachWithSimpleTypes() {
assumeThat(mongoVersion.isGreaterThanOrEqualTo(TWO_DOT_FOUR), is(true));
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));
}
/**
* @see DATAMONOGO-828
*/
@Test
public void updateFirstShouldDoNothingWhenCalledForEntitiesThatDoNotExist() {
Query q = query(where("id").is(Long.MIN_VALUE));
template.updateFirst(q, Update.update("lastname", "supercalifragilisticexpialidocious"), VersionedPerson.class);
assertThat(template.findOne(q, VersionedPerson.class), nullValue());
}
/**
* @see DATAMONGO-354
*/
@Test
public void testUpdateShouldAllowMultiplePushAll() {
DocumentWithMultipleCollections doc = new DocumentWithMultipleCollections();
doc.id = "1234";
doc.string1 = Arrays.asList("spring");
doc.string2 = Arrays.asList("one");
template.save(doc);
Update update = new Update().pushAll("string1", new Object[] { "data", "mongodb" });
update.pushAll("string2", new String[] { "two", "three" });
Query findQuery = new Query(Criteria.where("id").is(doc.id));
template.updateFirst(findQuery, update, DocumentWithMultipleCollections.class);
DocumentWithMultipleCollections result = template.findOne(findQuery, DocumentWithMultipleCollections.class);
assertThat(result.string1, hasItems("spring", "data", "mongodb"));
assertThat(result.string2, hasItems("one", "two", "three"));
}
/**
* @see DATAMONGO-404
*/
@Test
public void updateWithPullShouldRemoveNestedItemFromDbRefAnnotatedCollection() {
Sample sample1 = new Sample("1", "A");
Sample sample2 = new Sample("2", "B");
template.save(sample1);
template.save(sample2);
DocumentWithDBRefCollection doc = new DocumentWithDBRefCollection();
doc.id = "1";
doc.dbRefAnnotatedList = Arrays.asList( //
sample1, //
sample2 //
);
template.save(doc);
Update update = new Update().pull("dbRefAnnotatedList", doc.dbRefAnnotatedList.get(1));
Query qry = query(where("id").is("1"));
template.updateFirst(qry, update, DocumentWithDBRefCollection.class);
DocumentWithDBRefCollection result = template.findOne(qry, DocumentWithDBRefCollection.class);
assertThat(result, is(notNullValue()));
assertThat(result.dbRefAnnotatedList, hasSize(1));
assertThat(result.dbRefAnnotatedList.get(0), is(notNullValue()));
assertThat(result.dbRefAnnotatedList.get(0).id, is((Object) "1"));
}
/**
* @see DATAMONGO-404
*/
@Test
public void updateWithPullShouldRemoveNestedItemFromDbRefAnnotatedCollectionWhenGivenAnIdValueOfComponentTypeEntity() {
Sample sample1 = new Sample("1", "A");
Sample sample2 = new Sample("2", "B");
template.save(sample1);
template.save(sample2);
DocumentWithDBRefCollection doc = new DocumentWithDBRefCollection();
doc.id = "1";
doc.dbRefAnnotatedList = Arrays.asList( //
sample1, //
sample2 //
);
template.save(doc);
Update update = new Update().pull("dbRefAnnotatedList.id", "2");
Query qry = query(where("id").is("1"));
template.updateFirst(qry, update, DocumentWithDBRefCollection.class);
DocumentWithDBRefCollection result = template.findOne(qry, DocumentWithDBRefCollection.class);
assertThat(result, is(notNullValue()));
assertThat(result.dbRefAnnotatedList, hasSize(1));
assertThat(result.dbRefAnnotatedList.get(0), is(notNullValue()));
assertThat(result.dbRefAnnotatedList.get(0).id, is((Object) "1"));
}
/**
* @see DATAMONGO-852
*/
@Test
public void updateShouldNotBumpVersionNumberIfVersionPropertyIncludedInUpdate() {
VersionedPerson person = new VersionedPerson();
person.firstname = "Dave";
person.lastname = "Matthews";
template.save(person);
assertThat(person.id, is(notNullValue()));
Query qry = query(where("id").is(person.id));
VersionedPerson personAfterFirstSave = template.findOne(qry, VersionedPerson.class);
assertThat(personAfterFirstSave.version, is(0L));
template.updateFirst(qry, Update.update("lastname", "Bubu").set("version", 100L), VersionedPerson.class);
VersionedPerson personAfterUpdateFirst = template.findOne(qry, VersionedPerson.class);
assertThat(personAfterUpdateFirst.version, is(100L));
assertThat(personAfterUpdateFirst.lastname, is("Bubu"));
}
/**
* @see DATAMONGO-468
*/
@Test
public void shouldBeAbleToUpdateDbRefPropertyWithDomainObject() {
Sample sample1 = new Sample("1", "A");
Sample sample2 = new Sample("2", "B");
template.save(sample1);
template.save(sample2);
DocumentWithDBRefCollection doc = new DocumentWithDBRefCollection();
doc.id = "1";
doc.dbRefProperty = sample1;
template.save(doc);
Update update = new Update().set("dbRefProperty", sample2);
Query qry = query(where("id").is("1"));
template.updateFirst(qry, update, DocumentWithDBRefCollection.class);
DocumentWithDBRefCollection updatedDoc = template.findOne(qry, DocumentWithDBRefCollection.class);
assertThat(updatedDoc, is(notNullValue()));
assertThat(updatedDoc.dbRefProperty, is(notNullValue()));
assertThat(updatedDoc.dbRefProperty.id, is(sample2.id));
assertThat(updatedDoc.dbRefProperty.field, is(sample2.field));
}
/**
* @see DATAMONGO-862
*/
@Test
public void testUpdateShouldWorkForPathsOnInterfaceMethods() {
DocumentWithCollection document = new DocumentWithCollection(Arrays.<Model> asList(new ModelA("spring"),
new ModelA("data")));
template.save(document);
Query query = query(where("id").is(document.id).and("models._id").exists(true));
Update update = new Update().set("models.$.value", "mongodb");
template.findAndModify(query, update, DocumentWithCollection.class);
DocumentWithCollection result = template.findOne(query(where("id").is(document.id)), DocumentWithCollection.class);
assertThat(result.models.get(0).value(), is("mongodb"));
}
/**
* @see DATAMONGO-773
*/
@Test
public void testShouldSupportQueryWithIncludedDbRefField() {
Sample sample = new Sample("47111", "foo");
template.save(sample);
DocumentWithDBRefCollection doc = new DocumentWithDBRefCollection();
doc.id = "4711";
doc.dbRefProperty = sample;
template.save(doc);
Query qry = query(where("id").is(doc.id));
qry.fields().include("dbRefProperty");
List<DocumentWithDBRefCollection> result = template.find(qry, DocumentWithDBRefCollection.class);
assertThat(result, is(notNullValue()));
assertThat(result, hasSize(1));
assertThat(result.get(0), is(notNullValue()));
assertThat(result.get(0).dbRefProperty, is(notNullValue()));
assertThat(result.get(0).dbRefProperty.field, is(sample.field));
}
/**
* @see DATAMONGO-566
*/
@Test
public void testFindAllAndRemoveFullyReturnsAndRemovesDocuments() {
Sample spring = new Sample("100", "spring");
Sample data = new Sample("200", "data");
Sample mongodb = new Sample("300", "mongodb");
template.insert(Arrays.asList(spring, data, mongodb), Sample.class);
Query qry = query(where("field").in("spring", "mongodb"));
List<Sample> result = template.findAllAndRemove(qry, Sample.class);
assertThat(result, hasSize(2));
assertThat(
template.getDb().getCollection("sample")
.find(new BasicDBObject("field", new BasicDBObject("$in", Arrays.asList("spring", "mongodb")))).count(),
is(0));
assertThat(template.getDb().getCollection("sample").find(new BasicDBObject("field", "data")).count(), is(1));
}
/**
* @see DATAMONGO-1001
*/
@Test
public void shouldAllowSavingOfLazyLoadedDbRefs() {
template.dropCollection(SomeTemplate.class);
template.dropCollection(SomeMessage.class);
template.dropCollection(SomeContent.class);
SomeContent content = new SomeContent();
content.id = "content-1";
content.text = "spring";
template.save(content);
SomeTemplate tmpl = new SomeTemplate();
tmpl.id = "template-1";
tmpl.content = content; // @DBRef(lazy=true) tmpl.content
template.save(tmpl);
SomeTemplate savedTmpl = template.findById(tmpl.id, SomeTemplate.class);
SomeContent loadedContent = savedTmpl.getContent();
loadedContent.setText("data");
template.save(loadedContent);
assertThat(template.findById(content.id, SomeContent.class).getText(), is("data"));
}
/**
* @see DATAMONGO-880
*/
@Test
public void savingAndReassigningLazyLoadingProxies() {
template.dropCollection(SomeTemplate.class);
template.dropCollection(SomeMessage.class);
template.dropCollection(SomeContent.class);
SomeContent content = new SomeContent();
content.id = "C1";
content.text = "BUBU";
template.save(content);
SomeTemplate tmpl = new SomeTemplate();
tmpl.id = "T1";
tmpl.content = content; // @DBRef(lazy=true) tmpl.content
template.save(tmpl);
SomeTemplate savedTmpl = template.findById(tmpl.id, SomeTemplate.class);
SomeMessage message = new SomeMessage();
message.id = "M1";
message.dbrefContent = savedTmpl.content; // @DBRef message.dbrefContent
message.normalContent = savedTmpl.content;
template.save(message);
SomeMessage savedMessage = template.findById(message.id, SomeMessage.class);
assertThat(savedMessage.dbrefContent.text, is(content.text));
assertThat(savedMessage.normalContent.text, is(content.text));
}
/**
* @see DATAMONGO-884
*/
@Test
public void callingNonObjectMethodsOnLazyLoadingProxyShouldReturnNullIfUnderlyingDbrefWasDeletedInbetween() {
template.dropCollection(SomeTemplate.class);
template.dropCollection(SomeContent.class);
SomeContent content = new SomeContent();
content.id = "C1";
content.text = "BUBU";
template.save(content);
SomeTemplate tmpl = new SomeTemplate();
tmpl.id = "T1";
tmpl.content = content; // @DBRef(lazy=true) tmpl.content
template.save(tmpl);
SomeTemplate savedTmpl = template.findById(tmpl.id, SomeTemplate.class);
template.remove(content);
assertThat(savedTmpl.getContent().toString(), is("someContent:C1$LazyLoadingProxy"));
assertThat(savedTmpl.getContent(), is(instanceOf(LazyLoadingProxy.class)));
assertThat(savedTmpl.getContent().getText(), is(nullValue()));
}
/**
* @see DATAMONGO-471
*/
@Test
public void updateMultiShouldAddValuesCorrectlyWhenUsingAddToSetWithEach() {
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().addToSet("values").each("data", "mongodb");
template.updateMulti(query, update, DocumentWithCollectionOfSimpleType.class);
assertThat(template.findOne(query, DocumentWithCollectionOfSimpleType.class).values, hasSize(3));
}
/**
* @see DATAMONGO-888
*/
@Test
public void sortOnIdFieldPropertyShouldBeMappedCorrectly() {
DoucmentWithNamedIdField one = new DoucmentWithNamedIdField();
one.someIdKey = "1";
one.value = "a";
DoucmentWithNamedIdField two = new DoucmentWithNamedIdField();
two.someIdKey = "2";
two.value = "b";
template.save(one);
template.save(two);
Query query = query(where("_id").in("1", "2")).with(new Sort(Direction.DESC, "someIdKey"));
assertThat(template.find(query, DoucmentWithNamedIdField.class), contains(two, one));
}
/**
* @see DATAMONGO-888
*/
@Test
public void sortOnAnnotatedFieldPropertyShouldBeMappedCorrectly() {
DoucmentWithNamedIdField one = new DoucmentWithNamedIdField();
one.someIdKey = "1";
one.value = "a";
DoucmentWithNamedIdField two = new DoucmentWithNamedIdField();
two.someIdKey = "2";
two.value = "b";
template.save(one);
template.save(two);
Query query = query(where("_id").in("1", "2")).with(new Sort(Direction.DESC, "value"));
assertThat(template.find(query, DoucmentWithNamedIdField.class), contains(two, one));
}
/**
* @see DATAMONGO-913
*/
@Test
public void shouldRetrieveInitializedValueFromDbRefAssociationAfterLoad() {
SomeContent content = new SomeContent();
content.id = "content-1";
content.name = "Content 1";
content.text = "Some text";
template.save(content);
SomeTemplate tmpl = new SomeTemplate();
tmpl.id = "template-1";
tmpl.content = content;
template.save(tmpl);
SomeTemplate result = template.findOne(query(where("content").is(tmpl.getContent())), SomeTemplate.class);
assertThat(result, is(notNullValue()));
assertThat(result.getContent(), is(notNullValue()));
assertThat(result.getContent().getId(), is(notNullValue()));
assertThat(result.getContent().getName(), is(notNullValue()));
assertThat(result.getContent().getText(), is(content.getText()));
}
/**
* @see DATAMONGO-913
*/
@Test
public void shouldReuseExistingDBRefInQueryFromDbRefAssociationAfterLoad() {
SomeContent content = new SomeContent();
content.id = "content-1";
content.name = "Content 1";
content.text = "Some text";
template.save(content);
SomeTemplate tmpl = new SomeTemplate();
tmpl.id = "template-1";
tmpl.content = content;
template.save(tmpl);
SomeTemplate result = template.findOne(query(where("content").is(tmpl.getContent())), SomeTemplate.class);
// Use lazy-loading-proxy in query
result = template.findOne(query(where("content").is(result.getContent())), SomeTemplate.class);
assertNotNull(result.getContent().getName());
assertThat(result.getContent().getName(), is(content.getName()));
}
/**
* @see DATAMONGO-970
*/
@Test
public void insertsAndRemovesBasicDbObjectCorrectly() {
BasicDBObject object = new BasicDBObject("key", "value");
template.insert(object, "collection");
assertThat(object.get("_id"), is(notNullValue()));
assertThat(template.findAll(DBObject.class, "collection"), hasSize(1));
template.remove(object, "collection");
assertThat(template.findAll(DBObject.class, "collection"), hasSize(0));
}
static class DoucmentWithNamedIdField {
@Id String someIdKey;
@Field(value = "val")//
String value;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (someIdKey == null ? 0 : someIdKey.hashCode());
result = prime * result + (value == null ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof DoucmentWithNamedIdField)) {
return false;
}
DoucmentWithNamedIdField other = (DoucmentWithNamedIdField) obj;
if (someIdKey == null) {
if (other.someIdKey != null) {
return false;
}
} else if (!someIdKey.equals(other.someIdKey)) {
return false;
}
if (value == null) {
if (other.value != null) {
return false;
}
} else if (!value.equals(other.value)) {
return false;
}
return true;
}
}
static class DocumentWithDBRefCollection {
@Id public String id;
@Field("db_ref_list")/** @see DATAMONGO-1058 */
@org.springframework.data.mongodb.core.mapping.DBRef//
public List<Sample> dbRefAnnotatedList;
@org.springframework.data.mongodb.core.mapping.DBRef//
public Sample dbRefProperty;
}
static class DocumentWithCollection {
@Id String id;
List<Model> models;
DocumentWithCollection(List<Model> models) {
this.models = models;
}
}
static class DocumentWithCollectionOfSimpleType {
@Id String id;
List<String> values;
}
static class DocumentWithMultipleCollections {
@Id String id;
List<String> string1;
List<String> string2;
}
static interface Model {
String value();
String id();
}
static class ModelA implements Model {
@Id String id;
private String value;
ModelA(String value) {
this.value = value;
}
@Override
public String value() {
return this.value;
}
@Override
public String id() {
return id;
}
}
static class Document {
@Id public String id;
public Model model;
}
static class MyId {
String first;
String second;
}
static class TypeWithMyId {
@Id MyId id;
}
static class Sample {
@Id String id;
String field;
public Sample() {}
public Sample(String id, String field) {
this.id = id;
this.field = field;
}
}
static class TestClass {
DateTime myDate;
@PersistenceConstructor
TestClass(DateTime myDate) {
this.myDate = myDate;
}
}
static class PersonWithConvertedId {
String id;
String name;
}
static enum DateTimeToDateConverter implements Converter<DateTime, Date> {
INSTANCE;
public Date convert(DateTime source) {
return source == null ? null : source.toDate();
}
}
static enum DateToDateTimeConverter implements Converter<Date, DateTime> {
INSTANCE;
public DateTime convert(Date source) {
return source == null ? null : new DateTime(source.getTime());
}
}
public static class MyPerson {
String id;
String name;
Address address;
public String getName() {
return name;
}
}
static class Address {
String state;
String city;
}
static class VersionedPerson {
@Version Long version;
String id, firstname, lastname;
}
static class TypeWithFieldAnnotation {
@Id ObjectId id;
@Field("email") String emailAddress;
}
static class TypeWithDate {
@Id String id;
Date date;
}
static class ObjectWith3AliasedFields {
@Id String id;
@Field("prop1") String property1;
@Field("prop2") String property2;
@Field("prop3") String property3;
}
static class ObjectWith3AliasedFieldsAndNestedAddress extends ObjectWith3AliasedFields {
@Field("adr") Address address;
}
static enum EnumValue {
VALUE1, VALUE2, VALUE3
}
static class ObjectWithEnumValue {
@Id String id;
EnumValue value;
}
public static class SomeTemplate {
String id;
@org.springframework.data.mongodb.core.mapping.DBRef(lazy = true) SomeContent content;
public SomeContent getContent() {
return content;
}
}
public static class SomeContent {
String id;
String text;
String name;
public String getName() {
return name;
}
public void setText(String text) {
this.text = text;
}
public String getId() {
return id;
}
public String getText() {
return text;
}
}
static class SomeMessage {
String id;
@org.springframework.data.mongodb.core.mapping.DBRef SomeContent dbrefContent;
SomeContent normalContent;
}
}