Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { getUpdateTypesScriptDtos } = require('./columnHelpers/alterTypeHelper');
const { getModifyNonNullColumnsScriptDtos } = require('./columnHelpers/nonNullConstraintHelper');
const { getModifiedCommentOnColumnScriptDtos } = require('./columnHelpers/commentsHelper');
const { getRenameColumnScriptDtos } = require('./columnHelpers/renameColumnHelper');
const { getModifyColumnCheckConstraintScriptDtos } = require('./columnHelpers/checkConstraintHelper');
const { AlterScriptDto } = require('../types/AlterScriptDto');
const { AlterCollectionDto } = require('../types/AlterCollectionDto');
const { getModifyPkConstraintsScriptDtos } = require('./entityHelpers/primaryKeyHelper');
Expand Down Expand Up @@ -303,12 +304,14 @@ const getModifyColumnScriptDtos =
const modifyDefaultColumnValueScriptDtos = getModifiedDefaultColumnValueScriptDtos({
collection,
});
const modifyColumnCheckConstraintScriptDtos = getModifyColumnCheckConstraintScriptDtos(collection);

return [
...renameColumnScriptDtos,
...updateTypeScriptDtos,
...modifyNotNullScriptDtos,
...modifyDefaultColumnValueScriptDtos,
...modifyColumnCheckConstraintScriptDtos,
...modifyCommentScriptDtos,
].filter(Boolean);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
const _ = require('lodash');
const { AlterScriptDto } = require('../../types/AlterScriptDto');
const {
getFullTableName,
wrapInQuotes,
isObjectInDeltaModelActivated,
isParentContainerActivated,
} = require('../../../utils/general');
const assignTemplates = require('../../../utils/assignTemplates');
const templates = require('../../../ddlProvider/templates');

/**
* @typedef {{
* name: string,
* expression: string,
* noInherit?: boolean,
* }} ColumnCheckConstraint
*
* @typedef {{
* old?: ColumnCheckConstraint,
* new?: ColumnCheckConstraint,
* columnName: string,
* isActivated: boolean,
* }} ColumnCheckConstraintHistoryEntry
* */

/**
*
* @param {string} [constraintName]
* @param {string} columnName
* @param {string} tableName
* @returns {string}
*/
const getConstraintName = (constraintName, columnName, tableName) => {
return wrapInQuotes(constraintName || `chk_${tableName}.${columnName}`);
};

/**
* @param {string} tableName
* @param {string} constraintName
* @return string
* */
const dropConstraint = (tableName, constraintName) => {
const templateConfig = {
tableName,
constraintName,
};
return assignTemplates(templates.dropConstraint, templateConfig);
};

/**
* @param tableName {string}
* @param constraintName {string}
* @param expression {string}
* @param noInherit {boolean}
* @return string
* */
const addCheckConstraint = (tableName, constraintName, expression, noInherit = false) => {
const templateConfig = {
tableName,
constraintName,
expression,
noInherit: noInherit ? ' NO INHERIT' : '',
};
return assignTemplates(templates.addCheckConstraint, templateConfig);
};

/**
* @param {Object} collection
* @return {ColumnCheckConstraintHistoryEntry[]}
* */
const mapColumnCheckConstraintsToChangeHistory = collection => {
const history = [];

_.toPairs(collection.properties).forEach(([columnName, jsonSchema]) => {
const oldColumnName = jsonSchema.compMod?.oldField?.name || columnName;
const newCheckConstraint = !_.isEmpty(jsonSchema.checkConstraint)
? _.omit(_.first(jsonSchema.checkConstraint), 'id')
: undefined;

const oldCheckConstraintValue = collection.role.properties?.[oldColumnName]?.checkConstraint;
const oldCheckConstraint = !_.isEmpty(oldCheckConstraintValue)
? _.omit(_.first(oldCheckConstraintValue), 'id')
: undefined;

if (!newCheckConstraint && !oldCheckConstraint) {
return;
}

history.push({
columnName,
old: oldCheckConstraint,
new: newCheckConstraint,
isActivated: jsonSchema.isActivated,
});
});

return history;
};

