/** * Copyright (C) 2018-present MongoDB, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the Server Side Public License, version 1, * as published by MongoDB, Inc. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * Server Side Public License for more details. * * You should have received a copy of the Server Side Public License * along with this program. If not, see * . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the Server Side Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ #pragma once #include #include #include "mongo/base/status.h" #include "mongo/bson/bsonmisc.h" #include "mongo/bson/bsonobj.h" #include "mongo/db/matcher/expression_path.h" namespace mongo { /** * A path match expression which does not expand arrays at the end of the path, and which only * matches if the path contains an array. */ class ArrayMatchingMatchExpression : public PathMatchExpression { public: ArrayMatchingMatchExpression(MatchType matchType, boost::optional path, clonable_ptr annotation = nullptr) : PathMatchExpression(matchType, path, ElementPath::LeafArrayBehavior::kNoTraversal, ElementPath::NonLeafArrayBehavior::kTraverse, std::move(annotation)) {} /** * Returns whether or not the nested array, represented as the object 'anArray', matches. * * 'anArray' must be the nested array at this expression's path. */ virtual bool matchesArray(const BSONObj& anArray, MatchDetails* details) const = 0; bool matchesSingleElement(const BSONElement&, MatchDetails* details = nullptr) const final; bool equivalent(const MatchExpression* other) const override; MatchCategory getCategory() const final { return MatchCategory::kArrayMatching; } }; class ElemMatchObjectMatchExpression final : public ArrayMatchingMatchExpression { public: ElemMatchObjectMatchExpression(boost::optional path, std::unique_ptr sub, clonable_ptr annotation = nullptr); bool matchesArray(const BSONObj& anArray, MatchDetails* details) const; virtual std::unique_ptr clone() const { std::unique_ptr e = std::make_unique( path(), _sub->clone(), _errorAnnotation); if (getTag()) { e->setTag(getTag()->clone()); } return e; } virtual void debugString(StringBuilder& debug, int indentationLevel) const; BSONObj getSerializedRightHandSide(SerializationOptions opts) const final; std::vector>* getChildVector() final { return nullptr; } virtual size_t numChildren() const { return 1; } virtual MatchExpression* getChild(size_t i) const { tassert(6400204, "Out-of-bounds access to child of MatchExpression.", i < numChildren()); return _sub.get(); } virtual void resetChild(size_t i, MatchExpression* other) { tassert(6329401, "Out-of-bounds access to child of MatchExpression.", i < numChildren()); _sub.reset(other); } std::unique_ptr releaseChild() { return std::move(_sub); } void resetChild(std::unique_ptr newChild) { _sub = std::move(newChild); } void acceptVisitor(MatchExpressionMutableVisitor* visitor) final { visitor->visit(this); } void acceptVisitor(MatchExpressionConstVisitor* visitor) const final { visitor->visit(this); } private: ExpressionOptimizerFunc getOptimizer() const final; std::unique_ptr _sub; }; class ElemMatchValueMatchExpression final : public ArrayMatchingMatchExpression { public: ElemMatchValueMatchExpression(boost::optional path, std::unique_ptr sub, clonable_ptr annotation = nullptr); explicit ElemMatchValueMatchExpression(boost::optional path, clonable_ptr annotation = nullptr); void add(std::unique_ptr sub); bool matchesArray(const BSONObj& anArray, MatchDetails* details) const; virtual std::unique_ptr clone() const { std::unique_ptr e = std::make_unique(path(), _errorAnnotation); for (size_t i = 0; i < _subs.size(); ++i) { e->add(_subs[i]->clone()); } if (getTag()) { e->setTag(getTag()->clone()); } return e; } virtual void debugString(StringBuilder& debug, int indentationLevel) const; BSONObj getSerializedRightHandSide(SerializationOptions opts) const final; std::vector>* getChildVector() final { return &_subs; } virtual size_t numChildren() const { return _subs.size(); } virtual MatchExpression* getChild(size_t i) const { tassert(6400205, "Out-of-bounds access to child of MatchExpression.", i < numChildren()); return _subs[i].get(); } virtual void resetChild(size_t i, MatchExpression* other) override { tassert(6329402, "Out-of-bounds access to child of MatchExpression.", i < numChildren()); _subs[i].reset(other); } void acceptVisitor(MatchExpressionMutableVisitor* visitor) final { visitor->visit(this); } void acceptVisitor(MatchExpressionConstVisitor* visitor) const final { visitor->visit(this); } private: ExpressionOptimizerFunc getOptimizer() const final; bool _arrayElementMatchesAll(const BSONElement& e) const; std::vector> _subs; }; class SizeMatchExpression : public ArrayMatchingMatchExpression { public: SizeMatchExpression(boost::optional path, int size, clonable_ptr annotation = nullptr); std::unique_ptr clone() const final { std::unique_ptr e = std::make_unique(path(), _size, _errorAnnotation); if (getTag()) { e->setTag(getTag()->clone()); } if (getInputParamId()) { e->setInputParamId(*getInputParamId()); } return e; } size_t numChildren() const override { return 0; } MatchExpression* getChild(size_t i) const override { tassert(6400206, "SizeMatchExpression does not have any children.", i < numChildren()); return nullptr; } void resetChild(size_t i, MatchExpression* other) override { tassert(6329403, "SizeMatchExpression does not have any children.", i < numChildren()); } std::vector>* getChildVector() final { return nullptr; } virtual bool matchesArray(const BSONObj& anArray, MatchDetails* details) const; virtual void debugString(StringBuilder& debug, int indentationLevel) const; BSONObj getSerializedRightHandSide(SerializationOptions opts) const final; virtual bool equivalent(const MatchExpression* other) const; int getData() const { return _size; } void acceptVisitor(MatchExpressionMutableVisitor* visitor) final { visitor->visit(this); } void acceptVisitor(MatchExpressionConstVisitor* visitor) const final { visitor->visit(this); } void setInputParamId(boost::optional paramId) { _inputParamId = paramId; } boost::optional getInputParamId() const { return _inputParamId; } private: virtual ExpressionOptimizerFunc getOptimizer() const final { return [](std::unique_ptr expression) { return expression; }; } int _size; // >= 0 real, < 0, nothing will match boost::optional _inputParamId; }; } // namespace mongo