UNPKG

ddl-manager

Version:

store postgres procedures and triggers in files

148 lines (133 loc) 5.07 kB
import { Cache } from "../../ast"; import { AbstractTriggerBuilder } from "./AbstractTriggerBuilder"; import { CommutativeTriggerBuilder } from "./commutative/CommutativeTriggerBuilder"; import { ArrayRefCommutativeTriggerBuilder } from "./commutative/ArrayRefCommutativeTriggerBuilder"; import { Database } from "../../database/schema/Database"; import { TableID } from "../../database/schema/TableID"; import { buildFrom } from "../processor/buildFrom"; import { UniversalTriggerBuilder } from "./UniversalTriggerBuilder"; import { CacheContext } from "./CacheContext"; import { flatMap } from "lodash"; import { OneRowTriggerBuilder } from "./OneRowTriggerBuilder"; import { LastRowByIdTriggerBuilder } from "./one-last-row/LastRowByIdTriggerBuilder"; import { LastRowByMutableTriggerBuilder } from "./one-last-row/LastRowByMutableTriggerBuilder"; import { buildArrVars } from "../processor/buildArrVars"; import { FilesState } from "../../fs/FilesState"; import { CacheColumnGraph } from "../../Comparator/graph/CacheColumnGraph"; export class TriggerBuilderFactory { private readonly allCache: Cache[]; private readonly cache: Cache; private readonly database: Database; private readonly fs: FilesState; private readonly graph: CacheColumnGraph; constructor( allCache: Cache[], cache: Cache, database: Database, fs: FilesState, graph: CacheColumnGraph ) { this.allCache = allCache; this.cache = cache; this.database = database; this.fs = fs; this.graph = graph; } tryCreateBuilder( triggerTable: TableID, triggerTableColumns: string[] ): AbstractTriggerBuilder | undefined { const context = new CacheContext( this.cache, triggerTable, triggerTableColumns, this.database, this.fs, this.graph ); const Builder = this.chooseConstructor(context); if ( Builder ) { const builder = new Builder( context ); return builder; } } private chooseConstructor(context: CacheContext) { const from = buildFrom(context); const isTriggerOnCacheTable = context.triggerTable.equal(context.cache.for.table); const joins = flatMap(context.cache.select.from, fromItem => fromItem.joins); const isFromJoin = joins.some(join => join.getTableId().equal(context.triggerTable) ); const hasNotLeftJoin = joins.some(join => join.type !== "left join" ); const needUniversalTrigger = ( hasNotLeftJoin || from.length > 1 || from.length === 1 && isFromJoin ); if ( needUniversalTrigger ) { return UniversalTriggerBuilder; } else if ( context.hasAgg() ) { const noDepsToCacheTable = context.cache.select .getAllTableReferences() .every(tableRef => !tableRef.table.equal(context.cache.for.table) ); if ( isTriggerOnCacheTable && noDepsToCacheTable ) { return; } const arrayVars = buildArrVars(context); if ( arrayVars.length ) { return ArrayRefCommutativeTriggerBuilder; } else { return CommutativeTriggerBuilder; } } else if ( this.oneLastRow(context) ) { const arrayVars = buildArrVars(context); if ( arrayVars.length ) { return ArrayRefCommutativeTriggerBuilder; } const orderBy = context.cache.select.orderBy!; const orderByColumns = orderBy.getColumnReferences(); const firstOrderColumn = orderByColumns[0]; const byId = ( orderByColumns.length === 1 && firstOrderColumn.name === "id" && context.isColumnRefToTriggerTable( firstOrderColumn ) ); if ( byId ) { return LastRowByIdTriggerBuilder; } else { return LastRowByMutableTriggerBuilder; } } else if ( this.oneRowFromTable(context) ) { return OneRowTriggerBuilder; } else if ( from.length > 0 && !context.triggerTable.equal( context.cache.for.table ) ) { // order by and unknown where return UniversalTriggerBuilder; } } private oneRowFromTable(context: CacheContext) { return ( context.cache.select.from.length === 1 && context.referenceMeta.expressions.length > 0 ); } private oneLastRow(context: CacheContext) { const {select} = context.cache; return ( select.from.length === 1 && select.orderBy && select.limit === 1 && context.referenceMeta.expressions.length > 0 ); } }