From 779cf6a370b2b13ecc9a186d815e4228791b8081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Mon, 5 Dec 2016 16:04:54 +0100 Subject: [PATCH] Honour allowExtendedOperators in "DAO.find" Modify the coercion of filter.where to hounour "allowExtendedOperators" and don't coerce property values of type object (extended operators). --- lib/dao.js | 10 ++++- test/allow-extended-operators.test.js | 62 +++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 test/allow-extended-operators.test.js diff --git a/lib/dao.js b/lib/dao.js index 93b49c3a..2162ac8f 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -1658,13 +1658,19 @@ DataAccessObject._coerce = function(where) { } } else { if (val != null) { + const dsSettings = this.getDataSource().settings; + const allowExtendedOperators = dsSettings.allowExtendedOperators; if (operator === null && val instanceof RegExp) { // Normalize {name: /A/} to {name: {regexp: /A/}} operator = 'regexp'; } else if (operator === 'regexp' && val instanceof RegExp) { // Do not coerce regex literals/objects - } else if (!((operator === 'like' || operator === 'nlike' || - operator === 'ilike' || operator === 'nilike') && val instanceof RegExp)) { + } else if ((operator === 'like' || operator === 'nlike' || + operator === 'ilike' || operator === 'nilike') && val instanceof RegExp) { + // Do not coerce RegExp operator value + } else if (allowExtendedOperators && typeof val === 'object') { + // Do not coerce object values when extended operators are allowed + } else { val = DataType(val); } } diff --git a/test/allow-extended-operators.test.js b/test/allow-extended-operators.test.js new file mode 100644 index 00000000..9b108ea9 --- /dev/null +++ b/test/allow-extended-operators.test.js @@ -0,0 +1,62 @@ +// Copyright IBM Corp. 2015,2016. All Rights Reserved. +// Node module: loopback-datasource-juggler +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +const DataSource = require('..').DataSource; +const should = require('should'); + +describe('Model.settings.allowExtendedOperators', () => { + context('DAO.find()', () => { + it('converts extended operators to string value by default', () => { + const TestModel = createTestModel(); + return TestModel.find(extendedQuery()).then((results) => { + should(results[0].value).eql('[object Object]'); + }); + }); + + it('preserves extended operators wit allowExtendedOperators set', () => { + const TestModel = createTestModel({allowExtendedOperators: true}); + return TestModel.find(extendedQuery()).then((results) => { + should(results[0].value).eql({$exists: true}); + }); + }); + + function extendedQuery() { + // datasource modifies the query, + // we have to build a new object for each test + return {where: {value: {$exists: true}}}; + } + }); + + function createTestModel(connectorSettings) { + const ds = createTestDataSource(connectorSettings); + return ds.createModel('TestModel', {value: String}); + } + + function createTestDataSource(connectorSettings) { + connectorSettings = connectorSettings || {}; + connectorSettings.connector = { + initialize: (dataSource, cb) => { + dataSource.connector = new TestConnector(dataSource); + }, + }; + + return new DataSource(connectorSettings); + } + + class TestConnector { + constructor(dataSource) { + } + + all(model, filter, options, callback) { + // return the raw "value" query + var instanceFound = { + value: filter.where.value, + }; + callback(null, [instanceFound]); + } + } +});