From c23978bca03c798b1590756392c430fc24d54242 Mon Sep 17 00:00:00 2001 From: Alik Rakhmonov Date: Tue, 2 Dec 2025 12:54:45 +0100 Subject: [PATCH] HCK-4730: missing DROP PK/UK statement in alter script --- .../alterScript/alterScriptFromDeltaHelper.js | 7 +- .../areConstraintOptionsEqual.js | 18 -- .../extractKeyConstraintOptions.js | 18 ++ .../entityHelpers/primaryKeyHelper.js | 298 ++++++++++++++---- .../entityHelpers/uniqueKeyHelper.js | 207 ++++++------ .../ddlHelpers/constraintHelper.js | 13 + forward_engineering/ddlProvider/templates.js | 5 + forward_engineering/utils/general.js | 14 + 8 files changed, 413 insertions(+), 167 deletions(-) delete mode 100644 forward_engineering/alterScript/alterScriptHelpers/entityHelpers/areConstraintOptionsEqual.js create mode 100644 forward_engineering/alterScript/alterScriptHelpers/entityHelpers/extractKeyConstraintOptions.js diff --git a/forward_engineering/alterScript/alterScriptFromDeltaHelper.js b/forward_engineering/alterScript/alterScriptFromDeltaHelper.js index bd839ad..3862fe1 100644 --- a/forward_engineering/alterScript/alterScriptFromDeltaHelper.js +++ b/forward_engineering/alterScript/alterScriptFromDeltaHelper.js @@ -183,13 +183,18 @@ const getAlterCollectionsScriptDtos = ({ .flatMap(getDeleteColumnScriptDtos(app, scriptFormat)); const modifyColumnScriptDtos = modifyScriptsData.flatMap(getModifyColumnScriptDtos(app, dbVersion, scriptFormat)); + const [collectionDropDtos, modifyCollectionDtos] = _.partition(modifyCollectionScriptDtos, collectionDto => + collectionDto.scripts?.some(s => s.isDropScript), + ); + return [ ...createCollectionsScriptDtos, ...deleteCollectionScriptDtos, + ...collectionDropDtos, ...addColumnScriptDtos, ...deleteColumnScriptDtos, ...modifyColumnScriptDtos, - ...modifyCollectionScriptDtos, + ...modifyCollectionDtos, ].filter(Boolean); }; diff --git a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/areConstraintOptionsEqual.js b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/areConstraintOptionsEqual.js deleted file mode 100644 index ec140ae..0000000 --- a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/areConstraintOptionsEqual.js +++ /dev/null @@ -1,18 +0,0 @@ -const _ = require('lodash'); -const { AlterCollectionColumnKeyOptionDto } = require('../../types/AlterCollectionDto'); - -/** - * @param {Array>} oldConstraintOptions - * @param {Array>} constraintOptions - * @returns {boolean} - */ -const areConstraintOptionsEqual = (oldConstraintOptions = [], constraintOptions = []) => { - return ( - oldConstraintOptions.length === constraintOptions.length && - _(oldConstraintOptions).differenceWith(constraintOptions, _.isEqual).isEmpty() - ); -}; - -module.exports = { - areConstraintOptionsEqual, -}; diff --git a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/extractKeyConstraintOptions.js b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/extractKeyConstraintOptions.js new file mode 100644 index 0000000..82ae2cb --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/extractKeyConstraintOptions.js @@ -0,0 +1,18 @@ +/** + * @param {AlterCollectionColumnKeyOptionDto} optionHolder + * @return {Partial} + * */ +const extractKeyConstraintOptions = (optionHolder = {}) => { + return { + constraintName: optionHolder.constraintName, + deferClause: optionHolder.deferClause, + rely: optionHolder.rely, + validate: optionHolder.validate, + indexClause: optionHolder.indexClause, + exceptionClause: optionHolder.exceptionClause, + }; +}; + +module.exports = { + extractKeyConstraintOptions, +}; diff --git a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/primaryKeyHelper.js b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/primaryKeyHelper.js index d4ba88d..b270f47 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/primaryKeyHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/primaryKeyHelper.js @@ -12,29 +12,17 @@ const { getFullCollectionName, getSchemaOfAlterCollection, getEntityName, - wrapInQuotes, prepareNameForScriptFormat, + isParentContainerActivated, + isObjectInDeltaModelActivated, } = require('../../../utils/general'); -const { areConstraintOptionsEqual } = require('./areConstraintOptionsEqual'); const { sortModifyKeyConstraints } = require('./sortModifyKeyConstraints'); +const templates = require('../../../ddlProvider/templates'); +const { assignTemplates } = require('../../../utils/assignTemplates'); +const { extractKeyConstraintOptions } = require('./extractKeyConstraintOptions'); const amountOfColumnsInRegularPk = 1; -/** - * @param {AlterCollectionColumnKeyOptionDto} optionHolder - * @return {Partial} - * */ -const extractOptionsForComparisonWithRegularPkOptions = optionHolder => { - return { - constraintName: optionHolder.constraintName, - deferClause: optionHolder.deferClause, - rely: optionHolder.rely, - validate: optionHolder.validate, - indexClause: optionHolder.indexClause, - exceptionClause: optionHolder.exceptionClause, - }; -}; - /** * @param {AlterCollectionRoleCompModPKDto} primaryKey * @param {AlterCollectionDto} entity @@ -57,6 +45,97 @@ const getCreateCompositePKDDLProviderConfig = (primaryKey, entity) => { }; }; +const isCompositeEqualsToRegular = (compositeKeys, regularOptions) => { + return compositeKeys.some(compositePk => { + if (compositePk.compositePrimaryKey?.length !== amountOfColumnsInRegularPk) { + return false; + } + const compositePkAsRegularPkOptions = extractKeyConstraintOptions(compositePk); + + return _.isEqual(compositePkAsRegularPkOptions, regularOptions); + }); +}; + +const checkIsPrimaryKeyRegular = columnJsonSchema => { + return Boolean(columnJsonSchema?.primaryKey) && !columnJsonSchema?.compositePrimaryKey; +}; + +const wasCompositePkChangedInTransitionFromCompositeToRegular = collection => { + /** + * @type {AlterCollectionRoleCompModPrimaryKey} + * */ + const pkDto = collection?.role?.compMod?.primaryKey || {}; + /** + * @type {AlterCollectionRoleCompModPKDto[]} + * */ + const oldPrimaryKeys = pkDto.old || []; + const idsOfColumns = oldPrimaryKeys.flatMap(pk => pk.compositePrimaryKey?.map(dto => dto.keyId) || []); + + if (idsOfColumns.length !== amountOfColumnsInRegularPk) { + // We return false, because it wouldn't count as transition between regular PK and composite PK + // if composite PK did not constraint exactly 1 column + return PrimaryKeyTransitionDto.noTransition(); + } + + const idOfPkColumn = idsOfColumns[0]; + const newColumnJsonSchema = Object.values(collection.properties).find( + columnJsonSchema => columnJsonSchema.GUID === idOfPkColumn, + ); + + if (!newColumnJsonSchema) { + return PrimaryKeyTransitionDto.noTransition(); + } + + const isNewColumnARegularPrimaryKey = checkIsPrimaryKeyRegular(newColumnJsonSchema); + + if (!isNewColumnARegularPrimaryKey) { + return PrimaryKeyTransitionDto.noTransition(); + } + + const constraintOptions = extractKeyConstraintOptions(newColumnJsonSchema.primaryKeyOptions); + const areOptionsEqual = isCompositeEqualsToRegular(oldPrimaryKeys, constraintOptions); + + return PrimaryKeyTransitionDto.transition(!areOptionsEqual); +}; + +const wasCompositePkChangedInTransitionFromRegularToComposite = collection => { + /** + * @type {AlterCollectionRoleCompModPrimaryKey} + * */ + const pkDto = collection?.role?.compMod?.primaryKey || {}; + /** + * @type {AlterCollectionRoleCompModPKDto[]} + * */ + const newPrimaryKeys = pkDto.new || []; + const idsOfColumns = newPrimaryKeys.flatMap(pk => pk.compositePrimaryKey?.map(dto => dto.keyId) || []); + + if (idsOfColumns.length !== amountOfColumnsInRegularPk) { + // We return false, because it wouldn't count as transition between regular PK and composite PK + // if composite PK does not constraint exactly 1 column + return PrimaryKeyTransitionDto.noTransition(); + } + + const idOfPkColumn = idsOfColumns[0]; + const oldColumnJsonSchema = Object.values(collection.role.properties).find( + columnJsonSchema => columnJsonSchema.GUID === idOfPkColumn, + ); + + if (!oldColumnJsonSchema) { + return PrimaryKeyTransitionDto.noTransition(); + } + + const isOldColumnARegularPrimaryKey = checkIsPrimaryKeyRegular(oldColumnJsonSchema); + + if (!isOldColumnARegularPrimaryKey) { + return PrimaryKeyTransitionDto.noTransition(); + } + + const constraintOptions = extractKeyConstraintOptions(oldColumnJsonSchema.primaryKeyOptions); + const areOptionsEqual = isCompositeEqualsToRegular(newPrimaryKeys, constraintOptions); + + return PrimaryKeyTransitionDto.transition(!areOptionsEqual); +}; + /** * @param {AlterCollectionDto} collection * @return {Array} @@ -75,6 +154,11 @@ const getAddCompositePkScriptDtos = ({ scriptFormat, collection }) => { return []; } + const transitionToCompositeDto = wasCompositePkChangedInTransitionFromRegularToComposite(collection); + if (transitionToCompositeDto.didTransitionHappen && !transitionToCompositeDto.wasPkChangedInTransition) { + return []; + } + if (newPrimaryKeys.length === oldPrimaryKeys.length) { const areKeyArraysEqual = _(oldPrimaryKeys).differenceWith(newPrimaryKeys, _.isEqual).isEmpty(); if (areKeyArraysEqual) { @@ -95,6 +179,38 @@ const getAddCompositePkScriptDtos = ({ scriptFormat, collection }) => { .filter(scriptDto => Boolean(scriptDto.script)); }; +const getDropCompositePkScriptDtos = ({ scriptFormat, collection }) => { + const pkDto = collection?.role?.compMod?.primaryKey || {}; + const newPrimaryKeys = pkDto.new || []; + const oldPrimaryKeys = pkDto.old || []; + if (newPrimaryKeys.length === 0 && oldPrimaryKeys.length === 0) { + return []; + } + const transitionToCompositeDto = wasCompositePkChangedInTransitionFromCompositeToRegular(collection); + if (transitionToCompositeDto.didTransitionHappen && !transitionToCompositeDto.wasPkChangedInTransition) { + return []; + } + if (newPrimaryKeys.length === oldPrimaryKeys.length) { + const areKeyArraysEqual = _(oldPrimaryKeys).differenceWith(newPrimaryKeys, _.isEqual).isEmpty(); + if (areKeyArraysEqual) { + return []; + } + } + + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(scriptFormat)(collectionSchema); + + const isContainerActivated = isParentContainerActivated(collection); + const isCollectionActivated = isContainerActivated && isObjectInDeltaModelActivated(collection); + + return oldPrimaryKeys + .map(oldPk => { + const script = assignTemplates(templates.dropPrimaryKey, { tableName: fullTableName }); + return new KeyScriptModificationDto(script, fullTableName, true, isCollectionActivated); + }) + .filter(scriptDto => Boolean(scriptDto.script)); +}; + /** * @param {object} params * @property {string} [scriptFormat] @@ -102,9 +218,10 @@ const getAddCompositePkScriptDtos = ({ scriptFormat, collection }) => { * @return {Array} * */ const getModifyCompositePkScriptDtos = ({ scriptFormat, collection }) => { + const dropCompositePkScriptDtos = getDropCompositePkScriptDtos({ scriptFormat, collection }); const addCompositePkScriptDtos = getAddCompositePkScriptDtos({ scriptFormat, collection }); - return addCompositePkScriptDtos.filter(Boolean); + return [...dropCompositePkScriptDtos, ...addCompositePkScriptDtos].filter(Boolean); }; /** @@ -137,35 +254,29 @@ const getCreateRegularPKDDLProviderConfig = (columnName, columnJsonSchema) => { * @param {AlterCollectionDto} collection * @return {boolean} * */ -const wasFieldChangedToBeARegularPk = (columnJsonSchema, collection) => { +const isFieldChangedToRegularPk = (columnJsonSchema, collection) => { const oldName = columnJsonSchema.compMod.oldField.name; - const oldColumnJsonSchema = collection.role.properties[oldName]; + const oldJsonSchema = collection.role.properties[oldName]; - const isRegularPrimaryKey = columnJsonSchema.primaryKey && !columnJsonSchema.compositePrimaryKey; - const wasTheFieldAnyPrimaryKey = Boolean(oldColumnJsonSchema?.primaryKey); + const isRegularPrimaryKey = checkIsPrimaryKeyRegular(columnJsonSchema); + const wasTheFieldRegularPrimaryKey = Boolean(oldJsonSchema?.primaryKey); - return isRegularPrimaryKey && !wasTheFieldAnyPrimaryKey; + return isRegularPrimaryKey && !wasTheFieldRegularPrimaryKey; }; /** * @param {AlterCollectionColumnDto} columnJsonSchema - * @return {Array>} + * @param {AlterCollectionDto} collection + * @return {boolean} * */ -const getCustomPropertiesOfRegularPkForComparisonWithRegularPkOptions = columnJsonSchema => { - /** - * @type {Array} - * */ - const constraintOptions = columnJsonSchema.primaryKeyOptions ?? {}; - return extractOptionsForComparisonWithRegularPkOptions(constraintOptions); -}; +const isFieldNoLongerARegularPk = (columnJsonSchema, collection) => { + const oldName = columnJsonSchema.compMod.oldField.name; -/** - * @param {AlterCollectionRoleCompModPKDto} compositePk - * @return {Array>} - * */ -const getCustomPropertiesOfCompositePkForComparisonWithRegularPkOptions = compositePk => { - const optionsForComparison = extractOptionsForComparisonWithRegularPkOptions(compositePk); - return [optionsForComparison].filter(o => Object.values(o).some(Boolean)); + const oldJsonSchema = collection.role.properties[oldName]; + const wasTheFieldARegularPrimaryKey = checkIsPrimaryKeyRegular(oldJsonSchema); + + const isNotAnyPrimaryKey = !columnJsonSchema.primaryKey && !columnJsonSchema.compositePrimaryKey; + return wasTheFieldARegularPrimaryKey && isNotAnyPrimaryKey; }; /** @@ -177,7 +288,7 @@ const wasRegularPkChangedInTransitionFromCompositeToRegular = (columnJsonSchema, const oldName = columnJsonSchema.compMod.oldField.name; const oldColumnJsonSchema = collection.role.properties[oldName]; - const isRegularPrimaryKey = columnJsonSchema.primaryKey && !columnJsonSchema.compositePrimaryKey; + const isRegularPrimaryKey = checkIsPrimaryKeyRegular(columnJsonSchema); const wasTheFieldAnyPrimaryKey = Boolean(oldColumnJsonSchema?.primaryKey); if (!(isRegularPrimaryKey && wasTheFieldAnyPrimaryKey)) { @@ -206,16 +317,56 @@ const wasRegularPkChangedInTransitionFromCompositeToRegular = (columnJsonSchema, // return compare custom properties and amount of columns. // If there was a transition and amount of composite PK columns is not equal // to amount of regular pk columns, we must recreate PK - const constraintOptions = getCustomPropertiesOfRegularPkForComparisonWithRegularPkOptions(columnJsonSchema); - const areOptionsEqual = oldPrimaryKeys.some(oldCompositePk => { - if (oldCompositePk.compositePrimaryKey.length !== amountOfColumnsInRegularPk) { - return false; - } - const oldCompositePkAsRegularPkOptions = - getCustomPropertiesOfCompositePkForComparisonWithRegularPkOptions(oldCompositePk); + const constraintOptions = extractKeyConstraintOptions(columnJsonSchema.primaryKeyOptions); + const areOptionsEqual = isCompositeEqualsToRegular(oldPrimaryKeys, constraintOptions); + + return PrimaryKeyTransitionDto.transition(!areOptionsEqual); + } + + return PrimaryKeyTransitionDto.noTransition(); +}; + +/** + * @param {AlterCollectionColumnDto} columnJsonSchema + * @param {AlterCollectionDto} collection + * @return {PrimaryKeyTransitionDto} + * */ +const wasRegularPkChangedInTransitionFromRegularToComposite = (columnJsonSchema, collection) => { + const oldName = columnJsonSchema.compMod.oldField.name; + const oldColumnJsonSchema = collection.role.properties[oldName]; + + const wasRegularPrimaryKey = checkIsPrimaryKeyRegular(oldColumnJsonSchema); + const isTheFieldAnyPrimaryKey = Boolean(columnJsonSchema?.primaryKey); + + if (!(wasRegularPrimaryKey && isTheFieldAnyPrimaryKey)) { + return PrimaryKeyTransitionDto.noTransition(); + } + + /** + * @type {AlterCollectionRoleCompModPrimaryKey} + * */ + const pkDto = collection?.role?.compMod?.primaryKey || {}; + const newPrimaryKeys = pkDto.new || []; + /** + * @type {AlterCollectionRoleCompModPKDto[]} + * */ + const oldPrimaryKeys = pkDto.old || []; + const wasTheFieldACompositePrimaryKey = oldPrimaryKeys.some(compPk => + compPk.compositePrimaryKey?.some(pk => pk.keyId === oldColumnJsonSchema.GUID), + ); + const isTheFieldACompositePrimaryKey = newPrimaryKeys.some(compPk => + compPk.compositePrimaryKey?.some(pk => pk.keyId === columnJsonSchema.GUID), + ); + + const wasCompositePkAdded = isTheFieldACompositePrimaryKey && !wasTheFieldACompositePrimaryKey; + + if (wasRegularPrimaryKey && wasCompositePkAdded) { + // return compare custom properties and amount of columns. + // If there was a transition and amount of composite PK columns is not equal + // to amount of regular pk columns, we must recreate PK + const constraintOptions = extractKeyConstraintOptions(oldColumnJsonSchema.primaryKeyOptions); + const areOptionsEqual = isCompositeEqualsToRegular(newPrimaryKeys, constraintOptions); - return areConstraintOptionsEqual(oldCompositePkAsRegularPkOptions, constraintOptions); - }); return PrimaryKeyTransitionDto.transition(!areOptionsEqual); } @@ -231,17 +382,17 @@ const wasRegularPkModified = (columnJsonSchema, collection) => { const oldName = columnJsonSchema.compMod.oldField.name; const oldJsonSchema = collection.role.properties[oldName] || {}; - const isRegularPrimaryKey = columnJsonSchema.primaryKey && !columnJsonSchema.compositePrimaryKey; - const wasTheFieldARegularPrimaryKey = oldJsonSchema?.primaryKey && !oldJsonSchema?.compositePrimaryKey; + const isRegularPrimaryKey = checkIsPrimaryKeyRegular(columnJsonSchema); + const wasTheFieldARegularPrimaryKey = checkIsPrimaryKeyRegular(oldJsonSchema); - if (isRegularPrimaryKey && !wasTheFieldARegularPrimaryKey) { - return true; + if (!(isRegularPrimaryKey && wasTheFieldARegularPrimaryKey)) { + return false; } - const constraintOptions = getCustomPropertiesOfRegularPkForComparisonWithRegularPkOptions(columnJsonSchema); - const oldConstraintOptions = getCustomPropertiesOfRegularPkForComparisonWithRegularPkOptions(oldJsonSchema); + const constraintOptions = extractKeyConstraintOptions(columnJsonSchema.primaryKeyOptions); + const oldConstraintOptions = extractKeyConstraintOptions(oldJsonSchema.primaryKeyOptions); - return !areConstraintOptionsEqual(oldConstraintOptions, constraintOptions); + return !_.isEqual(oldConstraintOptions, constraintOptions); }; /** @@ -259,7 +410,7 @@ const getAddPkScriptDtos = ({ scriptFormat, collection }) => { return _.toPairs(collection.properties) .filter(([name, jsonSchema]) => { - if (wasFieldChangedToBeARegularPk(jsonSchema, collection)) { + if (isFieldChangedToRegularPk(jsonSchema, collection)) { return true; } const transitionToRegularDto = wasRegularPkChangedInTransitionFromCompositeToRegular( @@ -279,6 +430,38 @@ const getAddPkScriptDtos = ({ scriptFormat, collection }) => { .filter(scriptDto => Boolean(scriptDto.script)); }; +/** + * @param {AlterCollectionDto} collection + * @return {Array} + * */ +const getDropPkScriptDto = ({ scriptFormat, collection }) => { + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(scriptFormat)(collectionSchema); + + const isContainerActivated = isParentContainerActivated(collection); + const isCollectionActivated = isContainerActivated && isObjectInDeltaModelActivated(collection); + + return _.toPairs(collection.properties) + .filter(([name, jsonSchema]) => { + if (isFieldNoLongerARegularPk(jsonSchema, collection)) { + return true; + } + const transitionToRegularDto = wasRegularPkChangedInTransitionFromRegularToComposite( + jsonSchema, + collection, + ); + if (transitionToRegularDto.didTransitionHappen) { + return transitionToRegularDto.wasPkChangedInTransition; + } + return wasRegularPkModified(jsonSchema, collection); + }) + .map(([name, jsonSchema]) => { + const script = assignTemplates(templates.dropPrimaryKey, { tableName: fullTableName }); + return new KeyScriptModificationDto(script, fullTableName, true, isCollectionActivated); + }) + .filter(scriptDto => Boolean(scriptDto.script)); +}; + /** * @param {object} params * @property {string} [scriptFormat] @@ -286,9 +469,10 @@ const getAddPkScriptDtos = ({ scriptFormat, collection }) => { * @return {Array} * */ const getModifyPkScriptDtos = ({ scriptFormat, collection }) => { + const dropPkScriptDtos = getDropPkScriptDto({ scriptFormat, collection }); const addPkScriptDtos = getAddPkScriptDtos({ scriptFormat, collection }); - return addPkScriptDtos.filter(Boolean); + return [...dropPkScriptDtos, ...addPkScriptDtos].filter(Boolean); }; /** diff --git a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/uniqueKeyHelper.js b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/uniqueKeyHelper.js index dece595..d1c1def 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/uniqueKeyHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/uniqueKeyHelper.js @@ -14,46 +14,29 @@ const { getEntityName, wrapInQuotes, prepareNameForScriptFormat, + isParentContainerActivated, + isObjectInDeltaModelActivated, } = require('../../../utils/general'); -const { areConstraintOptionsEqual } = require('./areConstraintOptionsEqual'); const { sortModifyKeyConstraints } = require('./sortModifyKeyConstraints'); +const { assignTemplates } = require('../../../utils/assignTemplates'); +const templates = require('../../../ddlProvider/templates'); +const { extractKeyConstraintOptions } = require('./extractKeyConstraintOptions'); const amountOfColumnsInRegularUniqueKey = 1; -/** - * @param {AlterCollectionColumnKeyOptionDto} optionHolder - * @return {Partial} - * */ -const extractOptionsForComparisonWithRegularUniqueKeyOptions = optionHolder => { - return { - constraintName: optionHolder.constraintName, - deferClause: optionHolder.deferClause, - rely: optionHolder.rely, - validate: optionHolder.validate, - indexClause: optionHolder.indexClause, - exceptionClause: optionHolder.exceptionClause, - }; -}; +const isCompositeEqualsToRegular = (compositeKeys, regularOptions) => { + return compositeKeys.some(compositeUK => { + if (compositeUK.compositeUniqueKey.length !== amountOfColumnsInRegularUniqueKey) { + return false; + } + const oldCompositeUniqueKeyAsRegularUniqueKeyOptions = extractKeyConstraintOptions(compositeUK); -/** - * @param {AlterCollectionColumnDto} columnJsonSchema - * @return {Array>} - * */ -const getCustomPropertiesOfRegularUniqueKeyForComparisonWithRegularUniqueKeyOptions = columnJsonSchema => { - /** - * @type {Array} - * */ - const constraintOptions = columnJsonSchema.uniqueKeyOptions || {}; - return extractOptionsForComparisonWithRegularUniqueKeyOptions(constraintOptions); + return _.isEqual(oldCompositeUniqueKeyAsRegularUniqueKeyOptions, regularOptions); + }); }; -/** - * @param {AlterCollectionRoleCompModUniqueKeyDto} compositeUniqueKey - * @return {Array>} - * */ -const getCustomPropertiesOfCompositeUniqueKeyForComparisonWithRegularUniqueKeyOptions = compositeUniqueKey => { - const optionsForComparison = extractOptionsForComparisonWithRegularUniqueKeyOptions(compositeUniqueKey); - return [optionsForComparison].filter(o => Object.values(o).some(Boolean)); +const checkIsUniqueKeyRegular = columnJsonSchema => { + return Boolean(columnJsonSchema?.unique) && !columnJsonSchema?.compositeUniqueKey; }; /** @@ -82,21 +65,12 @@ const wasCompositeUniqueKeyChangedInTransitionFromCompositeToRegular = collectio if (!newColumnJsonSchema) { return UniqueKeyTransitionDto.noTransition(); } - const isNewColumnARegularUniqueKey = newColumnJsonSchema?.unique && !newColumnJsonSchema?.compositeUniqueKey; + const isNewColumnARegularUniqueKey = checkIsUniqueKeyRegular(newColumnJsonSchema); if (!isNewColumnARegularUniqueKey) { return UniqueKeyTransitionDto.noTransition(); } - const constraintOptions = - getCustomPropertiesOfRegularUniqueKeyForComparisonWithRegularUniqueKeyOptions(newColumnJsonSchema); - const areOptionsEqual = oldUniqueKeys.some(compositeUniqueKey => { - if (compositeUniqueKey.compositeUniqueKey.length !== amountOfColumnsInRegularUniqueKey) { - return false; - } - const oldCompositeUniqueKeyAsRegularUniqueKeyOptions = - getCustomPropertiesOfCompositeUniqueKeyForComparisonWithRegularUniqueKeyOptions(compositeUniqueKey); - - return areConstraintOptionsEqual(oldCompositeUniqueKeyAsRegularUniqueKeyOptions, constraintOptions); - }); + const constraintOptions = extractKeyConstraintOptions(newColumnJsonSchema.uniqueKeyOptions); + const areOptionsEqual = isCompositeEqualsToRegular(oldUniqueKeys, constraintOptions); return UniqueKeyTransitionDto.transition(!areOptionsEqual); }; @@ -127,21 +101,12 @@ const wasCompositeUniqueKeyChangedInTransitionFromRegularToComposite = collectio if (!oldColumnJsonSchema) { return UniqueKeyTransitionDto.noTransition(); } - const isOldColumnARegularUniqueKey = oldColumnJsonSchema?.unique && !oldColumnJsonSchema?.compositeUniqueKey; + const isOldColumnARegularUniqueKey = checkIsUniqueKeyRegular(oldColumnJsonSchema); if (!isOldColumnARegularUniqueKey) { return UniqueKeyTransitionDto.noTransition(); } - const constraintOptions = - getCustomPropertiesOfRegularUniqueKeyForComparisonWithRegularUniqueKeyOptions(oldColumnJsonSchema); - const areOptionsEqual = newUniqueKeys.some(compositeUniqueKey => { - if (compositeUniqueKey.compositeUniqueKey.length !== amountOfColumnsInRegularUniqueKey) { - return false; - } - const oldCompositeUniqueKeyAsRegularUniqueKeyOptions = - getCustomPropertiesOfCompositeUniqueKeyForComparisonWithRegularUniqueKeyOptions(compositeUniqueKey); - - return areConstraintOptionsEqual(oldCompositeUniqueKeyAsRegularUniqueKeyOptions, constraintOptions); - }); + const constraintOptions = extractKeyConstraintOptions(oldColumnJsonSchema.uniqueKeyOptions); + const areOptionsEqual = isCompositeEqualsToRegular(newUniqueKeys, constraintOptions); return UniqueKeyTransitionDto.transition(!areOptionsEqual); }; @@ -216,6 +181,41 @@ const getAddCompositeUniqueKeyScriptDtos = ({ scriptFormat, collection }) => { .filter(scriptDto => Boolean(scriptDto.script)); }; +const getDropCompositeUniqueKeyScriptDtos = ({ scriptFormat, collection }) => { + const uniqueDto = collection?.role?.compMod?.uniqueKey || {}; + const newUniqueKeys = uniqueDto.new || []; + const oldUniqueKeys = uniqueDto.old || []; + if (newUniqueKeys.length === 0 && oldUniqueKeys.length === 0) { + return []; + } + const transitionToCompositeDto = wasCompositeUniqueKeyChangedInTransitionFromCompositeToRegular(collection); + if (transitionToCompositeDto.didTransitionHappen && !transitionToCompositeDto.wasUniqueKeyChangedInTransition) { + return []; + } + if (newUniqueKeys.length === oldUniqueKeys.length) { + const areKeyArraysEqual = _(oldUniqueKeys).differenceWith(newUniqueKeys, _.isEqual).isEmpty(); + if (areKeyArraysEqual) { + return []; + } + } + + const prepareName = prepareNameForScriptFormat(scriptFormat); + const { dropKeyConstraint } = require('../../../ddlProvider/ddlHelpers/constraintHelper')({ prepareName }); + + const collectionSchema = getSchemaOfAlterCollection(collection); + const fullTableName = getFullCollectionName(scriptFormat)(collectionSchema); + + const isContainerActivated = isParentContainerActivated(collection); + const isCollectionActivated = isContainerActivated && isObjectInDeltaModelActivated(collection); + + return oldUniqueKeys + .map(oldUniqueKey => { + const script = dropKeyConstraint(fullTableName, oldUniqueKey.constraintName); + return new KeyScriptModificationDto(script, fullTableName, true, isCollectionActivated); + }) + .filter(scriptDto => Boolean(scriptDto.script)); +}; + /** * @param {object} params * @property {string} scriptFormat @@ -223,9 +223,10 @@ const getAddCompositeUniqueKeyScriptDtos = ({ scriptFormat, collection }) => { * @return {Array} * */ const getModifyCompositeUniqueKeyScriptDtos = ({ scriptFormat, collection }) => { + const dropCompositeUniqueKeyScriptDtos = getDropCompositeUniqueKeyScriptDtos({ scriptFormat, collection }); const addCompositeUniqueKeyScriptDtos = getAddCompositeUniqueKeyScriptDtos({ scriptFormat, collection }); - return addCompositeUniqueKeyScriptDtos.filter(Boolean); + return [...dropCompositeUniqueKeyScriptDtos, ...addCompositeUniqueKeyScriptDtos].filter(Boolean); }; /** @@ -263,7 +264,7 @@ const wasFieldChangedToBeARegularUniqueKey = (columnJsonSchema, collection) => { const oldName = columnJsonSchema.compMod.oldField.name; const oldColumnJsonSchema = collection.role.properties[oldName]; - const isRegularUniqueKey = columnJsonSchema.unique && !columnJsonSchema.compositeUniqueKey; + const isRegularUniqueKey = checkIsUniqueKeyRegular(columnJsonSchema); const wasTheFieldAnyUniqueKey = oldColumnJsonSchema?.unique || oldColumnJsonSchema.compositeUniqueKey; return isRegularUniqueKey && !wasTheFieldAnyUniqueKey; @@ -278,7 +279,7 @@ const wasRegularUniqueKeyChangedInTransitionFromCompositeToRegular = (columnJson const oldName = columnJsonSchema.compMod.oldField.name; const oldColumnJsonSchema = collection.role.properties[oldName]; - const isRegularUniqueKey = columnJsonSchema.unique && !columnJsonSchema.compositeUniqueKey; + const isRegularUniqueKey = checkIsUniqueKeyRegular(columnJsonSchema); const wasTheFieldAnyUniqueKey = oldColumnJsonSchema?.unique || oldColumnJsonSchema.compositeUniqueKey; if (!(isRegularUniqueKey && wasTheFieldAnyUniqueKey)) { @@ -307,17 +308,8 @@ const wasRegularUniqueKeyChangedInTransitionFromCompositeToRegular = (columnJson // return compare custom properties and amount of columns. // If there was a transition and amount of composite UniqueKey columns is not equal // to amount of regular unique columns, we must recreate UniqueKey - const constraintOptions = - getCustomPropertiesOfRegularUniqueKeyForComparisonWithRegularUniqueKeyOptions(columnJsonSchema); - const areOptionsEqual = oldUniqueKeys.some(oldCompositeUniqueKey => { - if (oldCompositeUniqueKey.compositeUniqueKey.length !== amountOfColumnsInRegularUniqueKey) { - return false; - } - const oldCompositeUniqueKeyAsRegularUniqueKeyOptions = - getCustomPropertiesOfCompositeUniqueKeyForComparisonWithRegularUniqueKeyOptions(oldCompositeUniqueKey); - - return areConstraintOptionsEqual(oldCompositeUniqueKeyAsRegularUniqueKeyOptions, constraintOptions); - }); + const constraintOptions = extractKeyConstraintOptions(columnJsonSchema.uniqueKeyOptions); + const areOptionsEqual = isCompositeEqualsToRegular(oldUniqueKeys, constraintOptions); return UniqueKeyTransitionDto.transition(!areOptionsEqual); } @@ -333,10 +325,10 @@ const wasRegularUniqueKeyChangedInTransitionFromRegularToComposite = (columnJson const oldName = columnJsonSchema.compMod.oldField.name; const oldColumnJsonSchema = collection.role.properties[oldName]; - const wasRegularUniqueKey = oldColumnJsonSchema.unique && !oldColumnJsonSchema.compositeUniqueKey; - const isTheFieldAnyUniqueKey = Boolean(columnJsonSchema?.unique); + const wasRegularUniqueKey = checkIsUniqueKeyRegular(oldColumnJsonSchema); + const isCompositeUniqueKey = Boolean(columnJsonSchema?.compositeUniqueKey); - if (!(wasRegularUniqueKey && isTheFieldAnyUniqueKey)) { + if (!(wasRegularUniqueKey && isCompositeUniqueKey)) { return UniqueKeyTransitionDto.noTransition(); } @@ -362,17 +354,8 @@ const wasRegularUniqueKeyChangedInTransitionFromRegularToComposite = (columnJson // return compare custom properties and amount of columns. // If there was a transition and amount of composite UniqueKey columns is not equal // to amount of regular unique columns, we must recreate UniqueKey - const constraintOptions = - getCustomPropertiesOfRegularUniqueKeyForComparisonWithRegularUniqueKeyOptions(oldColumnJsonSchema); - const areOptionsEqual = newUniqueKeys.some(oldCompositeUniqueKey => { - if (oldCompositeUniqueKey.compositeUniqueKey.length !== amountOfColumnsInRegularUniqueKey) { - return false; - } - const oldCompositeUniqueKeyAsRegularUniqueKeyOptions = - getCustomPropertiesOfCompositeUniqueKeyForComparisonWithRegularUniqueKeyOptions(oldCompositeUniqueKey); - - return areConstraintOptionsEqual(oldCompositeUniqueKeyAsRegularUniqueKeyOptions, constraintOptions); - }); + const constraintOptions = extractKeyConstraintOptions(oldColumnJsonSchema.uniqueKeyOptions); + const areOptionsEqual = isCompositeEqualsToRegular(newUniqueKeys, constraintOptions); return UniqueKeyTransitionDto.transition(!areOptionsEqual); } @@ -389,7 +372,7 @@ const isFieldNoLongerARegularUniqueKey = (columnJsonSchema, collection) => { const oldName = columnJsonSchema.compMod.oldField.name; const oldJsonSchema = collection.role.properties[oldName]; - const wasTheFieldARegularUniqueKey = oldJsonSchema?.unique && !oldJsonSchema?.compositeUniqueKey; + const wasTheFieldARegularUniqueKey = checkIsUniqueKeyRegular(oldJsonSchema); const isNotAnyUniqueKey = !columnJsonSchema.unique && !columnJsonSchema.compositeUniqueKey; return wasTheFieldARegularUniqueKey && isNotAnyUniqueKey; @@ -410,12 +393,11 @@ const wasRegularUniqueKeyModified = (columnJsonSchema, collection) => { if (!(isRegularUniqueKey && wasTheFieldARegularUniqueKey)) { return false; } - const constraintOptions = - getCustomPropertiesOfRegularUniqueKeyForComparisonWithRegularUniqueKeyOptions(columnJsonSchema); - const oldConstraintOptions = - getCustomPropertiesOfRegularUniqueKeyForComparisonWithRegularUniqueKeyOptions(oldJsonSchema); - return !areConstraintOptionsEqual(oldConstraintOptions, constraintOptions); + const constraintOptions = extractKeyConstraintOptions(columnJsonSchema.uniqueKeyOptions); + const oldConstraintOptions = extractKeyConstraintOptions(oldJsonSchema.uniqueKeyOptions); + + return !_.isEqual(oldConstraintOptions, constraintOptions); }; /** @@ -453,6 +435,48 @@ const getAddUniqueKeyScriptDtos = ({ scriptFormat, collection }) => { .filter(scriptDto => Boolean(scriptDto.script)); }; +const getDropUniqueKeyScriptDtos = ({ scriptFormat, collection }) => { + const collectionSchema = getSchemaOfAlterCollection(collection); + const tableName = getEntityName(collectionSchema); + const fullTableName = getFullCollectionName(scriptFormat)(collectionSchema); + + const isContainerActivated = isParentContainerActivated(collection); + const isCollectionActivated = isContainerActivated && isObjectInDeltaModelActivated(collection); + + return _.toPairs(collection.properties) + .filter(([name, jsonSchema]) => { + if (isFieldNoLongerARegularUniqueKey(jsonSchema, collection)) { + return true; + } + const transitionToRegularDto = wasRegularUniqueKeyChangedInTransitionFromRegularToComposite( + jsonSchema, + collection, + ); + if (transitionToRegularDto.didTransitionHappen) { + return transitionToRegularDto.wasUniqueKeyChangedInTransition; + } + return wasRegularUniqueKeyModified(jsonSchema, collection); + }) + .map(([name, jsonSchema]) => { + const oldName = jsonSchema.compMod.oldField.name; + const oldColumnJsonSchema = collection.role.properties[oldName]; + const constraintName = oldColumnJsonSchema?.uniqueKeyOptions?.constraintName; + + const script = constraintName + ? assignTemplates(templates.dropConstraint, { + tableName: fullTableName, + constraintName: prepareNameForScriptFormat(scriptFormat)(constraintName), + }) + : assignTemplates(templates.dropUniqueKey, { + tableName, + fullTableName, + tableColumn: name, + }); + return new KeyScriptModificationDto(script, fullTableName, true, isCollectionActivated); + }) + .filter(scriptDto => Boolean(scriptDto.script)); +}; + /** * @param {object} params * @property {string} scriptFormat @@ -460,9 +484,10 @@ const getAddUniqueKeyScriptDtos = ({ scriptFormat, collection }) => { * @return {Array} * */ const getModifyUniqueKeyScriptDtos = ({ scriptFormat, collection }) => { + const dropUniqueKeyScriptDtos = getDropUniqueKeyScriptDtos({ scriptFormat, collection }); const addUniqueKeyScriptDtos = getAddUniqueKeyScriptDtos({ scriptFormat, collection }); - return addUniqueKeyScriptDtos.filter(Boolean); + return [...dropUniqueKeyScriptDtos, ...addUniqueKeyScriptDtos].filter(Boolean); }; /** diff --git a/forward_engineering/ddlProvider/ddlHelpers/constraintHelper.js b/forward_engineering/ddlProvider/ddlHelpers/constraintHelper.js index eaccdca..658a0c7 100644 --- a/forward_engineering/ddlProvider/ddlHelpers/constraintHelper.js +++ b/forward_engineering/ddlProvider/ddlHelpers/constraintHelper.js @@ -60,9 +60,22 @@ module.exports = ({ prepareName }) => { }; }; + /** + * @param tableName {string} + * @param constraintName {string} + * */ + const dropKeyConstraint = (tableName, constraintName) => { + const templatesConfig = { + tableName, + constraintName: prepareName(_.trim(constraintName)), + }; + return assignTemplates(templates.dropConstraint, templatesConfig); + }; + return { getOptionsString, alterKeyConstraint, createKeyConstraint, + dropKeyConstraint, }; }; diff --git a/forward_engineering/ddlProvider/templates.js b/forward_engineering/ddlProvider/templates.js index beec1d3..f93bdfa 100644 --- a/forward_engineering/ddlProvider/templates.js +++ b/forward_engineering/ddlProvider/templates.js @@ -87,4 +87,9 @@ module.exports = { addNotNullConstraint: 'ALTER TABLE ${tableName} MODIFY ${columnName} NOT NULL;', updateColumnDefaultValue: 'ALTER TABLE ${tableName} MODIFY ${columnName}${defaultValue};', + + dropPrimaryKey: 'ALTER TABLE ${tableName} DROP PRIMARY KEY;', + + dropUniqueKey: + "SELECT 'ALTER TABLE ${fullTableName} DROP CONSTRAINT ' || uc.constraint_name || ';' AS sql_stmt\nFROM user_constraints uc\nJOIN user_cons_columns ucc ON uc.constraint_name = ucc.constraint_name\nWHERE uc.table_name = '${tableName}' AND uc.constraint_type = 'U' AND ucc.column_name = '${tableColumn}';", }; diff --git a/forward_engineering/utils/general.js b/forward_engineering/utils/general.js index 531483c..1dd136c 100644 --- a/forward_engineering/utils/general.js +++ b/forward_engineering/utils/general.js @@ -221,6 +221,18 @@ const getSchemaOfAlterCollection = collection => { return { ...collection, ...(_.omit(collection?.role, 'properties') || {}) }; }; +const isObjectInDeltaModelActivated = modelObject => { + return modelObject.compMod?.isActivated?.new ?? modelObject.role?.isActivated; +}; + +const isParentContainerActivated = collection => { + return ( + collection?.compMod?.bucketProperties?.isActivated ?? + collection?.role?.compMod?.bucketProperties?.isActivated ?? + true + ); +}; + module.exports = { getDbName, getBucketName, @@ -248,4 +260,6 @@ module.exports = { prepareNameForScriptFormat, getFullCollectionName, getSchemaOfAlterCollection, + isObjectInDeltaModelActivated, + isParentContainerActivated, };