UNPKG

ddl-manager

Version:

store postgres procedures and triggers in files

164 lines (140 loc) 4.96 kB
import { flatMap } from "lodash"; import { Table } from "./Table"; import { TableID } from "./TableID"; import { DatabaseTrigger } from "./DatabaseTrigger"; import { DatabaseFunction } from "./DatabaseFunction"; import { Migration } from "../../Migrator/Migration"; import { Index } from "./Index"; import { MAX_NAME_LENGTH } from "../postgres/constants"; export class Database { readonly tables: Table[]; functions: DatabaseFunction[]; readonly aggregators: string[]; private tablesMap: Record<string, Table>; private functionsMap: Record<string, DatabaseFunction[]>; constructor(tables: Table[] = []) { this.tablesMap = {}; this.tables = []; for (let table of tables) { table = table.clone(); this.tables.push(table); this.tablesMap[ table.toString() ] = table; } this.functions = []; this.functionsMap = {}; this.aggregators = [ "count", "max", "min", "sum", "avg", "array_agg", "string_agg", "bool_or", "bool_and", "every" ]; } getAllColumns() { return flatMap(this.tables, table => table.columns); } getAllTriggers() { return flatMap(this.tables, table => table.triggers); } getColumn(tableId: TableID, column: string) { const dbTable = this.tables.find(table => table.name === tableId.name && table.schema === tableId.schema ); return dbTable?.getColumn(column); } getTable(tableId: TableID) { return this.tablesMap[ tableId.toString() ]; } getTriggersByProcedure(procedure: {schema: string, name: string}) { return flatMap(this.tables, (table) => { return table.triggers.filter(trigger => trigger.procedure.schema === procedure.schema && trigger.procedure.name === procedure.name ); }); } setTable(table: Table) { if ( !this.tablesMap[ table.toString() ] ) { table = table.clone(); this.tables.push( table ); this.tablesMap[ table.toString() ] = table; } } addFunctions(functions: DatabaseFunction[]) { for (const func of functions) { this.functions.push(func); const name = func.name.slice(0, MAX_NAME_LENGTH); this.functionsMap[ name ] ??= []; this.functionsMap[ name ].push(func); } } addTrigger(trigger: DatabaseTrigger) { const table = this.getTable(trigger.table); if ( !table ) { throw new Error(`unknown table "${ trigger.table }" for trigger "${ trigger.name }"`) } table.addTrigger(trigger); } addIndex(index: Index) { const table = this.getTable(index.table); if ( !table ) { throw new Error(`unknown table "${ index.table }" for index "${ index.name }"`) } table.addIndex(index); } applyMigration(migration: Migration) { this.addFunctions(migration.toCreate.functions); for (const trigger of migration.toCreate.triggers) { this.addTrigger(trigger); } for (const column of migration.toCreate.columns) { const table = this.getTable(column.table); if ( table ) { table.addColumn(column); } } this.functions = this.functions.filter(existentFunc => !migration.toDrop.functions.some(dropFunc => existentFunc.getSignature() === dropFunc.getSignature() ) ); for (const dropFunc of migration.toDrop.functions) { const name = dropFunc.name.slice(0, MAX_NAME_LENGTH); this.functionsMap[name] = this.functionsMap[name].filter(existentFunc => existentFunc.getSignature() !== dropFunc.getSignature() ); } for (const trigger of migration.toDrop.triggers) { const table = this.getTable(trigger.table); if ( table ) { table.removeTrigger(trigger); } } for (const column of migration.toDrop.columns) { const table = this.getTable(column.table); if ( table ) { table.removeColumn(column); } } } addAggregators(newAggregators: string[]) { for (const aggName of newAggregators) { if ( !this.aggregators.includes(aggName) ) { this.aggregators.push(aggName); } } } allCacheTriggers() { return flatMap(this.tables, table => table.triggers) .filter(trigger => !!trigger.cacheSignature); } getFunctions(name: string) { return this.functionsMap[ name.slice(0, MAX_NAME_LENGTH) ] ?? []; } }