/**
* @param {ColumnCheckConstraintHistoryEntry[]} constraintHistory
* @param {string} fullTableName
* @return {AlterScriptDto[]}
* */
const getDropColumnCheckConstraintScriptDtos = (constraintHistory, fullTableName) => {
return constraintHistory
.filter(historyEntry => historyEntry.old && !historyEntry.new)
.map(historyEntry => {
const wrappedConstraintName = getConstraintName(
historyEntry.old.name,
historyEntry.columnName,
fullTableName,
);
const script = dropConstraint(fullTableName, wrappedConstraintName);
return AlterScriptDto.getInstance([script], historyEntry.isActivated, true);
});
};

/**
* @param {ColumnCheckConstraintHistoryEntry[]} constraintHistory
* @param {string} fullTableName
* @return {AlterScriptDto[]}
* */
const getAddColumnCheckConstraintScriptDtos = (constraintHistory, fullTableName) => {
return constraintHistory
.filter(historyEntry => historyEntry.new && !historyEntry.old)
.map(historyEntry => {
const { name, expression, noInherit } = historyEntry.new;
const constraintName = getConstraintName(name, historyEntry.columnName, fullTableName);

const script = addCheckConstraint(fullTableName, constraintName, expression, noInherit);
return AlterScriptDto.getInstance([script], historyEntry.isActivated);
});
};

/**
* @param {ColumnCheckConstraintHistoryEntry[]} constraintHistory
* @param {string} fullTableName
* @return {AlterScriptDto[]}
* */
const getUpdateColumnCheckConstraintScriptDtos = (constraintHistory, fullTableName) => {
return constraintHistory
.filter(historyEntry => {
if (historyEntry.old && historyEntry.new) {
const oldExpression = historyEntry.old.expression;
const newExpression = historyEntry.new.expression;
const oldNoInherit = historyEntry.old.noInherit;
const newNoInherit = historyEntry.new.noInherit;
const oldName = historyEntry.old.name;
const newName = historyEntry.new.name;
return oldExpression !== newExpression || oldNoInherit !== newNoInherit || oldName !== newName;
}
return false;
})
.map(historyEntry => {
const { name: oldConstrainName } = historyEntry.old;
const wrappedOldConstraintName = getConstraintName(
oldConstrainName,
historyEntry.columnName,
fullTableName,
);
const dropConstraintScript = dropConstraint(fullTableName, wrappedOldConstraintName);

const {
name: newConstrainName,
expression: newConstraintExpression,
noInherit: newNoInherit,
} = historyEntry.new;
const addConstraintScript = addCheckConstraint(
fullTableName,
getConstraintName(newConstrainName, historyEntry.columnName, fullTableName),
newConstraintExpression,
newNoInherit,
);

return [
AlterScriptDto.getInstance([dropConstraintScript], historyEntry.isActivated, true),
AlterScriptDto.getInstance([addConstraintScript], historyEntry.isActivated, false),
];
})
.flat();
};

/**
* @param {Object} collection
* @return {AlterScriptDto[]}
* */
const getModifyColumnCheckConstraintScriptDtos = collection => {
const fullTableName = getFullTableName(collection);
const constraintHistory = mapColumnCheckConstraintsToChangeHistory(collection);

const isContainerActivated = isParentContainerActivated(collection);
const isCollectionActivated = isObjectInDeltaModelActivated(collection);

const addCheckConstraintScripts = getAddColumnCheckConstraintScriptDtos(constraintHistory, fullTableName);
const dropCheckConstraintScripts = getDropColumnCheckConstraintScriptDtos(constraintHistory, fullTableName);
const updateCheckConstraintScripts = getUpdateColumnCheckConstraintScriptDtos(constraintHistory, fullTableName);

return [...addCheckConstraintScripts, ...dropCheckConstraintScripts, ...updateCheckConstraintScripts].map(dto => ({
...dto,
isActivated: isContainerActivated && isCollectionActivated && dto.isActivated,
}));
};

