ddl-manager
Version:
store postgres procedures and triggers in files
225 lines • 9.68 kB
JavaScript
"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