From 1ff9cb92c23bc04651150523a10107d1d5cadd5f Mon Sep 17 00:00:00 2001 From: Alessandro Martini <18130319+martini97@users.noreply.github.com> Date: Tue, 17 Sep 2024 14:24:43 -0300 Subject: [PATCH] feat(functions/subquery): add exists function Add postgres EXISTS(...subquery...) function. This is required by typeorm exists method. See: https://github.com/typeorm/typeorm/blob/e7649d2746f907ff36b1efb600402dedd5f5a499/src/query-builder/QueryBuilder.ts#L1273 --- src/functions/index.ts | 4 +++- src/functions/subquery.ts | 14 ++++++++++++++ src/tests/subqueries.spec.ts | 19 +++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/functions/subquery.ts diff --git a/src/functions/index.ts b/src/functions/index.ts index 512f3ad..dc17aaa 100644 --- a/src/functions/index.ts +++ b/src/functions/index.ts @@ -3,6 +3,7 @@ import { dateFunctions } from './date'; import { systemFunctions } from './system'; import { sequenceFunctions } from './sequence-fns'; import { numberFunctions } from './numbers'; +import { subqueryFunctions } from './subquery'; export const allFunctions = [ @@ -11,4 +12,5 @@ export const allFunctions = [ , ... systemFunctions , ... sequenceFunctions , ... numberFunctions -] \ No newline at end of file + , ... subqueryFunctions +] diff --git a/src/functions/subquery.ts b/src/functions/subquery.ts new file mode 100644 index 0000000..218b57b --- /dev/null +++ b/src/functions/subquery.ts @@ -0,0 +1,14 @@ +import { FunctionDefinition } from '../interfaces'; +import { DataType } from '../interfaces-private'; + +export const subqueryFunctions: FunctionDefinition[] = [ + { + name: 'exists', + args: [DataType.integer], + argsVariadic: DataType.integer, + returns: DataType.bool, + allowNullArguments: true, + impure: true, + implementation: (...items: number[]) => items?.some?.(Boolean) ?? false, + }, +]; diff --git a/src/tests/subqueries.spec.ts b/src/tests/subqueries.spec.ts index 5f9a86b..c9e9da5 100644 --- a/src/tests/subqueries.spec.ts +++ b/src/tests/subqueries.spec.ts @@ -10,11 +10,13 @@ describe('Subqueries', () => { let db: _IDb; let many: (str: string) => any[]; let none: (str: string) => void; + let one: (str: string) => any; beforeEach(() => { db = newDb() as _IDb; many = db.public.many.bind(db.public); none = db.public.none.bind(db.public); + one = db.public.one.bind(db.public); }); function setupBooks() { @@ -90,4 +92,21 @@ describe('Subqueries', () => { // expect(cnt).toBe(1, 'Was expecting subquery to be simplified'); // }) + + it('can check if a subquery exists', () => { + setupBooks(); + + // returns single row, regardless of matches + expect(many(`SELECT EXISTS(SELECT 1 FROM books WHERE created_at < 5) AS x;`)) + .toHaveLength(1); + + expect(one(`SELECT EXISTS(SELECT 1 FROM books WHERE created_at > 5) AS x;`)) + .toEqual({ x: false }); + + expect(one(`SELECT EXISTS(SELECT 1 FROM books WHERE name = 'one') AS x;`)) + .toEqual({ x: true }); + + expect(one(`SELECT EXISTS(SELECT 1 FROM books WHERE name = 'one') AS x;`)) + .toEqual({ x: true }); + }); });