summaryrefslogtreecommitdiff
path: root/src/mongo/db/matcher
diff options
context:
space:
mode:
authorBlake Oler <blake.oler@10gen.com>2017-09-11 13:26:16 -0400
committerBlake Oler <blake.oler@10gen.com>2017-09-12 13:24:44 -0400
commit33cb4a950c5de3c1c783b25ecf0fd4454cce844a (patch)
tree02220841b1d28906053395dc3c74b7e33afc11fe /src/mongo/db/matcher
parent152ade06b7c7db03d358d42f41a961b3e8787a35 (diff)
downloadmongo-33cb4a950c5de3c1c783b25ecf0fd4454cce844a.tar.gz
SERVER-30717 Serialize OrMatchExpression to {$alwaysFalse: 1}
Diffstat (limited to 'src/mongo/db/matcher')
-rw-r--r--src/mongo/db/matcher/expression_always_boolean.h8
-rw-r--r--src/mongo/db/matcher/expression_parser.cpp2
-rw-r--r--src/mongo/db/matcher/expression_parser_test.cpp23
-rw-r--r--src/mongo/db/matcher/expression_serialization_test.cpp24
-rw-r--r--src/mongo/db/matcher/expression_tree.cpp5
-rw-r--r--src/mongo/db/matcher/expression_with_placeholder_test.cpp9
-rw-r--r--src/mongo/db/matcher/schema/json_schema_parser_test.cpp8
7 files changed, 53 insertions, 26 deletions
diff --git a/src/mongo/db/matcher/expression_always_boolean.h b/src/mongo/db/matcher/expression_always_boolean.h
index 1625dcf7394..a22b8b1e479 100644
--- a/src/mongo/db/matcher/expression_always_boolean.h
+++ b/src/mongo/db/matcher/expression_always_boolean.h
@@ -87,10 +87,12 @@ private:
class AlwaysFalseMatchExpression final : public AlwaysBooleanMatchExpression {
public:
+ static constexpr StringData kName = "$alwaysFalse"_sd;
+
AlwaysFalseMatchExpression() : AlwaysBooleanMatchExpression(MatchType::ALWAYS_FALSE, false) {}
StringData name() const final {
- return "$alwaysFalse"_sd;
+ return kName;
}
std::unique_ptr<MatchExpression> shallowClone() const final {
@@ -100,10 +102,12 @@ public:
class AlwaysTrueMatchExpression final : public AlwaysBooleanMatchExpression {
public:
+ static constexpr StringData kName = "$alwaysTrue"_sd;
+
AlwaysTrueMatchExpression() : AlwaysBooleanMatchExpression(MatchType::ALWAYS_TRUE, true) {}
StringData name() const final {
- return "$alwaysTrue"_sd;
+ return kName;
}
std::unique_ptr<MatchExpression> shallowClone() const final {
diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp
index ba80393ccc8..1f55da8ef0f 100644
--- a/src/mongo/db/matcher/expression_parser.cpp
+++ b/src/mongo/db/matcher/expression_parser.cpp
@@ -101,6 +101,8 @@ const boost::container::flat_set<StringData> topLevelOperators{"$_internalSchema
namespace mongo {
constexpr StringData MatchExpressionParser::kAggExpression;
+constexpr StringData AlwaysFalseMatchExpression::kName;
+constexpr StringData AlwaysTrueMatchExpression::kName;
using std::string;
using stdx::make_unique;
diff --git a/src/mongo/db/matcher/expression_parser_test.cpp b/src/mongo/db/matcher/expression_parser_test.cpp
index 0caafd75f92..9d9fe4d7856 100644
--- a/src/mongo/db/matcher/expression_parser_test.cpp
+++ b/src/mongo/db/matcher/expression_parser_test.cpp
@@ -35,6 +35,7 @@
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
#include "mongo/db/matcher/expression.h"
+#include "mongo/db/matcher/expression_always_boolean.h"
#include "mongo/db/matcher/expression_leaf.h"
#include "mongo/db/matcher/extensions_callback_noop.h"
#include "mongo/db/pipeline/expression_context_for_test.h"
@@ -225,26 +226,25 @@ TEST(StatusWithTest, Fib1) {
}
TEST(MatchExpressionParserTest, AlwaysFalseFailsToParseNonOneArguments) {
- auto queryIntArgument = BSON("$alwaysFalse" << 0);
+ auto queryIntArgument = BSON(AlwaysFalseMatchExpression::kName << 0);
auto expr = MatchExpressionParser::parse(queryIntArgument, nullptr);
ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse);
- auto queryStringArgument = BSON("$alwaysFalse"
- << "");
+ auto queryStringArgument = BSON(AlwaysFalseMatchExpression::kName << "");
expr = MatchExpressionParser::parse(queryStringArgument, nullptr);
ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse);
- auto queryDoubleArgument = BSON("$alwaysFalse" << 1.1);
+ auto queryDoubleArgument = BSON(AlwaysFalseMatchExpression::kName << 1.1);
expr = MatchExpressionParser::parse(queryDoubleArgument, nullptr);
ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse);
- auto queryFalseArgument = BSON("$alwaysFalse" << true);
+ auto queryFalseArgument = BSON(AlwaysFalseMatchExpression::kName << true);
expr = MatchExpressionParser::parse(queryFalseArgument, nullptr);
ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse);
}
TEST(MatchExpressionParserTest, AlwaysFalseParsesIntegerArgument) {
- auto query = BSON("$alwaysFalse" << 1);
+ auto query = BSON(AlwaysFalseMatchExpression::kName << 1);
auto expr = MatchExpressionParser::parse(query, nullptr);
ASSERT_OK(expr.getStatus());
@@ -254,26 +254,25 @@ TEST(MatchExpressionParserTest, AlwaysFalseParsesIntegerArgument) {
}
TEST(MatchExpressionParserTest, AlwaysTrueFailsToParseNonOneArguments) {
- auto queryIntArgument = BSON("$alwaysTrue" << 0);
+ auto queryIntArgument = BSON(AlwaysTrueMatchExpression::kName << 0);
auto expr = MatchExpressionParser::parse(queryIntArgument, nullptr);
ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse);
- auto queryStringArgument = BSON("$alwaysTrue"
- << "");
+ auto queryStringArgument = BSON(AlwaysTrueMatchExpression::kName << "");
expr = MatchExpressionParser::parse(queryStringArgument, nullptr);
ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse);
- auto queryDoubleArgument = BSON("$alwaysTrue" << 1.1);
+ auto queryDoubleArgument = BSON(AlwaysTrueMatchExpression::kName << 1.1);
expr = MatchExpressionParser::parse(queryDoubleArgument, nullptr);
ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse);
- auto queryFalseArgument = BSON("$alwaysTrue" << true);
+ auto queryFalseArgument = BSON(AlwaysTrueMatchExpression::kName << true);
expr = MatchExpressionParser::parse(queryFalseArgument, nullptr);
ASSERT_EQ(expr.getStatus(), ErrorCodes::FailedToParse);
}
TEST(MatchExpressionParserTest, AlwaysTrueParsesIntegerArgument) {
- auto query = BSON("$alwaysTrue" << 1);
+ auto query = BSON(AlwaysTrueMatchExpression::kName << 1);
auto expr = MatchExpressionParser::parse(query, nullptr);
ASSERT_OK(expr.getStatus());
diff --git a/src/mongo/db/matcher/expression_serialization_test.cpp b/src/mongo/db/matcher/expression_serialization_test.cpp
index 2d2bd3127fc..4ae5a56848d 100644
--- a/src/mongo/db/matcher/expression_serialization_test.cpp
+++ b/src/mongo/db/matcher/expression_serialization_test.cpp
@@ -32,6 +32,7 @@
#include "mongo/db/json.h"
#include "mongo/db/matcher/expression.h"
+#include "mongo/db/matcher/expression_always_boolean.h"
#include "mongo/db/matcher/expression_parser.h"
#include "mongo/db/matcher/extensions_callback_noop.h"
#include "mongo/db/matcher/matcher.h"
@@ -142,6 +143,19 @@ TEST(SerializeBasic, ExpressionOr) {
ASSERT_EQ(original.matches(obj), reserialized.matches(obj));
}
+TEST(SerializeBasic, ExpressionOrWithNoChildrenSerializesCorrectly) {
+ boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
+ // We construct an OrMatchExpression directly rather than using the match expression
+ // parser, since the parser does not permit a $or with no children.
+ OrMatchExpression original;
+ Matcher reserialized(serialize(&original),
+ kSimpleCollator,
+ expCtx,
+ ExtensionsCallbackNoop(),
+ MatchExpressionParser::kAllowAllSpecialFeatures);
+ ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), BSON(AlwaysFalseMatchExpression::kName << 1));
+}
+
TEST(SerializeBasic, ExpressionElemMatchObjectSerializesCorrectly) {
boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
Matcher original(fromjson("{x: {$elemMatch: {a: {$gt: 0}, b: {$gt: 0}}}}"),
@@ -323,7 +337,7 @@ TEST(SerializeBasic, ExpressionAllWithEmptyArraySerializesCorrectly) {
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
- ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$alwaysFalse: 1}"));
+ ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), BSON(AlwaysFalseMatchExpression::kName << 1));
ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression()));
BSONObj obj = fromjson("{x: [1, 2, 3]}");
@@ -1444,7 +1458,7 @@ TEST(SerializeBasic, ExpressionTextWithDefaultLanguageSerializesCorrectly) {
TEST(SerializeBasic, ExpressionAlwaysTrueSerializesCorrectly) {
boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
- Matcher original(fromjson("{$alwaysTrue: 1}"),
+ Matcher original(BSON(AlwaysTrueMatchExpression::kName << 1),
kSimpleCollator,
expCtx,
ExtensionsCallbackNoop(),
@@ -1454,13 +1468,13 @@ TEST(SerializeBasic, ExpressionAlwaysTrueSerializesCorrectly) {
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
- ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$alwaysTrue: 1}"));
+ ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), BSON(AlwaysTrueMatchExpression::kName << 1));
ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression()));
}
TEST(SerializeBasic, ExpressionAlwaysFalseSerializesCorrectly) {
boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest());
- Matcher original(fromjson("{$alwaysFalse: 1}"),
+ Matcher original(BSON(AlwaysFalseMatchExpression::kName << 1),
kSimpleCollator,
expCtx,
ExtensionsCallbackNoop(),
@@ -1470,7 +1484,7 @@ TEST(SerializeBasic, ExpressionAlwaysFalseSerializesCorrectly) {
expCtx,
ExtensionsCallbackNoop(),
MatchExpressionParser::kAllowAllSpecialFeatures);
- ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), fromjson("{$alwaysFalse: 1}"));
+ ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), BSON(AlwaysFalseMatchExpression::kName << 1));
ASSERT_BSONOBJ_EQ(*reserialized.getQuery(), serialize(reserialized.getMatchExpression()));
}
diff --git a/src/mongo/db/matcher/expression_tree.cpp b/src/mongo/db/matcher/expression_tree.cpp
index e1dd45ee0e7..370b1e675b1 100644
--- a/src/mongo/db/matcher/expression_tree.cpp
+++ b/src/mongo/db/matcher/expression_tree.cpp
@@ -33,6 +33,7 @@
#include "mongo/bson/bsonmisc.h"
#include "mongo/bson/bsonobj.h"
#include "mongo/bson/bsonobjbuilder.h"
+#include "mongo/db/matcher/expression_always_boolean.h"
namespace mongo {
@@ -147,6 +148,10 @@ void OrMatchExpression::debugString(StringBuilder& debug, int level) const {
}
void OrMatchExpression::serialize(BSONObjBuilder* out) const {
+ if (!numChildren()) {
+ out->append(AlwaysFalseMatchExpression::kName, 1);
+ return;
+ }
BSONArrayBuilder arrBob(out->subarrayStart("$or"));
_listToBSON(&arrBob);
}
diff --git a/src/mongo/db/matcher/expression_with_placeholder_test.cpp b/src/mongo/db/matcher/expression_with_placeholder_test.cpp
index 3c7702e2703..1d717bb1f19 100644
--- a/src/mongo/db/matcher/expression_with_placeholder_test.cpp
+++ b/src/mongo/db/matcher/expression_with_placeholder_test.cpp
@@ -29,6 +29,7 @@
#include "mongo/platform/basic.h"
#include "mongo/db/json.h"
+#include "mongo/db/matcher/expression_always_boolean.h"
#include "mongo/db/matcher/expression_with_placeholder.h"
#include "mongo/db/query/collation/collator_interface_mock.h"
#include "mongo/unittest/unittest.h"
@@ -153,14 +154,14 @@ TEST(ExpressionWithPlaceholderTest, SuccessfullyParsesExpressionsWithTypeOther)
TEST(ExpressionWithPlaceholderTest, SuccessfullyParsesAlwaysTrue) {
constexpr CollatorInterface* collator = nullptr;
- auto rawFilter = fromjson("{$alwaysTrue: 1}");
+ auto rawFilter = BSON(AlwaysTrueMatchExpression::kName << 1);
auto result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator));
ASSERT_FALSE(result->getPlaceholder());
}
TEST(ExpressionWithPlaceholderTest, SuccessfullyParsesAlwaysFalse) {
constexpr CollatorInterface* collator = nullptr;
- auto rawFilter = fromjson("{$alwaysFalse: 1}");
+ auto rawFilter = BSON(AlwaysFalseMatchExpression::kName << 1);
auto result = assertGet(ExpressionWithPlaceholder::parse(rawFilter, collator));
ASSERT_FALSE(result->getPlaceholder());
}
@@ -299,11 +300,11 @@ TEST(ExpressionWithPlaceholderTest, SameObjectMatchesAreEquivalent) {
TEST(ExpressionWithPlaceholderTest, AlwaysTruesAreEquivalent) {
constexpr auto collator = nullptr;
- auto rawFilter1 = fromjson("{$alwaysTrue: 1}");
+ auto rawFilter1 = BSON(AlwaysTrueMatchExpression::kName << 1);
auto expressionWithPlaceholder1 = ExpressionWithPlaceholder::parse(rawFilter1, collator);
ASSERT_OK(expressionWithPlaceholder1.getStatus());
- auto rawFilter2 = fromjson("{$alwaysTrue: 1}");
+ auto rawFilter2 = BSON(AlwaysTrueMatchExpression::kName << 1);
auto expressionWithPlaceholder2 = ExpressionWithPlaceholder::parse(rawFilter2, collator);
ASSERT_OK(expressionWithPlaceholder2.getStatus());
ASSERT(expressionWithPlaceholder1.getValue()->equivalent(
diff --git a/src/mongo/db/matcher/schema/json_schema_parser_test.cpp b/src/mongo/db/matcher/schema/json_schema_parser_test.cpp
index 48f24f70012..1e6808e006e 100644
--- a/src/mongo/db/matcher/schema/json_schema_parser_test.cpp
+++ b/src/mongo/db/matcher/schema/json_schema_parser_test.cpp
@@ -29,6 +29,8 @@
#include "mongo/platform/basic.h"
#include "mongo/bson/json.h"
+#include "mongo/db/bson/bson_helper.h"
+#include "mongo/db/matcher/expression_always_boolean.h"
#include "mongo/db/matcher/schema/json_schema_parser.h"
#include "mongo/unittest/unittest.h"
@@ -139,7 +141,7 @@ TEST(JSONSchemaParserTest, TopLevelNonObjectTypeTranslatesCorrectly) {
BSONObj schema = fromjson("{type: 'string'}");
auto result = JSONSchemaParser::parse(schema);
ASSERT_OK(result.getStatus());
- ASSERT_SERIALIZES_TO(result.getValue().get(), fromjson("{$alwaysFalse: 1}"));
+ ASSERT_SERIALIZES_TO(result.getValue().get(), BSON(AlwaysFalseMatchExpression::kName << 1));
}
TEST(JSONSchemaParserTest, TypeNumberTranslatesCorrectly) {
@@ -1361,13 +1363,13 @@ TEST(JSONSchemaParserTest, FailsToParseIfBsonTypeArrayContainsUnknownAlias) {
TEST(JSONSchemaParserTest, CanTranslateTopLevelTypeArrayWithoutObject) {
BSONObj schema = fromjson("{type: ['number', 'string']}}}");
auto result = JSONSchemaParser::parse(schema);
- ASSERT_SERIALIZES_TO(result.getValue().get(), fromjson("{$alwaysFalse: 1}"));
+ ASSERT_SERIALIZES_TO(result.getValue().get(), BSON(AlwaysFalseMatchExpression::kName << 1));
}
TEST(JSONSchemaParserTest, CanTranslateTopLevelBsonTypeArrayWithoutObject) {
BSONObj schema = fromjson("{bsonType: ['number', 'string']}}}");
auto result = JSONSchemaParser::parse(schema);
- ASSERT_SERIALIZES_TO(result.getValue().get(), fromjson("{$alwaysFalse: 1}"));
+ ASSERT_SERIALIZES_TO(result.getValue().get(), BSON(AlwaysFalseMatchExpression::kName << 1));
}
TEST(JSONSchemaParserTest, CanTranslateTopLevelTypeArrayWithObject) {