From 8736544c4a2f4fbd38792f656408f7b807b786d7 Mon Sep 17 00:00:00 2001 From: Alya Berciu Date: Tue, 30 Mar 2021 16:29:12 +0100 Subject: SERVER-30417: Implement $getField expression Co-authored-by: Katherine Wu --- src/mongo/db/pipeline/expression.h | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'src/mongo/db/pipeline/expression.h') diff --git a/src/mongo/db/pipeline/expression.h b/src/mongo/db/pipeline/expression.h index f89e45a46a1..e0571735a18 100644 --- a/src/mongo/db/pipeline/expression.h +++ b/src/mongo/db/pipeline/expression.h @@ -50,6 +50,7 @@ #include "mongo/db/pipeline/field_path.h" #include "mongo/db/pipeline/variables.h" #include "mongo/db/query/datetime/date_time_support.h" +#include "mongo/db/query/query_feature_flags_gen.h" #include "mongo/db/query/sort_pattern.h" #include "mongo/db/server_options.h" #include "mongo/util/intrusive_counter.h" @@ -77,6 +78,25 @@ class DocumentSource; Expression::registerExpression("$" #key, (parser), boost::none); \ } +/** + * Registers a Parser so it can be called from parseExpression and friends (but only if + * 'featureFlag' is enabled). + * + * As an example, if your expression looks like {"$foo": [1,2,3]} and should be flag-guarded by + * feature_flags::gFoo, you would add this line: + * REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION(foo, ExpressionFoo::parse, feature_flags::gFoo); + * + * An expression registered this way can be used in any featureCompatibilityVersion. + */ +#define REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION(key, parser, featureFlag) \ + MONGO_INITIALIZER_GENERAL( \ + addToExpressionParserMap_##key, ("default"), ("expressionParserMap")) \ + (InitializerContext*) { \ + if (featureFlag.isEnabledAndIgnoreFCV()) { \ + Expression::registerExpression("$" #key, (parser), boost::none); \ + } \ + } + /** * Registers a Parser so it can be called from parseExpression and friends. Use this version if your * expression can only be persisted to a catalog data structure in a feature compatibility version @@ -3472,4 +3492,46 @@ private: // Accepted BSON type: String. If not specified, "sunday" is used. boost::intrusive_ptr& _startOfWeek; }; + +class ExpressionGetField final : public Expression { +public: + static boost::intrusive_ptr parse(ExpressionContext* const expCtx, + BSONElement exprElement, + const VariablesParseState& vps); + + /** + * Constructs a $getField expression where 'field' is an expression resolving to a string Value + * (or null) and 'from' is an expression resolving to an object Value (or null). + * + * If either 'field' or 'from' is nullish, $getField evaluates to null. Furthermore, if 'from' + * does not contain 'field', then $getField returns missing. + */ + ExpressionGetField(ExpressionContext* const expCtx, + boost::intrusive_ptr field, + boost::intrusive_ptr from) + : Expression(expCtx, {std::move(field), std::move(from)}), + _field(_children[0]), + _from(_children[1]) { + expCtx->sbeCompatible = false; + } + + Value serialize(const bool explain) const final; + + Value evaluate(const Document& root, Variables* variables) const final; + + boost::intrusive_ptr optimize() final; + + void acceptVisitor(ExpressionVisitor* visitor) final { + return visitor->visit(this); + } + + static constexpr auto kExpressionName = "$getField"_sd; + +protected: + void _doAddDependencies(DepsTracker* deps) const final override; + +private: + boost::intrusive_ptr& _field; + boost::intrusive_ptr& _from; +}; } // namespace mongo -- cgit v1.2.1