Ejemplo n.º 1
0
StatusWithMatchExpression JSONSchemaParser::_parse(StringData path, BSONObj schema) {
    // Map from JSON Schema keyword to the corresponding element from 'schema', or to an empty
    // BSONElement if the JSON Schema keyword is not specified.
    StringMap<BSONElement> keywordMap{
        {kSchemaTypeKeyword, {}}, {kSchemaPropertiesKeyword, {}}, {kSchemaMaximumKeyword, {}}};

    for (auto&& elt : schema) {
        auto it = keywordMap.find(elt.fieldNameStringData());
        if (it == keywordMap.end()) {
            return Status(ErrorCodes::FailedToParse,
                          str::stream() << "Unknown $jsonSchema keyword: "
                                        << elt.fieldNameStringData());
        }

        if (it->second) {
            return Status(ErrorCodes::FailedToParse,
                          str::stream() << "Duplicate $jsonSchema keyword: "
                                        << elt.fieldNameStringData());
        }

        keywordMap[elt.fieldNameStringData()] = elt;
    }

    auto typeExpr = parseType(path, keywordMap[kSchemaTypeKeyword]);
    if (!typeExpr.isOK()) {
        return typeExpr.getStatus();
    }

    auto andExpr = stdx::make_unique<AndMatchExpression>();

    if (auto propertiesElt = keywordMap[kSchemaPropertiesKeyword]) {
        auto propertiesExpr = _parseProperties(path, propertiesElt, typeExpr.getValue().get());
        if (!propertiesExpr.isOK()) {
            return propertiesExpr;
        }
        andExpr->add(propertiesExpr.getValue().release());
    }

    if (auto maximumElt = keywordMap[kSchemaMaximumKeyword]) {
        auto maxExpr = parseMaximum(path, maximumElt, typeExpr.getValue().get());
        if (!maxExpr.isOK()) {
            return maxExpr;
        }
        andExpr->add(maxExpr.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
        // "object". Since we only know how to store objects, this schema matches nothing.
        return {stdx::make_unique<FalseMatchExpression>(StringData{})};
    }

    if (!path.empty() && typeExpr.getValue()) {
        andExpr->add(typeExpr.getValue().release());
    }
    return {std::move(andExpr)};
}
Ejemplo n.º 2
0
StatusWithMatchExpression JSONSchemaParser::_parse(StringData path, BSONObj schema) {
    // Map from JSON Schema keyword to the corresponding element from 'schema', or to an empty
    // BSONElement if the JSON Schema keyword is not specified.
    StringMap<BSONElement> keywordMap{{kSchemaTypeKeyword, {}},
                                      {kSchemaPropertiesKeyword, {}},
                                      {kSchemaMaximumKeyword, {}},
                                      {kSchemaMinimumKeyword, {}},
                                      {kSchemaExclusiveMaximumKeyword, {}},
                                      {kSchemaExclusiveMinimumKeyword, {}},
                                      {kSchemaMaxLengthKeyword, {}},
                                      {kSchemaMinLengthKeyword, {}},
                                      {kSchemaPatternKeyword, {}},
                                      {kSchemaMultipleOfKeyword, {}}};

    for (auto&& elt : schema) {
        auto it = keywordMap.find(elt.fieldNameStringData());
        if (it == keywordMap.end()) {
            return Status(ErrorCodes::FailedToParse,
                          str::stream() << "Unknown $jsonSchema keyword: "
                                        << elt.fieldNameStringData());
        }

        if (it->second) {
            return Status(ErrorCodes::FailedToParse,
                          str::stream() << "Duplicate $jsonSchema keyword: "
                                        << elt.fieldNameStringData());
        }

        keywordMap[elt.fieldNameStringData()] = elt;
    }

    auto typeExpr = parseType(path, keywordMap[kSchemaTypeKeyword]);
    if (!typeExpr.isOK()) {
        return typeExpr.getStatus();
    }

    auto andExpr = stdx::make_unique<AndMatchExpression>();

    if (auto propertiesElt = keywordMap[kSchemaPropertiesKeyword]) {
        auto propertiesExpr = _parseProperties(path, propertiesElt, typeExpr.getValue().get());
        if (!propertiesExpr.isOK()) {
            return propertiesExpr;
        }
        andExpr->add(propertiesExpr.getValue().release());
    }

    if (auto maximumElt = keywordMap[kSchemaMaximumKeyword]) {
        bool isExclusiveMaximum = false;
        if (auto exclusiveMaximumElt = keywordMap[kSchemaExclusiveMaximumKeyword]) {
            if (!exclusiveMaximumElt.isBoolean()) {
                return {Status(ErrorCodes::TypeMismatch,
                               str::stream() << "$jsonSchema keyword '"
                                             << kSchemaExclusiveMaximumKeyword
                                             << "' must be a boolean")};
            } else {
                isExclusiveMaximum = exclusiveMaximumElt.boolean();
            }
        }
        auto maxExpr =
            parseMaximum(path, maximumElt, typeExpr.getValue().get(), isExclusiveMaximum);
        if (!maxExpr.isOK()) {
            return maxExpr;
        }
        andExpr->add(maxExpr.getValue().release());
    } else if (keywordMap[kSchemaExclusiveMaximumKeyword]) {
        // If "exclusiveMaximum" is present, "maximum" must also be present.
        return {Status(ErrorCodes::FailedToParse,
                       str::stream() << "$jsonSchema keyword '" << kSchemaMaximumKeyword
                                     << "' must be a present if "
                                     << kSchemaExclusiveMaximumKeyword
                                     << " is present")};
    }

    if (auto minimumElt = keywordMap[kSchemaMinimumKeyword]) {
        bool isExclusiveMinimum = false;
        if (auto exclusiveMinimumElt = keywordMap[kSchemaExclusiveMinimumKeyword]) {
            if (!exclusiveMinimumElt.isBoolean()) {
                return {Status(ErrorCodes::TypeMismatch,
                               str::stream() << "$jsonSchema keyword '"
                                             << kSchemaExclusiveMinimumKeyword
                                             << "' must be a boolean")};
            } else {
                isExclusiveMinimum = exclusiveMinimumElt.boolean();
            }
        }
        auto minExpr =
            parseMinimum(path, minimumElt, typeExpr.getValue().get(), isExclusiveMinimum);
        if (!minExpr.isOK()) {
            return minExpr;
        }
        andExpr->add(minExpr.getValue().release());
    } else if (keywordMap[kSchemaExclusiveMinimumKeyword]) {
        // If "exclusiveMinimum" is present, "minimum" must also be present.
        return {Status(ErrorCodes::FailedToParse,
                       str::stream() << "$jsonSchema keyword '" << kSchemaMinimumKeyword
                                     << "' must be a present if "
                                     << kSchemaExclusiveMinimumKeyword
                                     << " 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 (auto multipleOfElt = keywordMap[kSchemaMultipleOfKeyword]) {
        auto multipleOfExpr = parseMultipleOf(path, multipleOfElt, typeExpr.getValue().get());
        if (!multipleOfExpr.isOK()) {
            return multipleOfExpr;
        }
        andExpr->add(multipleOfExpr.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
        // "object". Since we only know how to store objects, this schema matches nothing.
        return {stdx::make_unique<AlwaysFalseMatchExpression>()};
    }

    if (!path.empty() && typeExpr.getValue()) {
        andExpr->add(makeTypeRestriction(std::move(typeExpr.getValue())).release());
    }
    return {std::move(andExpr)};
}