diff options
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/commands/mr_common.cpp | 25 | ||||
-rw-r--r-- | src/mongo/db/pipeline/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_function.cpp | 112 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_function.h | 79 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_javascript.cpp (renamed from src/mongo/db/pipeline/expression_js_emit.cpp) | 65 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_javascript.h (renamed from src/mongo/db/pipeline/expression_js_emit.h) | 41 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_javascript_test.cpp | 88 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_visitor.h | 4 |
8 files changed, 150 insertions, 267 deletions
diff --git a/src/mongo/db/commands/mr_common.cpp b/src/mongo/db/commands/mr_common.cpp index 098c702f408..fcdf998e125 100644 --- a/src/mongo/db/commands/mr_common.cpp +++ b/src/mongo/db/commands/mr_common.cpp @@ -52,8 +52,7 @@ #include "mongo/db/pipeline/document_source_single_document_transformation.h" #include "mongo/db/pipeline/document_source_sort.h" #include "mongo/db/pipeline/document_source_unwind.h" -#include "mongo/db/pipeline/expression_function.h" -#include "mongo/db/pipeline/expression_js_emit.h" +#include "mongo/db/pipeline/expression_javascript.h" #include "mongo/db/query/util/make_data_structure.h" #include "mongo/util/intrusive_counter.h" #include "mongo/util/log.h" @@ -140,15 +139,14 @@ auto translateReduce(boost::intrusive_ptr<ExpressionContext> expCtx, std::string auto translateFinalize(boost::intrusive_ptr<ExpressionContext> expCtx, MapReduceJavascriptCodeOrNull codeObj) { return codeObj.getCode().map([&](auto&& code) { - auto jsExpression = ExpressionFunction::create( + auto jsExpression = ExpressionInternalJs::create( expCtx, ExpressionArray::create( expCtx, make_vector<boost::intrusive_ptr<Expression>>( ExpressionFieldPath::parse(expCtx, "$_id", expCtx->variablesParseState), ExpressionFieldPath::parse(expCtx, "$value", expCtx->variablesParseState))), - code, - ExpressionFunction::kJavaScript); + code); auto node = std::make_unique<projection_executor::InclusionNode>( ProjectionPolicies{ProjectionPolicies::DefaultIdPolicy::kIncludeId}); node->addProjectionForPath(FieldPath{"_id"s}); @@ -189,24 +187,23 @@ auto translateOutReduce(boost::intrusive_ptr<ExpressionContext> expCtx, // Because of communication for sharding, $merge must hold on to a serializable BSON object // at the moment so we reparse here. Note that the reduce function signature expects 2 // arguments, the first being the key and the second being the array of values to reduce. - auto reduceObj = - BSON("args" << BSON_ARRAY("$_id" << BSON_ARRAY("$value" - << "$$new.value")) - << "body" << reduceCode << "lang" << ExpressionFunction::kJavaScript); + auto reduceObj = BSON("args" << BSON_ARRAY("$_id" << BSON_ARRAY("$value" + << "$$new.value")) + << "eval" << reduceCode); - auto reduceSpec = BSON(DocumentSourceProject::kStageName << BSON( - "value" << BSON(ExpressionFunction::kExpressionName << reduceObj))); + auto reduceSpec = + BSON(DocumentSourceProject::kStageName + << BSON("value" << BSON(ExpressionInternalJs::kExpressionName << reduceObj))); auto pipelineSpec = boost::make_optional(std::vector<BSONObj>{reduceSpec}); // Build finalize $project stage if given. if (finalizeCode && finalizeCode->hasCode()) { auto finalizeObj = BSON("args" << BSON_ARRAY("$_id" << "$value") - << "body" << finalizeCode->getCode().get() << "lang" - << ExpressionFunction::kJavaScript); + << "eval" << finalizeCode->getCode().get()); auto finalizeSpec = BSON(DocumentSourceProject::kStageName - << BSON("value" << BSON(ExpressionFunction::kExpressionName << finalizeObj))); + << BSON("value" << BSON(ExpressionInternalJs::kExpressionName << finalizeObj))); pipelineSpec->emplace_back(std::move(finalizeSpec)); } diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript index 45dceed8cf2..fa27da05155 100644 --- a/src/mongo/db/pipeline/SConscript +++ b/src/mongo/db/pipeline/SConscript @@ -103,8 +103,7 @@ env.Library( env.Library( target='expression_javascript', source=[ - 'expression_function.cpp', - 'expression_js_emit.cpp' + 'expression_javascript.cpp' ], LIBDEPS=[ '$BUILD_DIR/mongo/scripting/scripting_common', diff --git a/src/mongo/db/pipeline/expression_function.cpp b/src/mongo/db/pipeline/expression_function.cpp deleted file mode 100644 index 399a8847e03..00000000000 --- a/src/mongo/db/pipeline/expression_function.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (C) 2019-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 - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * 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. - */ - -#include "mongo/db/pipeline/expression_function.h" - -namespace mongo { - -REGISTER_EXPRESSION_WITH_MIN_VERSION( - function, - ExpressionFunction::parse, - ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo44); - -ExpressionFunction::ExpressionFunction(const boost::intrusive_ptr<ExpressionContext>& expCtx, - boost::intrusive_ptr<Expression> passedArgs, - std::string funcSource, - std::string lang) - : Expression(expCtx, {std::move(passedArgs)}), - _passedArgs(_children[0]), - _funcSource(std::move(funcSource)), - _lang(std::move(lang)) {} - -Value ExpressionFunction::serialize(bool explain) const { - return Value(Document{{kExpressionName, - Document{{"body", _funcSource}, - {"args", _passedArgs->serialize(explain)}, - {"lang", _lang}}}}); -} - -void ExpressionFunction::_doAddDependencies(mongo::DepsTracker* deps) const { - _children[0]->addDependencies(deps); -} - -boost::intrusive_ptr<Expression> ExpressionFunction::parse( - const boost::intrusive_ptr<ExpressionContext>& expCtx, - BSONElement expr, - const VariablesParseState& vps) { - - uassert(31260, - str::stream() << kExpressionName - << " requires an object as an argument, found: " << expr.type(), - expr.type() == BSONType::Object); - - BSONElement bodyField = expr["body"]; - - uassert(31261, "The body function must be specified.", bodyField); - - boost::intrusive_ptr<Expression> bodyExpr = Expression::parseOperand(expCtx, bodyField, vps); - - auto bodyConst = dynamic_cast<ExpressionConstant*>(bodyExpr.get()); - uassert(31432, "The body function must be a constant expression", bodyConst); - - auto bodyValue = bodyConst->getValue(); - uassert(31262, - "The body function must evaluate to type string or code", - bodyValue.getType() == BSONType::String || bodyValue.getType() == BSONType::Code); - - BSONElement argsField = expr["args"]; - uassert(31263, "The args field must be specified.", argsField); - boost::intrusive_ptr<Expression> argsExpr = parseOperand(expCtx, argsField, vps); - - BSONElement langField = expr["lang"]; - uassert(31418, "The lang field must be specified.", langField); - uassert(31419, - "Currently the only supported language specifier is 'js'.", - langField.type() == BSONType::String && langField.str() == kJavaScript); - - return new ExpressionFunction(expCtx, argsExpr, bodyValue.coerceToString(), langField.str()); -} - -Value ExpressionFunction::evaluate(const Document& root, Variables* variables) const { - auto jsExec = getExpressionContext()->getJsExecWithScope(); - - ScriptingFunction func = jsExec->getScope()->createFunction(_funcSource.c_str()); - uassert(31265, "The body function did not evaluate", func); - - auto argValue = _passedArgs->evaluate(root, variables); - uassert(31266, "The args field must be of type array", argValue.getType() == BSONType::Array); - - int argNum = 0; - BSONObjBuilder bob; - for (const auto& arg : argValue.getArray()) { - arg.addToBsonObj(&bob, "arg" + std::to_string(argNum++)); - } - return jsExec->callFunction(func, bob.done(), {}); -}; -} // namespace mongo
\ No newline at end of file diff --git a/src/mongo/db/pipeline/expression_function.h b/src/mongo/db/pipeline/expression_function.h deleted file mode 100644 index 3d8d5e2df7b..00000000000 --- a/src/mongo/db/pipeline/expression_function.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright (C) 2019-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 - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * 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 "mongo/db/pipeline/expression.h" -#include "mongo/db/pipeline/javascript_execution.h" - -namespace mongo { -/** - * This expression takes a function, an array of arguments to pass to it, and the language - * specifier (currently limited to JavaScript). It returns the return value of the function with - * the given arguments. - */ -class ExpressionFunction final : public Expression { -public: - static boost::intrusive_ptr<Expression> parse( - const boost::intrusive_ptr<ExpressionContext>& expCtx, - BSONElement expr, - const VariablesParseState& vps); - - static boost::intrusive_ptr<ExpressionFunction> create( - const boost::intrusive_ptr<ExpressionContext>& expCtx, - boost::intrusive_ptr<Expression> passedArgs, - std::string funcSourceString, - std::string lang) { - return new ExpressionFunction{ - expCtx, passedArgs, std::move(funcSourceString), std::move(lang)}; - } - - Value evaluate(const Document& root, Variables* variables) const final; - - Value serialize(bool explain) const final; - - void acceptVisitor(ExpressionVisitor* visitor) final { - return visitor->visit(this); - } - - static constexpr auto kExpressionName = "$function"_sd; - static constexpr auto kJavaScript = "js"; - -private: - ExpressionFunction(const boost::intrusive_ptr<ExpressionContext>& expCtx, - boost::intrusive_ptr<Expression> passedArgs, - std::string funcSourceString, - std::string lang); - void _doAddDependencies(DepsTracker* deps) const final override; - - const boost::intrusive_ptr<Expression>& _passedArgs; - std::string _funcSource; - std::string _lang; -}; -} // namespace mongo
\ No newline at end of file diff --git a/src/mongo/db/pipeline/expression_js_emit.cpp b/src/mongo/db/pipeline/expression_javascript.cpp index 4072ecee993..4e3f489e7f2 100644 --- a/src/mongo/db/pipeline/expression_js_emit.cpp +++ b/src/mongo/db/pipeline/expression_javascript.cpp @@ -30,13 +30,15 @@ #include "mongo/platform/basic.h" #include "mongo/db/auth/authorization_session.h" -#include "mongo/db/pipeline/expression_js_emit.h" +#include "mongo/db/pipeline/expression_javascript.h" #include "mongo/db/pipeline/make_js_function.h" #include "mongo/db/query/query_knobs_gen.h" namespace mongo { REGISTER_EXPRESSION(_internalJsEmit, ExpressionInternalJsEmit::parse); + +REGISTER_EXPRESSION(_internalJs, ExpressionInternalJs::parse); namespace { /** @@ -127,4 +129,65 @@ Value ExpressionInternalJsEmit::evaluate(const Document& root, Variables* variab _emitState.reset(); return returnValue; } + +ExpressionInternalJs::ExpressionInternalJs(const boost::intrusive_ptr<ExpressionContext>& expCtx, + boost::intrusive_ptr<Expression> passedArgs, + std::string funcSource) + : Expression(expCtx, {std::move(passedArgs)}), + _passedArgs(_children[0]), + _funcSource(std::move(funcSource)) {} + +Value ExpressionInternalJs::serialize(bool explain) const { + return Value( + Document{{kExpressionName, + Document{{"eval", _funcSource}, {"args", _passedArgs->serialize(explain)}}}}); +} + +void ExpressionInternalJs::_doAddDependencies(mongo::DepsTracker* deps) const { + _children[0]->addDependencies(deps); +} + +boost::intrusive_ptr<Expression> ExpressionInternalJs::parse( + const boost::intrusive_ptr<ExpressionContext>& expCtx, + BSONElement expr, + const VariablesParseState& vps) { + + uassert(31260, + str::stream() << kExpressionName + << " requires an object as an argument, found: " << expr.type(), + expr.type() == BSONType::Object); + + BSONElement evalField = expr["eval"]; + + uassert(31261, "The eval function must be specified.", evalField); + uassert(31262, + "The eval function must be of type string or code", + evalField.type() == BSONType::String || evalField.type() == BSONType::Code); + + BSONElement argsField = expr["args"]; + uassert(31263, "The args field must be specified.", argsField); + boost::intrusive_ptr<Expression> argsExpr = parseOperand(expCtx, argsField, vps); + + return new ExpressionInternalJs(expCtx, argsExpr, evalField._asCode()); +} + +Value ExpressionInternalJs::evaluate(const Document& root, Variables* variables) const { + auto& expCtx = getExpressionContext(); + + auto jsExec = expCtx->getJsExecWithScope(); + + ScriptingFunction func = jsExec->getScope()->createFunction(_funcSource.c_str()); + uassert(31265, "The eval function did not evaluate", func); + + auto argExpressions = _passedArgs->evaluate(root, variables); + uassert( + 31266, "The args field must be of type array", argExpressions.getType() == BSONType::Array); + + int argNum = 0; + BSONObjBuilder bob; + for (const auto& arg : argExpressions.getArray()) { + arg.addToBsonObj(&bob, "arg" + std::to_string(argNum++)); + } + return jsExec->callFunction(func, bob.done(), {}); +} } // namespace mongo diff --git a/src/mongo/db/pipeline/expression_js_emit.h b/src/mongo/db/pipeline/expression_javascript.h index b81c73baa75..4368b4985af 100644 --- a/src/mongo/db/pipeline/expression_js_emit.h +++ b/src/mongo/db/pipeline/expression_javascript.h @@ -32,6 +32,10 @@ #include "mongo/db/pipeline/expression.h" #include "mongo/db/pipeline/javascript_execution.h" +/** + * This file contains all expressions which make use of JavaScript execution and depend on the JS + * engine to operate. + */ namespace mongo { /** @@ -95,4 +99,41 @@ private: std::string _funcSource; }; +/** + * This expression takes a Javascript function and an array of arguments to pass to it. It returns + * the return value of the Javascript function with the given arguments. + */ +class ExpressionInternalJs final : public Expression { +public: + static boost::intrusive_ptr<Expression> parse( + const boost::intrusive_ptr<ExpressionContext>& expCtx, + BSONElement expr, + const VariablesParseState& vps); + + static boost::intrusive_ptr<ExpressionInternalJs> create( + const boost::intrusive_ptr<ExpressionContext>& expCtx, + boost::intrusive_ptr<Expression> passedArgs, + std::string funcSourceString) { + return new ExpressionInternalJs{expCtx, passedArgs, std::move(funcSourceString)}; + } + + Value evaluate(const Document& root, Variables* variables) const final; + + Value serialize(bool explain) const final; + + void acceptVisitor(ExpressionVisitor* visitor) final { + return visitor->visit(this); + } + + static constexpr auto kExpressionName = "$_internalJs"_sd; + +private: + ExpressionInternalJs(const boost::intrusive_ptr<ExpressionContext>& expCtx, + boost::intrusive_ptr<Expression> passedArgs, + std::string funcSourceString); + void _doAddDependencies(DepsTracker* deps) const final override; + + const boost::intrusive_ptr<Expression>& _passedArgs; + std::string _funcSource; +}; } // namespace mongo diff --git a/src/mongo/db/pipeline/expression_javascript_test.cpp b/src/mongo/db/pipeline/expression_javascript_test.cpp index f11d4c0e7ef..43539f7bf75 100644 --- a/src/mongo/db/pipeline/expression_javascript_test.cpp +++ b/src/mongo/db/pipeline/expression_javascript_test.cpp @@ -27,13 +27,12 @@ * it in the license file. */ -#include "mongo/db/pipeline/expression_js_emit.h" +#include "mongo/db/pipeline/expression_javascript.h" #include "mongo/db/commands/test_commands_enabled.h" #include "mongo/db/exec/document_value/document.h" #include "mongo/db/exec/document_value/document_value_test_util.h" #include "mongo/db/pipeline/expression_context_for_test.h" -#include "mongo/db/pipeline/expression_function.h" #include "mongo/db/pipeline/process_interface/non_shardsvr_process_interface.h" #include "mongo/db/query/query_knobs_gen.h" #include "mongo/db/service_context_d_test_fixture.h" @@ -83,105 +82,80 @@ void MapReduceFixture::tearDown() { ServiceContextMongoDTest::tearDown(); } -TEST_F(MapReduceFixture, ExpressionFunctionProducesExpectedResult) { - auto bsonExpr = BSON("expr" << BSON("body" +TEST_F(MapReduceFixture, ExpressionInternalJsProducesExpectedResult) { + auto bsonExpr = BSON("expr" << BSON("eval" << "function(first, second) {return first + second;};" - << "args" << BSON_ARRAY("$a" << 4) << "lang" - << ExpressionFunction::kJavaScript)); + << "args" << BSON_ARRAY("$a" << 4))); - auto expr = ExpressionFunction::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()); + auto expr = ExpressionInternalJs::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()); Value result = expr->evaluate(Document{BSON("a" << 2)}, getVariables()); ASSERT_VALUE_EQ(result, Value(6)); bsonExpr = - BSON("expr" << BSON("body" + BSON("expr" << BSON("eval" << "function(first, second, third) {return first + second + third;};" - << "args" << BSON_ARRAY(1 << 2 << 4) << "lang" - << ExpressionFunction::kJavaScript)); - expr = ExpressionFunction::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()); + << "args" << BSON_ARRAY(1 << 2 << 4))); + expr = ExpressionInternalJs::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()); result = expr->evaluate(Document{BSONObj{}}, getVariables()); ASSERT_VALUE_EQ(result, Value(7)); - bsonExpr = BSON("expr" << BSON("body" + bsonExpr = BSON("expr" << BSON("eval" << "function(first) {return first;};" - << "args" << BSON_ARRAY(1) << "lang" - << ExpressionFunction::kJavaScript)); - expr = ExpressionFunction::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()); + << "args" << BSON_ARRAY(1))); + expr = ExpressionInternalJs::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()); result = expr->evaluate(Document{BSONObj{}}, getVariables()); ASSERT_VALUE_EQ(result, Value(1)); } -TEST_F(MapReduceFixture, ExpressionFunctionFailsIfArgsDoesNotEvaluateToArray) { - auto bsonExpr = BSON("expr" << BSON("body" +TEST_F(MapReduceFixture, ExpressionInternalJsFailsIfArgsDoesNotEvaluateToArray) { + auto bsonExpr = BSON("expr" << BSON("eval" << "function(first, second) {return first + second;};" - << "args" << BSON("a" << 1) << "lang" - << ExpressionFunction::kJavaScript)); - auto expr = ExpressionFunction::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()); + << "args" << BSON("a" << 1))); + auto expr = ExpressionInternalJs::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()); ASSERT_THROWS_CODE(expr->evaluate({}, getVariables()), AssertionException, 31266); } -TEST_F(MapReduceFixture, ExpressionFunctionFailsWithInvalidFunction) { - auto bsonExpr = BSON("expr" << BSON("body" +TEST_F(MapReduceFixture, ExpressionInternalJsFailsWithInvalidFunction) { + auto bsonExpr = BSON("expr" << BSON("eval" << "INVALID" - << "args" << BSON_ARRAY(1 << 2) << "lang" - << ExpressionFunction::kJavaScript)); - auto expr = ExpressionFunction::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()); + << "args" << BSON_ARRAY(1 << 2))); + auto expr = ExpressionInternalJs::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()); ASSERT_THROWS_CODE( expr->evaluate({}, getVariables()), AssertionException, ErrorCodes::JSInterpreterFailure); } -TEST_F(MapReduceFixture, ExpressionFunctionFailsIfArgumentIsNotObject) { +TEST_F(MapReduceFixture, ExpressionInternalJsFailsIfArgumentIsNotObject) { auto bsonExpr = BSON("expr" << 1); - ASSERT_THROWS_CODE(ExpressionFunction::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()), + ASSERT_THROWS_CODE(ExpressionInternalJs::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()), AssertionException, 31260); } -TEST_F(MapReduceFixture, ExpressionFunctionFailsIfBodyNotSpecified) { - auto bsonExpr = BSON( - "expr" << BSON("args" << BSON_ARRAY(1 << 2) << "lang" << ExpressionFunction::kJavaScript)); - ASSERT_THROWS_CODE(ExpressionFunction::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()), +TEST_F(MapReduceFixture, ExpressionInternalJsFailsIfEvalNotSpecified) { + auto bsonExpr = BSON("expr" << BSON("args" << BSON_ARRAY(1 << 2))); + ASSERT_THROWS_CODE(ExpressionInternalJs::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()), AssertionException, 31261); } -TEST_F(MapReduceFixture, ExpressionFunctionFailsIfBodyIsNotConstantExpression) { - auto bsonExpr = BSON("expr" << BSON("body" << BSONObj() << "args" << BSON_ARRAY(1 << 2) - << "lang" << ExpressionFunction::kJavaScript)); - ASSERT_THROWS_CODE(ExpressionFunction::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()), - AssertionException, - 31432); -} - -TEST_F(MapReduceFixture, ExpressionFunctionFailsIfBodyIsNotCorrectType) { - auto bsonExpr = BSON("expr" << BSON("body" << 1 << "args" << BSON_ARRAY(1 << 2) << "lang" - << ExpressionFunction::kJavaScript)); - ASSERT_THROWS_CODE(ExpressionFunction::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()), +TEST_F(MapReduceFixture, ExpressionInternalJsFailsIfEvalIsNotCorrectType) { + auto bsonExpr = BSON("expr" << BSON("eval" << BSONObj() << "args" << BSON_ARRAY(1 << 2))); + ASSERT_THROWS_CODE(ExpressionInternalJs::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()), AssertionException, 31262); } -TEST_F(MapReduceFixture, ExpressionFunctionFailsIfArgsIsNotSpecified) { - auto bsonExpr = BSON("expr" << BSON("body" - << "function(first) {return first;};" - << "lang" << ExpressionFunction::kJavaScript)); - ASSERT_THROWS_CODE(ExpressionFunction::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()), +TEST_F(MapReduceFixture, ExpressionInternalJsFailsIfArgsIsNotSpecified) { + auto bsonExpr = BSON("expr" << BSON("eval" + << "function(first) {return first;};")); + ASSERT_THROWS_CODE(ExpressionInternalJs::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()), AssertionException, 31263); } -TEST_F(MapReduceFixture, ExpressionFunctionFailsIfLangIsNotSpecified) { - auto bsonExpr = BSON("expr" << BSON("body" - << "function(first) {return first;};" - << "args" << BSON_ARRAY(1 << 2))); - ASSERT_THROWS_CODE(ExpressionFunction::parse(getExpCtx(), bsonExpr.firstElement(), getVPS()), - AssertionException, - 31418); -} - TEST_F(MapReduceFixture, ExpressionInternalJsEmitProducesExpectedResult) { auto bsonExpr = BSON("expr" << BSON("this" << "$$ROOT" diff --git a/src/mongo/db/pipeline/expression_visitor.h b/src/mongo/db/pipeline/expression_visitor.h index 326c8e2e6ce..04100467daf 100644 --- a/src/mongo/db/pipeline/expression_visitor.h +++ b/src/mongo/db/pipeline/expression_visitor.h @@ -147,7 +147,7 @@ class ExpressionInternalFindSlice; class ExpressionInternalFindPositional; class ExpressionInternalFindElemMatch; class ExpressionInternalJsEmit; -class ExpressionFunction; +class ExpressionInternalJs; class ExpressionDegreesToRadians; class ExpressionRadiansToDegrees; @@ -293,7 +293,7 @@ public: virtual void visit(ExpressionFromAccumulator<AccumulatorMergeObjects>*) = 0; virtual void visit(ExpressionTests::Testable*) = 0; virtual void visit(ExpressionInternalJsEmit*) = 0; - virtual void visit(ExpressionFunction*) = 0; + virtual void visit(ExpressionInternalJs*) = 0; virtual void visit(ExpressionInternalFindSlice*) = 0; virtual void visit(ExpressionInternalFindPositional*) = 0; virtual void visit(ExpressionInternalFindElemMatch*) = 0; |