// Tests basic functionality of the $function expression. // // @tags: [ // requires_scripting, // ] import {resultsEq} from "jstests/aggregation/extras/utils.js"; const coll = db.expression_function; coll.drop(); function f_finalize(first, second) { return first + second; } for (let i = 0; i < 5; i++) { assert.commandWorked(coll.insert({value: i})); } let pipeline = [ { $project: { newValue: { $function: { args: ["$value", -1], body: f_finalize, lang: "js", }, }, _id: 0, }, }, ]; let results = coll.aggregate(pipeline, {cursor: {batchSize: 1}}).toArray(); assert(resultsEq(results, [{newValue: -1}, {newValue: 0}, {newValue: 1}, {newValue: 2}, {newValue: 3}]), results); // Test that the 'body' function accepts a string argument. pipeline[0].$project.newValue.$function.body = f_finalize.toString(); results = coll.aggregate(pipeline, {cursor: {}}).toArray(); assert(resultsEq(results, [{newValue: -1}, {newValue: 0}, {newValue: 1}, {newValue: 2}, {newValue: 3}]), results); // Test that function can take an expression that evaluates to an array for the 'args' parameter. coll.drop(); for (let i = 0; i < 5; i++) { assert.commandWorked(coll.insert({values: [i, i * 2]})); } pipeline = [ { $project: { newValue: { $function: { args: "$values", body: f_finalize, lang: "js", }, }, _id: 0, }, }, ]; results = coll.aggregate(pipeline, {cursor: {}}).toArray(); assert(resultsEq(results, [{newValue: 0}, {newValue: 3}, {newValue: 6}, {newValue: 9}, {newValue: 12}]), results); // Test that the command correctly fails for invalid arguments. pipeline = [ { $project: { newValue: { $function: { "args": "must evaluate to an array", "body": f_finalize, "lang": "js", }, }, _id: 0, }, }, ]; assert.commandFailedWithCode(db.runCommand({aggregate: coll.getName(), pipeline: pipeline, cursor: {}}), 31266); pipeline = [ { $project: { newValue: { $function: { "args": [1, 3], "body": "this is not a valid function!", "lang": "js", }, }, _id: 0, }, }, ]; assert.commandFailedWithCode( db.runCommand({aggregate: coll.getName(), pipeline: pipeline, cursor: {}}), ErrorCodes.JSInterpreterFailure, ); pipeline = [ { $project: { newValue: { $function: { "args": [1, 3], "body": f_finalize, }, }, _id: 0, }, }, ]; assert.commandFailedWithCode(db.runCommand({aggregate: coll.getName(), pipeline: pipeline, cursor: {}}), 31418); pipeline = [ { $project: { newValue: { $function: { "args": [1, 3], "body": f_finalize, "lang": "not js!", }, }, _id: 0, }, }, ]; assert.commandFailedWithCode(db.runCommand({aggregate: coll.getName(), pipeline: pipeline, cursor: {}}), 31419); // Test that we fail if the 'args' field is not an array. pipeline = [ { $project: { newValue: { $function: { "args": "A string!", "body": f_finalize, "lang": "js", }, }, _id: 0, }, }, ]; assert.commandFailedWithCode(db.runCommand({aggregate: coll.getName(), pipeline: pipeline, cursor: {}}), 31266);