From bd17e7e7326c089b504b8657f162a5384e9de5eb Mon Sep 17 00:00:00 2001 From: Paul Rauch Date: Fri, 16 Jun 2017 13:48:24 -0700 Subject: [PATCH 1/3] Fix issue #49 - $where operator is not evaluated last This change stores off any $where operators encountered in the _compile function, and then calls _processOperator on each after _processOperator is called for other operators. --- mingo.js | 13 +++++++++++- test/collections.js | 48 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/mingo.js b/mingo.js index f06bfd32..e9c0ce9e 100644 --- a/mingo.js +++ b/mingo.js @@ -1327,10 +1327,16 @@ Mingo.Query.prototype = { assert(isObject(this.__criteria), 'Criteria must be of type Object') + var whereOperators = []; + for (var field in this.__criteria) { if (has(this.__criteria, field)) { var expr = this.__criteria[field] - if (inArray(['$and', '$or', '$nor', '$where'], field)) { + // save $where operators to be executed after other operators + if (inArray(['$where'], field)) { + whereOperators.push({field: field, expr: expr}); + } + else if (inArray(['$and', '$or', '$nor'], field)) { this._processOperator(field, field, expr) } else { // normalize expression @@ -1342,6 +1348,11 @@ Mingo.Query.prototype = { } } } + var self = this; + console.log(whereOperators); + whereOperators.forEach(function(where) { + self._processOperator(where.field, where.field, where.expr); + }); } }, diff --git a/test/collections.js b/test/collections.js index c8928a79..babd1a5d 100644 --- a/test/collections.js +++ b/test/collections.js @@ -63,3 +63,51 @@ test('Match $all with $elemMatch on nested elements', function (t) { var result = Mingo.find(data, criteria).count() t.ok(result === 1, 'can match using $all with $elemMatch on nested elements') }) + +test('Evaluate $where last', function (t) { + t.plan(2) + + var data = [ + { + user: { + username: 'User1', + projects: [ + {name: 'Project 1', rating: {complexity: 6}}, + {name: 'Project 2', rating: {complexity: 2}} + ], + color: 'green', + number: 42 + } + }, + { + user: { + username: 'User2', + projects: [ + {name: 'Project 1', rating: {complexity: 6}}, + {name: 'Project 2', rating: {complexity: 8}} + ] + } + } + ] + + var criteria = { + 'user.color': {$exists: true}, + 'user.number': {$exists: true}, + $where: 'this.user.color === "green" && this.user.number === 42' + } + // It should return one user object + var result = Mingo.find(data, criteria).count() + t.ok(result === 1, 'can safely reference properties on this using $where and $exists') + + criteria = { + 'user.color': {$exists: true}, + 'user.number': {$exists: true}, + $and: [ + { $where: 'this.user.color === "green"' }, + { $where: 'this.user.number === 42' } + ] + } + // It should return one user object + var result = Mingo.find(data, criteria).count() + t.ok(result === 1, 'can safely reference properties on this using multiple $where operators and $exists') +}) From 8e90904486106db1eac3c40b2149bd26a31d474c Mon Sep 17 00:00:00 2001 From: Paul Rauch Date: Mon, 19 Jun 2017 08:41:29 -0700 Subject: [PATCH 2/3] Code review changes. --- mingo.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/mingo.js b/mingo.js index e9c0ce9e..37a9430b 100644 --- a/mingo.js +++ b/mingo.js @@ -1327,16 +1327,15 @@ Mingo.Query.prototype = { assert(isObject(this.__criteria), 'Criteria must be of type Object') - var whereOperators = []; + var whereOperator; for (var field in this.__criteria) { if (has(this.__criteria, field)) { var expr = this.__criteria[field] // save $where operators to be executed after other operators - if (inArray(['$where'], field)) { - whereOperators.push({field: field, expr: expr}); - } - else if (inArray(['$and', '$or', '$nor'], field)) { + if ('$where' === field) { + whereOperator = {field: field, expr: expr}; + } else if (inArray(['$and', '$or', '$nor'], field)) { this._processOperator(field, field, expr) } else { // normalize expression @@ -1348,11 +1347,11 @@ Mingo.Query.prototype = { } } } - var self = this; - console.log(whereOperators); - whereOperators.forEach(function(where) { - self._processOperator(where.field, where.field, where.expr); - }); + + if(whereOperator) { + this._processOperator(whereOperator.field, whereOperator.field, whereOperator.expr); + } + } }, From a77b2fd545c717ba5944dfed3bda5e2cc5f9aef8 Mon Sep 17 00:00:00 2001 From: Paul Rauch Date: Wed, 21 Jun 2017 13:47:04 -0700 Subject: [PATCH 3/3] Moved changes from mingo.js to lib/query.js --- lib/query.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/query.js b/lib/query.js index 83419e6d..b90d4351 100644 --- a/lib/query.js +++ b/lib/query.js @@ -20,10 +20,15 @@ Mingo.Query.prototype = { assert(isObject(this.__criteria), 'Criteria must be of type Object') + var whereOperator; + for (var field in this.__criteria) { if (has(this.__criteria, field)) { var expr = this.__criteria[field] - if (inArray(['$and', '$or', '$nor', '$where'], field)) { + // save $where operators to be executed after other operators + if ('$where' === field) { + whereOperator = {field: field, expr: expr}; + } else if (inArray(['$and', '$or', '$nor'], field)) { this._processOperator(field, field, expr) } else { // normalize expression @@ -35,6 +40,11 @@ Mingo.Query.prototype = { } } } + + if(whereOperator) { + this._processOperator(whereOperator.field, whereOperator.field, whereOperator.expr); + } + } },