/* * 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; } }