import {WhereOperator} from '../../../lib/src/collection/Where.ts' import RawValue from './RawValue.ts' export type FieldSet = string | string[] export type QuerySource = string | { ref: QuerySource, alias: string } export type JoinOperator = 'JOIN' | 'LEFT JOIN' | 'LEFT OUTER JOIN' | 'RIGHT JOIN' | 'RIGHT OUTER JOIN' | 'FULL OUTER JOIN' | 'INNER JOIN' | 'CROSS JOIN' export type WherePreOperator = 'AND' | 'OR' | 'AND NOT' | 'OR NOT' export type WhereClause = { field: string, operator: SQLWhereOperator, operand: string, preop: WherePreOperator } export type WhereGroup = { items: WhereStatement[], preop: WherePreOperator } export type WhereStatement = WhereClause | WhereGroup export type SQLWhereOperator = WhereOperator | 'IN' | 'NOT IN' | 'LIKE' export type OrderDirection = 'ASC' | 'DESC' export type OrderStatement = { direction: OrderDirection, field: string } export type HavingPreOperator = WherePreOperator export type HavingClause = WhereClause export type HavingGroup = WhereGroup export type HavingStatement = HavingClause | HavingGroup export type SQLHavingOperator = SQLWhereOperator export type EscapedValue = string | number | boolean | Date | RawValue | EscapedValue[] export type FieldValue = { field: string, value: EscapedValue } export type FieldValueObject = { [field: string]: EscapedValue } export type TableRef = { table: string, database?: string, alias?: string } export function isTableRef(something: any): something is TableRef { let is = true is = is && typeof something?.table === 'string' if ( typeof something?.database !== 'undefined' ) { is = typeof something?.database === 'string' } if ( typeof something?.alias !== 'undefined' ) { is = typeof something?.alias === 'string' } return is } export function isWherePreOperator(something: any): something is WherePreOperator { return ['AND', 'OR', 'AND NOT', 'OR NOT'].includes(something) } export function isHavingClause(something: any): something is HavingClause { return isWhereClause(something) } export function isWhereClause(something: any): something is WhereClause { return typeof something?.field === 'string' && typeof something?.operator === 'string' // TODO check this better && typeof something?.operand === 'string' && isWherePreOperator(something?.preop) } export function isHavingGroup(something: any): something is HavingGroup { return isWhereGroup(something) } export function isWhereGroup(something: any): something is WhereGroup { return Array.isArray(something?.items) && something.items.every((item: any) => isWhereStatement(item)) && isWherePreOperator(something?.preop) } export function isWhereStatement(something: any): something is WhereStatement { return isWhereClause(something) || isWhereGroup(something) } export function escape(value: EscapedValue): string { if ( value instanceof RawValue ) { return value.value } else if ( Array.isArray(value) ) { return `(${value.map(escape).join(',')})` } else if ( String(value).toLowerCase() === 'true' ) { return 'TRUE' } else if ( String(value).toLowerCase() === 'false' ) { return 'FALSE' } else if ( typeof value === 'number' ) { return `${value}` } else if ( value === true ) { return 'TRUE' } else if ( value === false ) { return 'FALSE' } else if ( value instanceof Date ) { // TODO custom formattig const pad = (val: number) => val < 10 ? `0${val}` : `${val}` return `'${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())} ${pad(value.getHours())}:${pad(value.getMinutes())}:${pad(value.getSeconds())}'` } else if ( !isNaN(Number(value)) ) { return String(Number(value)) } else { const escaped = value.replace(/"/g, '\\"').replace(/'/g, '\\\'').replace(/`/g, '\\`') return `'${escaped}'` } }