diff --git a/.mdeprc.js b/.mdeprc.js index bfe1cb67..ac472654 100644 --- a/.mdeprc.js +++ b/.mdeprc.js @@ -16,7 +16,7 @@ exports.in_one = false; exports.auto_compose = true; exports.with_local_compose = true; exports.tester_flavour = "chrome-tester"; -exports.rebuild = ['ms-flakeless']; +exports.rebuild = ['ms-flakeless', 'synchronous-worker']; exports.nycCoverage = false; exports.nycReport = false; exports.docker_compose = './test/docker-compose.yml'; diff --git a/src/utils/redis-search-stack/build-search-query.js b/src/utils/redis-search-stack/build-search-query.js index c750db9c..11878138 100644 --- a/src/utils/redis-search-stack/build-search-query.js +++ b/src/utils/redis-search-stack/build-search-query.js @@ -10,7 +10,7 @@ const { tokenize, quotedString, } = require('./expressions'); -const { FT_TYPE_TAG } = require('./extract-field-definitions'); +const { FT_TYPE_TAG, FT_TYPE_NUMERIC } = require('./extract-field-definitions'); const EMPTY_VALUE = typeof null; // NOTE Using "" occures the parser error const FIELD_PREFIX = 'f'; @@ -83,12 +83,28 @@ const operator = { lte: (_, field, expr) => ({ query: expression(field, numericRange(expr.gte, expr.lte)), }), - exists: (_, field) => ({ - query: negative(expression((field), EMPTY_VALUE)), - }), - isempty: (_, field) => ({ - query: expression((field), EMPTY_VALUE), - }), + exists: (prop, field, _expr, _paramPrefix, options) => { + if (options.fieldTypes[prop] === FT_TYPE_NUMERIC) { + return { + query: expression(field, numericRange()), + }; + } + + return { + query: negative(expression(field, EMPTY_VALUE)), + }; + }, + isempty: (prop, field, _expr, _paramPrefix, options) => { + if (options.fieldTypes[prop] === FT_TYPE_NUMERIC) { + return { + query: negative(expression(field, numericRange())), + }; + } + + return { + query: expression(field, EMPTY_VALUE), + }; + }, eq: (prop, field, expr, paramPrefix) => { const name = buildParamName(FIELD_PREFIX, paramPrefix, prop, ParamSuffix.eq); diff --git a/test/configs/redis-indexes.js b/test/configs/redis-indexes.js index a931b1ad..e5d501e4 100644 --- a/test/configs/redis-indexes.js +++ b/test/configs/redis-indexes.js @@ -32,7 +32,7 @@ exports.redisIndexDefinitions = [ }, { filterKey: 'wpropfilter', - filterByProperty: '@level >= 30', + filterByProperty: 'exists(@level) && @level >= 30', audience: ['http'], fields: [ ['id', 'TEXT', 'NOSTEM', 'SORTABLE'], diff --git a/test/suites/actions/list-search.js b/test/suites/actions/list-search.js index 66c7c370..1c4d29b5 100644 --- a/test/suites/actions/list-search.js +++ b/test/suites/actions/list-search.js @@ -32,7 +32,7 @@ const createUserApi = (id, { email, level } = {}) => ({ test: { id, email: email || faker.internet.email(), - level: level || 1, + ...typeof level === 'undefined' ? {} : { level: level || 1 }, }, [TEST_CATEGORY_PROPFILTER]: { id, @@ -108,7 +108,7 @@ describe('Redis Search: list', function listSuite() { const { username } = item; - const api = createUserApi(userId, { email: username, level: (i + 1) * 10 }); + const api = createUserApi(userId, { email: username, level: i > 1 ? (i + 1) * 10 : undefined }); const data = saveUser(this.users.redis, TEST_CATEGORY, TEST_AUDIENCE, api); promises.push(data); promises.push( @@ -354,6 +354,25 @@ describe('Redis Search: list', function listSuite() { }); }); + // -@level:[-inf +inf] + it('list: IS_EMPTY for NUMERIC action', function test() { + return this + .users + .dispatch('list', { + params: { + audience: TEST_AUDIENCE, + filter: { level: { isempty: true } }, + }, + }) + .then((result) => { + assert(result); + expect(result.users).to.have.length(2); + result.users.forEach((user) => { + expect(user.metadata[TEST_AUDIENCE]).to.not.have.ownProperty('level'); + }); + }); + }); + it('list: EXISTS action', function test() { return this .filteredListRequest({ lastName: { exists: true } }) @@ -363,6 +382,25 @@ describe('Redis Search: list', function listSuite() { }); }); + // @level:[-inf +inf] + it('list: EXISTS for NUMERIC action', function test() { + return this + .users + .dispatch('list', { + params: { + audience: TEST_AUDIENCE, + filter: { level: { exists: true } }, + }, + }) + .then((result) => { + assert(result); + expect(result.users).to.have.length(3); + result.users.forEach((user) => { + expect(user.metadata[TEST_AUDIENCE]).to.have.ownProperty('level'); + }); + }); + }); + it('list by id', function test() { // -@id:{$f_id_ne} PARAMS 2 f_id_ne unknown return this @@ -478,7 +516,7 @@ describe('Redis Search: list', function listSuite() { }) .then((result) => { assert(result); - expect(result.users).to.have.length(4); + expect(result.users).to.have.length(2); result.users.forEach((user) => { expect(user).to.have.ownProperty('id'); @@ -502,7 +540,7 @@ describe('Redis Search: list', function listSuite() { }, }) .then((result) => { - expect(result.users).to.have.length(3); + expect(result.users).to.have.length(1); expect(result.users.length); result.users.forEach((user) => {