From 79d5bce0b61510653ca1c100b742ba1333493fe7 Mon Sep 17 00:00:00 2001 From: Otavio Jacobi Date: Mon, 20 Jan 2025 10:39:50 -0300 Subject: [PATCH] Add EqualAny node Change-type: minor --- src/AbstractSQLCompiler.ts | 3 +++ src/AbstractSQLOptimiser.ts | 3 +++ src/AbstractSQLRules2SQL.ts | 6 ++++++ test/abstract-sql/comparisons.ts | 12 ++++++++++++ 4 files changed, 24 insertions(+) diff --git a/src/AbstractSQLCompiler.ts b/src/AbstractSQLCompiler.ts index e8e89db..eaffee3 100644 --- a/src/AbstractSQLCompiler.ts +++ b/src/AbstractSQLCompiler.ts @@ -45,6 +45,7 @@ export type DurationTypeNodes = StrictDurationTypeNodes | UnknownTypeNodes; export type BooleanNode = ['Boolean', boolean]; export type EqualsNode = ['Equals', AnyTypeNodes, AnyTypeNodes]; +export type EqualsAnyNode = ['EqualsAny', AnyTypeNodes, BindNode]; export type NotEqualsNode = ['NotEquals', AnyTypeNodes, AnyTypeNodes]; export type IsDistinctFromNode = ['IsDistinctFrom', AnyTypeNodes, AnyTypeNodes]; export type IsNotDistinctFromNode = [ @@ -89,6 +90,7 @@ export type ContainsNode = ['Contains', TextTypeNodes, TextTypeNodes]; export type StrictBooleanTypeNodes = | BooleanNode | EqualsNode + | EqualsAnyNode | NotEqualsNode | IsDistinctFromNode | IsNotDistinctFromNode @@ -246,6 +248,7 @@ export type UnknownTypeNodes = | NullNode | FieldNode | ReferencedFieldNode + | EqualsAnyNode | BindNode | CastNode | CaseNode diff --git a/src/AbstractSQLOptimiser.ts b/src/AbstractSQLOptimiser.ts index 500f801..fcf21c6 100644 --- a/src/AbstractSQLOptimiser.ts +++ b/src/AbstractSQLOptimiser.ts @@ -106,6 +106,7 @@ import type { FromTypeNode, StartsWithNode, EscapeForLikeNode, + EqualsAnyNode, } from './AbstractSQLCompiler'; import * as AbstractSQLRules2SQL from './AbstractSQLRules2SQL'; @@ -219,6 +220,7 @@ const UnknownValue: MetaMatchFn = (args) => { case 'Null': case 'Field': case 'ReferencedField': + case 'EqualsAny': case 'Bind': case 'Cast': case 'Coalesce': @@ -739,6 +741,7 @@ const typeRules = { }), Comparison('Equals'), ), + EqualsAny: matchArgs('EqualsAny', AnyValue, AnyValue), NotEquals: tryMatches( Helper>((args) => { checkArgs('NotEquals', args, 2); diff --git a/src/AbstractSQLRules2SQL.ts b/src/AbstractSQLRules2SQL.ts index 718e8fe..01c3a7d 100644 --- a/src/AbstractSQLRules2SQL.ts +++ b/src/AbstractSQLRules2SQL.ts @@ -82,6 +82,7 @@ const UnknownValue: MetaMatchFn = (args, indent) => { case 'Null': case 'Field': case 'ReferencedField': + case 'EqualsAny': case 'Bind': case 'Cast': case 'Coalesce': @@ -246,6 +247,7 @@ export const isNotNullable = (node: AbstractSqlType): boolean => { case 'Integer': case 'IsDistinctFrom': case 'IsNotDistinctFrom': + case 'EqualsAny': case 'Exists': case 'NotExists': return true; @@ -1000,6 +1002,10 @@ const typeRules: Dictionary = { return `COALESCE(JSON_AGG(${field}), '[]')`; }, Equals: Comparison('Equals'), + EqualsAny: (args, indent) => { + checkArgs('EqualsAny', args, 2); + return `${AnyValue(getAbstractSqlQuery(args, 0), indent)} = ANY(${AnyValue(getAbstractSqlQuery(args, 1), indent)})`; + }, GreaterThan: Comparison('GreaterThan'), GreaterThanOrEqual: Comparison('GreaterThanOrEqual'), LessThan: Comparison('LessThan'), diff --git a/test/abstract-sql/comparisons.ts b/test/abstract-sql/comparisons.ts index 31fae52..80d59bb 100644 --- a/test/abstract-sql/comparisons.ts +++ b/test/abstract-sql/comparisons.ts @@ -26,6 +26,18 @@ describe('Between', () => { ); }); +describe('Equals Any', () => { + test( + ['SelectQuery', ['Select', [['EqualsAny', ['Number', 5], ['Bind', 0]]]]], + [['Bind', 0]], + (result, sqlEquals) => { + it('should produce a valid EqualsAny statement', () => { + sqlEquals(result.query, 'SELECT 5 = ANY($1)'); + }); + }, + ); +}); + describe('Comparison Operator Precedence', () => { // Different precedence test(