/*
* Copyright 2011-2017 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.mapping;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
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.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.bson.types.ObjectId;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.MongoCollectionUtils;
import org.springframework.data.mongodb.config.AbstractIntegrationTests;
import org.springframework.data.mongodb.core.CollectionCallback;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.bson.Document;
import com.mongodb.MongoException;
import com.mongodb.client.MongoCollection;
/**
* @author Jon Brisbin
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
*/
public class MappingTests extends AbstractIntegrationTests {
@Autowired MongoOperations template;
@Test
public void testGeneratedId() {
GeneratedId genId = new GeneratedId("test");
template.insert(genId);
assertNotNull(genId.getId());
}
@Test
public void testPersonPojo() throws Exception {
PersonWithObjectId p = new PersonWithObjectId(12345, "Person", "Pojo");
template.insert(p);
assertNotNull(p.getId());
List<PersonWithObjectId> result = template.find(new Query(Criteria.where("ssn").is(12345)),
PersonWithObjectId.class);
assertThat(result.size(), is(1));
assertThat(result.get(0).getSsn(), is(12345));
}
@Test
public void testPersonWithCustomIdName() {
PersonCustomIdName p = new PersonCustomIdName(123456, "Custom Id", null);
template.insert(p);
List<PersonCustomIdName> result = template.find(new Query(Criteria.where("lastName").is(p.getLastName())),
PersonCustomIdName.class);
assertThat(result.size(), is(1));
assertThat(result.get(0).getFirstName(), is("Custom Id"));
PersonCustomIdName p2 = new PersonCustomIdName(654321, "Custom Id", "LastName");
template.insert(p2);
List<PersonCustomIdName> result2 = template.find(new Query(Criteria.where("lastName").is("LastName")),
PersonCustomIdName.class);
assertThat(result2.size(), is(1));
assertNotNull(result2.get(0).getLastName());
assertThat(result2.get(0).getLastName(), is("LastName"));
// Test "in" query
List<PersonCustomIdName> result3 = template.find(new Query(Criteria.where("lastName").in("LastName")),
PersonCustomIdName.class);
assertThat(result3.size(), is(1));
assertNotNull(result3.get(0).getLastName());
assertThat(result3.get(0).getLastName(), is("LastName"));
}
@Test
public void testPersonMapProperty() {
PersonMapProperty p = new PersonMapProperty(1234567, "Map", "PropertyPath");
Map<String, AccountPojo> accounts = new HashMap<String, AccountPojo>();
AccountPojo checking = new AccountPojo("checking", 1000.0f);
AccountPojo savings = new AccountPojo("savings", 10000.0f);
accounts.put("checking", checking);
accounts.put("savings", savings);
p.setAccounts(accounts);
template.insert(p);
assertNotNull(p.getId());
List<PersonMapProperty> result = template.find(new Query(Criteria.where("ssn").is(1234567)),
PersonMapProperty.class);
assertThat(result.size(), is(1));
assertThat(result.get(0).getAccounts().size(), is(2));
assertThat(result.get(0).getAccounts().get("checking").getBalance(), is(1000.0f));
}
@Test
@SuppressWarnings({ "unchecked", "rawtypes" })
public void testWriteEntity() {
Address addr = new Address();
addr.setLines(new String[] { "1234 W. 1st Street", "Apt. 12" });
addr.setCity("Anytown");
addr.setPostalCode(12345);
addr.setCountry("USA");
Account acct = new Account();
acct.setBalance(1000.00f);
template.insert(acct, "account");
List<Account> accounts = new ArrayList<Account>();
accounts.add(acct);
Person p = new Person(123456789, "John", "Doe", 37, addr);
p.setAccounts(accounts);
template.insert(p, "person");
Account newAcct = new Account();
newAcct.setBalance(10000.00f);
template.insert(newAcct, "account");
accounts.add(newAcct);
template.save(p, "person");
assertNotNull(p.getId());
List<Person> result = template.find(new Query(Criteria.where("ssn").is(123456789)), Person.class);
assertThat(result.size(), is(1));
assertThat(result.get(0).getAddress().getCountry(), is("USA"));
assertThat(result.get(0).getAccounts(), notNullValue());
}
@Test(expected = DuplicateKeyException.class)
@SuppressWarnings({ "unchecked", "rawtypes" })
public void testUniqueIndex() {
Address addr = new Address();
addr.setLines(new String[] { "1234 W. 1st Street", "Apt. 12" });
addr.setCity("Anytown");
addr.setPostalCode(12345);
addr.setCountry("USA");
Person p1 = new Person(1234567890, "John", "Doe", 37, addr);
Person p2 = new Person(1234567890, "Jane", "Doe", 38, addr);
template.insertAll(Arrays.asList(p1, p2));
}
@Test
public void testCustomCollectionInList() {
List<BasePerson> persons = new ArrayList<BasePerson>();
persons.add(new PersonCustomCollection1(55555, "Person", "One"));
persons.add(new PersonCustomCollection2(66666, "Person", "Two"));
template.insertAll(persons);
List<PersonCustomCollection1> p1Results = template.find(new Query(Criteria.where("ssn").is(55555)),
PersonCustomCollection1.class, "person1");
List<PersonCustomCollection2> p2Results = template.find(new Query(Criteria.where("ssn").is(66666)),
PersonCustomCollection2.class, "person2");
assertThat(p1Results.size(), is(1));
assertThat(p2Results.size(), is(1));
}
@Test
public void testPrimitivesAndCustomCollectionName() {
Location loc = new Location(new double[] { 1.0, 2.0 }, new int[] { 1, 2, 3, 4 }, new float[] { 1.0f, 2.0f });
template.insert(loc);
List<Location> result = template.find(new Query(Criteria.where("_id").is(loc.getId())), Location.class, "places");
assertThat(result.size(), is(1));
}
@Test
public void testIndexesCreatedInRightCollection() {
CustomCollectionWithIndex ccwi = new CustomCollectionWithIndex("test");
template.insert(ccwi);
assertTrue(template.execute("foobar", new CollectionCallback<Boolean>() {
public Boolean doInCollection(MongoCollection<Document> collection) throws MongoException, DataAccessException {
List<Document> indexes = new ArrayList<Document>();
collection.listIndexes(Document.class).into(indexes);
for (Document document : indexes) {
if (document.get("name") != null && document.get("name") instanceof String
&& ((String) document.get("name")).startsWith("name")) {
return true;
}
}
return false;
}
}));
DetectedCollectionWithIndex dcwi = new DetectedCollectionWithIndex("test");
template.insert(dcwi);
assertTrue(template.execute(MongoCollectionUtils.getPreferredCollectionName(DetectedCollectionWithIndex.class),
new CollectionCallback<Boolean>() {
public Boolean doInCollection(MongoCollection<Document> collection)
throws MongoException, DataAccessException {
List<Document> indexes = new ArrayList<Document>();
collection.listIndexes(Document.class).into(indexes);
for (Document document : indexes) {
if (document.get("name") != null && document.get("name") instanceof String
&& ((String) document.get("name")).startsWith("name")) {
return true;
}
}
return false;
}
}));
}
@Test
public void testMultiDimensionalArrayProperties() {
String[][] grid = new String[][] { new String[] { "1", "2", "3", "4" }, new String[] { "5", "6", "7", "8" },
new String[] { "9", "10", "11", "12" } };
PersonMultiDimArrays p = new PersonMultiDimArrays(123, "Multi", "Dimensional", grid);
template.insert(p);
List<PersonMultiDimArrays> result = template.find(new Query(Criteria.where("ssn").is(123)),
PersonMultiDimArrays.class);
assertThat(result.size(), is(1));
assertThat(result.get(0).getGrid().length, is(3));
}
@Test
public void testMultiDimensionalCollectionProperties() {
List<List<String>> grid = new ArrayList<List<String>>();
ArrayList<String> inner = new ArrayList<String>();
inner.add("1");
inner.add("2");
inner.add("3");
inner.add("4");
grid.add(inner);
PersonMultiCollection p = new PersonMultiCollection(321, "Multi Dim", "Collections", grid);
template.insert(p);
List<PersonMultiCollection> result = template.find(new Query(Criteria.where("ssn").is(321)),
PersonMultiCollection.class);
assertThat(result.size(), is(1));
assertThat(result.get(0).getGrid().size(), is(1));
}
@Test
public void testDbRef() {
double[] pos = new double[] { 37.0625, -95.677068 };
GeoLocation geo = new GeoLocation(pos);
template.insert(geo);
PersonWithDbRef p = new PersonWithDbRef(4321, "With", "DBRef", geo);
template.insert(p);
List<PersonWithDbRef> result = template.find(new Query(Criteria.where("ssn").is(4321)), PersonWithDbRef.class);
assertThat(result.size(), is(1));
assertThat(result.get(0).getHome().getLocation(), is(pos));
}
@Test
public void testPersonWithNullProperties() {
PersonNullProperties p = new PersonNullProperties();
template.insert(p);
assertNotNull(p.getId());
}
@Test
@SuppressWarnings({ "rawtypes", "unchecked" })
public void testQueryUpdate() {
Address addr = new Address();
addr.setLines(new String[] { "1234 W. 1st Street", "Apt. 12" });
addr.setCity("Anytown");
addr.setPostalCode(12345);
addr.setCountry("USA");
Person p = new Person(1111, "Query", "Update", 37, addr);
template.insert(p);
addr.setCity("New Town");
template.updateFirst(query(where("ssn").is(1111)), update("address", addr), Person.class);
Person p2 = template.findOne(query(where("ssn").is(1111)), Person.class);
assertThat(p2.getAddress().getCity(), is("New Town"));
}
@Test
@SuppressWarnings("rawtypes")
public void testUpsert() {
Address addr = new Address();
addr.setLines(new String[] { "1234 W. 1st Street", "Apt. 12" });
addr.setCity("Anytown");
addr.setPostalCode(12345);
addr.setCountry("USA");
Person p2 = template.findOne(query(where("ssn").is(1111)), Person.class);
assertNull(p2);
template.upsert(query(where("ssn").is(1111).and("firstName").is("Query").and("lastName").is("Update")),
update("address", addr), Person.class);
p2 = template.findOne(query(where("ssn").is(1111)), Person.class);
assertThat(p2.getAddress().getCity(), is("Anytown"));
template.dropCollection(Person.class);
template.upsert(query(where("ssn").is(1111).and("firstName").is("Query").and("lastName").is("Update")),
update("address", addr), "person");
p2 = template.findOne(query(where("ssn").is(1111)), Person.class);
assertThat(p2.getAddress().getCity(), is("Anytown"));
}
@Test
public void testOrQuery() {
PersonWithObjectId p1 = new PersonWithObjectId(1, "first", "");
template.save(p1);
PersonWithObjectId p2 = new PersonWithObjectId(2, "second", "");
template.save(p2);
List<PersonWithObjectId> results = template
.find(new Query(new Criteria().orOperator(where("ssn").is(1), where("ssn").is(2))), PersonWithObjectId.class);
assertNotNull(results);
assertThat(results.size(), is(2));
assertThat(results.get(1).getSsn(), is(2));
}
@Test
public void testPrimitivesAsIds() {
PrimitiveId p = new PrimitiveId(1);
p.setText("test text");
template.save(p);
PrimitiveId p2 = template.findOne(query(where("id").is(1)), PrimitiveId.class);
assertNotNull(p2);
}
@Test
public void testNoMappingAnnotationsUsingIntAsId() {
PersonPojoIntId p = new PersonPojoIntId(1, "Text");
template.insert(p);
template.updateFirst(query(where("id").is(1)), update("text", "New Text"), PersonPojoIntId.class);
PersonPojoIntId p2 = template.findOne(query(where("id").is(1)), PersonPojoIntId.class);
assertEquals("New Text", p2.getText());
p.setText("Different Text");
template.save(p);
PersonPojoIntId p3 = template.findOne(query(where("id").is(1)), PersonPojoIntId.class);
assertEquals("Different Text", p3.getText());
}
@Test
public void testNoMappingAnnotationsUsingLongAsId() {
PersonPojoLongId p = new PersonPojoLongId(1, "Text");
template.insert(p);
template.updateFirst(query(where("id").is(1)), update("text", "New Text"), PersonPojoLongId.class);
PersonPojoLongId p2 = template.findOne(query(where("id").is(1)), PersonPojoLongId.class);
assertEquals("New Text", p2.getText());
p.setText("Different Text");
template.save(p);
PersonPojoLongId p3 = template.findOne(query(where("id").is(1)), PersonPojoLongId.class);
assertEquals("Different Text", p3.getText());
}
@Test
public void testNoMappingAnnotationsUsingStringAsId() {
// Assign the String Id in code
PersonPojoStringId p = new PersonPojoStringId("1", "Text");
template.insert(p);
template.updateFirst(query(where("id").is("1")), update("text", "New Text"), PersonPojoStringId.class);
PersonPojoStringId p2 = template.findOne(query(where("id").is("1")), PersonPojoStringId.class);
assertEquals("New Text", p2.getText());
p.setText("Different Text");
template.save(p);
PersonPojoStringId p3 = template.findOne(query(where("id").is("1")), PersonPojoStringId.class);
assertEquals("Different Text", p3.getText());
PersonPojoStringId p4 = new PersonPojoStringId("2", "Text-2");
template.insert(p4);
Query q = query(where("id").in("1", "2"));
q.with(Sort.by(Direction.ASC, "id"));
List<PersonPojoStringId> people = template.find(q, PersonPojoStringId.class);
assertEquals(2, people.size());
}
@Test
public void testPersonWithLongDBRef() {
PersonPojoLongId personPojoLongId = new PersonPojoLongId(12L, "PersonWithLongDBRef");
template.insert(personPojoLongId);
PersonWithLongDBRef personWithLongDBRef = new PersonWithLongDBRef(21, "PersonWith", "LongDBRef", personPojoLongId);
template.insert(personWithLongDBRef);
Query q = query(where("ssn").is(21));
PersonWithLongDBRef p2 = template.findOne(q, PersonWithLongDBRef.class);
assertNotNull(p2);
assertNotNull(p2.getPersonPojoLongId());
assertEquals(12L, p2.getPersonPojoLongId().getId());
}
@Test // DATADOC-275
public void readsAndWritesDBRefsCorrectly() {
template.dropCollection(Item.class);
template.dropCollection(Container.class);
Item item = new Item();
Item items = new Item();
template.insert(item);
template.insert(items);
Container container = new Container();
container.item = item;
container.items = Arrays.asList(items);
template.insert(container);
Container result = template.findOne(query(where("id").is(container.id)), Container.class);
assertThat(result.item.id, is(item.id));
assertThat(result.items.size(), is(1));
assertThat(result.items.get(0).id, is(items.id));
}
@Test // DATAMONGO-805
public void supportExcludeDbRefAssociation() {
template.dropCollection(Item.class);
template.dropCollection(Container.class);
Item item = new Item();
template.insert(item);
Container container = new Container("foo");
container.item = item;
template.insert(container);
Query query = new Query(Criteria.where("id").is("foo"));
query.fields().exclude("item");
Container result = template.findOne(query, Container.class);
assertThat(result, is(notNullValue()));
assertThat(result.item, is(nullValue()));
}
@Test // DATAMONGO-805
public void shouldMapFieldsOfIterableEntity() {
template.dropCollection(IterableItem.class);
template.dropCollection(Container.class);
Item item = new IterableItem();
item.value = "bar";
template.insert(item);
Container container = new Container("foo");
container.item = item;
template.insert(container);
Query query = new Query(Criteria.where("id").is("foo"));
Container result = template.findOne(query, Container.class);
assertThat(result, is(notNullValue()));
assertThat(result.item, is(notNullValue()));
assertThat(result.item.value, is("bar"));
}
static class Container {
@Id final String id;
public Container() {
id = new ObjectId().toString();
}
public Container(String id) {
this.id = id;
}
@DBRef Item item;
@DBRef List<Item> items;
}
static class Item {
@Id final String id;
String value;
public Item() {
this.id = new ObjectId().toString();
}
}
static class IterableItem extends Item implements Iterable<ItemData> {
List<ItemData> data = new ArrayList<MappingTests.ItemData>();
@Override
public Iterator<ItemData> iterator() {
return data.iterator();
}
}
static class ItemData {
String id;
String value;
}
}