You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
3.9 KiB

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}'`
}
}