1 // expression_array.h
2 
3 
4 /**
5  *    Copyright (C) 2018-present MongoDB, Inc.
6  *
7  *    This program is free software: you can redistribute it and/or modify
8  *    it under the terms of the Server Side Public License, version 1,
9  *    as published by MongoDB, Inc.
10  *
11  *    This program is distributed in the hope that it will be useful,
12  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *    Server Side Public License for more details.
15  *
16  *    You should have received a copy of the Server Side Public License
17  *    along with this program. If not, see
18  *    <http://www.mongodb.com/licensing/server-side-public-license>.
19  *
20  *    As a special exception, the copyright holders give permission to link the
21  *    code of portions of this program with the OpenSSL library under certain
22  *    conditions as described in each individual source file and distribute
23  *    linked combinations including the program with the OpenSSL library. You
24  *    must comply with the Server Side Public License in all respects for
25  *    all of the code used other than as permitted herein. If you modify file(s)
26  *    with this exception, you may extend this exception to your version of the
27  *    file(s), but you are not obligated to do so. If you do not wish to do so,
28  *    delete this exception statement from your version. If you delete this
29  *    exception statement from all source files in the program, then also delete
30  *    it in the license file.
31  */
32 
33 #pragma once
34 
35 #include <vector>
36 
37 #include "mongo/base/status.h"
38 #include "mongo/bson/bsonmisc.h"
39 #include "mongo/bson/bsonobj.h"
40 #include "mongo/db/matcher/expression_path.h"
41 
42 namespace mongo {
43 
44 /**
45  * A path match expression which does not expand arrays at the end of the path, and which only
46  * matches if the path contains an array.
47  */
48 class ArrayMatchingMatchExpression : public PathMatchExpression {
49 public:
ArrayMatchingMatchExpression(MatchType matchType)50     ArrayMatchingMatchExpression(MatchType matchType)
51         : PathMatchExpression(matchType,
52                               ElementPath::LeafArrayBehavior::kNoTraversal,
53                               ElementPath::NonLeafArrayBehavior::kTraverse) {}
54 
~ArrayMatchingMatchExpression()55     virtual ~ArrayMatchingMatchExpression() {}
56 
57     /**
58      * Returns whether or not the nested array, represented as the object 'anArray', matches.
59      *
60      * 'anArray' must be the nested array at this expression's path.
61      */
62     virtual bool matchesArray(const BSONObj& anArray, MatchDetails* details) const = 0;
63 
64     bool matchesSingleElement(const BSONElement&, MatchDetails* details = nullptr) const final;
65 
66     bool equivalent(const MatchExpression* other) const override;
67 
getCategory()68     MatchCategory getCategory() const final {
69         return MatchCategory::kArrayMatching;
70     }
71 };
72 
73 class ElemMatchObjectMatchExpression : public ArrayMatchingMatchExpression {
74 public:
ElemMatchObjectMatchExpression()75     ElemMatchObjectMatchExpression() : ArrayMatchingMatchExpression(ELEM_MATCH_OBJECT) {}
76     Status init(StringData path, MatchExpression* sub);
77 
78     bool matchesArray(const BSONObj& anArray, MatchDetails* details) const;
79 
shallowClone()80     virtual std::unique_ptr<MatchExpression> shallowClone() const {
81         std::unique_ptr<ElemMatchObjectMatchExpression> e =
82             stdx::make_unique<ElemMatchObjectMatchExpression>();
83         e->init(path(), _sub->shallowClone().release()).transitional_ignore();
84         if (getTag()) {
85             e->setTag(getTag()->clone());
86         }
87         return std::move(e);
88     }
89 
90     virtual void debugString(StringBuilder& debug, int level) const;
91 
92     virtual void serialize(BSONObjBuilder* out) const;
93 
getChildVector()94     std::vector<MatchExpression*>* getChildVector() final {
95         return nullptr;
96     }
97 
numChildren()98     virtual size_t numChildren() const {
99         return 1;
100     }
101 
getChild(size_t i)102     virtual MatchExpression* getChild(size_t i) const {
103         return _sub.get();
104     }
105 
releaseChild()106     std::unique_ptr<MatchExpression> releaseChild() {
107         return std::move(_sub);
108     }
109 
resetChild(std::unique_ptr<MatchExpression> newChild)110     void resetChild(std::unique_ptr<MatchExpression> newChild) {
111         _sub = std::move(newChild);
112     }
113 
114 private:
115     ExpressionOptimizerFunc getOptimizer() const final;
116 
117     std::unique_ptr<MatchExpression> _sub;
118 };
119 
120 class ElemMatchValueMatchExpression : public ArrayMatchingMatchExpression {
121 public:
ElemMatchValueMatchExpression()122     ElemMatchValueMatchExpression() : ArrayMatchingMatchExpression(ELEM_MATCH_VALUE) {}
123     virtual ~ElemMatchValueMatchExpression();
124 
125     Status init(StringData path);
126     Status init(StringData path, MatchExpression* sub);
127     void add(MatchExpression* sub);
128 
129     bool matchesArray(const BSONObj& anArray, MatchDetails* details) const;
130 
shallowClone()131     virtual std::unique_ptr<MatchExpression> shallowClone() const {
132         std::unique_ptr<ElemMatchValueMatchExpression> e =
133             stdx::make_unique<ElemMatchValueMatchExpression>();
134         e->init(path()).transitional_ignore();
135         for (size_t i = 0; i < _subs.size(); ++i) {
136             e->add(_subs[i]->shallowClone().release());
137         }
138         if (getTag()) {
139             e->setTag(getTag()->clone());
140         }
141         return std::move(e);
142     }
143 
144     virtual void debugString(StringBuilder& debug, int level) const;
145 
146     virtual void serialize(BSONObjBuilder* out) const;
147 
getChildVector()148     virtual std::vector<MatchExpression*>* getChildVector() {
149         return &_subs;
150     }
151 
numChildren()152     virtual size_t numChildren() const {
153         return _subs.size();
154     }
155 
getChild(size_t i)156     virtual MatchExpression* getChild(size_t i) const {
157         return _subs[i];
158     }
159 
160 private:
161     ExpressionOptimizerFunc getOptimizer() const final;
162 
163     bool _arrayElementMatchesAll(const BSONElement& e) const;
164 
165     std::vector<MatchExpression*> _subs;
166 };
167 
168 class SizeMatchExpression : public ArrayMatchingMatchExpression {
169 public:
SizeMatchExpression()170     SizeMatchExpression() : ArrayMatchingMatchExpression(SIZE) {}
171     Status init(StringData path, int size);
172 
shallowClone()173     virtual std::unique_ptr<MatchExpression> shallowClone() const {
174         std::unique_ptr<SizeMatchExpression> e = stdx::make_unique<SizeMatchExpression>();
175         e->init(path(), _size).transitional_ignore();
176         if (getTag()) {
177             e->setTag(getTag()->clone());
178         }
179         return std::move(e);
180     }
181 
numChildren()182     size_t numChildren() const override {
183         return 0;
184     }
185 
getChild(size_t i)186     MatchExpression* getChild(size_t i) const override {
187         return nullptr;
188     }
189 
getChildVector()190     std::vector<MatchExpression*>* getChildVector() final {
191         return nullptr;
192     }
193 
194     virtual bool matchesArray(const BSONObj& anArray, MatchDetails* details) const;
195 
196     virtual void debugString(StringBuilder& debug, int level) const;
197 
198     virtual void serialize(BSONObjBuilder* out) const;
199 
200     virtual bool equivalent(const MatchExpression* other) const;
201 
getData()202     int getData() const {
203         return _size;
204     }
205 
206 private:
getOptimizer()207     virtual ExpressionOptimizerFunc getOptimizer() const final {
208         return [](std::unique_ptr<MatchExpression> expression) { return expression; };
209     }
210 
211     int _size;  // >= 0 real, < 0, nothing will match
212 };
213 }
214