From a9d381605e338cf273fc437059ac9bab953fc8a2 Mon Sep 17 00:00:00 2001 From: Simon Ho Date: Wed, 12 Oct 2016 19:19:31 -0700 Subject: [PATCH] Add ilike and nilike operators (#1136) Closes #633 Backport of #1091 --- lib/connectors/memory.js | 12 ++++++-- lib/dao.js | 9 +++++- test/basic-querying.test.js | 56 +++++++++++++++++++++++++++++++++++++ test/init.js | 4 +++ 4 files changed, 78 insertions(+), 3 deletions(-) diff --git a/lib/connectors/memory.js b/lib/connectors/memory.js index 54beb03b..d75e9391 100644 --- a/lib/connectors/memory.js +++ b/lib/connectors/memory.js @@ -605,8 +605,8 @@ function applyFilter(filter) { testInEquality({ lte: example.between[1] }, value)); } - if (example.like || example.nlike) { - var like = example.like || example.nlike; + if (example.like || example.nlike || example.ilike || example.nilike) { + var like = example.like || example.nlike || example.ilike || example.nilike; if (typeof like === 'string') { like = toRegExp(like); } @@ -617,6 +617,14 @@ function applyFilter(filter) { if (example.nlike) { return !new RegExp(like).test(value); } + + if (example.ilike) { + return !!new RegExp(like, 'i').test(value); + } + + if (example.nilike) { + return !new RegExp(like, 'i').test(value); + } } if (testInEquality(example, value)) { diff --git a/lib/dao.js b/lib/dao.js index 1b64a9b7..658c008b 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -1407,6 +1407,8 @@ var operators = { neq: '!=', like: 'LIKE', nlike: 'NOT LIKE', + ilike: 'ILIKE', + nilike: 'NOT ILIKE', regexp: 'REGEXP', }; @@ -1633,6 +1635,8 @@ DataAccessObject._coerce = function(where) { break; case 'like': case 'nlike': + case 'ilike': + case 'nilike': if (!(typeof val === 'string' || val instanceof RegExp)) { err = new Error(g.f('The %s property has invalid clause %j', p, where[p])); err.statusCode = 400; @@ -1665,7 +1669,8 @@ DataAccessObject._coerce = function(where) { operator = 'regexp'; } else if (operator === 'regexp' && val instanceof RegExp) { // Do not coerce regex literals/objects - } else if (!((operator === 'like' || operator === 'nlike') && val instanceof RegExp)) { + } else if (!((operator === 'like' || operator === 'nlike' || + operator === 'ilike' || operator === 'nilike') && val instanceof RegExp)) { val = DataType(val); } } @@ -1718,6 +1723,8 @@ DataAccessObject._coerce = function(where) { * - neq: != * - like: LIKE * - nlike: NOT LIKE + * - ilike: ILIKE + * - nilike: NOT ILIKE * - regexp: REGEXP * * You can also use `and` and `or` operations. See [Querying models](http://docs.strongloop.com/display/DOC/Querying+models) for more information. diff --git a/test/basic-querying.test.js b/test/basic-querying.test.js index b586ef9b..502f527f 100644 --- a/test/basic-querying.test.js +++ b/test/basic-querying.test.js @@ -461,6 +461,62 @@ describe('basic-querying', function() { }); }); + var itWhenIlikeSupported = connectorCapabilities.ilike ? it : it.skip.bind(it); + + itWhenIlikeSupported('should support "like" that is satisfied', function(done) { + User.find({ where: { name: { like: 'John' }}}, function(err, users) { + if (err) return done(err); + users.length.should.equal(1); + users[0].name.should.equal('John Lennon'); + done(); + }); + }); + + itWhenIlikeSupported('should support "like" that is not satisfied', function(done) { + User.find({ where: { name: { like: 'Bob' }}}, function(err, users) { + if (err) return done(err); + users.length.should.equal(0); + done(); + }); + }); + + var itWhenNilikeSupported = connectorCapabilities.nilike ? it : it.skip.bind(it); + + itWhenNilikeSupported('should support "nlike" that is satisfied', function(done) { + User.find({ where: { name: { nlike: 'John' }}}, function(err, users) { + if (err) return done(err); + users.length.should.equal(5); + users[0].name.should.equal('Paul McCartney'); + done(); + }); + }); + + itWhenIlikeSupported('should support "ilike" that is satisfied', function(done) { + User.find({ where: { name: { ilike: 'john' }}}, function(err, users) { + if (err) return done(err); + users.length.should.equal(1); + users[0].name.should.equal('John Lennon'); + done(); + }); + }); + + itWhenIlikeSupported('should support "ilike" that is not satisfied', function(done) { + User.find({ where: { name: { ilike: 'bob' }}}, function(err, users) { + if (err) return done(err); + users.length.should.equal(0); + done(); + }); + }); + + itWhenNilikeSupported('should support "nilike" that is satisfied', function(done) { + User.find({ where: { name: { nilike: 'john' }}}, function(err, users) { + if (err) return done(err); + users.length.should.equal(5); + users[0].name.should.equal('Paul McCartney'); + done(); + }); + }); + it('should only include fields as specified', function(done) { var remaining = 0; diff --git a/test/init.js b/test/init.js index 038e201a..612c595c 100644 --- a/test/init.js +++ b/test/init.js @@ -35,3 +35,7 @@ if (!('getModelBuilder' in global)) { if (!('Promise' in global)) { global.Promise = require('bluebird'); } + +if (!('connectorCapabilities' in global)) { + global.connectorCapabilities = {}; +}