diff --git a/lib/dao.js b/lib/dao.js index 9ecb8b87..0b042700 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -939,6 +939,27 @@ DataAccessObject.all = function () { return DataAccessObject.find.apply(this, arguments); }; +/** + * Get settings via hiarchical determiniation + * + * @param {String} key The setting key + */ +DataAccessObject._getSetting = function(key) { + // Check for settings in model + var m = this.definition; + if(m && m.settings && m.settings[key]) { + return m.settings[key] + } + + // Check for settings in connector + var ds = this.getDataSource(); + if(ds && ds.settings && ds.settings[key]) { + return ds.settings[key]; + } + + return; +}; + var operators = { gt: '>', gte: '>=', @@ -1037,7 +1058,9 @@ DataAccessObject._normalize = function (filter) { Object.keys(this.definition.properties), this.settings.strict); } - filter = removeUndefined(filter); + var handleUndefined = this._getSetting('normalizeUndefinedInQuery'); + // alter configuration of how removeUndefined handles undefined values + filter = removeUndefined(filter, handleUndefined); this._coerce(filter.where); return filter; }; diff --git a/lib/utils.js b/lib/utils.js index f6be3e98..15852f1b 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -294,9 +294,10 @@ function selectFields(fields) { /** * Remove undefined values from the queury object * @param query + * @param handleUndefined {String} either "nullify", "throw" or "ignore" (default: "ignore") * @returns {exports.map|*} */ -function removeUndefined(query) { +function removeUndefined(query, handleUndefined) { if (typeof query !== 'object' || query === null) { return query; } @@ -304,7 +305,17 @@ function removeUndefined(query) { // as traverse doesn't transform the ObjectId correctly return traverse(query).forEach(function (x) { if (x === undefined) { - this.remove(); + switch (handleUndefined) { + case 'nullify': + this.update(null); + break; + case 'throw': + throw new Error('Unexpected `undefined` in query'); + break; + case 'ignore': + default: + this.remove(); + } } if (!Array.isArray(x) && (typeof x === 'object' && x !== null diff --git a/test/loopback-dl.test.js b/test/loopback-dl.test.js index 14d9892b..3aeb54e3 100644 --- a/test/loopback-dl.test.js +++ b/test/loopback-dl.test.js @@ -1487,6 +1487,22 @@ describe('DataAccessObject', function () { assert.deepEqual(filter, {limit: 100, offset: 5, skip: 5}); }); + it('should apply settings for handling undefined', function () { + filter = model._normalize({filter: { x: undefined }}); + assert.deepEqual(filter, {filter: {}}); + + ds.settings.normalizeUndefinedInQuery = 'ignore'; + filter = model._normalize({filter: { x: undefined }}); + assert.deepEqual(filter, {filter: {}}, 'Should ignore undefined'); + + ds.settings.normalizeUndefinedInQuery = 'nullify'; + filter = model._normalize({filter: { x: undefined }}); + assert.deepEqual(filter, {filter: { x: null }}, 'Should nullify undefined'); + + ds.settings.normalizeUndefinedInQuery = 'throw'; + (function(){ model._normalize({filter: { x: undefined }}) }).should.throw(/`undefined` in query/); + }); + it('should skip GeoPoint', function () { where = model._coerce({location: {near: {lng: 10, lat: 20}, maxDistance: 20}}); assert.deepEqual(where, {location: {near: {lng: 10, lat: 20}, maxDistance: 20}}); @@ -1514,6 +1530,20 @@ describe('DataAccessObject', function () { assert.deepEqual(where, {age: {inq: ['xyz', 12]}}); }); + // settings + it('should get settings in priority', + function () { + ds.settings.test = 'test'; + assert.equal(model._getSetting('test'), ds.settings.test, 'Should get datasource setting'); + ds.settings.test = undefined; + + model.settings.test = 'test'; + assert.equal(model._getSetting('test'), model.settings.test, 'Should get model settings'); + + ds.settings.test = 'willNotGet'; + assert.notEqual(model._getSetting('test'), ds.settings.test, 'Should not get datasource setting'); + }); + }); describe('Load models from json', function () { @@ -1796,4 +1826,3 @@ describe('ModelBuilder options.models', function () { }); }); - diff --git a/test/util.test.js b/test/util.test.js index aa2859a1..27307e28 100644 --- a/test/util.test.js +++ b/test/util.test.js @@ -66,6 +66,13 @@ describe('util.removeUndefined', function () { var q4 = {where: {x: 1, y: date}}; should.deepEqual(removeUndefined(q4), {where: {x: 1, y: date}}); + // test handling of undefined + var q5 = {where: {x: 1, y: undefined}}; + should.deepEqual(removeUndefined(q5, 'nullify'), {where: {x: 1, y: null}}); + + var q6 = {where: {x: 1, y: undefined}}; + (function(){ removeUndefined(q6, 'throw') }).should.throw(/`undefined` in query/); + }); });