diff options
author | Spencer Jackson <spencer.jackson@mongodb.com> | 2017-08-11 14:30:40 -0400 |
---|---|---|
committer | Spencer Jackson <spencer.jackson@mongodb.com> | 2017-11-20 18:56:23 -0500 |
commit | 4c1bae566c0c00f996a2feb16febf84936ecaf6f (patch) | |
tree | 5b83d6f614e856487e8b05df09c92292bd716194 | |
parent | f6b8c4dea6b0f03632f86c29329eaa02d48ab803 (diff) | |
download | mongo-4c1bae566c0c00f996a2feb16febf84936ecaf6f.tar.gz |
SERVER-30009: Allow JS functions to be terminated with ';'r3.2.18-rc0r3.2.18
(cherry picked from commit 8024561b6a73b5b0b56200bdfa3233219ff7fb18)
-rw-r--r-- | jstests/core/function_string_representations.js | 38 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/mongohelpers.js | 8 |
2 files changed, 46 insertions, 0 deletions
diff --git a/jstests/core/function_string_representations.js b/jstests/core/function_string_representations.js new file mode 100644 index 00000000000..af66e9160a9 --- /dev/null +++ b/jstests/core/function_string_representations.js @@ -0,0 +1,38 @@ +/** Demonstrate that mapReduce can accept functions represented by strings. + * Some drivers do not have a type which represents a Javascript function. These languages represent + * the arguments to mapReduce as strings. + */ + +(function() { + "use strict"; + + var col = db.function_string_representations; + col.drop(); + assert.writeOK(col.insert({ + _id: "abc123", + ord_date: new Date("Oct 04, 2012"), + status: 'A', + price: 25, + items: [{sku: "mmm", qty: 5, price: 2.5}, {sku: "nnn", qty: 5, price: 2.5}] + })); + + var mapFunction = "function() {emit(this._id, this.price);}"; + var reduceFunction = "function(keyCustId, valuesPrices) {return Array.sum(valuesPrices);}"; + assert.commandWorked(col.mapReduce(mapFunction, reduceFunction, {out: "map_reduce_example"})); + + // Provided strings may end with semicolons and/or whitespace + mapFunction += " ; "; + reduceFunction += " ; "; + assert.commandWorked(col.mapReduce(mapFunction, reduceFunction, {out: "map_reduce_example"})); + + // $where exhibits the same behavior + var whereFunction = "function() {return this.price === 25;}"; + assert.eq(1, col.find({$where: whereFunction}).itcount()); + + whereFunction += ";"; + assert.eq(1, col.find({$where: whereFunction}).itcount()); + + // db.eval does not need to be tested, as it accepts code fragments, not functions. + // system.js does not need to be tested, as its contents types' are preserved, and + // strings are not promoted into functions. +})(); diff --git a/src/mongo/scripting/mozjs/mongohelpers.js b/src/mongo/scripting/mozjs/mongohelpers.js index b0b35bb2fe8..d3f743623a3 100644 --- a/src/mongo/scripting/mozjs/mongohelpers.js +++ b/src/mongo/scripting/mozjs/mongohelpers.js @@ -33,6 +33,14 @@ exportToMongoHelpers = { // This function accepts an expression or function body and returns a function definition 'functionExpressionParser': function functionExpressionParser(fnSrc) { + + // Ensure that a provided expression or function body is not terminated with a ';'. + // This ensures we interpret the input as a single expression, rather than a sequence + // of expressions, and can wrap it in parentheses. + while (fnSrc.endsWith(";") || fnSrc != fnSrc.trimRight()) { + fnSrc = fnSrc.slice(0, -1).trimRight(); + } + var parseTree; try { parseTree = this.Reflect.parse(fnSrc); |