UNPKG

ddl-manager

Version:

store postgres procedures and triggers in files

185 lines (151 loc) 6.13 kB
import { flatMap } from "lodash"; import { Cache } from "../ast"; import { DatabaseFunction } from "../database/schema/DatabaseFunction"; import { DatabaseTrigger } from "../database/schema/DatabaseTrigger"; import { File, IFileParams } from "./File"; import { TableID } from "../database/schema/TableID"; export class FilesState { readonly files: File[]; private cacheMap: Record<string, Cache[]> = {}; private functionsMap: Record<string, DatabaseFunction[]> = {}; private triggersMap: Record<string, DatabaseTrigger[]> = {}; constructor(files: File[] = []) { this.files = files; } allNotHelpersFiles() { return this.files.filter(file => file.folder !== "HELPERS" && !file.name.startsWith("CM_") ); } allCache() { return flatMap(this.files, file => file.content.cache) } allTriggers() { return flatMap(this.files, file => file.content.triggers); } allFunctions() { return flatMap(this.files, file => file.content.functions); } allNotHelperFunctions() { return flatMap(this.allNotHelpersFiles(), file => file.content.functions); } getCache(signature: string) { return this.allCache().find(cache => cache.getSignature() === signature ); } getCachesForTable(forTable: TableID) { return (this.cacheMap[ forTable.toString() ] ?? []).slice(); } getFunctionsByName(name: string) { return (this.functionsMap[ name ] ?? []).slice(); } getTableTriggers(table: TableID) { return (this.triggersMap[ table.toString() ] ?? []).slice(); } getTriggerFunction(trigger: DatabaseTrigger) { return (this.functionsMap[trigger.procedure.name] || []).find(func => func.schema === trigger.procedure.schema ); } addFile(fileOrParams: File | IFileParams) { let file!: File; if ( fileOrParams instanceof File ) { file = fileOrParams; } else { file = new File(fileOrParams); } this.checkDuplicate( file ); this.files.push(file); for (const func of file.content.functions) { this.functionsMap[ func.name ] ??= []; this.functionsMap[ func.name ].push(func); } for (const trigger of file.content.triggers) { const table = trigger.table.toString(); this.triggersMap[ table ] ??= []; this.triggersMap[ table ].push(trigger); } for (const cache of file.content.cache) { const table = cache.for.table.toString(); this.cacheMap[ table ] ??= []; this.cacheMap[ table ].push(cache); } } removeFile(file: File) { const fileIndex = this.files.indexOf(file); if ( fileIndex !== -1 ) { this.files.splice(fileIndex, 1); } for (const deletedFunc of file.content.functions) { this.functionsMap[ deletedFunc.name ] ??= []; this.functionsMap[ deletedFunc.name ] = this.functionsMap[ deletedFunc.name ] .filter(func => func.getSignature() != deletedFunc.getSignature()); } for (const deletedTrigger of file.content.triggers) { const table = deletedTrigger.table.toString(); this.triggersMap[ table ] ??= []; this.triggersMap[ table ] = this.triggersMap[ table ] .filter(trigger => trigger.getSignature() != deletedTrigger.getSignature()); } for (const deletedCache of file.content.cache) { const table = deletedCache.for.table.toString(); this.cacheMap[ table ] ??= []; this.cacheMap[ table ] = this.cacheMap[ table ] .filter(cache => cache.getSignature() !== deletedCache.getSignature()) } } private checkDuplicate(file: File) { file.content.functions.forEach(func => this.checkDuplicateFunction( func ) ); file.content.triggers.forEach(trigger => { this.checkDuplicateTrigger( trigger ); }); file.content.cache.forEach(cache => { this.checkDuplicateCache( cache ); }); } private checkDuplicateFunction(func: DatabaseFunction) { const identify = func.getSignature(); const hasDuplicate = this.getFunctionsByName(func.name).some(someFunc => { const someIdentify = someFunc.getSignature(); return identify === someIdentify; }); if ( hasDuplicate ) { throw new Error(`duplicated function ${ identify }`); } } private checkDuplicateTrigger(trigger: DatabaseTrigger) { const identify = trigger.getSignature(); const hasDuplicate = this.getTableTriggers(trigger.table).some(someTrigger => { const someIdentify = someTrigger.getSignature(); return identify === someIdentify; }); if ( hasDuplicate ) { throw new Error(`duplicated trigger ${ identify }`); } } private checkDuplicateCache(cache: Cache) { const identify = cache.getSignature(); const cacheColumns = cache.select.columns.map(col => col.name);; for (const someCache of this.getCachesForTable(cache.for.table)) { // duplicated cache name if ( someCache.getSignature() === identify ) { throw new Error(`duplicated ${ identify }`); } // duplicate cache columns if ( someCache.for.table.equal(cache.for.table) ) { const someCacheColumns = someCache.select.columns.map(col => col.name); const duplicatedColumns = someCacheColumns.filter(columnName => cacheColumns.includes(columnName) ); if ( duplicatedColumns.length > 0 ) { throw new Error(`duplicated columns: ${ duplicatedColumns } by cache: ${cache.name}, ${someCache.name}`); } } } } }