diff options
author | Katherine Wu <katherine.wu@mongodb.com> | 2020-06-01 13:51:34 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-06-11 18:22:47 +0000 |
commit | 5c7cdc392c2ea058d7ec93609203fcc5bb74bb99 (patch) | |
tree | 3033463c9f2afd7f09907a2f22b120de9776b41f | |
parent | 01707971319a5970604c20598f286b2e1882a682 (diff) | |
download | mongo-5c7cdc392c2ea058d7ec93609203fcc5bb74bb99.tar.gz |
SERVER-46116 Add integration tests for let variables
-rw-r--r-- | jstests/core/command_let_variables.js | 250 | ||||
-rw-r--r-- | jstests/noPassthroughWithMongod/command_let_variables.js | 7 | ||||
-rw-r--r-- | src/mongo/db/views/resolved_view.cpp | 1 |
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 |