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.

170 lines
5.3 KiB

import {EscapedValue, isWhereClause, isWhereGroup, WhereStatement} from '../types.ts'
import {escape, SQLWhereOperator, WherePreOperator} from '../types.ts'
import {WhereBuilderFunction} from './Select.ts'
import {apply_filter_to_where, QueryFilter} from '../../model/filter.ts'
import {Scope} from '../Scope.ts'
import {FunctionScope, ScopeFunction} from '../scope/FunctionScope.ts'
import {make} from '../../../../di/src/global.ts'
export class WhereBuilder {
protected _wheres: WhereStatement[] = []
protected _scopes: Scope[] = []
get where_items() {
return this._wheres
}
without_scope(scope: typeof Scope) {
this._scopes = this._scopes.filter(x => !(x instanceof Scope))
return this
}
with_scope(scope: Scope | ScopeFunction) {
if ( scope instanceof Scope ) {
this._scopes.push(scope)
} else {
this._scopes.push(new FunctionScope(scope))
}
return this
}
with_scopes(scopes: (Scope | ScopeFunction)[]) {
scopes.forEach(scope => this.with_scope(scope))
return this
}
wheres_to_sql(wheres?: WhereStatement[], level = 0): string {
this._scopes.forEach(scope => scope.apply(this))
const indent = Array(level * 2).fill(' ').join('')
let statements = []
for ( const where of wheres || this._wheres ) {
if ( isWhereClause(where) ) {
statements.push(`${indent}${statements.length < 1 ? '' : where.preop + ' '}${where.field} ${where.operator} ${where.operand}`)
} else if ( isWhereGroup(where) ) {
statements.push(`${indent}${statements.length < 1 ? '' : where.preop + ' '}(\n${this.wheres_to_sql(where.items, level + 1)}\n${indent})`)
}
}
return statements.filter(Boolean).join('\n')
}
private _createWhere(preop: WherePreOperator, field: string | WhereBuilderFunction, operator?: SQLWhereOperator, operand?: any) {
if ( typeof field === 'function' ) {
const where_builder = new WhereBuilder()
field(where_builder)
this._wheres.push({
preop,
items: where_builder.where_items,
})
} else if ( field && operator && typeof operand !== 'undefined' ) {
this._wheres.push({
field, operator, operand: escape(operand), preop
})
}
}
where(field: string | WhereBuilderFunction, operator?: SQLWhereOperator, operand?: any) {
this._createWhere('AND', field, operator, operand)
return this
}
whereIn(field: string, values: EscapedValue) {
this._wheres.push({
field,
operator: 'IN',
operand: escape(values),
preop: 'AND',
})
return this
}
whereNot(field: string | WhereBuilderFunction, operator?: SQLWhereOperator, operand?: EscapedValue) {
this._createWhere('AND NOT', field, operator, operand)
return this
}
whereNotIn(field: string, values: EscapedValue) {
this._wheres.push({
field,
operator: 'NOT IN',
operand: escape(values),
preop: 'AND'
})
return this
}
orWhere(field: string | WhereBuilderFunction, operator?: SQLWhereOperator, operand?: EscapedValue) {
this._createWhere('OR', field, operator, operand)
return this
}
orWhereNot(field: string | WhereBuilderFunction, operator?: SQLWhereOperator, operand?: EscapedValue) {
this._createWhere('OR NOT', field, operator, operand)
return this
}
orWhereIn(field: string, values: EscapedValue) {
this._wheres.push({
field,
operator: 'IN',
operand: escape(values),
preop: 'OR',
})
return this
}
orWhereNotIn(field: string, values: EscapedValue) {
this._wheres.push({
field,
operator: 'NOT IN',
operand: escape(values),
preop: 'OR',
})
return this
}
whereBetween(field: string, lower_bound: EscapedValue, upper_bound: EscapedValue) {
this._wheres.push({
field,
operator: 'BETWEEN',
operand: `${escape(lower_bound)} AND ${escape(upper_bound)}`,
preop: 'AND',
})
return this
}
orWhereBetween(field: string, lower_bound: EscapedValue, upper_bound: EscapedValue) {
this._wheres.push({
field,
operator: 'BETWEEN',
operand: `${escape(lower_bound)} AND ${escape(upper_bound)}`,
preop: 'OR',
})
return this
}
whereNotBetween(field: string, lower_bound: EscapedValue, upper_bound: EscapedValue) {
this._wheres.push({
field,
operator: 'NOT BETWEEN',
operand: `${escape(lower_bound)} AND ${escape(upper_bound)}`,
preop: 'AND',
})
return this
}
orWhereNotBetween(field: string, lower_bound: EscapedValue, upper_bound: EscapedValue) {
this._wheres.push({
field,
operator: 'NOT BETWEEN',
operand: `${escape(lower_bound)} AND ${escape(upper_bound)}`,
preop: 'OR',
})
return this
}
filter(filter: QueryFilter) {
return apply_filter_to_where(filter, this)
}
}