UNPKG

ddl-manager

Version:

store postgres procedures and triggers in files

225 lines 9.68 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OneRowTriggerBuilder = void 0; const ast_1 = require("../../ast"); const CoalesceFalseExpression_1 = require("../../ast/expression/CoalesceFalseExpression"); const TableReference_1 = require("../../database/schema/TableReference"); const findJoinsMeta_1 = require("../processor/findJoinsMeta"); const AbstractTriggerBuilder_1 = require("./AbstractTriggerBuilder"); const buildOneRowBody_1 = require("./body/buildOneRowBody"); class OneRowTriggerBuilder extends AbstractTriggerBuilder_1.AbstractTriggerBuilder { createTriggers() { return [{ trigger: this.createDatabaseTriggerOnDIU(), procedure: this.createDatabaseFunction(this.createBody()) }]; } createBody() { const body = buildOneRowBody_1.buildOneRowBody({ selects: this.buildSelectRecords(), onInsert: this.context.withoutInsertCase() ? undefined : { needUpdate: this.hasEffect("new"), update: new ast_1.Update({ table: this.context.cache.for.toString(), set: this.setNewItems(), where: ast_1.Expression.and([ this.conditions.simpleWhere("new"), this.whereDistinctNewValues() ]) }) }, onUpdate: { needUpdate: this.needUpdateOnUpdate(), noChanges: this.conditions.noChanges(), update: new ast_1.Update({ table: this.context.cache.for.toString(), set: this.setDeltaItems(), where: ast_1.Expression.and([ this.conditions.simpleWhere("new"), this.whereDistinctDeltaValues() ]) }) }, onDelete: { needUpdate: this.hasEffect("old"), update: new ast_1.Update({ table: this.context.cache.for.toString(), set: this.setNulls(), where: ast_1.Expression.and([ this.conditions.simpleWhere("old"), this.whereDistinctNullValues() ]) }) } }); return body; } buildSelectRecords() { const selects = []; const joins = findJoinsMeta_1.findJoinsMeta(this.context.cache.select); for (const join of joins) { const select = { recordName: buildRecordName(join), select: join.joinedColumns.map(column => column.name), from: join.joinedTable.table, where: join.joinByColumn.name }; selects.push(select); } return selects; } whereDistinctNewValues() { const selectColumns = this.context.cache.select.columns; const newValues = selectColumns.map(selectColumn => this.replaceTables("new", selectColumn.expression)); return this.whereDistinctFrom(newValues); } whereDistinctDeltaValues() { const selectColumns = this.context.cache.select.columns; const newValues = selectColumns.map(selectColumn => this.caseMatchedThenNewValue(selectColumn)); return this.whereDistinctFrom(newValues); } whereDistinctNullValues() { const selectColumns = this.context.cache.select.columns; const nullValues = selectColumns.map(selectColumn => this.createNullExpression(selectColumn.expression)); return this.whereDistinctFrom(nullValues); } whereDistinctFrom(values) { const selectColumns = this.context.cache.select.columns; const compareConditions = selectColumns.map((selectColumn, i) => { const cacheColumnRef = new ast_1.ColumnReference(this.context.cache.for, selectColumn.name); return ast_1.UnknownExpressionElement.fromSql(`${cacheColumnRef} is distinct from (${values[i]})`); }); return ast_1.Expression.or(compareConditions); } needUpdateOnUpdate() { if (!this.context.referenceMeta.filters.length) { return; } const { matchedNew, matchedOld } = this.buildMatches(); return ast_1.Expression.or([ matchedOld, matchedNew ]); } buildMatches() { const matchedOld = []; const matchedNew = []; this.context.referenceMeta.filters.forEach(filter => { const filterOld = this.replaceTriggerTableToRow("old", filter); const filterNew = this.replaceTriggerTableToRow("new", filter); matchedNew.push(new CoalesceFalseExpression_1.CoalesceFalseExpression(filterNew)); matchedOld.push(new CoalesceFalseExpression_1.CoalesceFalseExpression(filterOld)); }); return { matchedOld: ast_1.Expression.and(matchedOld), matchedNew: ast_1.Expression.and(matchedNew) }; } setNewItems() { const setItems = this.context.cache.select.columns.map(selectColumn => { const setItem = new ast_1.SetItem({ column: selectColumn.name, value: this.replaceTables("new", selectColumn.expression) }); return setItem; }); return setItems; } setDeltaItems() { const setItems = this.context.cache.select.columns.map(selectColumn => { const setItem = new ast_1.SetItem({ column: selectColumn.name, value: this.caseMatchedThenNewValue(selectColumn) }); return setItem; }); return setItems; } caseMatchedThenNewValue(selectColumn) { if (!this.context.referenceMeta.filters.length) { return this.replaceTables("new", selectColumn.expression); } const { matchedNew } = this.buildMatches(); return new ast_1.CaseWhen({ cases: [{ when: matchedNew, then: this.replaceTables("new", selectColumn.expression) }], else: ast_1.Expression.unknown("null") }); } setNulls() { const setItems = this.context.cache.select.columns.map(selectColumn => { const setItem = new ast_1.SetItem({ column: selectColumn.name, value: this.createNullExpression(selectColumn.expression) }); return setItem; }); return setItems; } createNullExpression(expression) { if (expression.isColumnReference() || expression.isArrayItemOfColumnReference()) { return ast_1.Expression.unknown("null"); } let nullExpression = expression; const columnRefs = expression.getColumnReferences() .filter(columnRef => this.notColumnToCacheRow(columnRef)); for (const columnRef of columnRefs) { const dbTable = this.context.database.getTable(columnRef.tableReference.table); const dbColumn = dbTable && dbTable.getColumn(columnRef.name); const nullSql = dbColumn ? ast_1.UnknownExpressionElement.fromSql(`(null::${dbColumn.type})`) : ast_1.UnknownExpressionElement.fromSql("null"); nullExpression = nullExpression.replaceColumn(columnRef, nullSql); } return nullExpression; } hasEffect(row) { const conditions = this.context.cache.select.columns .filter(selectColumn => selectColumn.expression.getColumnReferences() .every(columnRef => this.columnRefToTriggerTable(columnRef))) .map(selectColumn => { const expression = this.replaceTables(row, selectColumn.expression); if (expression.needWrapToBrackets()) { return `(${expression}) is not null`; } return `${expression} is not null`; }); if (this.context.referenceMeta.filters.length) { const filters = this.context.referenceMeta.filters.map(filter => this.replaceTables(row, filter)); if (conditions.length) { const hasEffectAndFilters = ast_1.Expression.and([ ast_1.Expression.or(conditions), ast_1.Expression.and(filters) ]); return hasEffectAndFilters; } return ast_1.Expression.and(filters); } return ast_1.Expression.or(conditions); } columnRefToTriggerTable(columnRef) { return columnRef.tableReference.equal(this.context.cache.select.getFromTable()); } notColumnToCacheRow(columnRef) { return !columnRef.tableReference.equal(this.context.cache.for); } replaceTables(row, expression) { expression = expression.replaceTable(this.context.triggerTable, new TableReference_1.TableReference(this.context.triggerTable, row)); const joins = findJoinsMeta_1.findJoinsMeta(this.context.cache.select); for (const join of joins) { const recordName = buildRecordName(join); expression = expression.replaceTable(join.joinedTable, new TableReference_1.TableReference(join.joinedTable.table, recordName)); } return expression; } } exports.OneRowTriggerBuilder = OneRowTriggerBuilder; function buildRecordName(join) { const recordName = join.joinedTable.getIdentifier() .replace(".", "_") + "_row"; return recordName; } //# sourceMappingURL=OneRowTriggerBuilder.js.map