Co-authored-by: Gregory Noma <gregory.noma@gmail.com> Co-authored-by: Alyssa Clark <alyssa.clark@mongodb.com> Co-authored-by: Thomas Goyne <thomas.goyne@mongodb.com> Co-authored-by: Philip Stoev <philip.stoev@mongodb.com> Co-authored-by: Joan Bruguera Micó (at MongoDB) <joan.bruguera-mico@mongodb.com> Co-authored-by: Matthew Boros <mattBoros@users.noreply.github.com> Co-authored-by: Finley Lau <finley.lau@mongodb.com> Co-authored-by: Daniel Moody <dmoody256@gmail.com> Co-authored-by: Ted Tuckman <TedTuckman@users.noreply.github.com> Co-authored-by: Yuhong Zhang <yuhong.zhang@mongodb.com> Co-authored-by: Copilot <copilot@github.com> GitOrigin-RevId: 0a318ad31b0a7881549f93fb6bc0dd4cb57934e3
149 lines
4.6 KiB
JavaScript
149 lines
4.6 KiB
JavaScript
// Tests that JavaScript functions stored in system.js are loaded on a per-expression basis.
|
|
// @tags: [
|
|
// assumes_unsharded_collection,
|
|
// requires_non_retryable_writes,
|
|
// # Uses $function operator.
|
|
// requires_scripting,
|
|
// requires_system_dot_js_stored_functions,
|
|
// # system.js stored functions only work for collections that live on the db-primary shard so
|
|
// # we have to make sure it wont be moved anywhere by the balancer
|
|
// assumes_balancer_off,
|
|
// # TODO(SERVER-84158): Try to include this test(s).
|
|
// exclude_from_timeseries_crud_passthrough,
|
|
// # TODO SERVER-116052: Add support for $function.
|
|
// # TODO SERVER-116054: Add support for $where.
|
|
// # TODO SERVER-116055: Add support for $accumulate.
|
|
// mozjs_wasm_unsupported,
|
|
// ]
|
|
|
|
const testDB = db.getSiblingDB("system_js_access");
|
|
const coll = testDB.system_js_access;
|
|
coll.drop();
|
|
testDB.getCollection("system.js").deleteMany({});
|
|
|
|
assert.commandWorked(
|
|
coll.insert([
|
|
{"name": "Alice", "age": 68},
|
|
{"name": "Bowen", "age": 20},
|
|
{"name": "Carlos", "age": 24},
|
|
{"name": "Daniel", "age": 47},
|
|
{"name": "Eric", "age": 14},
|
|
{"name": "France", "age": 1},
|
|
]),
|
|
);
|
|
|
|
// Store JS function in database.
|
|
assert.commandWorked(
|
|
testDB.getCollection("system.js").insert({
|
|
_id: "isAdult",
|
|
value: function (age) {
|
|
return age >= 21;
|
|
},
|
|
}),
|
|
);
|
|
|
|
// $where can access stored functions.
|
|
assert.commandWorked(testDB.runCommand({find: coll.getName(), filter: {$where: "isAdult(this.age)"}}));
|
|
|
|
// $function cannot access stored functions.
|
|
assert.commandFailedWithCode(
|
|
testDB.runCommand({
|
|
aggregate: coll.getName(),
|
|
pipeline: [{$addFields: {isAdult: {$function: {body: "isAdult(age)", args: ["$age"], lang: "js"}}}}],
|
|
cursor: {},
|
|
}),
|
|
ErrorCodes.JSInterpreterFailure,
|
|
);
|
|
|
|
// The same function specified in-line can be executed by $function.
|
|
assert.commandWorked(
|
|
testDB.runCommand({
|
|
aggregate: coll.getName(),
|
|
pipeline: [
|
|
{
|
|
$match: {
|
|
$expr: {
|
|
$function: {
|
|
body: function (age) {
|
|
return age >= 21;
|
|
},
|
|
args: ["$age"],
|
|
lang: "js",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
],
|
|
cursor: {},
|
|
}),
|
|
);
|
|
|
|
// Mixed queries with both $where and $function should fail, because $where has to provide system.js
|
|
// to user code, and $function has to not provide it.
|
|
assert.commandFailedWithCode(
|
|
testDB.runCommand({
|
|
find: coll.getName(),
|
|
filter: {
|
|
$and: [
|
|
{
|
|
$expr: {
|
|
$function: {
|
|
body: function (age) {
|
|
return age >= 21;
|
|
},
|
|
args: ["$age"],
|
|
lang: "js",
|
|
},
|
|
},
|
|
},
|
|
{$where: "isAdult(this.age)"},
|
|
],
|
|
},
|
|
}),
|
|
4649200,
|
|
);
|
|
|
|
// Queries with both $function and $accumulator should succeed, because both of these operators
|
|
// provide system.js to user code.
|
|
assert.commandWorked(
|
|
testDB.runCommand({
|
|
aggregate: coll.getName(),
|
|
pipeline: [
|
|
{
|
|
$match: {
|
|
$expr: {
|
|
$function: {
|
|
body: function (age) {
|
|
return age >= 21;
|
|
},
|
|
args: ["$age"],
|
|
lang: "js",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
$group: {
|
|
_id: "$name",
|
|
age: {
|
|
$accumulator: {
|
|
init: function () {
|
|
return 0;
|
|
},
|
|
accumulate: function (state, value) {
|
|
return state + value;
|
|
},
|
|
accumulateArgs: ["$age"],
|
|
merge: function (state1, state2) {
|
|
return state1 + state2;
|
|
},
|
|
lang: "js",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
],
|
|
cursor: {},
|
|
}),
|
|
);
|