ddl-manager
Version:
store postgres procedures and triggers in files
208 lines • 9.94 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConditionBuilder = void 0;
const ast_1 = require("../../../ast");
const TableReference_1 = require("../../../database/schema/TableReference");
const lodash_1 = require("lodash");
const buildHasReferenceCondition_1 = require("./buildHasReferenceCondition");
const replaceOperatorAnyToIndexedOperator_1 = require("./replaceOperatorAnyToIndexedOperator");
const replaceAmpArrayToAny_1 = require("./replaceAmpArrayToAny");
const findJoinsMeta_1 = require("../../processor/findJoinsMeta");
const buildJoinVariables_1 = require("../../processor/buildJoinVariables");
const CoalesceFalseExpression_1 = require("../../../ast/expression/CoalesceFalseExpression");
const fixArraySearchForDifferentArrayTypes_1 = require("./fixArraySearchForDifferentArrayTypes");
class ConditionBuilder {
constructor(context) {
this.context = context;
}
hasMutableColumns() {
return this.getMutableColumns().length > 0;
}
noReferenceChanges() {
const importantColumnsRefs = this.triggerTableColumnsToRefs(this.context.referenceMeta.columns);
for (const filter of this.context.referenceMeta.filters) {
const filterColumnsRefs = filter.getColumnReferences();
importantColumnsRefs.push(...filterColumnsRefs);
}
return this.buildNoChanges(importantColumnsRefs);
}
noChanges() {
const triggerTableColumnsRefs = this.triggerTableColumnsToRefs(this.context.triggerTableColumns);
return this.buildNoChanges(triggerTableColumnsRefs);
}
buildNoReference(row) {
const condition = buildHasReferenceCondition_1.buildNoReferenceCondition(this.context);
const output = this.replaceTriggerTableRefsTo(condition, row);
return output;
}
hasReferenceWithoutJoins(row) {
const needUpdate = this.buildHasReferenceWithoutJoins();
const output = this.replaceTriggerTableRefsTo(needUpdate, row);
return output;
}
filtersWithJoins(row) {
let conditions = this.context.referenceMeta.filters.slice();
const aggFilters = this.matchedAllAggFilters();
if (aggFilters) {
conditions.push(aggFilters);
}
conditions = conditions.filter(condition => this.hasJoinsInside(condition));
conditions = conditions.map(condition => this.replaceTriggerTableRefsTo(condition, row));
const output = conditions.length === 1 ? conditions[0] : ast_1.Expression.and(conditions);
if (!output.isEmpty()) {
return output;
}
}
needUpdateConditionOnUpdate(row) {
const needUpdate = this.buildNeedUpdateConditionOnUpdate();
const output = this.replaceTriggerTableRefsTo(needUpdate, row);
return output;
}
simpleWhere(row) {
const simpleWhere = this.buildSimpleWhere();
const output = this.replaceTriggerTableRefsTo(simpleWhere, row);
return output;
}
simpleWhereOnUpdate(row) {
const simpleWhere = this.buildSimpleWhere();
const output = this.replaceTriggerTableRefsTo(simpleWhere, row);
return output;
}
exitFromDeltaUpdateIf() {
const conditions = this.context.referenceMeta.filters.map(filter => new ast_1.NotExpression(this.replaceTriggerTableRefsTo(filter, "new")));
const hasNoReference = this.buildNoReference("new");
if (hasNoReference && !hasNoReference.isEmpty()) {
conditions.unshift(hasNoReference);
}
if (!conditions.length) {
return;
}
return ast_1.Expression.or(conditions);
}
buildNoChanges(columns) {
const mutableColumns = columns.filter(column => column.name !== "id");
const conditions = [];
for (const columnRef of mutableColumns) {
const tableStructure = this.context.database.getTable(columnRef.tableReference.table);
const column = (tableStructure &&
tableStructure.getColumn(columnRef.name));
const columnRefExpression = new ast_1.Expression([columnRef]);
let oldColumn = this.replaceTriggerTableRefsTo(columnRefExpression, "old");
let newColumn = this.replaceTriggerTableRefsTo(columnRefExpression, "new");
oldColumn = oldColumn.replaceTable(this.context.triggerTable, new TableReference_1.TableReference(this.context.triggerTable, "old"));
newColumn = newColumn.replaceTable(this.context.triggerTable, new TableReference_1.TableReference(this.context.triggerTable, "new"));
if (column && column.type.isArray()) {
conditions.push(`cm_equal_arrays(${newColumn}, ${oldColumn})`);
}
else {
conditions.push(`${newColumn} is not distinct from ${oldColumn}`);
}
}
const noChangesCondition = ast_1.Expression.and(conditions);
return noChangesCondition;
}
getMutableColumns() {
const mutableColumns = this.context.triggerTableColumns
.filter(col => col !== "id");
return mutableColumns;
}
buildSimpleWhere() {
const conditions = this.context.referenceMeta.expressions.map(expression => {
// TODO: recursive
const orExpressions = expression.extrude().splitBy("or").map(subExpression => {
subExpression = subExpression.extrude();
subExpression = replaceOperatorAnyToIndexedOperator_1.replaceOperatorAnyToIndexedOperator(this.context.cache.for, subExpression);
subExpression = replaceAmpArrayToAny_1.replaceAmpArrayToAny(this.context.cache.for, subExpression);
subExpression = fixArraySearchForDifferentArrayTypes_1.fixArraySearchForDifferentArrayTypesInCondition(this.context.cache.for, subExpression);
return subExpression;
});
return ast_1.Expression.or(orExpressions);
});
conditions.push(...this.context.referenceMeta.unknownExpressions);
conditions.push(...this.context.referenceMeta.cacheTableFilters);
const where = ast_1.Expression.and(conditions);
if (!where.isEmpty()) {
return where;
}
}
buildNeedUpdateConditionOnUpdate() {
const conditions = [
buildHasReferenceCondition_1.buildHasReferenceCondition(this.context),
ast_1.Expression.and(this.context.referenceMeta.filters),
this.matchedAllAggFilters()
].filter(condition => condition != null &&
!condition.isEmpty());
const needUpdate = ast_1.Expression.and(conditions);
if (!needUpdate.isEmpty()) {
return needUpdate;
}
}
buildHasReferenceWithoutJoins() {
let conditions = [];
const refCondition = buildHasReferenceCondition_1.buildHasReferenceCondition(this.context);
if (refCondition) {
conditions.push(refCondition);
}
for (const where of this.context.referenceMeta.filters) {
if (!this.hasJoinsInside(where)) {
conditions.push(where);
}
}
const aggFilters = this.matchedAllAggFilters();
if (aggFilters && !this.hasJoinsInside(aggFilters)) {
conditions.push(aggFilters);
}
conditions = conditions.filter(condition => condition != null &&
!condition.isEmpty());
const needUpdate = ast_1.Expression.and(conditions);
if (!needUpdate.isEmpty()) {
return needUpdate;
}
}
matchedAllAggFilters() {
const allAggCalls = lodash_1.flatMap(this.context.cache.select.columns, column => column.getAggregations(this.context.database.aggregators));
const everyAggCallHaveFilter = allAggCalls.every(aggCall => aggCall.where != null);
if (!everyAggCallHaveFilter) {
return;
}
const filterConditions = allAggCalls.map(aggCall => {
const expression = aggCall.where;
return new CoalesceFalseExpression_1.CoalesceFalseExpression(expression);
});
return ast_1.Expression.or(filterConditions);
}
replaceTriggerTableRefsTo(expression, row) {
if (!expression) {
return;
}
let outputExpression = expression;
const refsToTriggerTable = this.context.getTableReferencesToTriggerTable();
const joinsMeta = findJoinsMeta_1.findJoinsMeta(this.context.cache.select);
if (joinsMeta.length) {
const joins = buildJoinVariables_1.buildJoinVariables(this.context.database, joinsMeta, row);
joins.forEach((join) => {
outputExpression = outputExpression.replaceColumn(join.table.column, ast_1.UnknownExpressionElement.fromSql(join.variable.name));
});
}
refsToTriggerTable.forEach((triggerTableRef) => {
outputExpression = outputExpression.replaceTable(triggerTableRef, new TableReference_1.TableReference(this.context.triggerTable, row));
});
return outputExpression;
}
hasJoinsInside(condition) {
const joinsMeta = findJoinsMeta_1.findJoinsMeta(this.context.cache.select);
if (!joinsMeta.length) {
return false;
}
const columnsRefs = condition.getColumnReferences();
const hasJoins = columnsRefs.some(columnRef => !columnRef.tableReference.table.equal(this.context.triggerTable));
return hasJoins;
}
triggerTableColumnsToRefs(columnsNames) {
const triggerTableRef = new TableReference_1.TableReference(this.context.triggerTable);
const triggerTableColumnsRefs = columnsNames.map(columnName => new ast_1.ColumnReference(triggerTableRef, columnName));
return triggerTableColumnsRefs;
}
}
exports.ConditionBuilder = ConditionBuilder;
//# sourceMappingURL=ConditionBuilder.js.map