diff options
author | Anne Lim <anne.lim@mongodb.com> | 2017-08-02 09:48:19 -0400 |
---|---|---|
committer | Anne Lim <anne.lim@mongodb.com> | 2017-08-02 09:48:19 -0400 |
commit | b66d485345c99c8877f2d0bc72a4f123de720cb0 (patch) | |
tree | 31844a3949fd1c900b3f7e93929faea1671b0c9b /src | |
parent | 0deaa0f0ec0f659afcf39144e9dc0b60ec464ea8 (diff) | |
download | mongo-b66d485345c99c8877f2d0bc72a4f123de720cb0.tar.gz |
Revert "scalars part 2"
This reverts commit 0deaa0f0ec0f659afcf39144e9dc0b60ec464ea8.
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/matcher/schema/json_schema_parser.cpp | 93 | ||||
-rw-r--r-- | src/mongo/db/matcher/schema/json_schema_parser_test.cpp | 208 |
2 files changed, 46 insertions, 255 deletions
diff --git a/src/mongo/db/matcher/schema/json_schema_parser.cpp b/src/mongo/db/matcher/schema/json_schema_parser.cpp index 591c1a8be60..4418eb2f699 100644 --- a/src/mongo/db/matcher/schema/json_schema_parser.cpp +++ b/src/mongo/db/matcher/schema/json_schema_parser.cpp @@ -33,8 +33,6 @@ #include "mongo/bson/bsontypes.h" #include "mongo/db/matcher/expression_always_boolean.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/matcher/schema/expression_internal_schema_max_length.h" -#include "mongo/db/matcher/schema/expression_internal_schema_min_length.h" #include "mongo/db/matcher/schema/expression_internal_schema_object_match.h" #include "mongo/stdx/memory.h" #include "mongo/util/string_map.h" @@ -47,9 +45,6 @@ constexpr StringData kSchemaExclusiveMaximumKeyword = "exclusiveMaximum"_sd; constexpr StringData kSchemaExclusiveMinimumKeyword = "exclusiveMinimum"_sd; constexpr StringData kSchemaMaximumKeyword = "maximum"_sd; constexpr StringData kSchemaMinimumKeyword = "minimum"_sd; -constexpr StringData kSchemaMaxLengthKeyword = "maxLength"_sd; -constexpr StringData kSchemaMinLengthKeyword = "minLength"_sd; -constexpr StringData kSchemaPatternKeyword = "pattern"_sd; constexpr StringData kSchemaPropertiesKeyword = "properties"_sd; constexpr StringData kSchemaTypeKeyword = "type"_sd; @@ -174,6 +169,7 @@ StatusWithMatchExpression parseMaximum(StringData path, return status; } + // We use Number as a stand-in for all numeric restrictions. TypeMatchExpression::Type restrictionType; restrictionType.allNumbers = true; return makeRestriction(restrictionType, std::move(expr), typeExpr); @@ -205,65 +201,11 @@ StatusWithMatchExpression parseMinimum(StringData path, return status; } + // We use Number as a stand-in for all numeric restrictions. TypeMatchExpression::Type restrictionType; restrictionType.allNumbers = true; return makeRestriction(restrictionType, std::move(expr), typeExpr); } - -template <class T> -StatusWithMatchExpression parseStrLength(StringData path, - BSONElement strLength, - TypeMatchExpression* typeExpr, - StringData keyword) { - if (!strLength.isNumber()) { - return { - Status(ErrorCodes::TypeMismatch, - str::stream() << "$jsonSchema keyword '" << keyword << "' must be a number")}; - } - - auto strLengthWithStatus = - MatchExpressionParser::parseIntegerElementToNonNegativeLong(strLength); - - if (!strLengthWithStatus.isOK()) { - return strLengthWithStatus.getStatus(); - } - - if (path.empty()) { - return {stdx::make_unique<AlwaysTrueMatchExpression>()}; - } - - auto expr = stdx::make_unique<T>(); - auto status = expr->init(path, strLengthWithStatus.getValue()); - if (!status.isOK()) { - return status; - } - return makeRestriction(BSONType::String, std::move(expr), typeExpr); -} - -StatusWithMatchExpression parsePattern(StringData path, - BSONElement pattern, - TypeMatchExpression* typeExpr) { - if (pattern.type() != BSONType::String) { - return {Status(ErrorCodes::TypeMismatch, - str::stream() << "$jsonSchema keyword '" << kSchemaPatternKeyword - << "' must be a string")}; - } - - if (path.empty()) { - return {stdx::make_unique<AlwaysTrueMatchExpression>()}; - } - - auto expr = stdx::make_unique<RegexMatchExpression>(); - - // JSON Schema does not allow regex flags to be specified. - constexpr auto emptyFlags = ""; - auto status = expr->init(path, pattern.valueStringData(), emptyFlags); - if (!status.isOK()) { - return status; - } - return makeRestriction(BSONType::String, std::move(expr), typeExpr); -} - } // namespace StatusWithMatchExpression JSONSchemaParser::_parseProperties(StringData path, @@ -315,10 +257,7 @@ StatusWithMatchExpression JSONSchemaParser::_parse(StringData path, BSONObj sche {kSchemaMaximumKeyword, {}}, {kSchemaMinimumKeyword, {}}, {kSchemaExclusiveMaximumKeyword, {}}, - {kSchemaExclusiveMinimumKeyword, {}}, - {kSchemaMaxLengthKeyword, {}}, - {kSchemaMinLengthKeyword, {}}, - {kSchemaPatternKeyword, {}}}; + {kSchemaExclusiveMinimumKeyword, {}}}; for (auto&& elt : schema) { auto it = keywordMap.find(elt.fieldNameStringData()); @@ -406,32 +345,6 @@ StatusWithMatchExpression JSONSchemaParser::_parse(StringData path, BSONObj sche << " is present")}; } - if (auto maxLengthElt = keywordMap[kSchemaMaxLengthKeyword]) { - auto maxLengthExpr = parseStrLength<InternalSchemaMaxLengthMatchExpression>( - path, maxLengthElt, typeExpr.getValue().get(), kSchemaMaxLengthKeyword); - if (!maxLengthExpr.isOK()) { - return maxLengthExpr; - } - andExpr->add(maxLengthExpr.getValue().release()); - } - - if (auto minLengthElt = keywordMap[kSchemaMinLengthKeyword]) { - auto minLengthExpr = parseStrLength<InternalSchemaMinLengthMatchExpression>( - path, minLengthElt, typeExpr.getValue().get(), kSchemaMinLengthKeyword); - if (!minLengthExpr.isOK()) { - return minLengthExpr; - } - andExpr->add(minLengthExpr.getValue().release()); - } - - if (auto patternElt = keywordMap[kSchemaPatternKeyword]) { - auto patternExpr = parsePattern(path, patternElt, typeExpr.getValue().get()); - if (!patternExpr.isOK()) { - return patternExpr; - } - andExpr->add(patternExpr.getValue().release()); - } - if (path.empty() && typeExpr.getValue() && typeExpr.getValue()->getBSONType() != BSONType::Object) { // This is a top-level schema which requires that the type is something other than 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 81f43b7f6a2..a0de359d855 100644 --- a/src/mongo/db/matcher/schema/json_schema_parser_test.cpp +++ b/src/mongo/db/matcher/schema/json_schema_parser_test.cpp @@ -36,19 +36,19 @@ namespace mongo { namespace { TEST(JSONSchemaParserTest, FailsToParseIfTypeIsNotAString) { - BSONObj schema = fromjson("{type: 1}"); + BSONObj schema = fromjson("{type: 1}}"); auto result = JSONSchemaParser::parse(schema); ASSERT_EQ(result.getStatus(), ErrorCodes::TypeMismatch); } TEST(JSONSchemaParserTest, FailsToParseUnknownKeyword) { - BSONObj schema = fromjson("{unknown: 1}"); + BSONObj schema = fromjson("{unknown: 1}}"); auto result = JSONSchemaParser::parse(schema); ASSERT_EQ(result.getStatus(), ErrorCodes::FailedToParse); } TEST(JSONSchemaParserTest, FailsToParseIfPropertiesIsNotAnObject) { - BSONObj schema = fromjson("{properties: 1}"); + BSONObj schema = fromjson("{properties: 1}}"); auto result = JSONSchemaParser::parse(schema); ASSERT_EQ(result.getStatus(), ErrorCodes::TypeMismatch); } @@ -178,70 +178,63 @@ TEST(JSONSchemaParserTest, MaximumTranslatesCorrectlyWithNoType) { "{$or: [{$nor: [{num: {$type: 'number'}}]}, {num: {$lte: 0}}]}]}]}]}")); } -TEST(JSONSchemaParserTest, FailsToParseIfMaximumIsNotANumber) { - BSONObj schema = fromjson("{maximum: 'foo'}"); - auto result = JSONSchemaParser::parse(schema); - ASSERT_EQ(result.getStatus(), ErrorCodes::TypeMismatch); -} - -TEST(JSONSchemaParserTest, FailsToParseIfMaxLengthIsNotANumber) { - BSONObj schema = fromjson("{maxLength: 'foo'}"); - auto result = JSONSchemaParser::parse(schema); - ASSERT_EQ(result.getStatus(), ErrorCodes::TypeMismatch); -} - -TEST(JSONSchemaParserTest, FailsToParseIfMaxLengthIsLessThanZero) { - BSONObj schema = fromjson("{maxLength: -1}"); +TEST(JSONSchemaParserTest, MaximumTranslatesCorrectlyWithExclusiveMaximumTrue) { + BSONObj schema = fromjson( + "{properties: {num: {type: 'long', maximum: 0, exclusiveMaximum: true}}, type: 'object'}"); auto result = JSONSchemaParser::parse(schema); - ASSERT_EQ(result.getStatus(), ErrorCodes::FailedToParse); + ASSERT_OK(result.getStatus()); + BSONObjBuilder builder; + result.getValue()->serialize(&builder); + ASSERT_BSONOBJ_EQ(builder.obj(), + fromjson("{$and: [{$and: [{$and: [" + "{$or: [{$nor: [{num: {$type: 'number'}}]}, {num: {$lt: 0}}]}," + "{$or: [{$nor: [{num: {$exists: true}}]}, {num: {$type: 18}}]}" + "]}]}]}")); } -TEST(JSONSchemaParserTest, MinimumTranslatesCorrectlyWithTypeNumber) { - BSONObj schema = fromjson("{properties: {num: {type: 'number', minimum: 0}}, type: 'object'}"); +TEST(JSONSchemaParserTest, MaximumTranslatesCorrectlyWithExclusiveMaximumFalse) { + BSONObj schema = fromjson( + "{properties: {num: {type: 'long', maximum: 0, exclusiveMaximum: false}}, type: 'object'}"); auto result = JSONSchemaParser::parse(schema); ASSERT_OK(result.getStatus()); BSONObjBuilder builder; result.getValue()->serialize(&builder); ASSERT_BSONOBJ_EQ(builder.obj(), fromjson("{$and: [{$and: [{$and: [" - "{$or: [{$nor: [{num: {$type: 'number'}}]}, {num: {$gte: 0}}]}," - "{$or: [{$nor: [{num: {$exists: true}}]}, {num: {$type: 'number'}}]}" + "{$or: [{$nor: [{num: {$type: 'number'}}]}, {num: {$lte: 0}}]}," + "{$or: [{$nor: [{num: {$exists: true}}]}, {num: {$type: 18}}]}" "]}]}]}")); } -TEST(JSONSchemaParserTest, FailsToParseIfMaxLengthIsNonIntegralDouble) { - BSONObj schema = - fromjson("{properties: {foo: {type: 'string', maxLength: 5.5}}, type: 'object'}"); +TEST(JSONSchemaParserTest, FailsToParseIfMaximumIsNotANumber) { + BSONObj schema = fromjson("{maximum: 'foo'}"); + auto result = JSONSchemaParser::parse(schema); + ASSERT_EQ(result.getStatus(), ErrorCodes::TypeMismatch); +} + +TEST(JSONSchemaParserTest, FailsToParseIfExclusiveMaximumIsPresentButMaximumIsNot) { + BSONObj schema = fromjson("{exclusiveMaximum: true}"); auto result = JSONSchemaParser::parse(schema); ASSERT_EQ(result.getStatus(), ErrorCodes::FailedToParse); } -TEST(JSONSchemaParserTest, MaxLengthTranslatesCorrectlyWithIntegralDouble) { - BSONObj schema = - fromjson("{properties: {foo: {type: 'string', maxLength: 5.0}}, type: 'object'}"); +TEST(JSONSchemaParserTest, FailsToParseIfExclusiveMaximumIsNotABoolean) { + BSONObj schema = fromjson("{maximum: 5, exclusiveMaximum: 'foo'}"); auto result = JSONSchemaParser::parse(schema); - ASSERT_OK(result.getStatus()); - BSONObjBuilder builder; - result.getValue()->serialize(&builder); - ASSERT_BSONOBJ_EQ( - builder.obj(), - fromjson("{ $and: [ { $and: [ { $and: [ { $or: [ { $nor: [ { foo: { $type: 2 } } ] }, { " - "foo: { $_internalSchemaMaxLength: 5 } } ] }, { $or: [ { $nor: [ { foo: { " - "$exists: true } } ] }, { foo: { $type: 2 } } ] } ] } ] } ] }")); + ASSERT_EQ(result.getStatus(), ErrorCodes::TypeMismatch); } -TEST(JSONSchemaParserTest, MaxLengthTranslatesCorrectlyWithTypeString) { - BSONObj schema = - fromjson("{properties: {foo: {type: 'string', maxLength: 5}}, type: 'object'}"); +TEST(JSONSchemaParserTest, MinimumTranslatesCorrectlyWithTypeNumber) { + BSONObj schema = fromjson("{properties: {num: {type: 'number', minimum: 0}}, type: 'object'}"); auto result = JSONSchemaParser::parse(schema); ASSERT_OK(result.getStatus()); BSONObjBuilder builder; result.getValue()->serialize(&builder); - ASSERT_BSONOBJ_EQ( - builder.obj(), - fromjson("{ $and: [ { $and: [ { $and: [ { $or: [ { $nor: [ { foo: { $type: 2 } } ] }, { " - "foo: { $_internalSchemaMaxLength: 5 } } ] }, { $or: [ { $nor: [ { foo: { " - "$exists: true } } ] }, { foo: { $type: 2 } } ] } ] } ] } ] }")); + ASSERT_BSONOBJ_EQ(builder.obj(), + fromjson("{$and: [{$and: [{$and: [" + "{$or: [{$nor: [{num: {$type: 'number'}}]}, {num: {$gte: 0}}]}," + "{$or: [{$nor: [{num: {$exists: true}}]}, {num: {$type: 'number'}}]}" + "]}]}]}")); } TEST(JSONSchemaParserTest, MinimumTranslatesCorrectlyWithTypeLong) { @@ -281,46 +274,6 @@ TEST(JSONSchemaParserTest, MinimumTranslatesCorrectlyWithNoType) { "{$or: [{$nor: [{num: {$type: 'number'}}]}, {num: {$gte: 0}}]}]}]}]}")); } -TEST(JSONSchemaParserTest, MaximumTranslatesCorrectlyWithExclusiveMaximumTrue) { - BSONObj schema = fromjson( - "{properties: {num: {type: 'long', maximum: 0, exclusiveMaximum: true}}, type: 'object'}"); - auto result = JSONSchemaParser::parse(schema); - ASSERT_OK(result.getStatus()); - BSONObjBuilder builder; - result.getValue()->serialize(&builder); - ASSERT_BSONOBJ_EQ(builder.obj(), - fromjson("{ $and: [ { $and: [ { $and: [ { $or: [ { $nor: [ { " - "num: { $type: 'number' } } ] }, { num: { $lt: 0 } } " - "] }, { $or: [ { $nor: [ { num: { $exists: true } } " - "] }, { num: { $type: 18 } } ] } ] } ] } ] }")); -} - -TEST(JSONSchemaParserTest, MaximumTranslatesCorrectlyWithExclusiveMaximumFalse) { - BSONObj schema = fromjson( - "{properties: {num: {type: 'long', maximum: 0, exclusiveMaximum: false}}, type: 'object'}"); - auto result = JSONSchemaParser::parse(schema); - ASSERT_OK(result.getStatus()); - BSONObjBuilder builder; - result.getValue()->serialize(&builder); - ASSERT_BSONOBJ_EQ(builder.obj(), - fromjson("{ $and: [ { $and: [ { $and: [ { $or: [ { $nor: [ { " - "num: { $type: 'number' } } ] }, { num: { $lte: 0 } " - "} ] }, { $or: [ { $nor: [ { num: { $exists: true } " - "} ] }, { num: { $type: 18 } } ] } ] } ] } ] }")); -} - -TEST(JSONSchemaParserTest, FailsToParseIfExclusiveMaximumIsPresentButMaximumIsNot) { - BSONObj schema = fromjson("{exclusiveMaximum: true}"); - auto result = JSONSchemaParser::parse(schema); - ASSERT_EQ(result.getStatus(), ErrorCodes::FailedToParse); -} - -TEST(JSONSchemaParserTest, FailsToParseIfExclusiveMaximumIsNotABoolean) { - BSONObj schema = fromjson("{maximum: 5, exclusiveMaximum: 'foo'}"); - auto result = JSONSchemaParser::parse(schema); - ASSERT_EQ(result.getStatus(), ErrorCodes::TypeMismatch); -} - TEST(JSONSchemaParserTest, MinimumTranslatesCorrectlyWithExclusiveMinimumTrue) { BSONObj schema = fromjson( "{properties: {num: {type: 'long', minimum: 0, exclusiveMinimum: true}}, type: 'object'}"); @@ -349,99 +302,24 @@ TEST(JSONSchemaParserTest, MinimumTranslatesCorrectlyWithExclusiveMinimumFalse) "]}]}]}")); } -TEST(JSONSchemaParserTest, FailsToParseIfExclusiveMinimumIsPresentButMinimumIsNot) { - BSONObj schema = fromjson("{exclusiveMinimum: true}"); - auto result = JSONSchemaParser::parse(schema); - ASSERT_EQ(result.getStatus(), ErrorCodes::FailedToParse); -} - -TEST(JSONSchemaParserTest, FailsToParseIfExclusiveMinimumIsNotABoolean) { - BSONObj schema = fromjson("{minimum: 5, exclusiveMinimum: 'foo'}"); - auto result = JSONSchemaParser::parse(schema); - ASSERT_EQ(result.getStatus(), ErrorCodes::TypeMismatch); -} - -TEST(JSONSchemaParserTest, FailsToParseIfMinLengthIsNotANumber) { - BSONObj schema = fromjson("{minLength: 'foo'}"); +TEST(JSONSchemaParserTest, FailsToParseIfMinimumIsNotANumber) { + BSONObj schema = fromjson("{minimum: 'foo'}"); auto result = JSONSchemaParser::parse(schema); ASSERT_EQ(result.getStatus(), ErrorCodes::TypeMismatch); } -TEST(JSONSchemaParserTest, FailsToParseIfMinLengthIsLessThanZero) { - BSONObj schema = fromjson("{minLength: -1}"); - auto result = JSONSchemaParser::parse(schema); - ASSERT_EQ(result.getStatus(), ErrorCodes::FailedToParse); -} -TEST(JSONSchemaParserTest, FailsToParseIfMinLengthIsNonIntegralDouble) { - BSONObj schema = - fromjson("{properties: {foo: {type: 'string', minLength: 5.5}}, type: 'object'}"); +TEST(JSONSchemaParserTest, FailsToParseIfExclusiveMinimumIsPresentButMinimumIsNot) { + BSONObj schema = fromjson("{exclusiveMinimum: true}"); auto result = JSONSchemaParser::parse(schema); ASSERT_EQ(result.getStatus(), ErrorCodes::FailedToParse); } -TEST(JSONSchemaParserTest, MinLengthTranslatesCorrectlyWithTypeString) { - BSONObj schema = - fromjson("{properties: {foo: {type: 'string', minLength: 5}}, type: 'object'}"); - auto result = JSONSchemaParser::parse(schema); - ASSERT_OK(result.getStatus()); - BSONObjBuilder builder; - result.getValue()->serialize(&builder); - ASSERT_BSONOBJ_EQ( - builder.obj(), - fromjson("{ $and: [ { $and: [ { $and: [ { $or: [ { $nor: [ { foo: { $type: 2 } } ] }, { " - "foo: { $_internalSchemaMinLength: 5 } } ] }, { $or: [ { $nor: [ { foo: { " - "$exists: true } } ] }, { foo: { $type: 2 } } ] } ] } ] } ] }")); -} - -TEST(JSONSchemaParserTest, MinLengthTranslatesCorrectlyWithIntegralDouble) { - BSONObj schema = - fromjson("{properties: {foo: {type: 'string', minLength: 5.0}}, type: 'object'}"); - auto result = JSONSchemaParser::parse(schema); - ASSERT_OK(result.getStatus()); - BSONObjBuilder builder; - result.getValue()->serialize(&builder); - ASSERT_BSONOBJ_EQ( - builder.obj(), - fromjson("{ $and: [ { $and: [ { $and: [ { $or: [ { $nor: [ { foo: { $type: 2 } } ] }, { " - "foo: { $_internalSchemaMinLength: 5 } } ] }, { $or: [ { $nor: [ { foo: { " - "$exists: true } } ] }, { foo: { $type: 2 } } ] } ] } ] } ] }")); -} - -TEST(JSONSchemaParserTest, FailsToParseIfMinimumIsNotANumber) { - BSONObj schema = fromjson("{minimum: 'foo'}"); - auto result = JSONSchemaParser::parse(schema); - ASSERT_EQ(result.getStatus(), ErrorCodes::TypeMismatch); -} - -TEST(JSONSchemaParserTest, FailsToParseIfPatternIsNotString) { - BSONObj schema = fromjson("{pattern: 6}"); +TEST(JSONSchemaParserTest, FailsToParseIfExclusiveMinimumIsNotABoolean) { + BSONObj schema = fromjson("{minimum: 5, exclusiveMinimum: 'foo'}"); auto result = JSONSchemaParser::parse(schema); ASSERT_EQ(result.getStatus(), ErrorCodes::TypeMismatch); } -TEST(JSONSchemaParserTest, PatternTranslatesCorrectlyWithString) { - BSONObj schema = - fromjson("{properties: {foo: {type: 'string', pattern: 'abc'}}, type: 'object'}"); - auto result = JSONSchemaParser::parse(schema); - ASSERT_OK(result.getStatus()); - BSONObjBuilder builder; - result.getValue()->serialize(&builder); - - BSONObj expected = BSON( - "$and" << BSON_ARRAY(BSON( - "$and" << BSON_ARRAY(BSON( - "$and" << BSON_ARRAY( - BSON("$or" << BSON_ARRAY( - BSON("$nor" << BSON_ARRAY(BSON("foo" << BSON("$type" << 2)))) - << BSON("foo" << BSON("$regex" - << "abc")))) - << BSON("$or" << BSON_ARRAY( - BSON("$nor" << BSON_ARRAY(BSON("foo" << BSON("$exists" << true)))) - << BSON("foo" << BSON("$type" << 2)))))))))); - - ASSERT_BSONOBJ_EQ(builder.obj(), expected); -} - } // namespace } // namespace mongo |