import { AnyNumber , GetMostSignificantDataType , GetNotNull , Int4 , Int8 , Text , Uuid , } from './data-types' ; import { BooleanQuery , Query , SpecificQuery } from './query' ; import { CollectionToken , GroupToken , ParameterToken , SeparatorToken , StringToken , Token , } from './tokens' ; import { DbConfig , GetResultType } from './config' ; import { Err , GetDataType } from './types' ; import { Column } from './column' ; import { TableDefinition } from './table' ; import { wrapQuotes } from './naming' ; export interface SharedExpression < Config extends DbConfig , DataType , IsNotNull extends boolean , Name extends string > { internal toTokens ( includeAlias ? ) : Token [ ] ; internal hasName ( ) : boolean ; internal getName ( ) : string ; as < AliasName extends string > ( name ) : Expression < Config , DataType , IsNotNull , AliasName > ; isNull ( ) : DefaultExpression < Config , boolean > ; isNotNull ( ) : DefaultExpression < Config , boolean > ; isDistinctFrom ( a ) : DefaultExpression < Config , boolean > ; isNotDistinctFrom ( a ) : DefaultExpression < Config , boolean > ; eq < RightNotNull extends boolean > ( value ) : DefaultExpression < Config , boolean , GetNotNull < IsNotNull , RightNotNull > > ; eq < Q extends Query < any > > ( value ) : DefaultExpression < Config , boolean > ; ne < Q extends Query < any > > ( value ) : DefaultExpression < Config , boolean > ; gt < Q extends Query < any > > ( value ) : DefaultExpression < Config , boolean > ; gte < Q extends Query < any > > ( value ) : DefaultExpression < Config , boolean > ; lt < Q extends Query < any > > ( value ) : DefaultExpression < Config , boolean > ; lte < Q extends Query < any > > ( value ) : DefaultExpression < Config , boolean > ; orderBy ( ... expressions ) : DefaultExpression < Config , DataType , IsNotNull > ; asc ( ) : DefaultExpression < Config , DataType , IsNotNull > ; desc ( ) : DefaultExpression < Config , DataType , IsNotNull > ; nullsFirst ( ) : DefaultExpression < Config , DataType , IsNotNull > ; nullsLast ( ) : DefaultExpression < Config , DataType , IsNotNull > ; in < Q extends Query < any > > ( array ) : DefaultExpression < Config , boolean > ; notIn ( array ) : DefaultExpression < Config , boolean > ; } export interface TextExpression < Config extends DbConfig , DataType , IsNotNull extends boolean , Name extends string > extends SharedExpression < Config , DataType , IsNotNull , Name > { concat < RightIsNotNull extends boolean > ( value ) : DefaultExpression < Config , DataType , GetNotNull < IsNotNull , RightIsNotNull > > ; like ( value ) : DefaultExpression < Config , boolean > ; ilike ( value ) : DefaultExpression < Config , boolean > ; notLike ( value ) : DefaultExpression < Config , boolean > ; } export interface NumberExpression < Config extends DbConfig , DataType , IsNotNull extends boolean , Name extends string > extends SharedExpression < Config , DataType , IsNotNull , Name > { plus < T extends AnyNumber , RightIsNotNull extends boolean > ( expression ) : DefaultExpression < Config , GetMostSignificantDataType < DataType , T > , GetNotNull < IsNotNull , RightIsNotNull > > ; plus ( value ) : DefaultExpression < Config , DataType , IsNotNull > ; minus < T extends AnyNumber , RightIsNotNull extends boolean > ( expression ) : DefaultExpression < Config , GetMostSignificantDataType < DataType , T > , GetNotNull < IsNotNull , RightIsNotNull > > ; minus < T extends AnyNumber > ( value ) : DefaultExpression < Config , GetMostSignificantDataType < DataType , T > , IsNotNull > ; multiply < T extends AnyNumber , RightIsNotNull extends boolean > ( expression ) : DefaultExpression < Config , GetMostSignificantDataType < DataType , T > , GetNotNull < IsNotNull , RightIsNotNull > > ; multiply < T extends AnyNumber > ( value ) : DefaultExpression < Config , GetMostSignificantDataType < DataType , T > , IsNotNull > ; divide < T extends AnyNumber , RightIsNotNull extends boolean > ( expression ) : DefaultExpression < Config , GetMostSignificantDataType < DataType , T > , GetNotNull < IsNotNull , RightIsNotNull > > ; divide < T extends AnyNumber > ( value ) : DefaultExpression < Config , GetMostSignificantDataType < DataType , T > , IsNotNull > ; modulo < T extends AnyNumber , RightIsNotNull extends boolean > ( expression ) : DefaultExpression < Config , GetMostSignificantDataType < DataType , T > , GetNotNull < IsNotNull , RightIsNotNull > > ; modulo < T extends AnyNumber > ( value ) : DefaultExpression < Config , GetMostSignificantDataType < DataType , T > , IsNotNull > ; between ( a , b ) : DefaultExpression < Config , boolean > ; betweenSymmetric ( a , b ) : DefaultExpression < Config , boolean > ; } export interface BooleanExpression < Config extends DbConfig , DataType , IsNotNull extends boolean , Name extends string > { internal toTokens ( includeAlias ? ) : Token [ ] ; internal hasName ( ) : boolean ; internal getName ( ) : string ; as < AliasName extends string > ( name ) : Expression < Config , DataType , IsNotNull , AliasName > ; or ( query ) : DefaultExpression < Config , boolean , IsNotNull > ; or < RightIsNotNull extends boolean > ( expression ) : DefaultExpression < Config , boolean , GetNotNull < IsNotNull , RightIsNotNull > > ; and ( query ) : DefaultExpression < Config , boolean , IsNotNull > ; and < RightIsNotNull extends boolean > ( expression ) : DefaultExpression < Config , boolean , GetNotNull < IsNotNull , RightIsNotNull > > ; andNotExists ( query ) : DefaultExpression < Config , boolean , IsNotNull > ; andNotExists < RightIsNotNull extends boolean > ( expression ) : DefaultExpression < Config , boolean , GetNotNull < IsNotNull , RightIsNotNull > > ; andExists ( query ) : DefaultExpression < Config , boolean , IsNotNull > ; andExists < RightIsNotNull extends boolean > ( expression ) : DefaultExpression < Config , boolean , GetNotNull < IsNotNull , RightIsNotNull > > ; } export interface RawExpression < Config extends DbConfig , DataType , IsNotNull extends boolean , Name extends string > extends TextExpression < Config , DataType , IsNotNull , Name > , NumberExpression < Config , DataType , IsNotNull , Name > { } export interface UuidExpression < Config extends DbConfig , TD , IsNotNull extends boolean , Name extends string > extends Omit < SharedExpression < Config , Uuid < TD > , IsNotNull , Name > , 'eq' > { eq ( value ) : DefaultExpression < Config , boolean , IsNotNull > ; eq < RightExpression extends UuidExpression < Config , any , any , any > > ( expression ) : RightExpression extends UuidExpression < Config , infer RightTableDefinition , infer RightIsNotNull , any > ? RightTableDefinition extends TableDefinition < infer RightColumns > ? TD extends TableDefinition < infer LeftColumns > ? [ LeftColumns ] extends [ RightColumns ] ? [ RightColumns ] extends [ LeftColumns ] ? DefaultExpression < Config , boolean , GetNotNull < IsNotNull , RightIsNotNull > > : Err < 'not the right references' > : Err < 'not the right references' > : Err < 'no left table definition found in uuid' > : Err < 'no right table definition found in uuid' > : Err < 'no uuid expression' > ; } export type Expression < Config extends DbConfig , DataType , IsNotNull extends boolean , Name extends string > = DataType extends boolean ? BooleanExpression < Config , DataType , IsNotNull , Name > : DataType extends AnyNumber ? NumberExpression < Config , DataType , IsNotNull , Name > : DataType extends Text ? TextExpression < Config , DataType , IsNotNull , Name > : DataType extends number ? NumberExpression < Config , DataType , IsNotNull , Name > : DataType extends string ? TextExpression < Config , DataType , IsNotNull , Name > : DataType extends Uuid < infer TableDefinition > ? UuidExpression < Config , TableDefinition , IsNotNull , Name > : RawExpression < Config , DataType , IsNotNull , Name > ; export class InternalExpression < Config extends DbConfig , DataType , IsNotNull extends boolean , Name extends string > implements TextExpression < Config , DataType , IsNotNull , Name > , NumberExpression < Config , DataType , IsNotNull , Name > , BooleanExpression < Config , DataType , IsNotNull , Name > { private _expressionBrand ! : [ 'expression' , DataType , IsNotNull , Name ] ; internal getName ( ) { return this . name ; } internal hasName ( ) { return this . name !== `?column?` ; } protected unusedName ( ) { return this . name ; } constructor ( private readonly tokens , private readonly name , private readonly nameIsAlias = false ) { } private getDataTypeTokens ( value ) { if ( value && typeof value === `object` && 'toTokens' in value && typeof value . toTokens === `function` ) { if ( value instanceof Query ) { return [ new GroupToken ( value . toTokens ( ) ) ] ; } return value . toTokens ( ) ; } return [ new ParameterToken ( value ) ] ; } private toGroup ( expression ) { const newTokens = expression . toTokens ( ) ; if ( newTokens . length > 3 ) { return new GroupToken ( newTokens ) ; } return new CollectionToken ( newTokens ) ; } or ( expression ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `OR` ) , this . toGroup ( expression ) , ] ) as any ; } and ( expression ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `AND` ) , this . toGroup ( expression ) , ] ) as any ; } andNotExists ( expression ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `AND NOT EXISTS` ) , this . toGroup ( expression ) , ] ) as any ; } andExists ( expression ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `AND EXISTS` ) , this . toGroup ( expression ) , ] ) as any ; } as ( name ) { if ( this . tokens . length > 2 ) { return new InternalExpression ( [ new GroupToken ( this . tokens ) ] , name , true ) as any ; } return new InternalExpression ( [ ... this . tokens ] , name , true ) ; } isNull ( ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `IS NULL` ) ] ) as any ; } isNotNull ( ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `IS NOT NULL` ) ] ) as any ; } asc ( ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `ASC` ) ] ) as any ; } desc ( ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `DESC` ) ] ) as any ; } nullsFirst ( ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `NULLS FIRST` ) ] ) as any ; } nullsLast ( ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `NULLS LAST` ) ] ) as any ; } in ( array ) { if ( array && ( 'toTokens' in array || array instanceof Query ) ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `IN` ) , new GroupToken ( array . toTokens ( ) ) , ] ) as any ; } else { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `IN` ) , new GroupToken ( [ new SeparatorToken ( ',' , array . map ( ( item ) => new ParameterToken ( item ) ) ) , ] ) , ] ) as any ; } } notIn ( array ) { if ( array && ( 'toTokens' in array || array instanceof Query ) ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `NOT IN` ) , new GroupToken ( array . toTokens ( ) ) , ] ) as any ; } else { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `NOT IN` ) , new GroupToken ( [ new SeparatorToken ( ',' , array . map ( ( item ) => new ParameterToken ( item ) ) ) , ] ) , ] ) as any ; } } plus ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `+` ) , ... this . getDataTypeTokens ( value ) , ] ) as any ; } minus ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `-` ) , ... this . getDataTypeTokens ( value ) , ] ) ; } multiply ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `*` ) , ... this . getDataTypeTokens ( value ) , ] ) ; } divide ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `/` ) , ... this . getDataTypeTokens ( value ) , ] ) ; } modulo ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `%` ) , ... this . getDataTypeTokens ( value ) , ] ) ; } concat ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `||` ) , ... this . getDataTypeTokens ( value ) , ] ) as any ; } between ( a , b ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `BETWEEN` ) , new ParameterToken ( a ) , new StringToken ( `AND` ) , new ParameterToken ( b ) , ] ) ; } betweenSymmetric ( a , b ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `BETWEEN SYMMETRIC` ) , new ParameterToken ( a ) , new StringToken ( `AND` ) , new ParameterToken ( b ) , ] ) ; } isDistinctFrom ( a ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `IS DISTINCT FROM` ) , new ParameterToken ( a ) , ] ) ; } isNotDistinctFrom ( a ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `IS NOT DISTINCT FROM` ) , new ParameterToken ( a ) , ] ) ; } like ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `LIKE` ) , new ParameterToken ( value ) , ] ) ; } ilike ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `ILIKE` ) , new ParameterToken ( value ) , ] ) ; } notLike ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `NOT LIKE` ) , new ParameterToken ( value ) , ] ) ; } eq < Q extends Query < any > > ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `=` ) , ... this . getDataTypeTokens ( value ) , ] ) ; } ne < Q extends Query < any > > ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `<>` ) , ... this . getDataTypeTokens ( value ) , ] ) ; } gt < Q extends Query < any > > ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `>` ) , ... this . getDataTypeTokens ( value ) , ] ) ; } gte < Q extends Query < any > > ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `>=` ) , ... this . getDataTypeTokens ( value ) , ] ) ; } lt < Q extends Query < any > > ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `<` ) , ... this . getDataTypeTokens ( value ) , ] ) ; } lte < Q extends Query < any > > ( value ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `<=` ) , ... this . getDataTypeTokens ( value ) , ] ) ; } orderBy ( ... expressions ) { return new InternalDefaultExpression ( [ ... this . tokens , new StringToken ( `ORDER BY` ) , new SeparatorToken ( ',' , expressions . map ( ( expression ) => expression . hasName ( ) ? new CollectionToken ( [ new StringToken ( wrapQuotes ( expression . getName ( ) ) ) ] ) : new CollectionToken ( expression . toTokens ( ) ) ) ) , ] ) as any ; } internal toTokens ( includeAlias ? ) { if ( includeAlias && ( this . nameIsAlias || this . name . match ( /[A-Z]/ ) ) ) { return [ ... this . tokens , new StringToken ( `${ wrapQuotes ( this . name , true ) }` ) ] ; } return this . tokens ; } } export type DefaultExpression < Config extends DbConfig , DataType , IsNotNull extends boolean = true > = Expression < Config , DataType , IsNotNull , '?column?' > ; export class InternalDefaultExpression < Config extends DbConfig , DataType , IsNotNull extends boolean = true > extends InternalExpression < Config , DataType , IsNotNull , '?column?' > { constructor ( tokens ) { super ( tokens , '?column?' ) ; } } export type AnyExpression = Expression < any , any , any , any > ;