module.exports = {
getModifyColumnCheckConstraintScriptDtos,
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const templates = require('../../../ddlProvider/templates');
* id: string,
* chkConstrName: string,
* constrExpression: string,
* noInherit?: boolean,
* }} CheckConstraint
*
* @typedef {{
Expand Down Expand Up @@ -79,13 +80,15 @@ const getDropCheckConstraintScriptDtos = (constraintHistory, fullTableName) => {
* @param tableName {string}
* @param constraintName {string}
* @param expression {expression}
* @param noInherit {boolean}
* @return string
* */
const addCheckConstraint = (tableName, constraintName, expression) => {
const addCheckConstraint = (tableName, constraintName, expression, noInherit = false) => {
const templateConfig = {
tableName,
constraintName,
expression,
noInherit: noInherit ? ' NO INHERIT' : '',
};
return assignTemplates(templates.addCheckConstraint, templateConfig);
};
Expand All @@ -99,8 +102,8 @@ const getAddCheckConstraintScriptDtos = (constraintHistory, fullTableName) => {
return constraintHistory
.filter(historyEntry => historyEntry.new && !historyEntry.old)
.map(historyEntry => {
const { chkConstrName, constrExpression } = historyEntry.new;
return addCheckConstraint(fullTableName, wrapInQuotes(chkConstrName), constrExpression);
const { chkConstrName, constrExpression, noInherit } = historyEntry.new;
return addCheckConstraint(fullTableName, wrapInQuotes(chkConstrName), constrExpression, noInherit);
})
.map(script => AlterScriptDto.getInstance([script], true, false));
};
Expand All @@ -116,19 +119,26 @@ const getUpdateCheckConstraintScriptDtos = (constraintHistory, fullTableName) =>
if (historyEntry.old && historyEntry.new) {
const oldExpression = historyEntry.old.constrExpression;
const newExpression = historyEntry.new.constrExpression;
return oldExpression !== newExpression;
const oldNoInherit = historyEntry.old.noInherit;
const newNoInherit = historyEntry.new.noInherit;
return oldExpression !== newExpression || oldNoInherit !== newNoInherit;
}
return false;
})
.map(historyEntry => {
const { chkConstrName: oldConstrainName } = historyEntry.old;
const dropConstraintScript = dropConstraint(fullTableName, wrapInQuotes(oldConstrainName));

const { chkConstrName: newConstrainName, constrExpression: newConstraintExpression } = historyEntry.new;
const {
chkConstrName: newConstrainName,
constrExpression: newConstraintExpression,
noInherit: newNoInherit,
} = historyEntry.new;
const addConstraintScript = addCheckConstraint(
fullTableName,
wrapInQuotes(newConstrainName),
newConstraintExpression,
newNoInherit,
);

return [
Expand Down
16 changes: 13 additions & 3 deletions forward_engineering/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,21 @@
"adapters": [
{
"dependency": {
"key": "chkConstr",
"valueType": "array"
"type": "or",
"values": [
{
"key": "chkConstr",
"valueType": "array"
},
{
"key": "checkConstraint",
"valueType": "array"
}
]
},
"defaultValue": {
"chkConstr": []
"chkConstr": [],
"checkConstraint": []
}
}
]
Expand Down
26 changes: 26 additions & 0 deletions forward_engineering/ddlProvider/ddlHelpers/constraintsHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,30 @@ const createKeyConstraint = (templates, isParentActivated) => keyData => {
};
};

/**
* Cleans the check constraint expression by removing surrounding parentheses and trimming whitespace.
* @param expression {string}
* @returns string
*/
const cleanCheckConstraint = (expression = '') => _.trim(expression).replace(/^\(([\s\S]*)\)$/, '$1');

/**
* Creates an inline check constraint statement.
* @param checkConstraint {{
* name?: string,
* expression?: string,
* noInherit?: boolean,
* }}
* @returns string
*/
const createInlineCheckConstraint = checkConstraint => {
if (!checkConstraint?.expression) {
return '';
}

return ` CHECK (${cleanCheckConstraint(checkConstraint.expression)})${checkConstraint?.noInherit ? ' NO INHERIT' : ''}`;
};

/**
* @param tableName {string}
* @param isParentActivated {boolean}
Expand Down Expand Up @@ -196,4 +220,6 @@ module.exports = {
dropKeyConstraint,
getConstraintsWarnings,
additionalPropertiesForForeignKey,
cleanCheckConstraint,
createInlineCheckConstraint,
};
Loading