From e7af47750dbe68b0fbba43e1c04f8ba9793869df Mon Sep 17 00:00:00 2001 From: pajgo <51755949+pajgo@users.noreply.github.com> Date: Mon, 26 Jun 2023 22:22:35 +0600 Subject: [PATCH 1/3] fix: redisearch isempty/exists for numeric --- .../redis-search-stack/build-search-query.js | 30 +++++++++--- test/configs/redis-indexes.js | 2 +- test/suites/actions/list-search.js | 47 +++++++++++++++++-- 3 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/utils/redis-search-stack/build-search-query.js b/src/utils/redis-search-stack/build-search-query.js index c750db9c..3e6088f9 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..3ad614be 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) => { @@ -510,6 +548,7 @@ describe('Redis Search: list', function listSuite() { expect(user).to.have.ownProperty('metadata'); const data = user.metadata[TEST_AUDIENCE]; + console.debug('=== custom', data); expect(data).to.have.ownProperty('email'); expect(data.email.endsWith('.org')); From 240a810e4648a29a7b9bd05615c30bbcb593c0c9 Mon Sep 17 00:00:00 2001 From: pajgo <51755949+pajgo@users.noreply.github.com> Date: Mon, 26 Jun 2023 22:23:37 +0600 Subject: [PATCH 2/3] test: noconsole --- test/suites/actions/list-search.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/suites/actions/list-search.js b/test/suites/actions/list-search.js index 3ad614be..1c4d29b5 100644 --- a/test/suites/actions/list-search.js +++ b/test/suites/actions/list-search.js @@ -548,7 +548,6 @@ describe('Redis Search: list', function listSuite() { expect(user).to.have.ownProperty('metadata'); const data = user.metadata[TEST_AUDIENCE]; - console.debug('=== custom', data); expect(data).to.have.ownProperty('email'); expect(data.email.endsWith('.org')); From bd4f98ca843698b22921a24bc74b0b0548ed533f Mon Sep 17 00:00:00 2001 From: pajgo <51755949+pajgo@users.noreply.github.com> Date: Mon, 26 Jun 2023 23:10:00 +0600 Subject: [PATCH 3/3] chore: lint fix --- .mdeprc.js | 2 +- src/utils/redis-search-stack/build-search-query.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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 3e6088f9..11878138 100644 --- a/src/utils/redis-search-stack/build-search-query.js +++ b/src/utils/redis-search-stack/build-search-query.js @@ -91,7 +91,7 @@ const operator = { } return { - query: negative(expression((field), EMPTY_VALUE)), + query: negative(expression(field, EMPTY_VALUE)), }; }, isempty: (prop, field, _expr, _paramPrefix, options) => { @@ -102,7 +102,7 @@ const operator = { } return { - query: expression((field), EMPTY_VALUE), + query: expression(field, EMPTY_VALUE), }; }, eq: (prop, field, expr, paramPrefix) => {