From 4ba1ddb666b35731d983ad56478022c09e5e9b85 Mon Sep 17 00:00:00 2001 From: Christian Kvalheim Date: Wed, 19 Sep 2012 14:48:21 -0400 Subject: [PATCH] Fixed eval to work with system.js collection functions, Issue #709 --- lib/mongodb/commands/db_command.js | 1 + lib/mongodb/cursor.js | 16 ++----------- lib/mongodb/db.js | 24 +++++++++++-------- test/db_test.js | 38 +++++++++++++++++++++++++++--- 4 files changed, 52 insertions(+), 27 deletions(-) diff --git a/lib/mongodb/commands/db_command.js b/lib/mongodb/commands/db_command.js index 2b535f15291..87438e8ffee 100644 --- a/lib/mongodb/commands/db_command.js +++ b/lib/mongodb/commands/db_command.js @@ -32,6 +32,7 @@ DbCommand.SYSTEM_INDEX_COLLECTION = "system.indexes"; DbCommand.SYSTEM_PROFILE_COLLECTION = "system.profile"; DbCommand.SYSTEM_USER_COLLECTION = "system.users"; DbCommand.SYSTEM_COMMAND_COLLECTION = "$cmd"; +DbCommand.SYSTEM_JS_COLLECTION = "system.js"; // New commands DbCommand.NcreateIsMasterCommand = function(db, databaseName) { diff --git a/lib/mongodb/cursor.js b/lib/mongodb/cursor.js index 28395aea6d9..e27dc3655b3 100644 --- a/lib/mongodb/cursor.js +++ b/lib/mongodb/cursor.js @@ -658,22 +658,10 @@ Cursor.prototype.explain = function(callback) { }; /** - * Returns a stream object that can be used to listen to and stream records - * (**Use the CursorStream object instead as this is deprected**) - * - * Options - * - **fetchSize** {Number} the number of records to fetch in each batch (steam specific batchSize). - * - * Events - * - **data** {function(item) {}} the data event triggers when a document is ready. - * - **error** {function(err) {}} the error event triggers if an error happens. - * - **end** {function() {}} the end event triggers when there is no more documents available. - * - * @param {Object} [options] additional options for streamRecords. - * @return {EventEmitter} returns a stream object. - * @api public + * @ignore */ Cursor.prototype.streamRecords = function(options) { + console.log("[WARNING] streamRecords method is deprecated, please use stream method which is much faster"); var args = Array.prototype.slice.call(arguments, 0); options = args.length ? args.shift() : {}; diff --git a/lib/mongodb/db.js b/lib/mongodb/db.js index 82beb632f2d..a625d1085c4 100644 --- a/lib/mongodb/db.js +++ b/lib/mongodb/db.js @@ -533,6 +533,7 @@ Db.prototype.eval = function(code, parameters, options, callback) { } else if(parameters != null && parameters.constructor == Array && typeof parameters !== 'function') { finalParameters = parameters; } + // Create execution selector var selector = {'$eval':finalCode, 'args':finalParameters}; // Check if the nolock parameter is passed in @@ -540,17 +541,20 @@ Db.prototype.eval = function(code, parameters, options, callback) { selector['nolock'] = options['nolock']; } - // Iterate through all the fields of the index - new Cursor(this, new Collection(this, DbCommand.SYSTEM_COMMAND_COLLECTION), selector, options, 0, -1) - .setReadPreference(ReadPreference.PRIMARY) - .nextObject(function(err, result) { - if(err != null) return callback(err, null); + // Set primary read preference + options.readPreference = ReadPreference.PRIMARY; - if(result.ok == 1) { - callback(null, result.retval); - } else { - callback(new Error("eval failed: " + result.errmsg), null); return; - } + // Execute the eval + this.collection(DbCommand.SYSTEM_COMMAND_COLLECTION).findOne(selector, options, function(err, result) { + if(err) return callback(err); + + if(result && result.ok == 1) { + callback(null, result.retval); + } else if(result) { + callback(new Error("eval failed: " + result.errmsg), null); return; + } else { + callback(err, result); + } }); }; diff --git a/test/db_test.js b/test/db_test.js index 4d33175a1ad..cbada14d7ba 100644 --- a/test/db_test.js +++ b/test/db_test.js @@ -184,6 +184,7 @@ exports.shouldCorrectlyExecuteEvalFunctions = function(test) { // Establish connection to db db.open(function(err, db) { + var numberOfTests = // Evaluate a function on the server with the parameter 3 passed in db.eval('function (x) {return x;}', [3], function(err, result) { @@ -234,7 +235,6 @@ exports.shouldCorrectlyExecuteEvalFunctions = function(test) { // Evaluate a statement using the code object including a scope db.eval(new Code("i + 3;", {'i':2}), function(err, result) { test.equal(5, result); - test.done(); }); // Evaluate an illegal statement @@ -242,11 +242,43 @@ exports.shouldCorrectlyExecuteEvalFunctions = function(test) { test.ok(err instanceof Error); test.ok(err.message != null); // Let's close the db + db.close(); test.done(); }); + }); +} - db.close(); - test.done(); +/** + * Defining and calling a system level javascript function (NOT recommended, http://www.mongodb.org/display/DOCS/Server-side+Code+Execution) + * + * @_class db + * @_function eval + * @ignore + */ +exports.shouldCorrectlyDefineSystemLevelFunctionAndExecuteFunction = function(test) { + var db = new Db('integration_tests', new Server("127.0.0.1", 27017, + {auto_reconnect: false, poolSize: 1, ssl:useSSL}), {native_parser: native_parser}); + + // Establish connection to db + db.open(function(err, db) { + + // Clean out the collection + db.collection("system.js").remove({}, {safe:true}, function(err, result) { + test.equal(null, err); + + // Define a system level function + db.collection("system.js").insert({_id: "echo", value: new Code("function(x) { return x; }")}, {safe:true}, function(err, result) { + test.equal(null, err); + + db.eval("echo(5)", function(err, result) { + test.equal(null, err); + test.equal(5, result); + + db.close(); + test.done(); + }); + }); + }); }); }