From baceedf2012aec0b913d46f98eeed5d657486c6f Mon Sep 17 00:00:00 2001 From: Pascal Jufer Date: Tue, 20 Jun 2023 17:20:56 +0200 Subject: [PATCH] Allow plain query flags for boolean & geo filter operators (#18888) * Allow plain query flags for boolean & geo filter operators * Create blue-wolves-tell.md --------- Co-authored-by: Brainslug --- .changeset/blue-wolves-tell.md | 5 +++++ api/src/utils/apply-query.test.ts | 4 ++-- api/src/utils/validate-query.test.ts | 31 ++++++++++++++++++++++++++++ api/src/utils/validate-query.ts | 9 ++++---- 4 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 .changeset/blue-wolves-tell.md diff --git a/.changeset/blue-wolves-tell.md b/.changeset/blue-wolves-tell.md new file mode 100644 index 0000000000..0b4ace997e --- /dev/null +++ b/.changeset/blue-wolves-tell.md @@ -0,0 +1,5 @@ +--- +"@directus/api": patch +--- + +Added support for plain query flags for boolean & geo filter operators diff --git a/api/src/utils/apply-query.test.ts b/api/src/utils/apply-query.test.ts index 51301320d7..c421ffa1aa 100644 --- a/api/src/utils/apply-query.test.ts +++ b/api/src/utils/apply-query.test.ts @@ -156,7 +156,7 @@ describe('applyFilter', () => { }, operators); for (const { filterOperator, sqlWhereClause } of withReverseOperators) { - for (const filterValue of [true, false]) { + for (const filterValue of [true, '', false]) { test(`${filterOperator} with value ${filterValue}`, async () => { class Client_SQLite3 extends MockClient {} @@ -180,7 +180,7 @@ describe('applyFilter', () => { const sql = tracker.history.select[0]?.sql.match(/select \* where \((.*)\)/)?.[1]; - const expectedSql = sqlWhereClause[filterValue ? 'true' : 'false'].replaceAll( + const expectedSql = sqlWhereClause[filterValue === false ? 'false' : 'true'].replaceAll( '$column', `"${collection}"."${field}"` ); diff --git a/api/src/utils/validate-query.test.ts b/api/src/utils/validate-query.test.ts index 781f43fcb2..d654313222 100644 --- a/api/src/utils/validate-query.test.ts +++ b/api/src/utils/validate-query.test.ts @@ -55,3 +55,34 @@ describe('export', async () => { expect(() => validateQuery({ export: 'invalid-format' } as any)).toThrowError('"export" must be one of'); }); }); + +describe('validateBoolean', async () => { + const { validateBoolean } = await import('./validate-query.js'); + + test.each([true, '', null, false])('should allow value %s', (value: unknown) => { + expect(() => validateBoolean(value, 'test')).not.toThrowError(); + }); + + test.each([undefined, 'wrong'])('should fail on value %s', (value: unknown) => { + expect(() => validateBoolean(value, 'test')).toThrowError('"test" has to be a boolean'); + }); +}); + +describe('validateGeometry', async () => { + const { validateGeometry } = await import('./validate-query.js'); + + test.each([ + '', + null, + { + type: 'Point', + coordinates: [30.0, 10.0], + }, + ])('should allow value %s', (value: unknown) => { + expect(() => validateGeometry(value, 'test')).not.toThrowError(); + }); + + test.each([undefined, 'wrong', {}])('should fail on value %s', (value: unknown) => { + expect(() => validateGeometry(value, 'test')).toThrowError('"test" has to be a valid GeoJSON object'); + }); +}); diff --git a/api/src/utils/validate-query.ts b/api/src/utils/validate-query.ts index bb5bf1c23e..5786b6aa36 100644 --- a/api/src/utils/validate-query.ts +++ b/api/src/utils/validate-query.ts @@ -67,7 +67,6 @@ function validateFilter(filter: Query['filter']) { case '_nempty': validateBoolean(value, key); break; - case '_intersects': case '_nintersects': case '_intersects_bbox': @@ -135,8 +134,8 @@ function validateList(value: any, key: string) { return true; } -function validateBoolean(value: any, key: string) { - if (value === null) return true; +export function validateBoolean(value: any, key: string) { + if (value === null || value === '') return true; if (typeof value !== 'boolean') { throw new InvalidQueryException(`"${key}" has to be a boolean`); @@ -145,8 +144,8 @@ function validateBoolean(value: any, key: string) { return true; } -function validateGeometry(value: any, key: string) { - if (value === null) return true; +export function validateGeometry(value: any, key: string) { + if (value === null || value === '') return true; try { stringify(value);