From b8affdc59931aa059c8b0f26d693b2cba4dcf28e Mon Sep 17 00:00:00 2001 From: evanchooly Date: Fri, 24 May 2024 22:04:34 -0400 Subject: [PATCH] Discriminator added to all Queries when Polymorphism is not enabled fixes #2833 --- .../main/java/dev/morphia/mapping/Mapper.java | 11 +- .../java/dev/morphia/query/LegacyQuery.java | 13 +- .../mapping/codec/TestDocumentWriter.java | 2 - .../test/models/TestDiscriminatorEntity.java | 34 ++ .../dev/morphia/test/models/TestEntity.java | 1 + .../dev/morphia/test/query/TestQuery.java | 430 +++++++++--------- .../test/query/legacy/TestLegacyQuery.java | 311 +++++++------ 7 files changed, 441 insertions(+), 361 deletions(-) create mode 100644 core/src/test/java/dev/morphia/test/models/TestDiscriminatorEntity.java diff --git a/core/src/main/java/dev/morphia/mapping/Mapper.java b/core/src/main/java/dev/morphia/mapping/Mapper.java index 0d1a6e32cdb..eee60e60fd6 100644 --- a/core/src/main/java/dev/morphia/mapping/Mapper.java +++ b/core/src/main/java/dev/morphia/mapping/Mapper.java @@ -541,14 +541,19 @@ public void updateQueryWithDiscriminators(EntityModel model, Document query) { && !query.containsKey("_id") && !query.containsKey(model.getDiscriminatorKey())) { List values = new ArrayList<>(); - values.add(model.getDiscriminator()); + List classesMappedToCollection = getClassesMappedToCollection(model.getCollectionName()); + if (classesMappedToCollection.size() > 1 || config.enablePolymorphicQueries()) { + values.add(model.getDiscriminator()); + } if (config.enablePolymorphicQueries()) { for (EntityModel subtype : model.getSubtypes()) { values.add(subtype.getDiscriminator()); } } - query.put(model.getDiscriminatorKey(), - new Document("$in", values)); + if (!values.isEmpty()) { + query.put(model.getDiscriminatorKey(), + new Document("$in", values)); + } } } diff --git a/core/src/main/java/dev/morphia/query/LegacyQuery.java b/core/src/main/java/dev/morphia/query/LegacyQuery.java index db2370d3255..c7d125a2b77 100644 --- a/core/src/main/java/dev/morphia/query/LegacyQuery.java +++ b/core/src/main/java/dev/morphia/query/LegacyQuery.java @@ -1,6 +1,5 @@ package dev.morphia.query; -import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -24,6 +23,7 @@ import dev.morphia.annotations.Entity; import dev.morphia.annotations.internal.MorphiaInternal; import dev.morphia.internal.MorphiaInternals.DriverVersion; +import dev.morphia.mapping.Mapper; import dev.morphia.mapping.codec.pojo.EntityModel; import dev.morphia.query.internal.MorphiaCursor; import dev.morphia.query.internal.MorphiaKeyCursor; @@ -435,19 +435,16 @@ public Document getSort() { @MorphiaInternal public Document toDocument() { final Document query = getQueryDocument(); - EntityModel model = datastore.getMapper().getEntityModel(getEntityClass()); + Mapper mapper = datastore.getMapper(); + EntityModel model = mapper.getEntityModel(getEntityClass()); Entity entityAnnotation = model.getEntityAnnotation(); if (entityAnnotation != null && entityAnnotation.useDiscriminator() && !query.containsKey("_id") && !query.containsKey(model.getDiscriminatorKey())) { - List values = new ArrayList<>(); - values.add(model.getDiscriminator()); - for (EntityModel subtype : datastore.getMapper().getEntityModel(getEntityClass()).getSubtypes()) { - values.add(subtype.getDiscriminator()); + if (mapper.isMappable(getEntityClass())) { + mapper.updateQueryWithDiscriminators(mapper.getEntityModel(getEntityClass()), query); } - query.put(model.getDiscriminatorKey(), - new Document("$in", values)); } return query; } diff --git a/core/src/test/java/dev/morphia/test/mapping/codec/TestDocumentWriter.java b/core/src/test/java/dev/morphia/test/mapping/codec/TestDocumentWriter.java index 90d83b702c0..6d33f7c2e21 100644 --- a/core/src/test/java/dev/morphia/test/mapping/codec/TestDocumentWriter.java +++ b/core/src/test/java/dev/morphia/test/mapping/codec/TestDocumentWriter.java @@ -52,8 +52,6 @@ public void testOr() { of( new MergingDocument("$or", of(new Document("name", "A"), new Document("name", "B"))), new MergingDocument("$or", of(new Document("name", "C"), new Document("name", "D"))))); - System.out.println("document = " + document.toJson(JSON_WRITER_SETTINGS)); - System.out.println("expected = " + expected.toJson(JSON_WRITER_SETTINGS)); assertDocumentEquals(document, expected); } diff --git a/core/src/test/java/dev/morphia/test/models/TestDiscriminatorEntity.java b/core/src/test/java/dev/morphia/test/models/TestDiscriminatorEntity.java new file mode 100644 index 00000000000..694d8258ceb --- /dev/null +++ b/core/src/test/java/dev/morphia/test/models/TestDiscriminatorEntity.java @@ -0,0 +1,34 @@ +/* + Copyright (C) 2010 Olafur Gauti Gudmundsson +

