/*
* Copyright (C) 2010 Olafur Gauti Gudmundsson
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.mongodb.morphia.query;
import com.jayway.awaitility.Awaitility;
import com.mongodb.BasicDBObject;
import com.mongodb.CursorType;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.MongoException;
import com.mongodb.MongoInternalException;
import com.mongodb.ReadPreference;
import com.mongodb.client.model.CollationStrength;
import org.bson.types.CodeWScope;
import org.bson.types.ObjectId;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.mongodb.morphia.Key;
import org.mongodb.morphia.TestBase;
import org.mongodb.morphia.TestDatastore.FacebookUser;
import org.mongodb.morphia.TestDatastore.KeysKeysKeys;
import org.mongodb.morphia.TestMapper.CustomId;
import org.mongodb.morphia.TestMapper.UsesCustomIdObject;
import org.mongodb.morphia.annotations.CappedAt;
import org.mongodb.morphia.annotations.Embedded;
import org.mongodb.morphia.annotations.Entity;
import org.mongodb.morphia.annotations.Id;
import org.mongodb.morphia.annotations.Indexed;
import org.mongodb.morphia.annotations.PrePersist;
import org.mongodb.morphia.annotations.Property;
import org.mongodb.morphia.annotations.Reference;
import org.mongodb.morphia.mapping.Mapper;
import org.mongodb.morphia.testmodel.Hotel;
import org.mongodb.morphia.testmodel.Rectangle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import static com.mongodb.client.model.Collation.builder;
import static java.util.Arrays.asList;
import static java.util.Arrays.copyOfRange;
import static java.util.Collections.singletonList;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mongodb.morphia.query.Sort.ascending;
import static org.mongodb.morphia.query.Sort.descending;
import static org.mongodb.morphia.query.Sort.naturalAscending;
import static org.mongodb.morphia.query.Sort.naturalDescending;
/**
* @author Scott Hernandez
*/
@SuppressWarnings("unchecked")
public class TestQuery extends TestBase {
@Test
@SuppressWarnings("deprecation")
public void batchSize() {
QueryImpl<Photo> query = (QueryImpl<Photo>) getDs().find(Photo.class)
.batchSize(42);
Assert.assertEquals(42, query.getBatchSize());
Assert.assertEquals(42, query.getOptions().getBatchSize());
}
@Test
@SuppressWarnings("deprecation")
public void cursorTimeOut() {
QueryImpl<Photo> query = (QueryImpl<Photo>) getDs().find(Photo.class)
.enableCursorTimeout();
Assert.assertFalse(query.getOptions().isNoCursorTimeout());
query.disableCursorTimeout();
Assert.assertTrue(query.getOptions().isNoCursorTimeout());
}
@Test
public void genericMultiKeyValueQueries() {
getMorphia().map(GenericKeyValue.class);
getDs().ensureIndexes(GenericKeyValue.class);
final GenericKeyValue<String> value = new GenericKeyValue<String>();
final List<Object> keys = Arrays.<Object>asList("key1", "key2");
value.key = keys;
getDs().save(value);
final Query<GenericKeyValue> query = getDs().find(GenericKeyValue.class).field("key").hasAnyOf(keys);
Assert.assertTrue(query.toString().replaceAll("\\s", "").contains("{\"$in\":[\"key1\",\"key2\"]"));
assertEquals(query.get().id, value.id);
}
@Test
@SuppressWarnings("deprecation")
public void maxScan() {
getDs().save(asList(new Pic("pic1"), new Pic("pic2"), new Pic("pic3"), new Pic("pic4")));
assertEquals(2, getDs().find(Pic.class)
.maxScan(2)
.asList()
.size());
assertEquals(2, getDs().find(Pic.class)
.asList(new FindOptions()
.modifier("$maxScan", 2))
.size());
assertEquals(4, getDs().find(Pic.class).asList().size());
}
@Test
@SuppressWarnings("deprecation")
public void maxTime() {
Query<ContainsRenamedFields> query = getDs().find(ContainsRenamedFields.class)
.maxTime(15, TimeUnit.MINUTES);
assertEquals(900, ((QueryImpl) query).getMaxTime(TimeUnit.SECONDS));
}
@Test
public void multiKeyValueQueries() {
getMorphia().map(KeyValue.class);
getDs().ensureIndexes(KeyValue.class);
final KeyValue value = new KeyValue();
final List<Object> keys = Arrays.<Object>asList("key1", "key2");
value.key = keys;
getDs().save(value);
final Query<KeyValue> query = getDs().find(KeyValue.class).field("key").hasAnyOf(keys);
Assert.assertTrue(query.toString().replaceAll("\\s", "").contains("{\"$in\":[\"key1\",\"key2\"]"));
assertEquals(query.get().id, value.id);
}
@Test
@SuppressWarnings("deprecation")
public void oldReadPreference() {
QueryImpl<Photo> query = (QueryImpl<Photo>) getDs().find(Photo.class)
.queryNonPrimary();
Assert.assertEquals(ReadPreference.secondaryPreferred(), query.getOptions().getReadPreference());
query.queryPrimaryOnly();
Assert.assertEquals(ReadPreference.primary(), query.getOptions().getReadPreference());
}
@Test
public void referenceKeys() {
final ReferenceKey key1 = new ReferenceKey("key1");
getDs().save(asList(key1, new Pic("pic1"), new Pic("pic2"), new Pic("pic3"), new Pic("pic4")));
final ReferenceKeyValue value = new ReferenceKeyValue();
value.id = key1;
final Key<ReferenceKeyValue> key = getDs().save(value);
final ReferenceKeyValue byKey = getDs().getByKey(ReferenceKeyValue.class, key);
assertEquals(value.id, byKey.id);
}
@Test
public void snapshot() {
getDs().find(Photo.class)
.get(new FindOptions()
.modifier("$snapshot", true));
}
@Test
@SuppressWarnings("deprecation")
public void snapshotOld() {
QueryImpl<Photo> query = (QueryImpl<Photo>) getDs().find(Photo.class)
.enableSnapshotMode();
Assert.assertTrue(query.getOptions().getModifiers().containsField("$snapshot"));
query.get();
query.disableSnapshotMode();
Assert.assertFalse(query.getOptions().getModifiers().containsField("$snapshot"));
}
@Override
@After
public void tearDown() {
turnOffProfilingAndDropProfileCollection();
super.tearDown();
}
@Test
public void testAliasedFieldSort() {
getDs().save(asList(new Rectangle(1, 10), new Rectangle(3, 8), new Rectangle(6, 10), new Rectangle(10, 10), new Rectangle(10, 1)));
Rectangle r1 = getDs().find(Rectangle.class)
.order("w")
.get(new FindOptions()
.limit(1));
assertNotNull(r1);
assertEquals(1, r1.getWidth(), 0);
r1 = getDs().find(Rectangle.class)
.order("-w")
.get(new FindOptions()
.limit(1));
assertNotNull(r1);
assertEquals(10, r1.getWidth(), 0);
}
@Test
@SuppressWarnings("deprecation")
public void testAliasedFieldSortOld() {
getDs().save(asList(new Rectangle(1, 10), new Rectangle(3, 8), new Rectangle(6, 10), new Rectangle(10, 10), new Rectangle(10, 1)));
Rectangle r1 = getDs().find(Rectangle.class).limit(1).order("w").get();
assertNotNull(r1);
assertEquals(1, r1.getWidth(), 0);
r1 = getDs().find(Rectangle.class).limit(1).order("-w").get();
assertNotNull(r1);
assertEquals(10, r1.getWidth(), 0);
}
@Test
public void testCaseVariants() {
getDs().save(asList(new Pic("pic1"), new Pic("pic2"), new Pic("pic3"), new Pic("pic4")));
assertEquals(0, getDs().find(Pic.class)
.field("name").contains("PIC")
.asList()
.size());
assertEquals(4, getDs().find(Pic.class)
.field("name").containsIgnoreCase("PIC")
.asList()
.size());
assertEquals(0, getDs().find(Pic.class)
.field("name").equal("PIC1")
.asList()
.size());
assertEquals(1, getDs().find(Pic.class)
.field("name").equalIgnoreCase("PIC1")
.asList()
.size());
assertEquals(0, getDs().find(Pic.class)
.field("name").endsWith("C1")
.asList()
.size());
assertEquals(1, getDs().find(Pic.class)
.field("name").endsWithIgnoreCase("C1")
.asList()
.size());
assertEquals(0, getDs().find(Pic.class)
.field("name").startsWith("PIC")
.asList()
.size());
assertEquals(4, getDs().find(Pic.class)
.field("name").startsWithIgnoreCase("PIC")
.asList()
.size());
}
@Test
public void testCollations() {
checkMinServerVersion(3.4);
getMorphia().map(ContainsRenamedFields.class);
getDs().save(asList(new ContainsRenamedFields("first", "last"),
new ContainsRenamedFields("First", "Last")));
Query query = getDs().find(ContainsRenamedFields.class)
.field("last_name").equal("last");
assertEquals(1, query.asList().size());
assertEquals(2, query.asList(new FindOptions()
.collation(builder()
.locale("en")
.collationStrength(CollationStrength.SECONDARY)
.build()))
.size());
assertEquals(1, query.count());
assertEquals(2, query.count(new CountOptions()
.collation(builder()
.locale("en")
.collationStrength(CollationStrength.SECONDARY)
.build())));
}
@Test
public void testCombinationQuery() {
getDs().save(asList(new Rectangle(1, 10), new Rectangle(4, 2), new Rectangle(6, 10), new Rectangle(8, 5), new Rectangle(10, 4)));
Query<Rectangle> q = getDs().find(Rectangle.class);
q.and(q.criteria("width").equal(10), q.criteria("height").equal(1));
assertEquals(1, getDs().getCount(q));
q = getDs().find(Rectangle.class);
q.or(q.criteria("width").equal(10), q.criteria("height").equal(10));
assertEquals(3, getDs().getCount(q));
q = getDs().find(Rectangle.class);
q.or(q.criteria("width").equal(10), q.and(q.criteria("width").equal(5), q.criteria("height").equal(8)));
assertEquals(3, getDs().getCount(q));
}
@Test
public void testCommentsShowUpInLogs() {
getDs().save(asList(new Pic("pic1"), new Pic("pic2"), new Pic("pic3"), new Pic("pic4")));
getDb().command(new BasicDBObject("profile", 2));
String expectedComment = "test comment";
getDs().find(Pic.class)
.asList(new FindOptions()
.modifier("$comment", expectedComment));
DBCollection profileCollection = getDb().getCollection("system.profile");
assertNotEquals(0, profileCollection.count());
DBObject profileRecord = profileCollection.findOne(new BasicDBObject("op", "query")
.append("ns", getDs().getCollection(Pic.class).getFullName()));
final Object commentPre32 = ((DBObject) profileRecord.get("query")).get("$comment");
final Object commentPost32 = ((DBObject) profileRecord.get("query")).get("comment");
assertTrue(profileRecord.toString(), expectedComment.equals(commentPre32) || expectedComment.equals(commentPost32));
turnOffProfilingAndDropProfileCollection();
}
@Test
@SuppressWarnings("deprecation")
public void testCommentsShowUpInLogsOld() {
getDs().save(asList(new Pic("pic1"), new Pic("pic2"), new Pic("pic3"), new Pic("pic4")));
getDb().command(new BasicDBObject("profile", 2));
String expectedComment = "test comment";
getDs().find(Pic.class).comment(expectedComment).asList();
DBCollection profileCollection = getDb().getCollection("system.profile");
assertNotEquals(0, profileCollection.count());
DBObject profileRecord = profileCollection.findOne(new BasicDBObject("op", "query")
.append("ns", getDs().getCollection(Pic.class).getFullName()));
final Object commentPre32 = ((DBObject) profileRecord.get("query")).get("$comment");
final Object commentPost32 = ((DBObject) profileRecord.get("query")).get("comment");
assertTrue(profileRecord.toString(), expectedComment.equals(commentPre32) || expectedComment.equals(commentPost32));
turnOffProfilingAndDropProfileCollection();
}
@Test
public void testComplexElemMatchQuery() {
Keyword oscar = new Keyword("Oscar", 42);
getDs().save(new PhotoWithKeywords(oscar, new Keyword("Jim", 12)));
assertNull(getDs().find(PhotoWithKeywords.class)
.field("keywords")
.elemMatch(getDs()
.find(Keyword.class)
.filter("keyword = ", "Oscar")
.filter("score = ", 12))
.get());
List<PhotoWithKeywords> keywords = getDs().find(PhotoWithKeywords.class)
.field("keywords")
.elemMatch(getDs()
.find(Keyword.class)
.filter("score > ", 20)
.filter("score < ", 100))
.asList();
assertEquals(1, keywords.size());
assertEquals(oscar, keywords.get(0).keywords.get(0));
}
@Test
public void testComplexIdQuery() {
final CustomId cId = new CustomId();
cId.setId(new ObjectId());
cId.setType("banker");
final UsesCustomIdObject object = new UsesCustomIdObject();
object.setId(cId);
object.setText("hllo");
getDs().save(object);
assertNotNull(getDs().find(UsesCustomIdObject.class).filter("_id.type", "banker").get());
assertNotNull(getDs().find(UsesCustomIdObject.class).field("_id").hasAnyOf(singletonList(cId)).get());
}
@Test
public void testComplexIdQueryWithRenamedField() {
final CustomId cId = new CustomId();
cId.setId(new ObjectId());
cId.setType("banker");
final UsesCustomIdObject object = new UsesCustomIdObject();
object.setId(cId);
object.setText("hllo");
getDs().save(object);
assertNotNull(getDs().find(UsesCustomIdObject.class).filter("_id.t", "banker").get());
}
@Test
public void testComplexRangeQuery() {
getDs().save(asList(new Rectangle(1, 10), new Rectangle(4, 2), new Rectangle(6, 10), new Rectangle(8, 5), new Rectangle(10, 4)));
assertEquals(2, getDs().getCount(getDs().find(Rectangle.class)
.filter("height >", 3)
.filter("height <", 8)));
assertEquals(1, getDs().getCount(getDs().find(Rectangle.class)
.filter("height >", 3)
.filter("height <", 8)
.filter("width", 10)));
}
@Test
public void testCompoundSort() {
getDs().save(asList(new Rectangle(1, 10), new Rectangle(3, 8), new Rectangle(6, 10), new Rectangle(10, 10), new Rectangle(10, 1)));
Rectangle r1 = getDs().find(Rectangle.class).order("width,-height").get();
assertNotNull(r1);
assertEquals(1, r1.getWidth(), 0);
assertEquals(10, r1.getHeight(), 0);
r1 = getDs().find(Rectangle.class).order("-height,-width").get();
assertNotNull(r1);
assertEquals(10, r1.getWidth(), 0);
assertEquals(10, r1.getHeight(), 0);
}
@Test
public void testCompoundSortWithSortBeans() {
List<Rectangle> list =
asList(new Rectangle(1, 10), new Rectangle(3, 8), new Rectangle(6, 10), new Rectangle(10, 10), new Rectangle(10, 1));
Collections.shuffle(list);
getDs().save(list);
compareLists(list,
getDs().find(Rectangle.class).order("width,-height"),
getDs().find(Rectangle.class).order(ascending("width"), descending("height")),
new RectangleComparator());
compareLists(list,
getDs().find(Rectangle.class).order("-height,-width"),
getDs().find(Rectangle.class).order(descending("height"), descending("width")),
new RectangleComparator1());
compareLists(list,
getDs().find(Rectangle.class).order("width,height"),
getDs().find(Rectangle.class).order(ascending("width"), ascending("height")),
new RectangleComparator2());
compareLists(list,
getDs().find(Rectangle.class).order("width,height"),
getDs().find(Rectangle.class).order("width, height"),
new RectangleComparator3());
}
@Test
@SuppressWarnings("deprecation")
public void testCorrectQueryForNotWithSizeEqIssue514() {
Query<PhotoWithKeywords> query = getAds()
.find(PhotoWithKeywords.class)
.field("keywords").not().sizeEq(3);
assertEquals(new BasicDBObject("keywords", new BasicDBObject("$not", new BasicDBObject("$size", 3))), query.getQueryObject());
}
@Test
public void testDBObjectOrQuery() {
getDs().save(new PhotoWithKeywords("scott", "hernandez"));
final List<DBObject> orList = new ArrayList<DBObject>();
orList.add(new BasicDBObject("keywords.keyword", "scott"));
orList.add(new BasicDBObject("keywords.keyword", "ralph"));
final BasicDBObject orQuery = new BasicDBObject("$or", orList);
Query<PhotoWithKeywords> q = getAds().createQuery(PhotoWithKeywords.class, orQuery);
assertEquals(1, q.count());
q = getAds().find(PhotoWithKeywords.class).disableValidation().filter("$or", orList);
assertEquals(1, q.count());
}
@Test
public void testDeepQuery() {
getDs().save(new PhotoWithKeywords(new Keyword("california"), new Keyword("nevada"), new Keyword("arizona")));
assertNotNull(getDs().find(PhotoWithKeywords.class).filter("keywords.keyword", "california").get());
assertNull(getDs().find(PhotoWithKeywords.class).filter("keywords.keyword", "not").get());
}
@Test
public void testDeepQueryWithBadArgs() {
getDs().save(new PhotoWithKeywords(new Keyword("california"), new Keyword("nevada"), new Keyword("arizona")));
assertNull(getDs().find(PhotoWithKeywords.class).filter("keywords.keyword", 1).get());
assertNull(getDs().find(PhotoWithKeywords.class).filter("keywords.keyword", "california".getBytes()).get());
assertNull(getDs().find(PhotoWithKeywords.class).filter("keywords.keyword", null).get());
}
@Test
public void testDeepQueryWithRenamedFields() {
getDs().save(new PhotoWithKeywords(new Keyword("california"), new Keyword("nevada"), new Keyword("arizona")));
assertNotNull(getDs().find(PhotoWithKeywords.class).filter("keywords.keyword", "california").get());
assertNull(getDs().find(PhotoWithKeywords.class).filter("keywords.keyword", "not").get());
}
@Test
public void testDeleteQuery() {
getDs().save(asList(new Rectangle(1, 10),
new Rectangle(1, 10),
new Rectangle(1, 10),
new Rectangle(10, 10),
new Rectangle(10, 10)));
assertEquals(5, getDs().getCount(Rectangle.class));
getDs().delete(getDs().find(Rectangle.class).filter("height", 1D));
assertEquals(2, getDs().getCount(Rectangle.class));
}
@Test
public void testElemMatchQuery() {
getDs().save(asList(new PhotoWithKeywords(), new PhotoWithKeywords("Scott", "Joe", "Sarah")));
assertNotNull(getDs().find(PhotoWithKeywords.class)
.field("keywords").elemMatch(getDs().find(Keyword.class).filter("keyword", "Scott"))
.get());
assertNull(getDs().find(PhotoWithKeywords.class)
.field("keywords").elemMatch(getDs().find(Keyword.class).filter("keyword", "Randy"))
.get());
}
@Test
@SuppressWarnings("deprecation")
public void testElemMatchQueryOld() {
getDs().save(asList(new PhotoWithKeywords(), new PhotoWithKeywords("Scott", "Joe", "Sarah")));
assertNotNull(getDs().find(PhotoWithKeywords.class)
.field("keywords")
.hasThisElement(new Keyword("Scott"))
.get());
// TODO add back when $and is done (> 1.5) this needs multiple $elemMatch clauses
// query = getDs().find(PhotoWithKeywords.class)
// .field("keywords")
// .hasThisElement(new Keyword[]{new Keyword("Scott"), new Keyword("Joe")});
// System.out.println("************ query = " + query);
// PhotoWithKeywords pwkScottSarah = query.get();
// assertNotNull(pwkScottSarah);
assertNull(getDs().find(PhotoWithKeywords.class)
.field("keywords")
.hasThisElement(new Keyword("Randy"))
.get());
}
@Test
@SuppressWarnings("deprecation")
public void testElemMatchVariants() {
final PhotoWithKeywords pwk1 = new PhotoWithKeywords();
final PhotoWithKeywords pwk2 = new PhotoWithKeywords("Kevin");
final PhotoWithKeywords pwk3 = new PhotoWithKeywords("Scott", "Joe", "Sarah");
final PhotoWithKeywords pwk4 = new PhotoWithKeywords(new Keyword("Scott", 14));
Iterator<Key<PhotoWithKeywords>> iterator = getDs().save(asList(pwk1, pwk2, pwk3, pwk4)).iterator();
Key<PhotoWithKeywords> key1 = iterator.next();
Key<PhotoWithKeywords> key2 = iterator.next();
Key<PhotoWithKeywords> key3 = iterator.next();
Key<PhotoWithKeywords> key4 = iterator.next();
assertEquals(asList(key3, key4), getDs().find(PhotoWithKeywords.class)
.field("keywords")
.hasThisElement(new Keyword("Scott"))
.asKeyList());
assertEquals(asList(key3, key4), getDs().find(PhotoWithKeywords.class)
.field("keywords")
.elemMatch(getDs()
.find(Keyword.class)
.field("keyword").equal("Scott"))
.asKeyList());
assertEquals(singletonList(key4), getDs().find(PhotoWithKeywords.class)
.field("keywords")
.hasThisElement(new Keyword(14))
.asKeyList());
assertEquals(singletonList(key4), getDs().find(PhotoWithKeywords.class)
.field("keywords")
.elemMatch(getDs()
.find(Keyword.class)
.field("score").equal(14))
.asKeyList());
assertEquals(asList(key1, key2), getDs().find(PhotoWithKeywords.class)
.field("keywords")
.doesNotHaveThisElement(new Keyword("Scott"))
.asKeyList());
assertEquals(asList(key1, key2), getDs().find(PhotoWithKeywords.class)
.field("keywords").not()
.elemMatch(getDs()
.find(Keyword.class)
.field("keyword").equal("Scott"))
.asKeyList());
}
@Test
public void testExplainPlan() {
getDs().save(asList(new Pic("pic1"), new Pic("pic2"), new Pic("pic3"), new Pic("pic4")));
Map<String, Object> explainResult = getDs().find(Pic.class).explain();
assertEquals(explainResult.toString(), 4, serverIsAtMostVersion(2.7)
? explainResult.get("n")
: ((Map) explainResult.get("executionStats")).get("nReturned"));
}
@Test
public void testFetchEmptyEntities() {
PhotoWithKeywords pwk1 = new PhotoWithKeywords("california", "nevada", "arizona");
PhotoWithKeywords pwk2 = new PhotoWithKeywords("Joe", "Sarah");
PhotoWithKeywords pwk3 = new PhotoWithKeywords("MongoDB", "World");
getDs().save(asList(pwk1, pwk2, pwk3));
MorphiaIterator<PhotoWithKeywords, PhotoWithKeywords> keys = getDs().find(PhotoWithKeywords.class).fetchEmptyEntities();
assertTrue(keys.hasNext());
assertEquals(pwk1.id, keys.next().id);
assertEquals(pwk2.id, keys.next().id);
assertEquals(pwk3.id, keys.next().id);
}
@Test
public void testFetchKeys() {
PhotoWithKeywords pwk1 = new PhotoWithKeywords("california", "nevada", "arizona");
PhotoWithKeywords pwk2 = new PhotoWithKeywords("Joe", "Sarah");
PhotoWithKeywords pwk3 = new PhotoWithKeywords("MongoDB", "World");
getDs().save(asList(pwk1, pwk2, pwk3));
MorphiaKeyIterator<PhotoWithKeywords> keys = getDs().find(PhotoWithKeywords.class).fetchKeys();
assertTrue(keys.hasNext());
assertEquals(pwk1.id, keys.next().getId());
assertEquals(pwk2.id, keys.next().getId());
assertEquals(pwk3.id, keys.next().getId());
}
@Test
@SuppressWarnings("deprecation")
public void testFluentAndOrQuery() {
getDs().save(new PhotoWithKeywords("scott", "hernandez"));
final Query<PhotoWithKeywords> q = getAds().find(PhotoWithKeywords.class);
q.and(
q.or(q.criteria("keywords.keyword").equal("scott")),
q.or(q.criteria("keywords.keyword").equal("hernandez")));
assertEquals(1, q.count());
assertTrue(q.getQueryObject().containsField("$and"));
}
@Test
@SuppressWarnings("deprecation")
public void testFluentAndQuery1() {
getDs().save(new PhotoWithKeywords("scott", "hernandez"));
final Query<PhotoWithKeywords> q = getAds().find(PhotoWithKeywords.class);
q.and(q.criteria("keywords.keyword").hasThisOne("scott"),
q.criteria("keywords.keyword").hasAnyOf(asList("scott", "hernandez")));
assertEquals(1, q.count());
assertTrue(q.getQueryObject().containsField("$and"));
}
@Test
public void testFluentNotQuery() {
final PhotoWithKeywords pwk = new PhotoWithKeywords("scott", "hernandez");
getDs().save(pwk);
final Query<PhotoWithKeywords> query = getAds().find(PhotoWithKeywords.class);
query.criteria("keywords.keyword").not().startsWith("ralph");
assertEquals(1, query.count());
}
@Test
public void testFluentOrQuery() {
final PhotoWithKeywords pwk = new PhotoWithKeywords("scott", "hernandez");
getDs().save(pwk);
final Query<PhotoWithKeywords> q = getAds().find(PhotoWithKeywords.class);
q.or(
q.criteria("keywords.keyword").equal("scott"),
q.criteria("keywords.keyword").equal("ralph"));
assertEquals(1, q.count());
}
@Test
public void testGetByKeysHetero() {
final Iterable<Key<Object>> keys = getDs().save(asList(new FacebookUser(1, "scott"), new Rectangle(1, 1)));
final List<Object> entities = getDs().getByKeys(keys);
assertNotNull(entities);
assertEquals(2, entities.size());
int userCount = 0;
int rectCount = 0;
for (final Object o : entities) {
if (o instanceof Rectangle) {
rectCount++;
} else if (o instanceof FacebookUser) {
userCount++;
}
}
assertEquals(1, rectCount);
assertEquals(1, userCount);
}
@Test
public void testIdFieldNameQuery() {
getDs().save(new PhotoWithKeywords("scott", "hernandez"));
assertNotNull(getDs().find(PhotoWithKeywords.class).filter("id !=", "scott").get());
}
@Test
public void testIdRangeQuery() {
getDs().save(asList(new HasIntId(1), new HasIntId(11), new HasIntId(12)));
assertEquals(2, getDs().find(HasIntId.class).filter("_id >", 5).filter("_id <", 20).count());
assertEquals(1, getDs().find(HasIntId.class).field("_id").greaterThan(0).field("_id").lessThan(11).count());
}
@Test
public void testInQuery() {
getDs().save(new Photo(asList("red", "green", "blue")));
assertNotNull(getDs()
.find(Photo.class)
.field("keywords").in(asList("red", "yellow"))
.get());
}
@Test
public void testInQueryWithObjects() {
getDs().save(asList(new PhotoWithKeywords(), new PhotoWithKeywords("Scott", "Joe", "Sarah")));
final Query<PhotoWithKeywords> query = getDs()
.find(PhotoWithKeywords.class)
.field("keywords").in(asList(new Keyword("Scott"), new Keyword("Randy")));
assertNotNull(query.get());
}
@Test
public void testKeyList() {
final Rectangle rect = new Rectangle(1000, 1);
final Key<Rectangle> rectKey = getDs().save(rect);
assertEquals(rectKey.getId(), rect.getId());
final FacebookUser fbUser1 = new FacebookUser(1, "scott");
final FacebookUser fbUser2 = new FacebookUser(2, "tom");
final FacebookUser fbUser3 = new FacebookUser(3, "oli");
final FacebookUser fbUser4 = new FacebookUser(4, "frank");
final Iterable<Key<FacebookUser>> fbKeys = getDs().save(asList(fbUser1, fbUser2, fbUser3, fbUser4));
assertEquals(1, fbUser1.getId());
final List<Key<FacebookUser>> fbUserKeys = new ArrayList<Key<FacebookUser>>();
for (final Key<FacebookUser> key : fbKeys) {
fbUserKeys.add(key);
}
assertEquals(fbUser1.getId(), fbUserKeys.get(0).getId());
assertEquals(fbUser2.getId(), fbUserKeys.get(1).getId());
assertEquals(fbUser3.getId(), fbUserKeys.get(2).getId());
assertEquals(fbUser4.getId(), fbUserKeys.get(3).getId());
final KeysKeysKeys k1 = new KeysKeysKeys(rectKey, fbUserKeys);
final Key<KeysKeysKeys> k1Key = getDs().save(k1);
assertEquals(k1.getId(), k1Key.getId());
final KeysKeysKeys k1Loaded = getDs().get(k1);
for (final Key<FacebookUser> key : k1Loaded.getUsers()) {
assertNotNull(key.getId());
}
assertNotNull(k1Loaded.getRect().getId());
}
@Test
public void testKeyListLookups() {
final FacebookUser fbUser1 = new FacebookUser(1, "scott");
final FacebookUser fbUser2 = new FacebookUser(2, "tom");
final FacebookUser fbUser3 = new FacebookUser(3, "oli");
final FacebookUser fbUser4 = new FacebookUser(4, "frank");
final Iterable<Key<FacebookUser>> fbKeys = getDs().save(asList(fbUser1, fbUser2, fbUser3, fbUser4));
assertEquals(1, fbUser1.getId());
final List<Key<FacebookUser>> fbUserKeys = new ArrayList<Key<FacebookUser>>();
for (final Key<FacebookUser> key : fbKeys) {
fbUserKeys.add(key);
}
assertEquals(fbUser1.getId(), fbUserKeys.get(0).getId());
assertEquals(fbUser2.getId(), fbUserKeys.get(1).getId());
assertEquals(fbUser3.getId(), fbUserKeys.get(2).getId());
assertEquals(fbUser4.getId(), fbUserKeys.get(3).getId());
final KeysKeysKeys k1 = new KeysKeysKeys(null, fbUserKeys);
final Key<KeysKeysKeys> k1Key = getDs().save(k1);
assertEquals(k1.getId(), k1Key.getId());
final KeysKeysKeys k1Reloaded = getDs().get(k1);
final KeysKeysKeys k1Loaded = getDs().getByKey(KeysKeysKeys.class, k1Key);
assertNotNull(k1Reloaded);
assertNotNull(k1Loaded);
for (final Key<FacebookUser> key : k1Loaded.getUsers()) {
assertNotNull(key.getId());
}
assertEquals(4, k1Loaded.getUsers().size());
final List<FacebookUser> fbUsers = getDs().getByKeys(FacebookUser.class, k1Loaded.getUsers());
assertEquals(4, fbUsers.size());
for (final FacebookUser fbUser : fbUsers) {
assertNotNull(fbUser);
assertNotNull(fbUser.getId());
assertNotNull(fbUser.getUsername());
}
}
@Test
public void testMixedProjection() {
getDs().save(new ContainsRenamedFields("Frank", "Zappa"));
try {
getDs().find(ContainsRenamedFields.class)
.project("first_name", true)
.project("last_name", false);
fail("An exception should have been thrown indication a mixed projection");
} catch (ValidationException e) {
// all good
}
try {
getDs().find(ContainsRenamedFields.class)
.project("first_name", true)
.project("last_name", true)
.project("_id", false);
} catch (ValidationException e) {
fail("An exception should not have been thrown indication a mixed projection because _id suppression is a special case");
}
try {
getDs().find(ContainsRenamedFields.class)
.project("first_name", false)
.project("last_name", false)
.project("_id", true);
fail("An exception should have been thrown indication a mixed projection");
} catch (ValidationException e) {
// all good
}
try {
getDs().find(IntVector.class)
.project("name", false)
.project("scalars", new ArraySlice(5));
fail("An exception should have been thrown indication a mixed projection");
} catch (ValidationException e) {
// all good
}
}
@Test
public void testMultipleConstraintsOnOneField() {
checkMinServerVersion(3.0);
getMorphia().map(ContainsPic.class);
getDs().ensureIndexes();
Query<ContainsPic> query = getDs().find(ContainsPic.class);
query.field("size").greaterThanOrEq(10);
query.field("size").lessThan(100);
Map<String, Object> explain = query.explain();
Map<String, Object> queryPlanner = (Map<String, Object>) explain.get("queryPlanner");
Map<String, Object> winningPlan = (Map<String, Object>) queryPlanner.get("winningPlan");
Map<String, Object> inputStage = (Map<String, Object>) winningPlan.get("inputStage");
assertEquals("IXSCAN", inputStage.get("stage"));
}
@Test
public void testNaturalSortAscending() {
getDs().save(asList(new Rectangle(6, 10), new Rectangle(3, 8), new Rectangle(10, 10), new Rectangle(10, 1)));
List<Rectangle> results = getDs().find(Rectangle.class).order(naturalAscending()).asList();
assertEquals(4, results.size());
Rectangle r;
r = results.get(0);
assertNotNull(r);
assertEquals(6, r.getHeight(), 0);
assertEquals(10, r.getWidth(), 0);
r = results.get(1);
assertNotNull(r);
assertEquals(3, r.getHeight(), 0);
assertEquals(8, r.getWidth(), 0);
r = results.get(2);
assertNotNull(r);
assertEquals(10, r.getHeight(), 0);
assertEquals(10, r.getWidth(), 0);
}
@Test
public void testNaturalSortDescending() {
getDs().save(asList(new Rectangle(6, 10), new Rectangle(3, 8), new Rectangle(10, 10), new Rectangle(10, 1)));
List<Rectangle> results = getDs().find(Rectangle.class).order(naturalDescending()).asList();
assertEquals(4, results.size());
Rectangle r;
r = results.get(0);
assertNotNull(r);
assertEquals(10, r.getHeight(), 0);
assertEquals(1, r.getWidth(), 0);
r = results.get(1);
assertNotNull(r);
assertEquals(10, r.getHeight(), 0);
assertEquals(10, r.getWidth(), 0);
r = results.get(2);
assertNotNull(r);
assertEquals(3, r.getHeight(), 0);
assertEquals(8, r.getWidth(), 0);
}
@Test
public void testNegativeBatchSize() {
getDs().delete(getDs().find(PhotoWithKeywords.class));
getDs().save(asList(new PhotoWithKeywords("scott", "hernandez"),
new PhotoWithKeywords("scott", "hernandez"),
new PhotoWithKeywords("scott", "hernandez"),
new PhotoWithKeywords("1", "2"),
new PhotoWithKeywords("3", "4"),
new PhotoWithKeywords("5", "6")));
assertEquals(2, getDs().find(PhotoWithKeywords.class)
.asList(new FindOptions()
.batchSize(-2))
.size());
}
@Test
@SuppressWarnings("deprecation")
public void testNegativeBatchSizeOld() {
getDs().delete(getDs().find(PhotoWithKeywords.class));
getDs().save(asList(new PhotoWithKeywords("scott", "hernandez"),
new PhotoWithKeywords("scott", "hernandez"),
new PhotoWithKeywords("scott", "hernandez"),
new PhotoWithKeywords("1", "2"),
new PhotoWithKeywords("3", "4"),
new PhotoWithKeywords("5", "6")));
assertEquals(2, getDs().find(PhotoWithKeywords.class)
.batchSize(-2)
.asList()
.size());
}
@Test
@SuppressWarnings("deprecation")
public void testNoLifeCycleEventsOnParameters() throws Exception {
final ContainsPic cpk = new ContainsPic();
final Pic p = new Pic("some pic");
getDs().save(p);
cpk.setPic(p);
getDs().save(cpk);
Pic queryPic = new Pic("some pic");
queryPic.setId(p.getId());
Query query = getDs().find(ContainsPic.class)
.field("pic").equal(queryPic);
assertFalse(queryPic.isPrePersist());
assertNotNull(query.get());
getDs().find(ContainsPic.class)
.field("pic").hasThisElement(queryPic);
assertFalse(queryPic.isPrePersist());
}
@Test
public void testNonSnapshottedQuery() {
getDs().delete(getDs().find(PhotoWithKeywords.class));
getDs().save(asList(new PhotoWithKeywords("scott", "hernandez"),
new PhotoWithKeywords("scott", "hernandez"),
new PhotoWithKeywords("scott", "hernandez")));
final Iterator<PhotoWithKeywords> it = getDs().find(PhotoWithKeywords.class)
.fetch(new FindOptions()
.modifier("$snapshot", true)
.batchSize(2)
);
getDs().save(asList(new PhotoWithKeywords("1", "2"),
new PhotoWithKeywords("3", "4"),
new PhotoWithKeywords("5", "6")));
assertNotNull(it.next());
assertNotNull(it.next());
//okay, now we should getMore...
assertTrue(it.hasNext());
assertNotNull(it.next());
assertTrue(it.hasNext());
assertNotNull(it.next());
}
@Test
public void testNonexistentFindGet() {
assertNull(getDs().find(Hotel.class).filter("_id", -1).get());
}
@Test
public void testNonexistentGet() {
assertNull(getDs().get(Hotel.class, -1));
}
@Test
@SuppressWarnings("deprecation")
public void testNotGeneratesCorrectQueryForGreaterThan() {
final Query<Keyword> query = getDs().find(Keyword.class);
query.criteria("score").not().greaterThan(7);
assertEquals(new BasicDBObject("score", new BasicDBObject("$not", new BasicDBObject("$gt", 7))), query.getQueryObject());
}
@Test
@SuppressWarnings("deprecation")
public void testNotGeneratesCorrectQueryForRegex() {
final Query<PhotoWithKeywords> query = getAds().find(PhotoWithKeywords.class);
query.criteria("keywords.keyword").not().startsWith("ralph");
DBObject queryObject = query.getQueryObject();
BasicDBObject expected = new BasicDBObject("keywords.keyword",
new BasicDBObject("$not", new BasicDBObject("$regex", "^ralph")));
assertEquals(expected.toString(), queryObject.toString());
}
@Test
@SuppressWarnings("deprecation")
public void testProject() {
getDs().save(new ContainsRenamedFields("Frank", "Zappa"));
ContainsRenamedFields found = getDs().find(ContainsRenamedFields.class)
.project("first_name", true)
.get();
assertNotNull(found.firstName);
assertNull(found.lastName);
found = getDs().find(ContainsRenamedFields.class)
.project("firstName", true)
.get();
assertNotNull(found.firstName);
assertNull(found.lastName);
try {
getDs()
.find(ContainsRenamedFields.class)
.project("bad field name", true)
.get();
fail("Validation should have caught the bad field");
} catch (ValidationException e) {
// success!
}
DBObject fields = getDs()
.find(ContainsRenamedFields.class)
.project("_id", true)
.project("first_name", true)
.getFieldsObject();
assertNull(fields.get(Mapper.CLASS_NAME_FIELDNAME));
}
@Test
public void testProjectArrayField() {
int[] ints = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30};
IntVector vector = new IntVector(ints);
getDs().save(vector);
assertArrayEquals(copy(ints, 0, 4), getDs().find(IntVector.class)
.project("scalars", new ArraySlice(4))
.get().scalars);
assertArrayEquals(copy(ints, 5, 4), getDs().find(IntVector.class)
.project("scalars", new ArraySlice(5, 4))
.get().scalars);
assertArrayEquals(copy(ints, ints.length - 10, 6), getDs().find(IntVector.class)
.project("scalars", new ArraySlice(-10, 6))
.get().scalars);
assertArrayEquals(copy(ints, ints.length - 12, 12), getDs().find(IntVector.class)
.project("scalars", new ArraySlice(-12))
.get().scalars);
}
@Test
public void testQBE() {
final CustomId cId = new CustomId();
cId.setId(new ObjectId());
cId.setType("banker");
final UsesCustomIdObject object = new UsesCustomIdObject();
object.setId(cId);
object.setText("hllo");
getDs().save(object);
final UsesCustomIdObject loaded;
// Add back if/when query by example for embedded fields is supported (require dotting each field).
// CustomId exId = new CustomId();
// exId.type = cId.type;
// loaded = getDs().find(UsesCustomIdObject.class, "_id", exId).get();
// assertNotNull(loaded);
final UsesCustomIdObject ex = new UsesCustomIdObject();
ex.setText(object.getText());
loaded = getDs().queryByExample(ex).get();
assertNotNull(loaded);
}
@Test
public void testQueryCount() {
getDs().save(asList(new Rectangle(1, 10),
new Rectangle(1, 10),
new Rectangle(1, 10),
new Rectangle(10, 10),
new Rectangle(10, 10)));
assertEquals(3, getDs().getCount(getDs().find(Rectangle.class).filter("height", 1D)));
assertEquals(2, getDs().getCount(getDs().find(Rectangle.class).filter("height", 10D)));
assertEquals(5, getDs().getCount(getDs().find(Rectangle.class).filter("width", 10D)));
}
@Test
public void testQueryOverLazyReference() {
final ContainsPic cpk = new ContainsPic();
final Pic p = new Pic();
getDs().save(p);
cpk.lazyPic = p;
getDs().save(cpk);
assertEquals(1, getDs().find(ContainsPic.class)
.field("lazyPic").equal(p)
.asList()
.size());
}
@Test
public void testQueryOverReference() {
final ContainsPic cpk = new ContainsPic();
final Pic p = new Pic();
getDs().save(p);
cpk.pic = p;
getDs().save(cpk);
final Query<ContainsPic> query = getDs().find(ContainsPic.class);
assertEquals(1, query.field("pic").equal(p).asList().size());
try {
getDs().find(ContainsPic.class).filter("pic.name", "foo").get();
assertNull("query validation should have thrown an exception");
} catch (ValidationException e) {
assertTrue(e.getMessage().contains("Cannot use dot-"));
}
}
@Test
public void testRangeQuery() {
getDs().save(asList(new Rectangle(1, 10), new Rectangle(4, 2), new Rectangle(6, 10), new Rectangle(8, 5), new Rectangle(10, 4)));
assertEquals(4, getDs().getCount(getDs().find(Rectangle.class).filter("height >", 3)));
assertEquals(3, getDs().getCount(getDs().find(Rectangle.class).filter("height >", 3).filter("height <", 10)));
assertEquals(1, getDs().getCount(getDs().find(Rectangle.class).filter("height >", 9).filter("width <", 5)));
assertEquals(3, getDs().getCount(getDs().find(Rectangle.class).filter("height <", 7)));
}
@Test(expected = ValidationException.class)
public void testReferenceQuery() {
final Photo p = new Photo();
final ContainsPhotoKey cpk = new ContainsPhotoKey();
cpk.photo = getDs().save(p);
getDs().save(cpk);
assertNotNull(getDs().find(ContainsPhotoKey.class).filter("photo", p).get());
assertNotNull(getDs().find(ContainsPhotoKey.class).filter("photo", cpk.photo).get());
assertNull(getDs().find(ContainsPhotoKey.class).filter("photo", 1).get());
getDs().find(ContainsPhotoKey.class).filter("photo.keywords", "foo").get();
}
@Test
public void testRegexInsensitiveQuery() {
getDs().save(new PhotoWithKeywords(new Keyword("california"), new Keyword("nevada"), new Keyword("arizona")));
final Pattern p = Pattern.compile("(?i)caLifornia");
assertNotNull(getDs().find(PhotoWithKeywords.class).disableValidation().filter("keywords.keyword", p).get());
assertNull(getDs().find(PhotoWithKeywords.class).filter("keywords.keyword", Pattern.compile("blah")).get());
}
@Test
public void testRegexQuery() {
getDs().save(new PhotoWithKeywords(new Keyword("california"), new Keyword("nevada"), new Keyword("arizona")));
assertNotNull(getDs().find(PhotoWithKeywords.class)
.disableValidation()
.filter("keywords.keyword", Pattern.compile("california"))
.get());
assertNull(getDs().find(PhotoWithKeywords.class).filter("keywords.keyword", Pattern.compile("blah")).get());
}
@Test
public void testRenamedFieldQuery() {
getDs().save(new ContainsRenamedFields("Scott", "Bakula"));
assertNotNull(getDs().find(ContainsRenamedFields.class).field("firstName").equal("Scott").get());
assertNotNull(getDs().find(ContainsRenamedFields.class).field("first_name").equal("Scott").get());
}
@Test
@SuppressWarnings("deprecation")
public void testRetrievedFields() {
getDs().save(new ContainsRenamedFields("Frank", "Zappa"));
ContainsRenamedFields found = getDs()
.find(ContainsRenamedFields.class)
.retrievedFields(true, "first_name")
.get();
assertNotNull(found.firstName);
assertNull(found.lastName);
found = getDs()
.find(ContainsRenamedFields.class)
.retrievedFields(true, "firstName")
.get();
assertNotNull(found.firstName);
assertNull(found.lastName);
try {
getDs()
.find(ContainsRenamedFields.class)
.retrievedFields(true, "bad field name")
.get();
fail("Validation should have caught the bad field");
} catch (ValidationException e) {
// success!
}
DBObject fields = getDs()
.find(ContainsRenamedFields.class)
.retrievedFields(true, "_id", "first_name").getFieldsObject();
assertNull(fields.get(Mapper.CLASS_NAME_FIELDNAME));
}
@Test
@SuppressWarnings("deprecation")
public void testReturnOnlyIndexedFields() {
getDs().save(asList(new Pic("pic1"), new Pic("pic2"), new Pic("pic3"), new Pic("pic4")));
getDs().ensureIndex(Pic.class, "name");
// When
// find a document by using a search on the field in the index
// Then
Pic foundItem = getDs().find(Pic.class)
.returnKey()
.field("name").equal("pic2")
.get();
assertNotNull(foundItem);
assertThat("Name should be populated", foundItem.getName(), is("pic2"));
assertNull("ID should not be populated", foundItem.getId());
}
@Test
public void testSimpleSort() {
getDs().save(asList(new Rectangle(1, 10), new Rectangle(3, 8), new Rectangle(6, 10), new Rectangle(10, 10), new Rectangle(10, 1)));
Rectangle r1 = getDs().find(Rectangle.class)
.order("width")
.get();
assertNotNull(r1);
assertEquals(1, r1.getWidth(), 0);
r1 = getDs().find(Rectangle.class)
.order("-width")
.get();
assertNotNull(r1);
assertEquals(10, r1.getWidth(), 0);
}
@Test
@SuppressWarnings("deprecation")
public void testSizeEqQuery() {
assertEquals(new BasicDBObject("keywords", new BasicDBObject("$size", 3)), getDs().find(PhotoWithKeywords.class)
.field("keywords")
.sizeEq(3).getQueryObject());
}
@Test
public void testSnapshottedQuery() {
getDs().delete(getDs().find(PhotoWithKeywords.class));
getDs().save(asList(new PhotoWithKeywords("scott", "hernandez"),
new PhotoWithKeywords("scott", "hernandez"),
new PhotoWithKeywords("scott", "hernandez")));
final Iterator<PhotoWithKeywords> it = getDs().find(PhotoWithKeywords.class)
.filter("keywords.keyword", "scott")
.fetch(new FindOptions()
.modifier("$snapshot", true)
.batchSize(2));
getDs().save(asList(new PhotoWithKeywords("1", "2"),
new PhotoWithKeywords("3", "4"),
new PhotoWithKeywords("5", "6")));
assertNotNull(it.next());
assertNotNull(it.next());
//okay, now we should getMore...
assertTrue(it.hasNext());
assertNotNull(it.next());
assertTrue(!it.hasNext());
}
@Test
public void testStartsWithQuery() {
getDs().save(new Photo());
Photo p = getDs().find(Photo.class).field("keywords").startsWith("amaz").get();
assertNotNull(p);
p = getDs().find(Photo.class).field("keywords").startsWith("notareal").get();
assertNull(p);
}
@Test
public void testTailableCursors() {
getMorphia().map(CappedPic.class);
getDs().ensureCaps();
final Query<CappedPic> query = getDs().find(CappedPic.class);
final List<CappedPic> found = new ArrayList<CappedPic>();
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
assertEquals(0, query.count());
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
getDs().save(new CappedPic(System.currentTimeMillis() + ""));
}
}, 0, 500, TimeUnit.MILLISECONDS);
final Iterator<CappedPic> tail = query
.fetch(new FindOptions()
.cursorType(CursorType.Tailable));
Awaitility
.await()
.pollDelay(500, TimeUnit.MILLISECONDS)
.atMost(10, TimeUnit.SECONDS)
.until(new Callable<Boolean>() {
@Override
public Boolean call() {
if (tail.hasNext()) {
found.add(tail.next());
}
return found.size() >= 10;
}
});
executorService.shutdownNow();
Assert.assertTrue(query.count() >= 10);
}
@Test
@SuppressWarnings("deprecation")
public void testThatElemMatchQueriesOnlyChecksRequiredFields() {
final PhotoWithKeywords pwk1 = new PhotoWithKeywords(new Keyword("california"), new Keyword("nevada"), new Keyword("arizona"));
final PhotoWithKeywords pwk2 = new PhotoWithKeywords("Joe", "Sarah");
pwk2.keywords.add(new Keyword("Scott", 14));
getDs().save(asList(pwk1, pwk2));
// In this case, we only want to match on the keyword field, not the
// score field, which shouldn't be included in the elemMatch query.
// As a result, the query in MongoDB should look like:
// find({ keywords: { $elemMatch: { keyword: "Scott" } } })
// NOT:
// find({ keywords: { $elemMatch: { keyword: "Scott", score: 12 } } })
assertNotNull(getDs().find(PhotoWithKeywords.class)
.field("keywords")
.hasThisElement(new Keyword("Scott")).get());
assertNotNull(getDs().find(PhotoWithKeywords.class)
.field("keywords").elemMatch(getDs().find(Keyword.class)
.filter("keyword", "Scott"))
.get());
assertNull(getDs().find(PhotoWithKeywords.class)
.field("keywords").hasThisElement(new Keyword("Randy"))
.get());
assertNull(getDs().find(PhotoWithKeywords.class)
.field("keywords").elemMatch(getDs().find(Keyword.class)
.filter("keyword", "Randy"))
.get());
}
@Test
public void testWhereCodeWScopeQuery() {
getDs().save(new PhotoWithKeywords(new Keyword("california"), new Keyword("nevada"), new Keyword("arizona")));
// CodeWScope hasKeyword = new CodeWScope("for (kw in this.keywords) { if(kw.keyword == kwd) return true; } return false;
// ", new BasicDBObject("kwd","california"));
final CodeWScope hasKeyword = new CodeWScope("this.keywords != null", new BasicDBObject());
assertNotNull(getDs().find(PhotoWithKeywords.class).where(hasKeyword).get());
}
@Test
public void testWhereStringQuery() {
getDs().save(new PhotoWithKeywords(new Keyword("california"), new Keyword("nevada"), new Keyword("arizona")));
assertNotNull(getDs().find(PhotoWithKeywords.class).where("this.keywords != null").get());
}
@Test
public void testWhereWithInvalidStringQuery() {
getDs().save(new PhotoWithKeywords());
final CodeWScope hasKeyword = new CodeWScope("keywords != null", new BasicDBObject());
try {
// must fail
assertNotNull(getDs().find(PhotoWithKeywords.class).where(hasKeyword.getCode()).get());
fail("Invalid javascript magically isn't invalid anymore?");
} catch (MongoInternalException e) {
// fine
} catch (MongoException e) {
// fine
}
}
@Test
public void testQueryUnmappedData() throws Exception {
getMorphia().map(Class1.class);
getDs().ensureIndexes(true);
getDs().getDB().getCollection("user").save(
new BasicDBObject()
.append("@class", Class1.class.getName())
.append("value1", "foo")
.append("someMap", new BasicDBObject("someKey", "value")));
Query<Class1> query = getDs().createQuery(Class1.class);
query.disableValidation().criteria("someMap.someKey").equal("value");
Class1 retrievedValue = query.get();
Assert.assertNotNull(retrievedValue);
Assert.assertEquals("foo", retrievedValue.value1);
}
@Entity(value = "user", noClassnameStored = true)
public static class Class1 {
@Id
private ObjectId id;
private String value1;
}
private int[] copy(final int[] array, final int start, final int count) {
return copyOfRange(array, start, start + count);
}
private void turnOffProfilingAndDropProfileCollection() {
getDb().command(new BasicDBObject("profile", 0));
DBCollection profileCollection = getDb().getCollection("system.profile");
profileCollection.drop();
}
@Entity
public static class Photo {
@Id
private ObjectId id;
private List<String> keywords = singletonList("amazing");
public Photo() {
}
public Photo(final List<String> keywords) {
this.keywords = keywords;
}
}
public static class PhotoWithKeywords {
@Id
private ObjectId id;
@Embedded
private List<Keyword> keywords = new ArrayList<Keyword>();
public PhotoWithKeywords() {
}
public PhotoWithKeywords(final String... words) {
keywords = new ArrayList<Keyword>(words.length);
for (final String word : words) {
keywords.add(new Keyword(word));
}
}
public PhotoWithKeywords(final Keyword... keyword) {
keywords.addAll(asList(keyword));
}
}
@Embedded(concreteClass = Keyword.class)
public static class Keyword {
private String keyword;
private Integer score;
protected Keyword() {
}
public Keyword(final String k) {
this.keyword = k;
}
public Keyword(final String k, final Integer score) {
this.keyword = k;
this.score = score;
}
public Keyword(final Integer score) {
this.score = score;
}
@Override
public int hashCode() {
int result = keyword != null ? keyword.hashCode() : 0;
result = 31 * result + (score != null ? score.hashCode() : 0);
return result;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Keyword)) {
return false;
}
final Keyword keyword1 = (Keyword) o;
if (keyword != null ? !keyword.equals(keyword1.keyword) : keyword1.keyword != null) {
return false;
}
return score != null ? score.equals(keyword1.score) : keyword1.score == null;
}
}
public static class ContainsPhotoKey {
@Id
private ObjectId id;
private Key<Photo> photo;
}
@Entity
public static class HasIntId {
@Id
private int id;
protected HasIntId() {
}
HasIntId(final int id) {
this.id = id;
}
}
@Entity
public static class ContainsPic {
@Id
private ObjectId id;
private String name = "test";
@Reference
private Pic pic;
@Reference(lazy = true)
private Pic lazyPic;
@Reference(lazy = true)
private PicWithObjectId lazyObjectIdPic;
@Indexed
private int size;
public ObjectId getId() {
return id;
}
public void setId(final ObjectId id) {
this.id = id;
}
public PicWithObjectId getLazyObjectIdPic() {
return lazyObjectIdPic;
}
public void setLazyObjectIdPic(final PicWithObjectId lazyObjectIdPic) {
this.lazyObjectIdPic = lazyObjectIdPic;
}
public Pic getLazyPic() {
return lazyPic;
}
public void setLazyPic(final Pic lazyPic) {
this.lazyPic = lazyPic;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public Pic getPic() {
return pic;
}
public void setPic(final Pic pic) {
this.pic = pic;
}
public int getSize() {
return size;
}
public void setSize(final int size) {
this.size = size;
}
}
@Entity
public static class PicWithObjectId {
@Id
private ObjectId id;
private String name;
}
@Entity
public static class Pic {
@Id
private ObjectId id;
private String name;
private boolean prePersist = false;
public Pic() {
}
public Pic(final String name) {
this.name = name;
}
public ObjectId getId() {
return id;
}
public void setId(final ObjectId id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public boolean isPrePersist() {
return prePersist;
}
public void setPrePersist(final boolean prePersist) {
this.prePersist = prePersist;
}
@PrePersist
public void tweak() {
prePersist = true;
}
}
@Entity(value = "capped_pic", cap = @CappedAt(count = 1000))
public static class CappedPic extends Pic {
public CappedPic() {
}
public CappedPic(final String name) {
super(name);
}
}
@Entity(noClassnameStored = true)
public static class ContainsRenamedFields {
@Id
private ObjectId id;
@Property("first_name")
private String firstName;
@Property("last_name")
private String lastName;
public ContainsRenamedFields() {
}
public ContainsRenamedFields(final String firstName, final String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
@Entity
static class KeyValue {
@Id
private ObjectId id;
/**
* The list of keys for this value.
*/
@Indexed(unique = true)
private List<Object> key;
/**
* The id of the value document
*/
@Indexed
private ObjectId value;
}
@Entity
static class GenericKeyValue<T> {
@Id
private ObjectId id;
@Indexed(unique = true)
private List<Object> key;
@Embedded
private T value;
}
@Entity
static class ReferenceKeyValue {
@Id
private ReferenceKey id;
/**
* The list of keys for this value.
*/
@Indexed(unique = true)
@Reference
private List<Pic> key;
/**
* The id of the value document
*/
@Indexed
private ObjectId value;
}
static class ReferenceKey {
@Id
private ObjectId id;
private String name;
ReferenceKey() {
}
ReferenceKey(final String name) {
this.name = name;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final ReferenceKey that = (ReferenceKey) o;
if (id != null ? !id.equals(that.id) : that.id != null) {
return false;
}
if (name != null ? !name.equals(that.name) : that.name != null) {
return false;
}
return true;
}
}
static class IntVector {
@Id
private ObjectId id;
private String name;
private int[] scalars;
public IntVector() {
}
public IntVector(final int... scalars) {
this.scalars = scalars;
}
}
private static class RectangleComparator implements Comparator<Rectangle> {
@Override
public int compare(final Rectangle o1, final Rectangle o2) {
int compare = Double.compare(o1.getWidth(), o2.getWidth());
return compare != 0 ? compare : Double.compare(o2.getHeight(), o1.getHeight());
}
}
private static class RectangleComparator1 implements Comparator<Rectangle> {
@Override
public int compare(final Rectangle o1, final Rectangle o2) {
int compare = Double.compare(o2.getHeight(), o1.getHeight());
return compare != 0 ? compare : Double.compare(o2.getWidth(), o1.getWidth());
}
}
private static class RectangleComparator2 implements Comparator<Rectangle> {
@Override
public int compare(final Rectangle o1, final Rectangle o2) {
int compare = Double.compare(o1.getWidth(), o2.getWidth());
return compare != 0 ? compare : Double.compare(o1.getHeight(), o2.getHeight());
}
}
private static class RectangleComparator3 implements Comparator<Rectangle> {
@Override
public int compare(final Rectangle o1, final Rectangle o2) {
int compare = Double.compare(o1.getWidth(), o2.getWidth());
return compare != 0 ? compare : Double.compare(o1.getHeight(), o2.getHeight());
}
}
void compareLists(final List<Rectangle> list, final Query<Rectangle> query1, final Query<Rectangle> query2,
final Comparator<Rectangle> comparator) {
Collections.sort(list, comparator);
assertEquals(query1.asList(), list);
assertEquals(query2.asList(), list);
}
}