summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKatherine Wu <katherine.wu@mongodb.com>2020-06-01 13:51:34 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-06-11 18:22:47 +0000
commit5c7cdc392c2ea058d7ec93609203fcc5bb74bb99 (patch)
tree3033463c9f2afd7f09907a2f22b120de9776b41f
parent01707971319a5970604c20598f286b2e1882a682 (diff)
downloadmongo-5c7cdc392c2ea058d7ec93609203fcc5bb74bb99.tar.gz
SERVER-46116 Add integration tests for let variables
-rw-r--r--jstests/core/command_let_variables.js250
-rw-r--r--jstests/noPassthroughWithMongod/command_let_variables.js7
-rw-r--r--src/mongo/db/views/resolved_view.cpp1
3 files changed, 152 insertions, 106 deletions
diff --git a/jstests/core/command_let_variables.js b/jstests/core/command_let_variables.js
index ea3de4d391b..2ae1b7f5f15 100644
--- a/jstests/core/command_let_variables.js
+++ b/jstests/core/command_let_variables.js
@@ -7,10 +7,11 @@
load("jstests/libs/fixture_helpers.js"); // For 'isMongos' and 'isSharded'.
-const coll = db.command_let_variables;
-const targetColl = db.command_let_variables_target;
+const testDB = db.getSiblingDB("command_let_variables");
+const coll = testDB.command_let_variables;
+const targetColl = testDB.command_let_variables_target;
-coll.drop();
+assert.commandWorked(testDB.dropDatabase());
const testDocs = [
{
@@ -80,7 +81,7 @@ expectedResults = [
assert.eq(coll.aggregate(pipeline, {let : {target_trend: "weak decline"}}).toArray(),
expectedResults);
-if (!FixtureHelpers.isMongos(db)) {
+if (!FixtureHelpers.isMongos(testDB)) {
// Test that if runtimeConstants and let are both specified, both will coexist.
// Runtime constants are not allowed on mongos passthroughs.
let constants = {
@@ -94,7 +95,7 @@ if (!FixtureHelpers.isMongos(db)) {
expectedResults);
// Test that undefined let params in the pipeline fail gracefully.
- assert.commandFailedWithCode(db.runCommand({
+ assert.commandFailedWithCode(testDB.runCommand({
aggregate: coll.getName(),
pipeline: pipeline,
runtimeConstants: constants,
@@ -112,7 +113,7 @@ if (!FixtureHelpers.isMongos(db)) {
assert.eq(coll.aggregate(pipeline_no_lets, {runtimeConstants: constants, let : {}}).toArray(),
expectedResults);
- assert.commandFailedWithCode(db.runCommand({
+ assert.commandFailedWithCode(testDB.runCommand({
aggregate: coll.getName(),
pipeline: pipeline_no_lets,
runtimeConstants: constants,
@@ -123,111 +124,119 @@ if (!FixtureHelpers.isMongos(db)) {
}
// Test that $project stage can use 'let' variables
-assert.eq(db.runCommand({
- aggregate: coll.getName(),
- pipeline: [
- {
- $project: {
- "var": {
- $let: {
- vars: {variable: "INNER"},
- "in": {
- $cond: {
- "if": {$eq: [{$substr: ["$Species", 0, 1]}, "B"]},
- then: "$$variable",
- "else": "---"
- }
- }
- }
- }
- }
- },
- {$match: {$expr: {$eq: ["$var", "INNER"]}}}
- ],
- cursor: {}
- }).cursor.firstBatch.length,
+assert.eq(testDB
+ .runCommand({
+ aggregate: coll.getName(),
+ pipeline: [
+ {
+ $project: {
+ "var": {
+ $let: {
+ vars: {variable: "INNER"},
+ "in": {
+ $cond: {
+ "if": {$eq: [{$substr: ["$Species", 0, 1]}, "B"]},
+ then: "$$variable",
+ "else": "---"
+ }
+ }
+ }
+ }
+ }
+ },
+ {$match: {$expr: {$eq: ["$var", "INNER"]}}}
+ ],
+ cursor: {}
+ })
+ .cursor.firstBatch.length,
2);
// Test that $project stage can access command-level 'let' variables.
-assert.eq(db.runCommand({
- aggregate: coll.getName(),
- pipeline: [
- {
- $project: {
- "var": {
- $cond: {
- "if": {$eq: [{$substr: ["$Species", 0, 1]}, "B"]},
- then: "$$variable",
- "else": "---"
- }
- }
- }
- },
- {$match: {$expr: {$eq: ["$var", "OUTER"]}}}
- ],
- cursor: {},
- "let": {variable: "OUTER"}
- }).cursor.firstBatch.length,
+assert.eq(testDB
+ .runCommand({
+ aggregate: coll.getName(),
+ pipeline: [
+ {
+ $project: {
+ "var": {
+ $cond: {
+ "if": {$eq: [{$substr: ["$Species", 0, 1]}, "B"]},
+ then: "$$variable",
+ "else": "---"
+ }
+ }
+ }
+ },
+ {$match: {$expr: {$eq: ["$var", "OUTER"]}}}
+ ],
+ cursor: {},
+ "let": {variable: "OUTER"}
+ })
+ .cursor.firstBatch.length,
2);
// Test that $project stage can use stage-level and command-level 'let' variables in same command.
-assert.eq(db.runCommand({
- aggregate: coll.getName(),
- pipeline: [
- {
- $project: {
- "var": {
- $let: {
- vars: {innerVar: "INNER"},
- "in": {
- $cond: {
- "if": {$eq: [{$substr: ["$Species", 0, 1]}, "B"]},
- then: {$concat: ["$$innerVar", "$$outerVar"]},
- "else": "---"
- }
- }
- }
- }
- }
- },
- {$match: {$expr: {$eq: ["$var", "INNEROUTER"]}}}
- ],
- cursor: {},
- "let": {outerVar: "OUTER"}
- }).cursor.firstBatch.length,
+assert.eq(testDB
+ .runCommand({
+ aggregate: coll.getName(),
+ pipeline: [
+ {
+ $project: {
+ "var": {
+ $let: {
+ vars: {innerVar: "INNER"},
+ "in": {
+ $cond: {
+ "if": {$eq: [{$substr: ["$Species", 0, 1]}, "B"]},
+ then: {$concat: ["$$innerVar", "$$outerVar"]},
+ "else": "---"
+ }
+ }
+ }
+ }
+ }
+ },
+ {$match: {$expr: {$eq: ["$var", "INNEROUTER"]}}}
+ ],
+ cursor: {},
+ "let": {outerVar: "OUTER"}
+ })
+ .cursor.firstBatch.length,
2);
// Test that $project stage follows variable scoping rules with stage-level and command-level 'let'
// variables.
-assert.eq(db.runCommand({
- aggregate: coll.getName(),
- pipeline: [
- {
- $project: {
- "var": {
- $let: {
- vars: {variable: "INNER"},
- "in": {
- $cond: {
- "if": {$eq: [{$substr: ["$Species", 0, 1]}, "B"]},
- then: "$$variable",
- "else": "---"
- }
- }
- }
- }
- }
- },
- {$match: {$expr: {$eq: ["$var", "INNER"]}}}
- ],
- cursor: {},
- "let": {variable: "OUTER"}
- }).cursor.firstBatch.length,
+assert.eq(testDB
+ .runCommand({
+ aggregate: coll.getName(),
+ pipeline: [
+ {
+ $project: {
+ "var": {
+ $let: {
+ vars: {variable: "INNER"},
+ "in": {
+ $cond: {
+ "if": {$eq: [{$substr: ["$Species", 0, 1]}, "B"]},
+ then: "$$variable",
+ "else": "---"
+ }
+ }
+ }
+ }
+ }
+ },
+ {$match: {$expr: {$eq: ["$var", "INNER"]}}}
+ ],
+ cursor: {},
+ "let": {variable: "OUTER"}
+ })
+ .cursor.firstBatch.length,
2);
// Test that the find command works correctly with a let parameter argument.
let result = assert
- .commandWorked(db.runCommand({
+ .commandWorked(testDB.runCommand({
find: coll.getName(),
let : {target_species: "Song Thrush (Turdus philomelos)"},
filter: {$expr: {$eq: ["$Species", "$$target_species"]}},
@@ -247,13 +256,56 @@ assert.eq(expectedResults, result[0]);
// Delete tests with let params will delete a record, assert that a point-wise find yields an empty
// result, and then restore the collection state for further tests down the line. We can't exercise
// a multi-delete here (limit: 0) because of failures in sharded txn passthrough tests.
-assert.commandWorked(db.runCommand({
+assert.commandWorked(testDB.runCommand({
delete: coll.getName(),
let : {target_species: "Song Thrush (Turdus philomelos)"},
deletes: [{q: {$and: [{_id: 4}, {$expr: {$eq: ["$Species", "$$target_species"]}}]}, limit: 1}]
}));
-assert.eq(db.runCommand({find: coll.getName(), filter: {$expr: {$eq: ["$_id", "4"]}}})
+assert.eq(testDB.runCommand({find: coll.getName(), filter: {$expr: {$eq: ["$_id", "4"]}}})
.cursor.firstBatch.length,
0);
+
+// Test that reserved names are not allowed as let variable names.
+assert.commandFailedWithCode(
+ testDB.runCommand(
+ {aggregate: coll.getName(), pipeline: [], cursor: {}, let : {Reserved: "failure"}}),
+ 16867);
+assert.commandFailedWithCode(
+ testDB.runCommand(
+ {aggregate: coll.getName(), pipeline: [], cursor: {}, let : {NOW: "failure"}}),
+ 16867);
+assert.commandFailedWithCode(
+ testDB.runCommand(
+ {aggregate: coll.getName(), pipeline: [], cursor: {}, let : {CLUSTER_TIME: "failure"}}),
+ 16867);
+assert.commandFailedWithCode(
+ testDB.runCommand(
+ {aggregate: coll.getName(), pipeline: [], cursor: {}, let : {IS_MR: "failure"}}),
+ 16867);
+assert.commandFailedWithCode(
+ testDB.runCommand(
+ {aggregate: coll.getName(), pipeline: [], cursor: {}, let : {JS_SCOPE: "failure"}}),
+ 16867);
+assert.commandFailedWithCode(
+ testDB.runCommand(
+ {aggregate: coll.getName(), pipeline: [], cursor: {}, let : {ROOT: "failure"}}),
+ 16867);
+assert.commandFailedWithCode(
+ testDB.runCommand(
+ {aggregate: coll.getName(), pipeline: [], cursor: {}, let : {REMOVE: "failure"}}),
+ 16867);
+
+// Test that let variables can be used within views.
+assert.commandWorked(testDB.runCommand({
+ create: "core-viewColl",
+ viewOn: coll.getName(),
+ pipeline: [{$match: {Species: "Song Thrush (Turdus philomelos)"}}]
+}));
+assert.commandWorked(testDB.runCommand({
+ aggregate: "core-viewColl",
+ pipeline: [{$addFields: {var : "$$variable"}}],
+ let : {variable: "Song Thrush"},
+ cursor: {}
+}));
}());
diff --git a/jstests/noPassthroughWithMongod/command_let_variables.js b/jstests/noPassthroughWithMongod/command_let_variables.js
index 80004ab9fc7..42f5ee4c2fc 100644
--- a/jstests/noPassthroughWithMongod/command_let_variables.js
+++ b/jstests/noPassthroughWithMongod/command_let_variables.js
@@ -218,13 +218,6 @@ result = db.runCommand({
});
assert.eq(result.value, {Species: "not_a_bird", suspect: "dino"}, result);
-// Delete
-result = assert.commandWorked(db.runCommand({
- delete: coll.getName(),
- let : {target_species: "not_a_bird"},
- deletes: [{q: {$expr: {$eq: ["$Species", "$$target_species"]}}, limit: 0}]
-}));
-
// Update
assert.commandWorked(db.runCommand({
update: coll.getName(),
diff --git a/src/mongo/db/views/resolved_view.cpp b/src/mongo/db/views/resolved_view.cpp
index a8a1c9cf4a5..714644ecca3 100644
--- a/src/mongo/db/views/resolved_view.cpp
+++ b/src/mongo/db/views/resolved_view.cpp
@@ -112,6 +112,7 @@ AggregationRequest ResolvedView::asExpandedViewAggregation(
expandedRequest.setBypassDocumentValidation(request.shouldBypassDocumentValidation());
expandedRequest.setAllowDiskUse(request.shouldAllowDiskUse());
expandedRequest.setIsMapReduceCommand(request.getIsMapReduceCommand());
+ expandedRequest.letParameters = request.letParameters;
// Operations on a view must always use the default collation of the view. We must have already
// checked that if the user's request specifies a collation, it matches the collation of the