import { sql } from '../template' import { ArrayType, BooleanType, ByteaType, JSONBType, NumericType, TextType, TimestampType, Type, UnknownType } from '../types' import { ArrayOps } from './array' import { AnyExpression } from './any' import { JSONOps } from './json' import { IntegralOps, NumberOps } from './math' import { TextSearchOps } from './search' import { StringOps } from './string' import { TimeZoneOps } from './timezone' export * from './any' export * from './array' export * from './json' export * from './math' export * from './search' export * from './string' export * from './timezone' export class ExpressionImpl extends StringOps(TimeZoneOps(NumberOps(IntegralOps(ArrayOps(JSONOps(TextSearchOps(AnyExpression))))))) {} export type Constructor = new (...args: any[]) => T export const expression = (strings: TemplateStringsArray, ...literals: any[]) => { return new ExpressionImpl([...strings], literals) as any } export type Expression = T['expression'] export type PrimitiveToType = T extends boolean ? BooleanType : T extends number ? NumericType : T extends string ? TextType : T extends Buffer ? ByteaType : T extends Date ? TimestampType : T extends Array ? ArrayType, R> : T extends Record ? JSONBType : UnknownType export type ToType = T extends Expression ? T['type'] : Exclude extends never ? UnknownType : null extends T ? PrimitiveToType, true> : undefined extends T ? PrimitiveToType, true> : PrimitiveToType export type ToExpression = T extends Expression ? T : Expression> type IsUnknownRequired = null extends T ? true : undefined extends T ? true : false export type UnknownLiteral = UnknownType> export function literal (lit: T): Expression> { return expression`${lit}` as any } export type Condition = Condition[] | AnyExpression | 'AND' | 'OR' | 'NOT' export const condition = (cond: Condition): Expression => { if (Array.isArray(cond)) return expression`( ${sql.join(cond.map(condition), ' ')} )` if (typeof cond === 'string' && ['AND', 'OR', 'NOT'].includes(cond.toUpperCase())) return expression`${sql.keyword(cond, ['AND', 'OR', 'NOT'])}` return expression`${cond}` } export const toExpression = (val: any): Expression> => { if (val instanceof AnyExpression) return val as any return expression`${val}` }