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.

119 lines
3.7 KiB

import ConnectionMutable from './ConnectionMutable.ts'
import {EscapedValue, FieldValueObject, QuerySource} from '../types.ts'
import {MalformedSQLGrammarError} from './Select.ts'
import {TableRefBuilder} from './TableRefBuilder.ts'
import {applyMixins} from '../../../../lib/src/support/mixins.ts'
import {escape, FieldSet} from '../types.ts'
import {raw} from '../Builder.ts'
// TODO support DEFAULT VALUES
// TODO support ON CONFLICT
export class Insert extends ConnectionMutable {
protected _target?: QuerySource = undefined
protected _columns: string[] = []
protected _rows: string[] = []
protected _fields: string[] = []
protected _return_all = false
sql(level = 0): string {
const indent = Array(level * 2).fill(' ').join('')
if ( typeof this._target === 'undefined' )
throw new MalformedSQLGrammarError('No table reference has been provided.')
if ( this._rows.length < 1 )
throw new MalformedSQLGrammarError('There are no rows to insert.')
const table_ref = this.source_alias_to_table_ref(this._target)
const returning = this._return_all ? this._columns.join(', ') : this._fields.join(', ')
const fields = escape(this._columns.map(x => raw(x)))
return [
`INSERT INTO ${this.serialize_table_ref(table_ref)}`,
` ${fields}`,
'VALUES',
` ${this._rows.join(',\n ')}`,
...(returning.trim() ? [`RETURNING ${returning}`] : [])
].filter(x => String(x).trim()).join(`\n${indent}`)
}
into(source: QuerySource, alias?: string) {
if ( !alias ) this._target = source
else this._target = { ref: source, alias }
return this
}
columns(...columns: string[]) {
this._columns = columns
return this
}
row_raw(...row: EscapedValue[]) {
if ( row.length !== this._columns.length )
throw new MalformedSQLGrammarError(`Cannot insert row with ${row.length} values using a query that has ${this._columns.length} columns specified.`)
this._rows.push(escape(row))
return this
}
row(row: FieldValueObject) {
const columns = []
const row_raw = []
for ( const field in row ) {
if ( !row.hasOwnProperty(field) ) continue
columns.push(field)
row_raw.push(row[field])
}
this.columns(...columns)
this.row_raw(...row_raw)
return this
}
rows(rows: FieldValueObject[]) {
const [initial, ...rest] = rows
const columns = []
const initial_raw = []
for ( const field in initial ) {
if ( !initial.hasOwnProperty(field) ) continue
columns.push(field)
initial_raw.push(initial[field])
}
this.columns(...columns)
this.row_raw(...initial_raw)
for ( const row of rest ) {
const values = []
for ( const col of columns ) {
values.push(row[col])
}
this.row_raw(...values)
}
return this
}
returning(...fields: FieldSet[]) {
for ( const field_set of fields ) {
if ( typeof field_set === 'string' ) {
if ( !this._fields.includes(field_set) )
this._fields.push(field_set)
} else {
for ( const field of field_set ) {
if ( !this._fields.includes(field) )
this._fields.push(field)
}
}
}
this._return_all = this._fields.length === 0
return this
}
}
export interface Insert extends TableRefBuilder {}
applyMixins(Insert, [TableRefBuilder])