+ 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 dev.morphia.test.models; + +import dev.morphia.annotations.Entity; +import dev.morphia.annotations.Id; + +import org.bson.types.ObjectId; + +@Entity +public class TestDiscriminatorEntity { + @Id + public ObjectId id; + public String something; + + public ObjectId getId() { + return id; + } + + public void setId(ObjectId id) { + this.id = id; + } +} diff --git a/core/src/test/java/dev/morphia/test/models/TestEntity.java b/core/src/test/java/dev/morphia/test/models/TestEntity.java index b024ef3090d..91b5830374e 100644 --- a/core/src/test/java/dev/morphia/test/models/TestEntity.java +++ b/core/src/test/java/dev/morphia/test/models/TestEntity.java @@ -22,6 +22,7 @@ public class TestEntity { @Id public ObjectId id; + public String something; public ObjectId getId() { return id; diff --git a/core/src/test/java/dev/morphia/test/query/TestQuery.java b/core/src/test/java/dev/morphia/test/query/TestQuery.java index 0891b7b5bbe..d648c4177ff 100644 --- a/core/src/test/java/dev/morphia/test/query/TestQuery.java +++ b/core/src/test/java/dev/morphia/test/query/TestQuery.java @@ -32,6 +32,7 @@ import dev.morphia.annotations.PrePersist; import dev.morphia.annotations.Property; import dev.morphia.annotations.Reference; +import dev.morphia.mapping.DiscriminatorFunction; import dev.morphia.query.ArraySlice; import dev.morphia.query.CountOptions; import dev.morphia.query.DefaultQueryFactory; @@ -46,6 +47,7 @@ import dev.morphia.test.models.Keys; import dev.morphia.test.models.Rectangle; import dev.morphia.test.models.Student; +import dev.morphia.test.models.TestDiscriminatorEntity; import dev.morphia.test.models.User; import dev.morphia.test.models.UsesCustomIdObject; @@ -95,19 +97,6 @@ public TestQuery() { .applyIndexes(true)); } - @Test - public void testNativeQuery() { - User user = getDs().save(new User("Malcolm 'Mal' Reynolds", now())); - assertEquals(getDs().find(User.class, new Document("_id", user.getId())).first(), user); - assertEquals(getDs().find(User.class, new Document()).filter(eq("id", user.getId())).first(), user); - - assertEquals(getDs().find(User.class, new Document("_id", user.getId())).first(), - user); - - assertEquals(getDs().find(User.class, new Document()).filter(eq("id", user.getId())).first(), - user); - } - @Test public void genericMultiKeyValueQueries() { checkMinDriverVersion(4.6); @@ -127,25 +116,6 @@ public void genericMultiKeyValueQueries() { assertTrue(loggedQuery.contains("{\"$in\": [\"key1\", \"key2\"]"), loggedQuery); } - @Test - public void testStreams() { - getMapper().map(City.class); - installData(); - - List list = getDs().find(City.class) - .stream(new FindOptions().limit(50)) - .map(City::getName) - .collect(Collectors.toList()); - assertEquals(list.size(), 50); - - int sum = getDs().find(City.class) - .stream() - .mapToInt(c -> 1) - .sum(); - - assertTrue(sum > 0, sum + ""); - } - @Test public void multiKeyValueQueries() { checkMinDriverVersion(4.6); @@ -419,6 +389,26 @@ public void testCommentsShowUpInLogs() { } } + private String getCommentFromProfileRecord(Document profileRecord) { + if (profileRecord != null) { + if (profileRecord.containsKey("command")) { + Document commandDocument = ((Document) profileRecord.get("command")); + if (commandDocument.containsKey("comment")) { + return (String) commandDocument.get("comment"); + } + } + if (profileRecord.containsKey("query")) { + Document queryDocument = ((Document) profileRecord.get("query")); + if (queryDocument.containsKey("comment")) { + return (String) queryDocument.get("comment"); + } else if (queryDocument.containsKey("$comment")) { + return (String) queryDocument.get("$comment"); + } + } + } + return null; + } + @Test public void testComplexElemMatchQuery() { Keyword oscar = new Keyword("Oscar", 42); @@ -518,6 +508,31 @@ public void testCriteriaContainers() { }); } + @SuppressWarnings("removal") + private void check(Query query) { + query.field("version").equal("latest") + .and( + query.or( + query.criteria("fieldA").equal("a"), + query.criteria("fieldB").equal("b")), + query.and( + query.criteria("fieldC").equal("c"), + query.or( + query.criteria("fieldD").equal("d"), + query.criteria("fieldE").equal("e")))); + + query.and(query.criteria("fieldF").equal("f")); + + final Document queryObject = query.toDocument(); + + final Document parse = parse( + "{\"version\": \"latest\", \"$and\": [{\"$or\": [{\"fieldA\": \"a\"}, {\"fieldB\": \"b\"}]}, {\"fieldC\": \"c\", \"$or\": " + + "[{\"fieldD\": \"d\"}, {\"fieldE\": \"e\"}]}], \"fieldF\": \"f\"," + + "\"_t\": { \"$in\" : [ \"User\"]}}"); + + assertEquals(parse, queryObject); + } + @Test public void testDeepQuery() { getDs().save(new PhotoWithKeywords(new Keyword("california"), new Keyword("nevada"), new Keyword("arizona"))); @@ -602,6 +617,12 @@ public void testElemMatchVariants() { .iterator()); } + private void assertListEquals(List list, MongoCursor cursor) { + for (T t : list) { + assertEquals(cursor.next(), t, list.toString()); + } + } + @Test public void testFetchKeys() { PhotoWithKeywords pwk1 = new PhotoWithKeywords("california", "nevada", "arizona"); @@ -847,6 +868,19 @@ public void testMultipleConstraintsOnOneField() { assertEquals(inputStage.get("stage"), "IXSCAN"); } + @Test + public void testNativeQuery() { + User user = getDs().save(new User("Malcolm 'Mal' Reynolds", now())); + assertEquals(getDs().find(User.class, new Document("_id", user.getId())).first(), user); + assertEquals(getDs().find(User.class, new Document()).filter(eq("id", user.getId())).first(), user); + + assertEquals(getDs().find(User.class, new Document("_id", user.getId())).first(), + user); + + assertEquals(getDs().find(User.class, new Document()).filter(eq("id", user.getId())).first(), + user); + } + @Test public void testNaturalSortAscending() { getDs().save(asList(new Rectangle(6, 10), new Rectangle(3, 8), new Rectangle(10, 10), new Rectangle(10, 1))); @@ -1011,6 +1045,10 @@ public void testProjectArrayField() { .next().scalars); } + private int[] copy(int[] array, int start, int count) { + return copyOfRange(array, start, start + count); + } + @Test public void testQBE() { final CustomId cId = new CustomId(); @@ -1056,6 +1094,22 @@ public void testQueryCount() { } + @Test + public void testQueryDoesNotContainDiscriminator() { + withConfig(buildConfig(TestDiscriminatorEntity.class) + .discriminator(DiscriminatorFunction.className()) + .enablePolymorphicQueries(false), () -> { + + Datastore datastore = getDs(); + Query q = datastore.createQuery(TestDiscriminatorEntity.class); + q.filter(eq("something", "foo")); + Document doc = q.toDocument(); + System.out.println(doc); + assertFalse(doc.containsKey("_t"), "The discriminator was found in the query document: \n" + + doc.toJson(JSON_WRITER_SETTINGS)); + }); + } + @Test public void testQueryOverLazyReference() { final ContainsPic cpk = new ContainsPic(); @@ -1228,6 +1282,25 @@ public void testSimpleSort() { assertEquals(r1.getWidth(), 10, 0); } + @Test + public void testStreams() { + getMapper().map(City.class); + installData(); + + List list = getDs().find(City.class) + .stream(new FindOptions().limit(50)) + .map(City::getName) + .collect(Collectors.toList()); + assertEquals(list.size(), 50); + + int sum = getDs().find(City.class) + .stream() + .mapToInt(c -> 1) + .sum(); + + assertTrue(sum > 0, sum + ""); + } + @Test public void testTailableCursors() { final Datastore ds = getDs(); @@ -1290,66 +1363,11 @@ public void testThatElemMatchQueriesOnlyChecksRequiredFields() { .tryNext()); } - private void assertListEquals(List list, MongoCursor cursor) { - for (T t : list) { - assertEquals(cursor.next(), t, list.toString()); - } - } - - @SuppressWarnings("removal") - private void check(Query query) { - query.field("version").equal("latest") - .and( - query.or( - query.criteria("fieldA").equal("a"), - query.criteria("fieldB").equal("b")), - query.and( - query.criteria("fieldC").equal("c"), - query.or( - query.criteria("fieldD").equal("d"), - query.criteria("fieldE").equal("e")))); - - query.and(query.criteria("fieldF").equal("f")); - - final Document queryObject = query.toDocument(); - - final Document parse = parse( - "{\"version\": \"latest\", \"$and\": [{\"$or\": [{\"fieldA\": \"a\"}, {\"fieldB\": \"b\"}]}, {\"fieldC\": \"c\", \"$or\": " - + "[{\"fieldD\": \"d\"}, {\"fieldE\": \"e\"}]}], \"fieldF\": \"f\"," - + "\"_t\": { \"$in\" : [ \"User\"]}}"); - - assertEquals(parse, queryObject); - } - - private int[] copy(int[] array, int start, int count) { - return copyOfRange(array, start, start + count); - } - private void dropProfileCollection() { MongoCollection profileCollection = getDatabase().getCollection("system.profile"); profileCollection.drop(); } - private String getCommentFromProfileRecord(Document profileRecord) { - if (profileRecord != null) { - if (profileRecord.containsKey("command")) { - Document commandDocument = ((Document) profileRecord.get("command")); - if (commandDocument.containsKey("comment")) { - return (String) commandDocument.get("comment"); - } - } - if (profileRecord.containsKey("query")) { - Document queryDocument = ((Document) profileRecord.get("query")); - if (queryDocument.containsKey("comment")) { - return (String) queryDocument.get("comment"); - } else if (queryDocument.containsKey("$comment")) { - return (String) queryDocument.get("$comment"); - } - } - } - return null; - } - private Query getQuery(QueryFactory queryFactory) { return queryFactory.createQuery(getDs(), Pic.class); } @@ -1373,30 +1391,21 @@ public CappedPic() { } } - @Entity(value = "user", useDiscriminator = false) - private static class Class1 { - @Id - private ObjectId id; - - private String value1; - - } - @Entity public static class ContainsPic { @Id private ObjectId id; - private String name = "test"; - - @Reference - private Pic pic; + @Reference(lazy = true) + private PicWithObjectId lazyObjectIdPic; @Reference(lazy = true) private Pic lazyPic; - @Reference(lazy = true) - private PicWithObjectId lazyObjectIdPic; + private String name = "test"; + + @Reference + private Pic pic; @Indexed private int size; @@ -1461,12 +1470,12 @@ public String toString() { @Entity(useDiscriminator = false) public static class ContainsRenamedFields { - @Id - private ObjectId id; - @Property("first_name") private String firstName; + @Id + private ObjectId id; + @Property("last_name") private String lastName; @@ -1479,18 +1488,6 @@ public ContainsRenamedFields() { } } - @Entity - private static class GenericKeyValue { - - @Id - private ObjectId id; - - @Indexed(options = @IndexOptions(unique = true)) - private List key; - - private T value; - } - @Entity public static class HasIntId { @Id @@ -1504,50 +1501,6 @@ protected HasIntId() { } } - @Entity - private static class HasPhotoReference { - @Id - private ObjectId id; - - @Reference - private Photo photo; - } - - @Entity - static class IntVector { - @Id - private ObjectId id; - - private String name; - - private int[] scalars; - - IntVector() { - } - - IntVector(int... scalars) { - this.scalars = scalars; - } - } - - @Entity - private static class KeyValue { - @Id - private ObjectId id; - - /** - * The list of keys for this value. - */ - @Indexed(options = @IndexOptions(unique = true)) - private List key; - - /** - * The id of the value document - */ - @Indexed - private ObjectId value; - } - @Entity public static class Keyword { private String keyword; @@ -1677,6 +1630,14 @@ public Pic() { this.name = name; } + @Override + public int hashCode() { + int result = getId() != null ? getId().hashCode() : 0; + result = 31 * result + (getName() != null ? getName().hashCode() : 0); + result = 31 * result + (isPrePersist() ? 1 : 0); + return result; + } + public ObjectId getId() { return id; } @@ -1693,12 +1654,12 @@ public void setName(String name) { this.name = name; } - @Override - public int hashCode() { - int result = getId() != null ? getId().hashCode() : 0; - result = 31 * result + (getName() != null ? getName().hashCode() : 0); - result = 31 * result + (isPrePersist() ? 1 : 0); - return result; + boolean isPrePersist() { + return prePersist; + } + + public void setPrePersist(boolean prePersist) { + this.prePersist = prePersist; } @Override @@ -1725,14 +1686,6 @@ public boolean equals(Object o) { public void tweak() { prePersist = true; } - - boolean isPrePersist() { - return prePersist; - } - - public void setPrePersist(boolean prePersist) { - this.prePersist = prePersist; - } } @Entity @@ -1743,35 +1696,20 @@ public static class PicWithObjectId { private String name; } - private static class RectangleComparator implements Comparator { - @Override - public int compare(Rectangle o1, Rectangle o2) { - int compare = Double.compare(o1.getWidth(), o2.getWidth()); - return compare != 0 ? compare : Double.compare(o2.getHeight(), o1.getHeight()); - } - } + @Entity + static class IntVector { + @Id + private ObjectId id; - private static class RectangleComparator1 implements Comparator { - @Override - public int compare(Rectangle o1, Rectangle o2) { - int compare = Double.compare(o2.getHeight(), o1.getHeight()); - return compare != 0 ? compare : Double.compare(o2.getWidth(), o1.getWidth()); - } - } + private String name; - private static class RectangleComparator2 implements Comparator { - @Override - public int compare(Rectangle o1, Rectangle o2) { - int compare = Double.compare(o1.getWidth(), o2.getWidth()); - return compare != 0 ? compare : Double.compare(o1.getHeight(), o2.getHeight()); + private int[] scalars; + + IntVector() { } - } - private static class RectangleComparator3 implements Comparator { - @Override - public int compare(Rectangle o1, Rectangle o2) { - int compare = Double.compare(o1.getWidth(), o2.getWidth()); - return compare != 0 ? compare : Double.compare(o1.getHeight(), o2.getHeight()); + IntVector(int... scalars) { + this.scalars = scalars; } } @@ -1814,6 +1752,92 @@ public boolean equals(Object o) { } } + static class UserImpl implements UserInterface { + @Id + @SuppressWarnings("unused") + private ObjectId id; + } + + @Entity(value = "user", useDiscriminator = false) + private static class Class1 { + @Id + private ObjectId id; + + private String value1; + + } + + @Entity + private static class GenericKeyValue { + + @Id + private ObjectId id; + + @Indexed(options = @IndexOptions(unique = true)) + private List key; + + private T value; + } + + @Entity + private static class HasPhotoReference { + @Id + private ObjectId id; + + @Reference + private Photo photo; + } + + @Entity + private static class KeyValue { + @Id + private ObjectId id; + + /** + * The list of keys for this value. + */ + @Indexed(options = @IndexOptions(unique = true)) + private List key; + + /** + * The id of the value document + */ + @Indexed + private ObjectId value; + } + + private static class RectangleComparator implements Comparator { + @Override + public int compare(Rectangle o1, 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 { + @Override + public int compare(Rectangle o1, 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 { + @Override + public int compare(Rectangle o1, 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 { + @Override + public int compare(Rectangle o1, Rectangle o2) { + int compare = Double.compare(o1.getWidth(), o2.getWidth()); + return compare != 0 ? compare : Double.compare(o1.getHeight(), o2.getHeight()); + } + } + @Entity private static class ReferenceKeyValue { @Id @@ -1832,10 +1856,4 @@ private static class ReferenceKeyValue { @Indexed private ObjectId value; } - - static class UserImpl implements UserInterface { - @Id - @SuppressWarnings("unused") - private ObjectId id; - } } diff --git a/core/src/test/java/dev/morphia/test/query/legacy/TestLegacyQuery.java b/core/src/test/java/dev/morphia/test/query/legacy/TestLegacyQuery.java index 6b45408d8e4..d90725c3a45 100644 --- a/core/src/test/java/dev/morphia/test/query/legacy/TestLegacyQuery.java +++ b/core/src/test/java/dev/morphia/test/query/legacy/TestLegacyQuery.java @@ -28,9 +28,11 @@ import dev.morphia.annotations.PrePersist; import dev.morphia.annotations.Property; import dev.morphia.annotations.Reference; +import dev.morphia.mapping.DiscriminatorFunction; import dev.morphia.query.ArraySlice; import dev.morphia.query.CountOptions; import dev.morphia.query.FindOptions; +import dev.morphia.query.LegacyQueryFactory; import dev.morphia.query.Query; import dev.morphia.query.QueryFactory; import dev.morphia.query.ValidationException; @@ -40,6 +42,7 @@ import dev.morphia.test.mapping.TestReferences.Complex; import dev.morphia.test.models.Hotel; import dev.morphia.test.models.Rectangle; +import dev.morphia.test.models.TestDiscriminatorEntity; import dev.morphia.test.models.User; import dev.morphia.test.query.TestQuery; import dev.morphia.test.query.TestQuery.CappedPic; @@ -82,19 +85,6 @@ public TestLegacyQuery() { .legacy()); } - @Test - public void testNativeQuery() { - User user = getDs().save(new User("Malcolm 'Mal' Reynolds", now())); - - assertEquals(getDs().find(User.class, new Document("_id", user.getId())).first(), - user); - - assertEquals(getDs().find(User.class, new Document()) - .field("id").equal(user.getId()) - .first(), - user); - } - @Test @SuppressWarnings("rawtypes") public void genericMultiKeyValueQueries() { @@ -339,6 +329,26 @@ public void testCommentsShowUpInLogs() { } } + private String getCommentFromProfileRecord(Document profileRecord) { + if (profileRecord != null) { + if (profileRecord.containsKey("command")) { + Document commandDocument = ((Document) profileRecord.get("command")); + if (commandDocument.containsKey("comment")) { + return (String) commandDocument.get("comment"); + } + } + if (profileRecord.containsKey("query")) { + Document queryDocument = ((Document) profileRecord.get("query")); + if (queryDocument.containsKey("comment")) { + return (String) queryDocument.get("comment"); + } else if (queryDocument.containsKey("$comment")) { + return (String) queryDocument.get("$comment"); + } + } + } + return null; + } + @Test public void testComplexElemMatchQuery() { Keyword oscar = new Keyword("Oscar", 42); @@ -406,6 +416,30 @@ public void testCriteriaContainers() { check(getDs().find(User.class).disableValidation()); } + private void check(Query query) { + query + .field("version").equal("latest") + .and( + query.or( + query.criteria("fieldA").equal("a"), + query.criteria("fieldB").equal("b")), + query.and( + query.criteria("fieldC").equal("c"), + query.or( + query.criteria("fieldD").equal("d"), + query.criteria("fieldE").equal("e")))); + + query.and(query.criteria("fieldF").equal("f")); + + final Document queryObject = query.toDocument(); + + final Document parse = parse( + "{\"version\": \"latest\", \"$and\": [{\"$or\": [{\"fieldA\": \"a\"}, {\"fieldB\": \"b\"}]}, {\"fieldC\": \"c\", \"$or\": " + + "[{\"fieldD\": \"d\"}, {\"fieldE\": \"e\"}]}], \"fieldF\": \"f\"}}"); + + assertEquals(queryObject, parse); + } + @Test public void testDeepQuery() { getDs().save(new PhotoWithKeywords(new Keyword("california"), new Keyword("nevada"), new Keyword("arizona"))); @@ -528,6 +562,12 @@ public void testElemMatchVariants() { .keys()); } + private void assertListEquals(List> list, MongoCursor cursor) { + for (Key tKey : list) { + assertEquals(cursor.next(), tKey, list.toString()); + } + } + @Test public void testFetchKeys() { PhotoWithKeywords pwk1 = new PhotoWithKeywords("california", "nevada", "arizona"); @@ -769,6 +809,19 @@ public void testMultipleConstraintsOnOneField() { assertEquals(inputStage.get("stage"), "IXSCAN"); } + @Test + public void testNativeQuery() { + User user = getDs().save(new User("Malcolm 'Mal' Reynolds", now())); + + assertEquals(getDs().find(User.class, new Document("_id", user.getId())).first(), + user); + + assertEquals(getDs().find(User.class, new Document()) + .field("id").equal(user.getId()) + .first(), + user); + } + @Test public void testNaturalSortAscending() { getDs().save(asList(new Rectangle(6, 10), new Rectangle(3, 8), new Rectangle(10, 10), new Rectangle(10, 1))); @@ -918,6 +971,10 @@ public void testProjectArrayField() { .next().scalars); } + private int[] copy(int[] array, int start, int count) { + return copyOfRange(array, start, start + count); + } + @Test public void testQueryCount() { getDs().save(asList(new Rectangle(1, 10), @@ -932,6 +989,22 @@ public void testQueryCount() { } + @Test + public void testQueryDoesNotContainDiscriminator() { + withConfig(buildConfig(TestDiscriminatorEntity.class) + .discriminator(DiscriminatorFunction.className()) + .queryFactory(new LegacyQueryFactory()) + .enablePolymorphicQueries(false), () -> { + + Datastore datastore = getDs(); + Query q = datastore.createQuery(TestDiscriminatorEntity.class); + q.field("something").equal("foo"); + Document doc = q.toDocument(); + assertFalse(doc.containsKey("_t"), "The discriminator was found in the query document: \n" + + doc.toJson(JSON_WRITER_SETTINGS)); + }); + } + @Test public void testQueryOverLazyReference() { final ContainsPic cpk = new ContainsPic(); @@ -1185,66 +1258,11 @@ public void testThatElemMatchQueriesOnlyChecksRequiredFields() { .tryNext()); } - private void assertListEquals(List> list, MongoCursor cursor) { - for (Key tKey : list) { - assertEquals(cursor.next(), tKey, list.toString()); - } - } - - private void check(Query query) { - query - .field("version").equal("latest") - .and( - query.or( - query.criteria("fieldA").equal("a"), - query.criteria("fieldB").equal("b")), - query.and( - query.criteria("fieldC").equal("c"), - query.or( - query.criteria("fieldD").equal("d"), - query.criteria("fieldE").equal("e")))); - - query.and(query.criteria("fieldF").equal("f")); - - final Document queryObject = query.toDocument(); - - final Document parse = parse( - "{\"version\": \"latest\", \"$and\": [{\"$or\": [{\"fieldA\": \"a\"}, {\"fieldB\": \"b\"}]}, {\"fieldC\": \"c\", \"$or\": " - + "[{\"fieldD\": \"d\"}, {\"fieldE\": \"e\"}]}], \"fieldF\": \"f\"," - + "\"className\": { \"$in\" : [ \"dev.morphia.test.models.User\"]}}"); - - assertEquals(queryObject, parse); - } - - private int[] copy(int[] array, int start, int count) { - return copyOfRange(array, start, start + count); - } - private void dropProfileCollection() { MongoCollection profileCollection = getDatabase().getCollection("system.profile"); profileCollection.drop(); } - private String getCommentFromProfileRecord(Document profileRecord) { - if (profileRecord != null) { - if (profileRecord.containsKey("command")) { - Document commandDocument = ((Document) profileRecord.get("command")); - if (commandDocument.containsKey("comment")) { - return (String) commandDocument.get("comment"); - } - } - if (profileRecord.containsKey("query")) { - Document queryDocument = ((Document) profileRecord.get("query")); - if (queryDocument.containsKey("comment")) { - return (String) queryDocument.get("comment"); - } else if (queryDocument.containsKey("$comment")) { - return (String) queryDocument.get("$comment"); - } - } - } - return null; - } - private Query getQuery(QueryFactory queryFactory) { return queryFactory.createQuery(getDs(), Pic.class); } @@ -1257,6 +1275,59 @@ private void turnOnProfiling() { getDatabase().runCommand(new Document("profile", 2).append("slowms", 0)); } + @Entity + static class IntVector { + @Id + private ObjectId id; + private String name; + private int[] scalars; + + IntVector() { + } + + IntVector(int... scalars) { + this.scalars = scalars; + } + } + + @Entity + static class ReferenceKey { + @Id + private ObjectId id; + private String name; + + ReferenceKey() { + } + + ReferenceKey(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(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; + } + return name != null ? name.equals(that.name) : that.name == null; + } + } + @Entity(value = "legacy_capped_pic", cap = @CappedAt(count = 1000)) private static class CappedPic extends Pic { public CappedPic() { @@ -1277,13 +1348,18 @@ private static class Class1 { private static class ContainsPic { @Id private ObjectId id; + + @Reference(lazy = true) + private PicWithObjectId lazyObjectIdPic; + + @Reference(lazy = true) + private Pic lazyPic; + private String name = "test"; + @Reference private Pic pic; - @Reference(lazy = true) - private Pic lazyPic; - @Reference(lazy = true) - private PicWithObjectId lazyObjectIdPic; + @Indexed private int size; @@ -1347,10 +1423,12 @@ public String toString() { @Entity(useDiscriminator = false) private static class ContainsRenamedFields { - @Id - private ObjectId id; @Property("first_name") private String firstName; + + @Id + private ObjectId id; + @Property("last_name") private String lastName; @@ -1419,21 +1497,6 @@ private static class HasPhotoReference { private Photo photo; } - @Entity - static class IntVector { - @Id - private ObjectId id; - private String name; - private int[] scalars; - - IntVector() { - } - - IntVector(int... scalars) { - this.scalars = scalars; - } - } - @Entity private static class KeyValue { @Id @@ -1455,9 +1518,11 @@ private static class KeyValue { private static class Keys { @Id private ObjectId id; - private List> users; + private Key rect; + private List> users; + private Keys() { } @@ -1578,6 +1643,14 @@ public Pic() { this.name = name; } + @Override + public int hashCode() { + int result = getId() != null ? getId().hashCode() : 0; + result = 31 * result + (getName() != null ? getName().hashCode() : 0); + result = 31 * result + (isPrePersist() ? 1 : 0); + return result; + } + public ObjectId getId() { return id; } @@ -1594,12 +1667,12 @@ public void setName(String name) { this.name = name; } - @Override - public int hashCode() { - int result = getId() != null ? getId().hashCode() : 0; - result = 31 * result + (getName() != null ? getName().hashCode() : 0); - result = 31 * result + (isPrePersist() ? 1 : 0); - return result; + boolean isPrePersist() { + return prePersist; + } + + public void setPrePersist(boolean prePersist) { + this.prePersist = prePersist; } @Override @@ -1626,14 +1699,6 @@ public boolean equals(Object o) { public void tweak() { prePersist = true; } - - boolean isPrePersist() { - return prePersist; - } - - public void setPrePersist(boolean prePersist) { - this.prePersist = prePersist; - } } @Entity @@ -1675,44 +1740,6 @@ public int compare(Rectangle o1, Rectangle o2) { } } - @Entity - static class ReferenceKey { - @Id - private ObjectId id; - private String name; - - ReferenceKey() { - } - - ReferenceKey(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(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; - } - return name != null ? name.equals(that.name) : that.name == null; - } - } - @Entity private static class ReferenceKeyValue { @Id