From 7047e02097edbed53606958e473c9321a5ee1602 Mon Sep 17 00:00:00 2001 From: Warren Seine Date: Wed, 19 Oct 2016 19:45:59 +0200 Subject: [PATCH 1/8] Make Cursor MongoDB-compatible by adding a toArray() function. --- lib/cursor.js | 7 ++++++- lib/datastore.js | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/cursor.js b/lib/cursor.js index 673d7a43..d9fbee19 100755 --- a/lib/cursor.js +++ b/lib/cursor.js @@ -198,7 +198,12 @@ Cursor.prototype.exec = function () { this.db.executor.push({ this: this, fn: this._exec, arguments: arguments }); }; - +Cursor.prototype.toArray = function(callback) { + var self = this; + process.nextTick(function() { + callback(null, self.res); + }); +}; // Interface module.exports = Cursor; diff --git a/lib/datastore.js b/lib/datastore.js index 4b978ad3..6a1af65b 100755 --- a/lib/datastore.js +++ b/lib/datastore.js @@ -482,7 +482,8 @@ Datastore.prototype.find = function (query, projection, callback) { for (i = 0; i < docs.length; i += 1) { res.push(model.deepCopy(docs[i])); } - return callback(null, res); + this.res = res; + return callback(null, this); }); cursor.projection(projection); From b14a3059e696c3e8c1e72a34b66307508ac90efd Mon Sep 17 00:00:00 2001 From: Warren Seine Date: Tue, 18 Oct 2016 19:40:27 +0200 Subject: [PATCH 2/8] Make ensureIndex Mongoose-compatible (passing indexes as a third argument). --- lib/datastore.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/datastore.js b/lib/datastore.js index 6a1af65b..bd05084f 100755 --- a/lib/datastore.js +++ b/lib/datastore.js @@ -120,6 +120,15 @@ Datastore.prototype.resetIndexes = function (newData) { * @param {Function} cb Optional callback, signature: err */ Datastore.prototype.ensureIndex = function (options, cb) { + // Add compatibility with Mongoose which calls ensureIndex with 3 arguments. + if (arguments.length == 3) { + cb = arguments[2]; + options = arguments[1]; + indexFields = arguments[0]; + for (var i in indexFields) + options.fieldName = i; + } + var err , callback = cb || function () {}; From 64621b9043790f8642052aabfabb80f3a9297aa4 Mon Sep 17 00:00:00 2001 From: Jean-Marc Le Roux Date: Wed, 30 Nov 2016 20:14:23 +0100 Subject: [PATCH 3/8] Fix areThingsEqual() and compareThings() to work with bson.ObjectID. This fix is required to make the mongoose-nedb driver (https://github.com/aerys/mongoose-nedb) work properly when dealing with query using the "_id" field. --- lib/model.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/model.js b/lib/model.js index 0aa9e928..01d980f3 100755 --- a/lib/model.js +++ b/lib/model.js @@ -190,6 +190,14 @@ function compareThings (a, b, _compareStrings) { var aKeys, bKeys, comp, i , compareStrings = _compareStrings || compareNSB; + // Custom type (ex: bson.ObjectID) + if (!!a.equals && typeof a.equals == 'function') { + return a.equals(b) ? 0 : -1; + } + if (!!b.equals && typeof b.equals == 'function') { + return b.equals(a) ? 0 : -1; + } + // undefined if (a === undefined) { return b === undefined ? 0 : -1; } if (b === undefined) { return a === undefined ? 0 : 1; } @@ -528,6 +536,14 @@ function getDotValue (obj, field) { function areThingsEqual (a, b) { var aKeys , bKeys , i; + // Custom type (ex: bson.ObjectID) + if (!!a.equals && typeof a.equals == 'function') { + return a.equals(b); + } + if (!!b.equals && typeof b.equals == 'function') { + return b.equals(a); + } + // Strings, booleans, numbers, null if (a === null || typeof a === 'string' || typeof a === 'boolean' || typeof a === 'number' || b === null || typeof b === 'string' || typeof b === 'boolean' || typeof b === 'number') { return a === b; } From a6b52aaacde8100e3204b27d7e8b76c951b0faec Mon Sep 17 00:00:00 2001 From: Jonathan Jarri Date: Mon, 5 Dec 2016 10:58:54 +0100 Subject: [PATCH 4/8] Fix an error when we try to compare values from a null or undefined objects. --- lib/model.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/model.js b/lib/model.js index 01d980f3..ca22e533 100755 --- a/lib/model.js +++ b/lib/model.js @@ -190,14 +190,6 @@ function compareThings (a, b, _compareStrings) { var aKeys, bKeys, comp, i , compareStrings = _compareStrings || compareNSB; - // Custom type (ex: bson.ObjectID) - if (!!a.equals && typeof a.equals == 'function') { - return a.equals(b) ? 0 : -1; - } - if (!!b.equals && typeof b.equals == 'function') { - return b.equals(a) ? 0 : -1; - } - // undefined if (a === undefined) { return b === undefined ? 0 : -1; } if (b === undefined) { return a === undefined ? 0 : 1; } @@ -206,6 +198,14 @@ function compareThings (a, b, _compareStrings) { if (a === null) { return b === null ? 0 : -1; } if (b === null) { return a === null ? 0 : 1; } + // Custom type (ex: bson.ObjectID) + if (!!a.equals && typeof a.equals == 'function') { + return a.equals(b) ? 0 : -1; + } + if (!!b.equals && typeof b.equals == 'function') { + return b.equals(a) ? 0 : -1; + } + // Numbers if (typeof a === 'number') { return typeof b === 'number' ? compareNSB(a, b) : -1; } if (typeof b === 'number') { return typeof a === 'number' ? compareNSB(a, b) : 1; } @@ -536,6 +536,10 @@ function getDotValue (obj, field) { function areThingsEqual (a, b) { var aKeys , bKeys , i; + // Strings, booleans, numbers, null + if (a === null || typeof a === 'string' || typeof a === 'boolean' || typeof a === 'number' || + b === null || typeof b === 'string' || typeof b === 'boolean' || typeof b === 'number') { return a === b; } + // Custom type (ex: bson.ObjectID) if (!!a.equals && typeof a.equals == 'function') { return a.equals(b); @@ -544,10 +548,6 @@ function areThingsEqual (a, b) { return b.equals(a); } - // Strings, booleans, numbers, null - if (a === null || typeof a === 'string' || typeof a === 'boolean' || typeof a === 'number' || - b === null || typeof b === 'string' || typeof b === 'boolean' || typeof b === 'number') { return a === b; } - // Dates if (util.isDate(a) || util.isDate(b)) { return util.isDate(a) && util.isDate(b) && a.getTime() === b.getTime(); } From f31db555c457d36306c776b21df5c2e932b5af94 Mon Sep 17 00:00:00 2001 From: Jonathan Jarri Date: Mon, 5 Dec 2016 11:42:47 +0100 Subject: [PATCH 5/8] Fix the last commit to keep the order of operations. --- lib/model.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/model.js b/lib/model.js index ca22e533..222662e8 100755 --- a/lib/model.js +++ b/lib/model.js @@ -190,6 +190,14 @@ function compareThings (a, b, _compareStrings) { var aKeys, bKeys, comp, i , compareStrings = _compareStrings || compareNSB; + // Custom type (ex: bson.ObjectID) + if (!!a && !!a.equals && typeof a.equals == 'function') { + return a.equals(b) ? 0 : -1; + } + if (!!b && !!b.equals && typeof b.equals == 'function') { + return b.equals(a) ? 0 : -1; + } + // undefined if (a === undefined) { return b === undefined ? 0 : -1; } if (b === undefined) { return a === undefined ? 0 : 1; } @@ -198,14 +206,6 @@ function compareThings (a, b, _compareStrings) { if (a === null) { return b === null ? 0 : -1; } if (b === null) { return a === null ? 0 : 1; } - // Custom type (ex: bson.ObjectID) - if (!!a.equals && typeof a.equals == 'function') { - return a.equals(b) ? 0 : -1; - } - if (!!b.equals && typeof b.equals == 'function') { - return b.equals(a) ? 0 : -1; - } - // Numbers if (typeof a === 'number') { return typeof b === 'number' ? compareNSB(a, b) : -1; } if (typeof b === 'number') { return typeof a === 'number' ? compareNSB(a, b) : 1; } @@ -536,18 +536,18 @@ function getDotValue (obj, field) { function areThingsEqual (a, b) { var aKeys , bKeys , i; - // Strings, booleans, numbers, null - if (a === null || typeof a === 'string' || typeof a === 'boolean' || typeof a === 'number' || - b === null || typeof b === 'string' || typeof b === 'boolean' || typeof b === 'number') { return a === b; } - // Custom type (ex: bson.ObjectID) - if (!!a.equals && typeof a.equals == 'function') { + if (!!a && !!a.equals && typeof a.equals == 'function') { return a.equals(b); } - if (!!b.equals && typeof b.equals == 'function') { + if (!!b && !!b.equals && typeof b.equals == 'function') { return b.equals(a); } + // Strings, booleans, numbers, null + if (a === null || typeof a === 'string' || typeof a === 'boolean' || typeof a === 'number' || + b === null || typeof b === 'string' || typeof b === 'boolean' || typeof b === 'number') { return a === b; } + // Dates if (util.isDate(a) || util.isDate(b)) { return util.isDate(a) && util.isDate(b) && a.getTime() === b.getTime(); } From c1d673391821e0ef9461348f8569aaa20a2191de Mon Sep 17 00:00:00 2001 From: Jonathan Jarri Date: Mon, 5 Dec 2016 16:52:12 +0100 Subject: [PATCH 6/8] Fix an issue where options can be null updating a datastore. --- lib/datastore.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/datastore.js b/lib/datastore.js index bd05084f..5846fcfb 100755 --- a/lib/datastore.js +++ b/lib/datastore.js @@ -575,6 +575,8 @@ Datastore.prototype._update = function (query, updateQuery, options, cb) { ; if (typeof options === 'function') { cb = options; options = {}; } + if (!options) options = {}; + callback = cb || function () {}; multi = options.multi !== undefined ? options.multi : false; upsert = options.upsert !== undefined ? options.upsert : false; From 382cf642e3c3b2a741a002069c2db3bb8f42474b Mon Sep 17 00:00:00 2001 From: Julien Cloute Date: Fri, 14 Apr 2017 12:34:37 +0200 Subject: [PATCH 7/8] Ensure compatibility with Mongoose projection argument from cursor.js. --- lib/cursor.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/cursor.js b/lib/cursor.js index d9fbee19..7a90f214 100755 --- a/lib/cursor.js +++ b/lib/cursor.js @@ -67,6 +67,13 @@ Cursor.prototype.project = function (candidates) { , keepId, action, keys ; + // Mongoose stores specified projection in a 'fields' property '{ fields: {} }'. + var projectionKeys = Object.keys(this._projection); + if (projectionKeys.length === 1 && + projectionKeys[0] === 'fields') { + this._projection = this._projection.fields; + } + if (this._projection === undefined || Object.keys(this._projection).length === 0) { return candidates; } From fcaad30220f0012f19a64ca3dc17f2d8ee4ef408 Mon Sep 17 00:00:00 2001 From: Julien Cloute Date: Fri, 14 Apr 2017 18:02:35 +0200 Subject: [PATCH 8/8] Skip query matching in the case where the query is based on a single field with an existing corresponding index. --- lib/cursor.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/cursor.js b/lib/cursor.js index 7a90f214..915781fd 100755 --- a/lib/cursor.js +++ b/lib/cursor.js @@ -139,9 +139,15 @@ Cursor.prototype._exec = function(_callback) { this.db.getCandidates(this.query, function (err, candidates) { if (err) { return callback(err); } + var queryKeys = Object.keys(self.query); + + // If query contains a single field which has an existing index, + // index results can be directly returned without further matching + var matchingNeeded = queryKeys.length > 1 || !self.db.indexes || !self.db.indexes[queryKeys[0]]; + try { for (i = 0; i < candidates.length; i += 1) { - if (model.match(candidates[i], self.query)) { + if (!matchingNeeded || model.match(candidates[i], self.query)) { // If a sort is defined, wait for the results to be sorted before applying limit and skip if (!self._sort) { if (self._skip && self._skip > skipped) {