import ConnectionMutable from "./ConnectionMutable.ts"; import {Type} from "../../db/types.ts"; import {Collection} from "../../../../lib/src/collection/Collection.ts"; import {MalformedSQLGrammarError} from "./Select.ts"; export interface ColumnDefinition { with_name: string, with_type: Type, type_size?: string | number, null: boolean, as_primary_key: boolean, with_default?: string, sql: (level: number) => string, check_expression?: string, check_no_inherit: boolean, } export class ColumnFluency implements ColumnDefinition { public with_name: string = '' public with_type: Type = Type.varchar public null: boolean = false public as_primary_key: boolean = false public with_default?: string public type_size?: string | number public check_expression?: string public check_no_inherit: boolean = false public clone() { const col = new ColumnFluency() col.with_name = this.with_name col.with_type = this.with_type col.null = this.null col.as_primary_key = this.as_primary_key col.with_default = this.with_default col.type_size = this.type_size col.check_expression = this.check_expression col.check_no_inherit = this.check_no_inherit return col } public name(name: string): this { this.with_name = name return this } public type(type: Type, size?: string | number): this { this.with_type = type if ( size ) this.type_size = size return this } public nullable() { this.null = true return this } public primary_key() { this.as_primary_key = true return this } public default(val: string) { this.with_default = val } public check(expression: string, inherit: boolean = true): this { this.check_expression = expression this.check_no_inherit = !inherit return this } public sql(level: number = 0): string { const indent = Array(level).fill(' ').join('') const parts = [] if ( this.null ) parts.push('NULL') else parts.push('NOT NULL') if ( this.as_primary_key ) parts.push('PRIMARY KEY') if ( this.with_default ) parts.push(`DEFAULT ${this.with_default}`) if ( this.check_expression ) { parts.push(`CHECK (${this.check_expression})${this.check_no_inherit ? ' NO INHERIT' : ''}`) } return `${indent}${this.with_name} ${this.with_type}${this.type_size ? '('+this.type_size+')' : ''}${parts.length > 0 ? ' '+parts.join(' ') : ''}` } } export type FluencyFunction = (col: ColumnFluency) => any export class CreateTable extends ConnectionMutable { protected _name?: string protected _column_defs: Collection = new Collection() constructor(name?: string) { super() if ( name ) this._name = name } sql(level: number = 0): string { const indent = Array(level).fill(' ').join('') if ( !this._name ) { throw new MalformedSQLGrammarError(`Missing required table name for create statement.`) } const column_sql = this._column_defs.map(x => `${indent}${x.sql(level + 1)}`) return [ `CREATE TABLE ${this._name} (`, column_sql.join(`,\n${indent}`), ')' ].filter(x => String(x).trim()).join(`\n${indent}`) } name(name: string): this { this._name = name return this } column(name_or_fluency_fn: string | FluencyFunction, type?: Type, type_size?: string | number): this { const col = new ColumnFluency() if ( typeof name_or_fluency_fn === 'string' ) { if ( !type ) throw new MalformedSQLGrammarError(`Missing type for column: ${name_or_fluency_fn}`) col.name(name_or_fluency_fn) .type(type, type_size) } else { name_or_fluency_fn(col) } this._column_defs.push(col) return this } }