UNPKG

ddl-manager

Version:

store postgres procedures and triggers in files

208 lines 9.94 kB
"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