1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #pragma once
32 
33 #include "mongo/db/matcher/expression_leaf.h"
34 #include "mongo/db/matcher/matcher_type_set.h"
35 
36 namespace mongo {
37 
38 template <class T>
39 class TypeMatchExpressionBase : public LeafMatchExpression {
40 public:
TypeMatchExpressionBase(MatchType matchType,ElementPath::LeafArrayBehavior leafArrBehavior)41     explicit TypeMatchExpressionBase(MatchType matchType,
42                                      ElementPath::LeafArrayBehavior leafArrBehavior)
43         : LeafMatchExpression(
44               matchType, leafArrBehavior, ElementPath::NonLeafArrayBehavior::kTraverse) {}
45 
46     virtual ~TypeMatchExpressionBase() = default;
47 
48     /**
49      * Returns the name of this MatchExpression.
50      */
51     virtual StringData name() const = 0;
52 
init(StringData path,MatcherTypeSet typeSet)53     Status init(StringData path, MatcherTypeSet typeSet) {
54         _typeSet = std::move(typeSet);
55         return setPath(path);
56     }
57 
shallowClone()58     std::unique_ptr<MatchExpression> shallowClone() const final {
59         auto expr = stdx::make_unique<T>();
60         invariantOK(expr->init(path(), _typeSet));
61         if (getTag()) {
62             expr->setTag(getTag()->clone());
63         }
64         return std::move(expr);
65     }
66 
67     bool matchesSingleElement(const BSONElement& elem,
68                               MatchDetails* details = nullptr) const final {
69         return _typeSet.hasType(elem.type());
70     }
71 
debugString(StringBuilder & debug,int level)72     void debugString(StringBuilder& debug, int level) const final {
73         _debugAddSpace(debug, level);
74         debug << path() << " " << name() << ": " << _typeSet.toBSONArray().toString();
75 
76         MatchExpression::TagData* td = getTag();
77         if (td) {
78             debug << " ";
79             td->debugString(&debug);
80         }
81         debug << "\n";
82     }
83 
serialize(BSONObjBuilder * out)84     void serialize(BSONObjBuilder* out) const final {
85         BSONObjBuilder subBuilder(out->subobjStart(path()));
86         BSONArrayBuilder arrBuilder(subBuilder.subarrayStart(name()));
87         _typeSet.toBSONArray(&arrBuilder);
88         arrBuilder.doneFast();
89         subBuilder.doneFast();
90     }
91 
equivalent(const MatchExpression * other)92     bool equivalent(const MatchExpression* other) const final {
93         if (matchType() != other->matchType())
94             return false;
95 
96         auto realOther = static_cast<const T*>(other);
97 
98         if (path() != realOther->path()) {
99             return false;
100         }
101 
102         return _typeSet == realOther->_typeSet;
103     }
104 
105     /**
106      * Returns a representation of the set of matching types.
107      */
typeSet()108     const MatcherTypeSet& typeSet() const {
109         return _typeSet;
110     }
111 
112 private:
getOptimizer()113     ExpressionOptimizerFunc getOptimizer() const final {
114         return [](std::unique_ptr<MatchExpression> expression) { return expression; };
115     }
116 
117     // The set of matching types.
118     MatcherTypeSet _typeSet;
119 };
120 
121 class TypeMatchExpression final : public TypeMatchExpressionBase<TypeMatchExpression> {
122 public:
123     static constexpr StringData kName = "$type"_sd;
124 
TypeMatchExpression()125     TypeMatchExpression()
126         : TypeMatchExpressionBase(MatchExpression::TYPE_OPERATOR,
127                                   ElementPath::LeafArrayBehavior::kTraverse) {}
128 
name()129     StringData name() const final {
130         return kName;
131     }
132 };
133 
134 /**
135  * Implements matching semantics for the JSON Schema type keyword. Although the MongoDB query
136  * language has a $type operator, its meaning for arrays differs from JSON Schema. Therefore, we
137  * implement a separate type node for schema matching.
138  */
139 class InternalSchemaTypeExpression final
140     : public TypeMatchExpressionBase<InternalSchemaTypeExpression> {
141 public:
142     static constexpr StringData kName = "$_internalSchemaType"_sd;
143 
InternalSchemaTypeExpression()144     InternalSchemaTypeExpression()
145         : TypeMatchExpressionBase(MatchExpression::INTERNAL_SCHEMA_TYPE,
146                                   ElementPath::LeafArrayBehavior::kNoTraversal) {}
147 
name()148     StringData name() const final {
149         return kName;
150     }
151 
getCategory()152     MatchCategory getCategory() const final {
153         return MatchCategory::kOther;
154     }
155 };
156 
157 }  // namespace mongo
158