/* * Copyright 2011, Mysema Ltd * * 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 com.mysema.query.mongodb; import static java.util.Arrays.asList; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import com.mysema.query.mongodb.domain.*; import org.bson.types.ObjectId; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.mongodb.morphia.Datastore; import org.mongodb.morphia.Morphia; import com.google.common.collect.Lists; import com.mongodb.Mongo; import com.mongodb.MongoException; import com.mongodb.ReadPreference; import com.mysema.query.NonUniqueResultException; import com.mysema.query.SearchResults; import com.mysema.query.mongodb.domain.QAddress; import com.mysema.query.mongodb.domain.QItem; import com.mysema.query.mongodb.domain.QMapEntity; import com.mysema.query.mongodb.domain.QUser; import com.mysema.query.mongodb.domain.User.Gender; import com.mysema.query.mongodb.morphia.MorphiaQuery; import com.mysema.query.types.EntityPath; import com.mysema.query.types.OrderSpecifier; import com.mysema.query.types.Predicate; import com.mysema.query.types.path.StringPath; import com.mysema.testutil.ExternalDB; @Category(ExternalDB.class) public class MongodbQueryTest { private final Mongo mongo; private final Morphia morphia; private final Datastore ds; private final String dbname = "testdb"; private final QUser user = QUser.user; private final QItem item = QItem.item; private final QAddress address = QAddress.address; private final QMapEntity mapEntity = QMapEntity.mapEntity; private final QDates dates = QDates.dates; List users = Lists.newArrayList(); User u1, u2, u3, u4; City tampere, helsinki; public MongodbQueryTest() throws UnknownHostException, MongoException { mongo = new Mongo(); morphia = new Morphia().map(User.class).map(Item.class).map(MapEntity.class).map(Dates.class); ds = morphia.createDatastore(mongo, dbname); } @Before public void before() throws UnknownHostException, MongoException { ds.delete(ds.createQuery(Item.class)); ds.delete(ds.createQuery(User.class)); ds.delete(ds.createQuery(MapEntity.class)); tampere = new City("Tampere", 61.30, 23.50); helsinki= new City("Helsinki", 60.15, 20.03); u1 = addUser("Jaakko", "Jantunen", 20, new Address("Aakatu", "00100", helsinki), new Address("Aakatu1", "00100", helsinki), new Address("Aakatu2", "00100", helsinki)); u2 = addUser("Jaakki", "Jantunen", 30, new Address("Beekatu", "00200", helsinki)); u3 = addUser("Jaana", "Aakkonen", 40, new Address("Ceekatu","00300", tampere)); u4 = addUser("Jaana", "BeekkoNen", 50, new Address("Deekatu","00400",tampere)); } @Test public void List_Keys() { User u = where(user.firstName.eq("Jaakko")).list(user.firstName, user.mainAddress().street).get(0); assertEquals("Jaakko", u.getFirstName()); assertNull(u.getLastName()); assertEquals("Aakatu", u.getMainAddress().street); assertNull(u.getMainAddress().postCode); } @Test public void SingleResult_Keys() { User u = where(user.firstName.eq("Jaakko")).singleResult(user.firstName); assertEquals("Jaakko", u.getFirstName()); assertNull(u.getLastName()); } @Test public void UniqueResult_Keys() { User u = where(user.firstName.eq("Jaakko")).uniqueResult(user.firstName); assertEquals("Jaakko", u.getFirstName()); assertNull(u.getLastName()); } @Test public void List_Deep_Keys() { User u = where(user.firstName.eq("Jaakko")).singleResult(user.addresses.any().street); for (Address a : u.getAddresses()) { assertNotNull(a.street); assertNull(a.city); } } @Test public void Contains() { assertQuery(user.friends.contains(u1), u3, u4, u2); } @Test public void Contains2() { assertQuery(user.friends.contains(u4)); } @Test public void NotContains() { assertQuery(user.friends.contains(u1).not(), u1); } @Test public void Contains_Key() { MapEntity entity = new MapEntity(); entity.getProperties().put("key", "value"); ds.save(entity); assertTrue(query(mapEntity).where(mapEntity.properties.get("key").isNotNull()).exists()); assertFalse(query(mapEntity).where(mapEntity.properties.get("key2").isNotNull()).exists()); assertTrue(query(mapEntity).where(mapEntity.properties.containsKey("key")).exists()); assertFalse(query(mapEntity).where(mapEntity.properties.containsKey("key2")).exists()); } @Test public void Equals_Ignore_Case() { assertTrue(where(user.firstName.equalsIgnoreCase("jAaKko")).exists()); assertFalse(where(user.firstName.equalsIgnoreCase("AaKk")).exists()); } @Test public void Exists() { assertTrue(where(user.firstName.eq("Jaakko")).exists()); assertFalse(where(user.firstName.eq("JaakkoX")).exists()); assertTrue(where(user.id.eq(u1.getId())).exists()); } @Test public void Find_By_Id() { assertNotNull(where(user.id.eq(u1.getId())).singleResult() != null); } @Test public void NotExists() { assertFalse(where(user.firstName.eq("Jaakko")).notExists()); assertTrue(where(user.firstName.eq("JaakkoX")).notExists()); } @Test public void UniqueResult() { assertEquals("Jantunen", where(user.firstName.eq("Jaakko")).uniqueResult().getLastName()); } @Test(expected=NonUniqueResultException.class) public void UniqueResultContract() { where(user.firstName.isNotNull()).uniqueResult(); } @Test public void SingleResult() { where(user.firstName.isNotNull()).singleResult(); } @Test public void LongPath() { assertEquals(2, query().where(user.mainAddress().city().name.eq("Helsinki")).count()); assertEquals(2, query().where(user.mainAddress().city().name.eq("Tampere")).count()); } @Test public void CollectionPath() { assertEquals(1, query().where(user.addresses.any().street.eq("Aakatu1")).count()); assertEquals(0, query().where(user.addresses.any().street.eq("akatu")).count()); } @Test public void Dates() { Date start = new Date(); ds.delete(ds.createQuery(Dates.class)); Dates d = new Dates(); d.setDate(new Date()); ds.save(d); Date end = new Date(); assertEquals(d, query(dates).where(dates.date.between(start, end)).singleResult()); } @Test public void ElemMatch() { // { "addresses" : { "$elemMatch" : { "street" : "Aakatu1"}}} assertEquals(1, query().anyEmbedded(user.addresses, address).on(address.street.eq("Aakatu1")).count()); // { "addresses" : { "$elemMatch" : { "street" : "Aakatu1" , "postCode" : "00100"}}} assertEquals(1, query().anyEmbedded(user.addresses, address).on(address.street.eq("Aakatu1"), address.postCode.eq("00100")).count()); // { "addresses" : { "$elemMatch" : { "street" : "akatu"}}} assertEquals(0, query().anyEmbedded(user.addresses, address).on(address.street.eq("akatu")).count()); // { "addresses" : { "$elemMatch" : { "street" : "Aakatu1" , "postCode" : "00200"}}} assertEquals(0, query().anyEmbedded(user.addresses, address).on(address.street.eq("Aakatu1"), address.postCode.eq("00200")).count()); } @Test public void IndexedAccess() { assertEquals(1, query().where(user.addresses.get(0).street.eq("Aakatu1")).count()); assertEquals(0, query().where(user.addresses.get(1).street.eq("Aakatu1")).count()); } @Test public void Count() { assertEquals(4, query().count()); } @Test public void Order() { List users = query().orderBy(user.age.asc()).list(); assertEquals(asList(u1, u2, u3, u4), users); users = query().orderBy(user.age.desc()).list(); assertEquals(asList(u4, u3, u2, u1), users); } @Test public void Restrict() { assertEquals(asList(u1, u2), query().limit(2).orderBy(user.age.asc()).list()); assertEquals(asList(u2, u3), query().limit(2).offset(1).orderBy(user.age.asc()).list()); } @Test public void ListResults() { SearchResults results = query().limit(2).orderBy(user.age.asc()).listResults(); assertEquals(4l, results.getTotal()); assertEquals(2, results.getResults().size()); results = query().offset(2).orderBy(user.age.asc()).listResults(); assertEquals(4l, results.getTotal()); assertEquals(2, results.getResults().size()); } @Test public void EmptyResults() { SearchResults results = query().where(user.firstName.eq("XXX")).listResults(); assertEquals(0l, results.getTotal()); assertEquals(Collections.emptyList(), results.getResults()); } @Test public void EqInAndOrderByQueries() { assertQuery(user.firstName.eq("Jaakko"), u1); assertQuery(user.firstName.equalsIgnoreCase("jaakko"), u1); assertQuery(user.lastName.eq("Aakkonen"), u3); assertQuery(user.firstName.in("Jaakko","Teppo"), u1); assertQuery(user.lastName.in("Aakkonen","BeekkoNen"), u3, u4); assertQuery(user.firstName.eq("Jouko")); assertQuery(user.firstName.eq("Jaana"), user.lastName.asc(), u3, u4); assertQuery(user.firstName.eq("Jaana"), user.lastName.desc(), u4, u3); assertQuery(user.lastName.eq("Jantunen"), user.firstName.asc(), u2, u1); assertQuery(user.lastName.eq("Jantunen"), user.firstName.desc(), u1, u2); assertQuery(user.firstName.eq("Jaana").and(user.lastName.eq("Aakkonen")), u3); //This shoud produce 'and' also assertQuery(where(user.firstName.eq("Jaana"), user.lastName.eq("Aakkonen")), u3); assertQuery(user.firstName.ne("Jaana"), u2, u1); } @Test public void RegexQueries() { assertQuery(user.firstName.startsWith("Jaan"), u3, u4); assertQuery(user.firstName.startsWith("jaan")); assertQuery(user.firstName.startsWithIgnoreCase("jaan"), u3, u4); assertQuery(user.lastName.endsWith("unen"), u2, u1); assertQuery(user.lastName.endsWithIgnoreCase("onen"), u3, u4); assertQuery(user.lastName.contains("oN"), u4); assertQuery(user.lastName.containsIgnoreCase("on"), u3, u4); assertQuery(user.firstName.matches(".*aa.*[^i]$"), u3, u4, u1); } @Test public void Like() { assertQuery(user.firstName.like("Jaan")); assertQuery(user.firstName.like("Jaan%"), u3, u4); assertQuery(user.firstName.like("jaan%")); assertQuery(user.lastName.like("%unen"), u2, u1); } @Test public void IsNotNull() { assertQuery(user.firstName.isNotNull(), u3, u4, u2, u1); } @Test public void IsNull() { assertQuery(user.firstName.isNull()); } @Test public void IsEmpty() { assertQuery(user.firstName.isEmpty()); } @Test public void isEmpty2() { assertQuery(user.friends.isEmpty(), u1); } @Test public void Not() { assertQuery(user.firstName.eq("Jaakko").not(), u3, u4, u2); assertQuery(user.firstName.ne("Jaakko").not(), u1); assertQuery(user.firstName.matches("Jaakko").not(), u3, u4, u2); } @Test public void Or() { assertQuery(user.lastName.eq("Aakkonen").or(user.lastName.eq("BeekkoNen")), u3, u4); } //This is not supported yet // @Test // public void UniqueResult() { // // addUser("Dille", "Duplikaatti"); // addUser("Dille", "Duplikaatti"); // // assertEquals(2, where(user.firstName.eq("Dille")).count()); // assertEquals(1, where(user.firstName.eq("Dille")).countDistinct()); // // } @Test public void Iterate() { User a = addUser("A", "A"); User b = addUser("A1", "B"); User c = addUser("A2", "C"); Iterator i = where(user.firstName.startsWith("A")) .orderBy(user.firstName.asc()) .iterate(); assertEquals(a, i.next()); assertEquals(b, i.next()); assertEquals(c, i.next()); assertEquals(false, i.hasNext()); } @Test public void UniqueResultAndLimitAndOffset() { MongodbQuery q = query().where(user.firstName.startsWith("Ja")).orderBy(user.age.asc()); assertEquals(4, q.list().size()); assertEquals(u1, q.list().get(0)); } @Test public void Various() { StringPath str = user.lastName; List predicates = new ArrayList(); predicates.add(str.between("a", "b")); predicates.add(str.contains("a")); predicates.add(str.containsIgnoreCase("a")); predicates.add(str.endsWith("a")); predicates.add(str.endsWithIgnoreCase("a")); predicates.add(str.eq("a")); predicates.add(str.equalsIgnoreCase("a")); predicates.add(str.goe("a")); predicates.add(str.gt("a")); predicates.add(str.in("a","b","c")); predicates.add(str.isEmpty()); predicates.add(str.isNotNull()); predicates.add(str.isNull()); // predicates.add(str.like("a")); predicates.add(str.loe("a")); predicates.add(str.lt("a")); predicates.add(str.matches("a")); predicates.add(str.ne("a")); predicates.add(str.notBetween("a", "b")); predicates.add(str.notIn("a","b","c")); predicates.add(str.startsWith("a")); predicates.add(str.startsWithIgnoreCase("a")); for (Predicate predicate : predicates) { where(predicate).count(); where(predicate.not()).count(); } } @Test public void Enum_Eq() { assertQuery(user.gender.eq(Gender.MALE), u3, u4, u2, u1); } @Test public void Enum_Ne() { assertQuery(user.gender.ne(Gender.MALE)); } @Test public void In_ObjectIds() { Item i = new Item(); i.setCtds(Arrays.asList(ObjectId.get(), ObjectId.get(), ObjectId.get())); ds.save(i); assertTrue(where(item, item.ctds.contains(i.getCtds().get(0))).count() > 0); assertTrue(where(item, item.ctds.contains(ObjectId.get())).count() == 0); } @Test public void In_ObjectIds2() { Item i = new Item(); i.setCtds(Arrays.asList(ObjectId.get(), ObjectId.get(), ObjectId.get())); ds.save(i); assertTrue(where(item, item.ctds.any().in(i.getCtds())).count() > 0); assertTrue(where(item, item.ctds.any().in(Arrays.asList(ObjectId.get(), ObjectId.get()))).count() == 0); } @Test public void Size() { assertQuery(user.addresses.size().eq(2), u1); } @Test public void ReadPreference() { MorphiaQuery query = query(); query.setReadPreference(ReadPreference.primary()); assertEquals(4, query.count()); } //TODO // - test dates // - test with empty values and nulls // - test more complex ands private void assertQuery(Predicate e, User ... expected) { assertQuery(where(e).orderBy(user.lastName.asc(), user.firstName.asc()), expected ); } private void assertQuery(Predicate e, OrderSpecifier orderBy, User ... expected ) { assertQuery(where(e).orderBy(orderBy), expected); } private MongodbQuery where(EntityPath entity, Predicate... e) { return new MorphiaQuery(morphia, ds, entity).where(e); } private MongodbQuery where(Predicate ... e) { return query().where(e); } private MorphiaQuery query() { return new MorphiaQuery(morphia, ds, user); } private MorphiaQuery query(EntityPath path) { return new MorphiaQuery(morphia, ds, path); } private void assertQuery(MongodbQuery query, User ... expected ) { //System.out.println(query.toString()); List results = query.list(); assertNotNull(results); if (expected == null ) { assertEquals("Should get empty result", 0, results.size()); return; } assertEquals(expected.length, results.size()); int i = 0; for (User u : expected) { assertEquals(u, results.get(i++)); } } private User addUser(String first, String last) { User user = new User(first, last); ds.save(user); return user; } private User addUser(String first, String last, int age, Address mainAddress, Address... addresses) { User user = new User(first, last, age, new Date()); user.setGender(Gender.MALE); user.setMainAddress(mainAddress); for (Address address : addresses) { user.addAddress(address); } for (User u : users) { user.addFriend(u); } ds.save(user); users.add(user); return user; } }