From 17bb56a772b58af9d8785e86bd80d43206e31956 Mon Sep 17 00:00:00 2001 From: Mel O'Hagan Date: Wed, 27 Jul 2022 13:19:47 +0100 Subject: [PATCH] Has any of MySQL filter --- packages/frontend-core/src/constants.js | 2 +- packages/server/src/definitions/datasource.ts | 3 ++ packages/server/src/integrations/base/sql.ts | 8 +++- .../server/src/integrations/tests/sql.spec.js | 45 +++++++++++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/packages/frontend-core/src/constants.js b/packages/frontend-core/src/constants.js index c55dcd3f8f..6140bce2e6 100644 --- a/packages/frontend-core/src/constants.js +++ b/packages/frontend-core/src/constants.js @@ -48,7 +48,7 @@ export const OperatorOptions = { }, ContainsAny: { value: "containsAny", - label: "Has any" + label: "Has any", }, } diff --git a/packages/server/src/definitions/datasource.ts b/packages/server/src/definitions/datasource.ts index 0033d35550..5f767dfc13 100644 --- a/packages/server/src/definitions/datasource.ts +++ b/packages/server/src/definitions/datasource.ts @@ -137,6 +137,9 @@ export interface SearchFilters { notContains?: { [key: string]: any[] } + containsAny?: { + [key: string]: any[] + } } export interface SortJson { diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index 5a0151c4d4..c0e74bfb06 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -157,7 +157,7 @@ class InternalBuilder { } } - const contains = (mode: object) => { + const contains = (mode: object, any: boolean = false) => { const fnc = allOr ? "orWhere" : "where" const rawFnc = `${fnc}Raw` const not = mode === filters?.notContains ? "NOT " : "" @@ -182,10 +182,11 @@ class InternalBuilder { ) }) } else if (this.client === SqlClients.MY_SQL) { + const jsonFnc = any ? "JSON_OVERLAPS" : "JSON_CONTAINS" iterate(mode, (key: string, value: Array) => { // @ts-ignore query = query[rawFnc]( - `${not}JSON_CONTAINS(${key}, ${stringifyArray(value)})` + `${not}${jsonFnc}(${key}, ${stringifyArray(value)})` ) }) } else { @@ -282,6 +283,9 @@ class InternalBuilder { if (filters.notContains) { contains(filters.notContains) } + if (filters.containsAny) { + contains(filters.containsAny, true) + } return query } diff --git a/packages/server/src/integrations/tests/sql.spec.js b/packages/server/src/integrations/tests/sql.spec.js index 4d1d031458..66606516ea 100644 --- a/packages/server/src/integrations/tests/sql.spec.js +++ b/packages/server/src/integrations/tests/sql.spec.js @@ -329,4 +329,49 @@ describe("SQL query builder", () => { sql: `select * from (select * from \"${TABLE_NAME}\" where NOT \"${TABLE_NAME}\".\"age\"::jsonb @> '[20]' and NOT \"${TABLE_NAME}\".\"name\"::jsonb @> '["John"]' limit $1) as \"${TABLE_NAME}\"` }) }) + + it("should use OR like expression for MS-SQL when filter is containsAny", () => { + const query = new Sql(SqlClients.MS_SQL, 10)._query(generateReadJson({ + filters: { + containsAny: { + age: [20, 25], + name: ["John", "Mary"] + } + } + })) + expect(query).toEqual({ + bindings: [10, "%20%", "%25%", `%"John"%`, `%"Mary"%`], + sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where LOWER(${TABLE_NAME}.age) LIKE @p1 and LOWER(${TABLE_NAME}.name) LIKE @p2) as [${TABLE_NAME}]` + }) + }) + + it("should use JSON_OVERLAPS expression for MySQL when filter is containsAny", () => { + const query = new Sql(SqlClients.MY_SQL, 10)._query(generateReadJson({ + filters: { + containsAny: { + age: [20, 25], + name: ["John", "Mary"] + } + } + })) + expect(query).toEqual({ + bindings: [10], + sql: `select * from (select * from \`${TABLE_NAME}\` where JSON_OVERLAPS(${TABLE_NAME}.age, '[20,25]') and JSON_OVERLAPS(${TABLE_NAME}.name, '["John","Mary"]') limit ?) as \`${TABLE_NAME}\`` + }) + }) + + it("should use OR jsonb operator expression for PostgreSQL when filter is containsAny", () => { + const query = new Sql(SqlClients.POSTGRES, 10)._query(generateReadJson({ + filters: { + containsAny: { + age: [20], + name: ["John"] + } + } + })) + expect(query).toEqual({ + bindings: [10], + sql: `select * from (select * from \"${TABLE_NAME}\" where \"${TABLE_NAME}\".\"age\"::jsonb @> '[20]' and \"${TABLE_NAME}\".\"name\"::jsonb @> '["John"]' limit $1) as \"${TABLE_NAME}\"` + }) + }) })