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