From a761e0d114486ea547ad0ae4391cfa3faccc9580 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Sun, 14 Oct 2018 09:27:46 -0700 Subject: [PATCH] Tidy up extended operator check --- lib/dao.js | 21 ++++++++- test/allow-extended-operators.test.js | 63 +++++++++++++++------------ 2 files changed, 55 insertions(+), 29 deletions(-) diff --git a/lib/dao.js b/lib/dao.js index 1faff391..f119403b 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -1477,6 +1477,7 @@ DataAccessObject._getSetting = function(key) { }; var operators = { + eq: '=', gt: '>', gte: '>=', lt: '<', @@ -1818,6 +1819,7 @@ DataAccessObject._coerce = function(where, options) { // NOOP when not coercable into an array. } + var allowExtendedOperators = self._allowExtendedOperators(options); // Coerce the array items if (Array.isArray(val)) { for (var i = 0; i < val.length; i++) { @@ -1829,7 +1831,6 @@ DataAccessObject._coerce = function(where, options) { } } else { if (val != null) { - var allowExtendedOperators = self._allowExtendedOperators(options); if (operator === null && val instanceof RegExp) { // Normalize {name: /A/} to {name: {regexp: /A/}} operator = 'regexp'; @@ -1841,12 +1842,28 @@ DataAccessObject._coerce = function(where, options) { } else if (allowExtendedOperators && typeof val === 'object') { // Do not coerce object values when extended operators are allowed } else { + if (!allowExtendedOperators) { + var extendedOperators = Object.keys(val).filter(function(k) { + return k[0] === '$'; + }); + if (extendedOperators.length) { + const msg = g.f('Operators "' + extendedOperators.join(', ') + '" are not allowed in query'); + const err = new Error(msg); + err.code = 'OPERATOR_NOT_ALLOWED_IN_QUERY'; + err.statusCode = 400; + err.details = { + operators: extendedOperators, + where: where, + }; + throw err; + } + } val = DataType(val); } } } // Rebuild {property: {operator: value}} - if (operator) { + if (operator && operator !== 'eq') { var value = {}; value[operator] = val; if (exp.options) { diff --git a/test/allow-extended-operators.test.js b/test/allow-extended-operators.test.js index 359b73f3..19331dd3 100644 --- a/test/allow-extended-operators.test.js +++ b/test/allow-extended-operators.test.js @@ -67,50 +67,59 @@ describe('allowExtendedOperators', () => { } } + function assertOperatorNotAllowed(err) { + should.exist(err); + err.message.should.match(/Operators "\$exists" are not allowed in query/); + err.code.should.equal('OPERATOR_NOT_ALLOWED_IN_QUERY'); + err.statusCode.should.equal(400); + err.details.should.have.property('operators'); + err.details.should.have.property('where'); + } + describe('dataSource.settings.allowExtendedOperators', () => { context('DAO.find()', () => { - it('converts extended operators to string value by default', () => { + it('reports invalid operator by default', () => { const TestModel = createTestModel(); - return TestModel.find(extendedQuery()).then((results) => { - should(results[0].value).eql('[object Object]'); + return TestModel.find(extendedQuery()).catch(err => { + assertOperatorNotAllowed(err); }); }); it('preserves extended operators with allowExtendedOperators set', () => { const TestModel = createTestModel({allowExtendedOperators: true}); - return TestModel.find(extendedQuery()).then((results) => { + return TestModel.find(extendedQuery()).then(results => { should(results[0].value).eql({$exists: true}); }); }); it('`Model.settings.allowExtendedOperators` override data source settings - ' + - 'converts extended operators', () => { + 'reports invalid operator', () => { const TestModel = createTestModel({allowExtendedOperators: true}, {allowExtendedOperators: false}); - return TestModel.find(extendedQuery()).then((results) => { - should(results[0].value).eql('[object Object]'); + return TestModel.find(extendedQuery()).catch(err => { + assertOperatorNotAllowed(err); }); }); it('`Model.settings.allowExtendedOperators` override data source settings - ' + 'preserves extended operators', () => { const TestModel = createTestModel({allowExtendedOperators: false}, {allowExtendedOperators: true}); - return TestModel.find(extendedQuery()).then((results) => { + return TestModel.find(extendedQuery()).then(results => { should(results[0].value).eql({$exists: true}); }); }); it('`options.allowExtendedOperators` override data source settings - ' + - 'converts extended operators', () => { + 'reports invalid operator', () => { const TestModel = createTestModel({allowExtendedOperators: true}); - return TestModel.find(extendedQuery(), {allowExtendedOperators: false}).then((results) => { - should(results[0].value).eql('[object Object]'); + return TestModel.find(extendedQuery(), {allowExtendedOperators: false}).catch(err => { + assertOperatorNotAllowed(err); }); }); it('`options.allowExtendedOperators` override data source settings - ' + 'preserves extended operators', () => { const TestModel = createTestModel({allowExtendedOperators: false}); - return TestModel.find(extendedQuery(), {allowExtendedOperators: true}).then((results) => { + return TestModel.find(extendedQuery(), {allowExtendedOperators: true}).then(results => { should(results[0].value).eql({$exists: true}); }); }); @@ -168,37 +177,37 @@ describe('allowExtendedOperators', () => { context('DAO.find()', () => { it('preserves extended operators with allowExtendedOperators set', () => { const TestModel = createTestModel({}, {allowExtendedOperators: true}); - return TestModel.find(extendedQuery()).then((results) => { + return TestModel.find(extendedQuery()).then(results => { should(results[0].value).eql({$exists: true}); }); }); it('`dataSource.settings.allowExtendedOperators` honor Model settings - ' + - 'converts extended operators', () => { + 'reports invalid operator', () => { const TestModel = createTestModel({allowExtendedOperators: true}, {allowExtendedOperators: false}); - return TestModel.find(extendedQuery()).then((results) => { - should(results[0].value).eql('[object Object]'); + return TestModel.find(extendedQuery()).catch(err => { + assertOperatorNotAllowed(err); }); }); it('`dataSource.settings.allowExtendedOperators` honor Model settings - ' + 'preserves extended operators', () => { const TestModel = createTestModel({allowExtendedOperators: false}, {allowExtendedOperators: true}); - return TestModel.find(extendedQuery()).then((results) => { + return TestModel.find(extendedQuery()).then(results => { should(results[0].value).eql({$exists: true}); }); }); it('`options.allowExtendedOperators` override Model settings - converts extended operators', () => { const TestModel = createTestModel({allowExtendedOperators: true}); - return TestModel.find(extendedQuery(), {allowExtendedOperators: false}).then((results) => { - should(results[0].value).eql('[object Object]'); + return TestModel.find(extendedQuery(), {allowExtendedOperators: false}).catch(err => { + assertOperatorNotAllowed(err); }); }); it('`options.allowExtendedOperators` Model settings - preserves extended operators', () => { const TestModel = createTestModel({allowExtendedOperators: false}); - return TestModel.find(extendedQuery(), {allowExtendedOperators: true}).then((results) => { + return TestModel.find(extendedQuery(), {allowExtendedOperators: true}).then(results => { should(results[0].value).eql({$exists: true}); }); }); @@ -255,7 +264,7 @@ describe('allowExtendedOperators', () => { context('DAO.find()', () => { it('preserves extended operators with allowExtendedOperators set', () => { const TestModel = createTestModel(); - return TestModel.find(extendedQuery(), {allowExtendedOperators: true}).then((results) => { + return TestModel.find(extendedQuery(), {allowExtendedOperators: true}).then(results => { should(results[0].value).eql({$exists: true}); }); }); @@ -263,15 +272,15 @@ describe('allowExtendedOperators', () => { it('`dataSource.settings.allowExtendedOperators` honor options settings - ' + 'converts extended operators', () => { const TestModel = createTestModel({allowExtendedOperators: true}); - return TestModel.find(extendedQuery(), {allowExtendedOperators: false}).then((results) => { - should(results[0].value).eql('[object Object]'); + return TestModel.find(extendedQuery(), {allowExtendedOperators: false}).catch(err => { + assertOperatorNotAllowed(err); }); }); it('`dataSource.settings.allowExtendedOperators` honor options settings - ' + 'preserves extended operators', () => { const TestModel = createTestModel({allowExtendedOperators: false}); - return TestModel.find(extendedQuery(), {allowExtendedOperators: true}).then((results) => { + return TestModel.find(extendedQuery(), {allowExtendedOperators: true}).then(results => { should(results[0].value).eql({$exists: true}); }); }); @@ -279,15 +288,15 @@ describe('allowExtendedOperators', () => { it('`Model.settings.allowExtendedOperators` honor options settings - ' + 'converts extended operators', () => { const TestModel = createTestModel({}, {allowExtendedOperators: true}); - return TestModel.find(extendedQuery(), {allowExtendedOperators: false}).then((results) => { - should(results[0].value).eql('[object Object]'); + return TestModel.find(extendedQuery(), {allowExtendedOperators: false}).catch(err => { + assertOperatorNotAllowed(err); }); }); it('`Model.settings.allowExtendedOperators` honor options settings - ' + 'preserves extended operators', () => { const TestModel = createTestModel({}, {allowExtendedOperators: false}); - return TestModel.find(extendedQuery(), {allowExtendedOperators: true}).then((results) => { + return TestModel.find(extendedQuery(), {allowExtendedOperators: true}).then(results => { should(results[0].value).eql({$exists: true}); }); });