From fb8afbd74df5ce0fadcd536fbcd7959a00a54cab Mon Sep 17 00:00:00 2001 From: yevhenii-moroziuk Date: Tue, 27 Jan 2026 21:27:17 +0200 Subject: [PATCH 1/7] HCK-14450: Add logic to handle comments --- .../indexHelpers/commentsHelper.js | 50 +++++++++++++++++++ .../ddlHelpers/comment/commentHelper.js | 13 +++++ forward_engineering/utils/general.js | 11 ++++ 3 files changed, 74 insertions(+) create mode 100644 forward_engineering/alterScript/alterScriptHelpers/indexHelpers/commentsHelper.js diff --git a/forward_engineering/alterScript/alterScriptHelpers/indexHelpers/commentsHelper.js b/forward_engineering/alterScript/alterScriptHelpers/indexHelpers/commentsHelper.js new file mode 100644 index 0000000..3993c54 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/indexHelpers/commentsHelper.js @@ -0,0 +1,50 @@ +const { AlterScriptDto } = require('../../types/AlterScriptDto'); +const { + getSchemaNameFromCollection, + getNamePrefixedWithSchemaName, + wrapInQuotes, + isEntityActivated, +} = require('../../../utils/general'); +const { + getIndexCommentStatement, + dropIndexCommentStatement, +} = require('../../../ddlProvider/ddlHelpers/comment/commentHelper'); + +/** + * @param {Object} newIndex + * @param {Object} oldIndex + * @param {Object} collection + * @return {AlterScriptDto | undefined} + */ +const getModifyIndexCommentsScriptDtos = ({ newIndex, oldIndex, collection }) => { + const newDescription = newIndex.indxDescription; + const oldDescription = oldIndex.indxDescription; + const schemaName = getSchemaNameFromCollection({ collection }); + const fullIndexName = getNamePrefixedWithSchemaName({ + name: newIndex.indxName, + schemaName, + }); + + const isActivated = isEntityActivated(collection) && newIndex.isActivated; + + if (newDescription && newDescription !== oldDescription) { + const script = getIndexCommentStatement({ + indexName: fullIndexName, + description: newDescription, + }); + return AlterScriptDto.getInstance([script], isActivated, false); + } + + if (oldDescription && !newDescription) { + const script = dropIndexCommentStatement({ + indexName: fullIndexName, + }); + return AlterScriptDto.getInstance([script], isActivated, true); + } + + return undefined; +}; + +module.exports = { + getModifyIndexCommentsScriptDtos, +}; diff --git a/forward_engineering/ddlProvider/ddlHelpers/comment/commentHelper.js b/forward_engineering/ddlProvider/ddlHelpers/comment/commentHelper.js index e5d85a6..0bb9aff 100644 --- a/forward_engineering/ddlProvider/ddlHelpers/comment/commentHelper.js +++ b/forward_engineering/ddlProvider/ddlHelpers/comment/commentHelper.js @@ -155,6 +155,18 @@ const dropTableColumnCommentStatement = ({ tableName, columnName }) => { }); }; +/** + * @param {{ indexName: string }} + * @returns {string} + */ +const dropIndexCommentStatement = ({ indexName }) => { + return getCommentStatement({ + objectName: indexName, + objectType: OBJECT_TYPE.index, + mode: COMMENT_MODE.remove, + }); +}; + module.exports = { getColumnCommentStatement, getSchemaCommentStatement, @@ -165,4 +177,5 @@ module.exports = { dropSchemaCommentStatement, dropTableCommentStatement, dropTableColumnCommentStatement, + dropIndexCommentStatement, }; diff --git a/forward_engineering/utils/general.js b/forward_engineering/utils/general.js index 37aa491..05e86b9 100644 --- a/forward_engineering/utils/general.js +++ b/forward_engineering/utils/general.js @@ -150,6 +150,16 @@ const checkFieldPropertiesChanged = (compMod, propertiesToCheck) => { return propertiesToCheck.some(prop => compMod?.oldField[prop] !== compMod?.newField[prop]); }; +/** + * @param {object} collection + * @returns {boolean} + */ +const isEntityActivated = collection => { + const isContainerActivated = isParentContainerActivated(collection); + const isCollectionActivated = isObjectInDeltaModelActivated(collection); + return isContainerActivated && isCollectionActivated; +}; + /** * * @template {object} T @@ -198,4 +208,5 @@ module.exports = { getSchemaNameFromCollection, getUpdatedProperties, checkFieldPropertiesChanged, + isEntityActivated, }; From 632ae9fb28986305ce32d2c34f125441ab26e490 Mon Sep 17 00:00:00 2001 From: yevhenii-moroziuk Date: Tue, 27 Jan 2026 21:44:05 +0200 Subject: [PATCH 2/7] HCK-14450: Add logic to drop and recreate indexes --- .../alterScriptHelpers/alterEntityHelper.js | 12 +- .../entityHelpers/indexesHelper.js | 267 ++++++++++++++++++ .../ddlProvider/ddlProvider.js | 4 + forward_engineering/ddlProvider/templates.js | 4 + 4 files changed, 282 insertions(+), 5 deletions(-) create mode 100644 forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js diff --git a/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js b/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js index 0148f52..f1e631c 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js @@ -11,6 +11,7 @@ const { getRenameColumnScriptDtos } = require('./columnHelpers/alterColumnNameHe const { getModifyEntityCommentsScriptDtos } = require('./entityHelpers/commentsHelper'); const { getModifyPkConstraintsScriptDtos } = require('./entityHelpers/primaryKeyHelper'); const { getModifyUkConstraintsScriptDtos } = require('./entityHelpers/uniqueKeyHelper'); +const { getModifyIndexesScriptDtos } = require('./entityHelpers/indexesHelper'); const { getModifiedDefaultColumnValueScriptDtos } = require('./columnHelpers/defaultValueHelper'); const { getEntityName, @@ -109,13 +110,14 @@ const getModifyCollectionScriptDtos = collection => { }; /** - * @param {Object} collection - * @returns {Array} + * @param {Object} ddlProvider + * @returns {(collection: Object) => Array} */ -const getModifyCollectionKeysScriptDtos = collection => { +const getModifyCollectionKeysScriptDtos = ddlProvider => collection => { const modifyPkConstraintDtos = getModifyPkConstraintsScriptDtos(collection); const modifyUkConstraintDtos = getModifyUkConstraintsScriptDtos(collection); - return [...modifyPkConstraintDtos, ...modifyUkConstraintDtos].filter(Boolean); + const modifyIndexesScriptDtos = getModifyIndexesScriptDtos({ ddlProvider, collection }); + return [...modifyPkConstraintDtos, ...modifyUkConstraintDtos, ...modifyIndexesScriptDtos].filter(Boolean); }; /** @@ -197,7 +199,7 @@ const getEntitiesScripts = (app, inlineDeltaRelationships) => { getDeleteCollectionScriptDto: getDeleteCollectionScriptDto(ddlProvider), getModifyCollectionScriptDtos, getModifyColumnScriptDtos: getModifyColumnScriptDtos(ddlProvider), - getModifyCollectionKeysScriptDtos, + getModifyCollectionKeysScriptDtos: getModifyCollectionKeysScriptDtos(ddlProvider), getAddColumnScriptDtos: getAddColumnScriptDtos(ddlProvider), getDeleteColumnScriptDtos: getDeleteColumnScriptDtos(ddlProvider), }; diff --git a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js new file mode 100644 index 0000000..b431cab --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js @@ -0,0 +1,267 @@ +const _ = require('lodash'); +const { AlterScriptDto } = require('../../types/AlterScriptDto'); +const { + getSchemaNameFromCollection, + getNamePrefixedWithSchemaName, + wrapInQuotes, + getSchemaOfAlterCollection, + getFullCollectionName, + getEntityName, + isEntityActivated, +} = require('../../../utils/general'); +const { assignTemplates } = require('../../../utils/assignTemplates'); +const templates = require('../../../ddlProvider/templates'); +const { getIndexCommentsScriptDtos, getModifyIndexCommentsScriptDtos } = require('../indexHelpers/commentsHelper'); + +/** + * @param {string} columnId + * @param {Object} collection + * @return {string | undefined} + * */ +const getColumnNameById = ({ columnId, collection }) => { + const collectionProperties = _.toPairs(collection?.role?.properties || collection?.properties || {}).map( + ([name, value]) => ({ ...value, name }), + ); + const oldProperties = (collection?.role?.compMod?.oldProperties || []).map(property => ({ + ...property, + GUID: property.id, + })); + const properties = collectionProperties.length > 0 ? collectionProperties : oldProperties; + const propertySchema = properties.find(fieldJsonSchema => fieldJsonSchema.GUID === columnId); + + if (propertySchema) { + return propertySchema.name; + } + + return undefined; +}; + +/** + * @param {AlterIndexDto} index + * @param {Object} collection + * @return {Object} + * */ +const addNameToIndexKey = ({ index, collection }) => { + if (!index?.indxKey?.length) { + return index; + } + + const schemaName = getSchemaNameFromCollection({ collection }); + + const columnsWithNames = index.indxKey + .map(column => { + return { + ...column, + name: getColumnNameById({ columnId: column.keyId, collection }), + }; + }) + .filter(column => Boolean(column.name)); + + return { + ...index, + schemaName, + indxKey: columnsWithNames, + }; +}; + +const alterIndexRebuildProperties = ['indxCompress']; +const dropAndRecreateIndexProperties = ['indxType', 'indxTablespace', 'indxNullKeys']; +// need to recreate if key is removed, but can alter if added +const customLogicProperties = ['indxKey', 'indxIncludeKey']; + +const hasRemovedIndexKeys = ({ oldIndex, newIndex, property }) => { + const oldKeys = oldIndex[property] || []; + const newKeys = newIndex[property] || []; + + return oldKeys.some(oldKey => !newKeys.find(newKey => newKey.keyId === oldKey.keyId)); +}; + +const shouldDropAndRecreateIndex = ({ oldIndex, newIndex }) => { + return ( + dropAndRecreateIndexProperties.some(property => !_.isEqual(oldIndex[property], newIndex[property])) || + hasRemovedIndexKeys({ oldIndex, newIndex, property: 'indxKey' }) || + hasRemovedIndexKeys({ oldIndex, newIndex, property: 'indxIncludeKey' }) + ); +}; + +/** + * @param {AlterIndexDto} oldIndex + * @param {AlterIndexDto} newIndex + * @return {boolean} + * */ +const areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex = ({ oldIndex, newIndex }) => { + return oldIndex.id === newIndex.id || oldIndex.indxName === newIndex.indxName; +}; + +/** + * @param {AlterIndexDto} index + * @param {Object} collection + * @param {Object} additionalDataForDdlProvider + * @return {AlterScriptDto | undefined} + * */ +const getCreateIndexScriptDto = ({ index, collection, ddlProvider }) => { + const indexWithAddedKeyNames = addNameToIndexKey({ index, collection }); + const collectionSchema = getSchemaOfAlterCollection(collection); + const tableName = getEntityName(collectionSchema); + const isParentActivated = isEntityActivated(collection); + + const script = ddlProvider.createIndex(tableName, indexWithAddedKeyNames); + const isIndexActivated = indexWithAddedKeyNames.isActivated && isParentActivated; + return AlterScriptDto.getInstance([script], isIndexActivated, false); +}; + +/** + * @param {Object} collection + * @param {Object} additionalDataForDdlProvider + * @return {Array} + * */ +const getAddedIndexesScriptDtos = + ddlProvider => + ({ collection }) => { + const newIndexes = collection?.role?.Indxs || []; + const oldIndexes = collection?.role?.compMod?.Indxs?.old || []; + + return newIndexes + .filter(newIndex => { + const correspondingOldIndex = oldIndexes.find(oldIndex => + areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex({ + oldIndex, + newIndex, + }), + ); + return !correspondingOldIndex; + }) + .map(newIndex => { + return getCreateIndexScriptDto({ + index: newIndex, + collection, + ddlProvider, + }); + }) + .filter(Boolean); + }; + +const getDeleteIndexScriptDto = ({ index, collection, ddlProvider }) => { + const schemaName = getSchemaNameFromCollection({ collection }); + const isParentActivated = isEntityActivated(collection); + + const fullIndexName = getNamePrefixedWithSchemaName({ + name: index.indxName, + schemaName, + }); + const script = ddlProvider.dropIndex(fullIndexName); + const isIndexActivated = index.isActivated && isParentActivated; + return AlterScriptDto.getInstance([script], isIndexActivated, true); +}; + +/** + * @param {Object} collection + * @param {Object} additionalDataForDdlProvider + * @return {Array} + * */ +const getDeletedIndexesScriptDtos = + ddlProvider => + ({ collection }) => { + const newIndexes = collection?.role?.compMod?.Indxs?.new || []; + const oldIndexes = collection?.role?.compMod?.Indxs?.old || []; + + return oldIndexes + .filter(oldIndex => { + const correspondingNewIndex = newIndexes.find(newIndex => + areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex({ + oldIndex, + newIndex, + }), + ); + return !correspondingNewIndex; + }) + .map(oldIndex => { + return getDeleteIndexScriptDto({ index: oldIndex, collection, ddlProvider }); + }) + .filter(Boolean); + }; + +const getModifyIndexScriptDto = ({ newIndex, oldIndex, collection, ddlProvider }) => { + const scripts = []; + const shouldDropAndRecreate = shouldDropAndRecreateIndex({ newIndex, oldIndex }); + if (shouldDropAndRecreate) { + const deleteIndexScriptDto = getDeleteIndexScriptDto({ + index: oldIndex, + collection, + ddlProvider, + }); + const createIndexScriptDto = getCreateIndexScriptDto({ + index: newIndex, + collection, + ddlProvider, + }); + scripts.push(deleteIndexScriptDto, createIndexScriptDto); + } + const commentDtos = getModifyIndexCommentsScriptDtos({ newIndex, oldIndex, collection }); + + if (commentDtos) { + scripts.push(commentDtos); + } + + return scripts; +}; + +/** + * @param {Object} collection + * @param {Object} additionalDataForDdlProvider + * @return {Array} + * */ +const getModifiedIndexesScriptDtos = ({ collection, ddlProvider }) => { + const newIndexes = collection?.role?.compMod?.Indxs?.new || []; + const oldIndexes = collection?.role?.compMod?.Indxs?.old || []; + + return newIndexes + .map(newIndex => { + const correspondingOldIndex = oldIndexes.find(oldIndex => + areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex({ + oldIndex, + newIndex, + }), + ); + if (correspondingOldIndex) { + return { + newIndex, + oldIndex: correspondingOldIndex, + }; + } + return undefined; + }) + .filter(Boolean) + .flatMap(({ newIndex, oldIndex }) => { + return getModifyIndexScriptDto({ + newIndex, + oldIndex, + collection, + ddlProvider, + }); + }) + .filter(Boolean); +}; + +/** + * @param {Object} collection + * @return {Array} + * */ +const getModifyIndexesScriptDtos = ({ ddlProvider, collection }) => { + const deletedIndexesScriptDtos = getDeletedIndexesScriptDtos(ddlProvider)({ + collection, + }); + const addedIndexesScriptDtos = getAddedIndexesScriptDtos(ddlProvider)({ + collection, + }); + const modifiedIndexesScriptDtos = getModifiedIndexesScriptDtos({ + collection, + ddlProvider, + }); + + return [...deletedIndexesScriptDtos, ...addedIndexesScriptDtos, ...modifiedIndexesScriptDtos].filter(Boolean); +}; + +module.exports = { + getModifyIndexesScriptDtos, +}; diff --git a/forward_engineering/ddlProvider/ddlProvider.js b/forward_engineering/ddlProvider/ddlProvider.js index c9a824b..fe6afb6 100644 --- a/forward_engineering/ddlProvider/ddlProvider.js +++ b/forward_engineering/ddlProvider/ddlProvider.js @@ -449,6 +449,10 @@ module.exports = (baseProvider, options, app) => { }); }, + dropIndex(name) { + return assignTemplates({ template: templates.dropIndex, templateData: { name } }); + }, + hydrateViewColumn(data) { return { name: data.name, diff --git a/forward_engineering/ddlProvider/templates.js b/forward_engineering/ddlProvider/templates.js index 57906fc..3a07a4f 100644 --- a/forward_engineering/ddlProvider/templates.js +++ b/forward_engineering/ddlProvider/templates.js @@ -66,4 +66,8 @@ module.exports = { dropView: 'DROP VIEW ${viewName};', renameTable: 'RENAME TABLE ${oldTableName} TO ${newTableName};', + + renameIndex: 'RENAME INDEX ${oldIndexName} TO ${newIndexName};', + + dropIndex: 'DROP INDEX ${name};', }; From 82437090b086f61f218caf3d740c11d20f8f9497 Mon Sep 17 00:00:00 2001 From: yevhenii-moroziuk Date: Tue, 27 Jan 2026 22:02:01 +0200 Subject: [PATCH 3/7] HCK-14450: Add logic to rename indexes --- .../entityHelpers/indexesHelper.js | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js index b431cab..b9ec335 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js @@ -93,6 +93,31 @@ const areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex = ({ oldIndex, new return oldIndex.id === newIndex.id || oldIndex.indxName === newIndex.indxName; }; +/** + * @param {string} schemaName + * @param {string} oldIndexName + * @param {string} newIndexName + * @param {boolean} isActivated + * @return {string} + * */ +const alterIndexRenameSto = ({ schemaName, oldIndexName, newIndexName, isActivated }) => { + const ddlOldIndexName = getNamePrefixedWithSchemaName({ + name: oldIndexName, + schemaName, + }); + const ddlNewIndexName = wrapInQuotes(newIndexName); + + const script = assignTemplates({ + template: templates.renameIndex, + templateData: { + oldIndexName: ddlOldIndexName, + newIndexName: ddlNewIndexName, + }, + }); + + return AlterScriptDto.getInstance([script], isActivated, false); +}; + /** * @param {AlterIndexDto} index * @param {Object} collection @@ -183,6 +208,7 @@ const getDeletedIndexesScriptDtos = const getModifyIndexScriptDto = ({ newIndex, oldIndex, collection, ddlProvider }) => { const scripts = []; + const shouldDropAndRecreate = shouldDropAndRecreateIndex({ newIndex, oldIndex }); if (shouldDropAndRecreate) { const deleteIndexScriptDto = getDeleteIndexScriptDto({ @@ -196,7 +222,18 @@ const getModifyIndexScriptDto = ({ newIndex, oldIndex, collection, ddlProvider } ddlProvider, }); scripts.push(deleteIndexScriptDto, createIndexScriptDto); + } else if (oldIndex.indxName !== newIndex.indxName) { + const schemaName = getSchemaNameFromCollection({ collection }); + const renameScript = alterIndexRenameSto({ + schemaName, + oldIndexName: oldIndex.indxName, + newIndexName: newIndex.indxName, + isActivated: isEntityActivated(collection) && newIndex.isActivated, + }); + + scripts.push(renameScript); } + const commentDtos = getModifyIndexCommentsScriptDtos({ newIndex, oldIndex, collection }); if (commentDtos) { From 2fe6a36874fd0329458d5f8deb97882340b03594 Mon Sep 17 00:00:00 2001 From: yevhenii-moroziuk Date: Wed, 28 Jan 2026 15:36:50 +0200 Subject: [PATCH 4/7] HCK-14474: Add missing api method --- .../alterScript/alterScriptBuilder.js | 10 ++++++++++ forward_engineering/api.js | 5 ++--- forward_engineering/api/generateScript.js | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 forward_engineering/api/generateScript.js diff --git a/forward_engineering/alterScript/alterScriptBuilder.js b/forward_engineering/alterScript/alterScriptBuilder.js index a5e0923..3c75f21 100644 --- a/forward_engineering/alterScript/alterScriptBuilder.js +++ b/forward_engineering/alterScript/alterScriptBuilder.js @@ -44,6 +44,15 @@ const mapCoreDataForContainerLevelScripts = data => { }; }; +const buildEntityLevelAlterScript = (data, app) => { + const alterScriptDtos = getAlterScriptDtos(data, app); + const shouldApplyDropStatements = data.options?.additionalOptions?.some( + option => option.id === 'applyDropStatements' && option.value, + ); + + return joinAlterScriptDtosIntoScript(alterScriptDtos, shouldApplyDropStatements); +}; + const buildContainerLevelAlterScript = (data, app) => { const preparedData = mapCoreDataForContainerLevelScripts(data); const alterScriptDtos = getAlterScriptDtos(preparedData, app); @@ -66,6 +75,7 @@ const doesContainerLevelAlterScriptContainDropStatements = (data, app) => { module.exports = { doesEntityLevelAlterScriptContainDropStatements, + buildEntityLevelAlterScript, buildContainerLevelAlterScript, doesContainerLevelAlterScriptContainDropStatements, }; diff --git a/forward_engineering/api.js b/forward_engineering/api.js index 20f1620..29cd49e 100644 --- a/forward_engineering/api.js +++ b/forward_engineering/api.js @@ -2,11 +2,10 @@ const { generateContainerScript } = require('./api/generateContainerScript'); const { isDropInStatements } = require('./api/isDropInStatements'); const { testConnection } = require('../shared/api/testConnection'); const { applyToInstance } = require('./api/applyToInstance'); +const { generateScript } = require('./api/generateScript'); module.exports = { - generateScript(data, logger, callback, app) { - throw new Error('Not implemented'); - }, + generateScript, generateViewScript(data, logger, callback, app) { throw new Error('Not implemented'); diff --git a/forward_engineering/api/generateScript.js b/forward_engineering/api/generateScript.js new file mode 100644 index 0000000..d2987d8 --- /dev/null +++ b/forward_engineering/api/generateScript.js @@ -0,0 +1,16 @@ +const { buildEntityLevelAlterScript } = require('../alterScript/alterScriptBuilder'); + +function generateScript(data, logger, callback, app) { + try { + const script = buildEntityLevelAlterScript(data, app); + callback(null, script); + } catch (error) { + logger.log('error', { message: error.message, stack: error.stack }, 'Oracle Forward-Engineering Error'); + + callback({ message: error.message, stack: error.stack }); + } +} + +module.exports = { + generateScript, +}; From 9487d098ae500f769f1b26775376e9e75520d09c Mon Sep 17 00:00:00 2001 From: yevhenii-moroziuk Date: Thu, 29 Jan 2026 12:23:30 +0200 Subject: [PATCH 5/7] HCK-14450: Adapt the logic to always recreate a script --- .../entityHelpers/indexesHelper.js | 47 ++++++++++--------- .../ddlProvider/ddlProvider.js | 23 +++++++-- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js index b9ec335..1e85a12 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js @@ -65,23 +65,18 @@ const addNameToIndexKey = ({ index, collection }) => { }; const alterIndexRebuildProperties = ['indxCompress']; -const dropAndRecreateIndexProperties = ['indxType', 'indxTablespace', 'indxNullKeys']; -// need to recreate if key is removed, but can alter if added -const customLogicProperties = ['indxKey', 'indxIncludeKey']; - -const hasRemovedIndexKeys = ({ oldIndex, newIndex, property }) => { - const oldKeys = oldIndex[property] || []; - const newKeys = newIndex[property] || []; - - return oldKeys.some(oldKey => !newKeys.find(newKey => newKey.keyId === oldKey.keyId)); -}; +const columnProperties = ['indxKey', 'indxIncludeKey']; +// Temporary always drop and recreate index if any of these properties changed +const dropAndRecreateIndexProperties = [ + 'indxType', + 'indxTablespace', + 'indxNullKeys', + ...alterIndexRebuildProperties, + ...columnProperties, +]; const shouldDropAndRecreateIndex = ({ oldIndex, newIndex }) => { - return ( - dropAndRecreateIndexProperties.some(property => !_.isEqual(oldIndex[property], newIndex[property])) || - hasRemovedIndexKeys({ oldIndex, newIndex, property: 'indxKey' }) || - hasRemovedIndexKeys({ oldIndex, newIndex, property: 'indxIncludeKey' }) - ); + return dropAndRecreateIndexProperties.some(property => !_.isEqual(oldIndex[property], newIndex[property])); }; /** @@ -100,7 +95,7 @@ const areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex = ({ oldIndex, new * @param {boolean} isActivated * @return {string} * */ -const alterIndexRenameSto = ({ schemaName, oldIndexName, newIndexName, isActivated }) => { +const alterIndexRenameDto = ({ schemaName, oldIndexName, newIndexName, isActivated }) => { const ddlOldIndexName = getNamePrefixedWithSchemaName({ name: oldIndexName, schemaName, @@ -128,11 +123,9 @@ const getCreateIndexScriptDto = ({ index, collection, ddlProvider }) => { const indexWithAddedKeyNames = addNameToIndexKey({ index, collection }); const collectionSchema = getSchemaOfAlterCollection(collection); const tableName = getEntityName(collectionSchema); - const isParentActivated = isEntityActivated(collection); const script = ddlProvider.createIndex(tableName, indexWithAddedKeyNames); - const isIndexActivated = indexWithAddedKeyNames.isActivated && isParentActivated; - return AlterScriptDto.getInstance([script], isIndexActivated, false); + return AlterScriptDto.getInstance([script], true, false); }; /** @@ -222,9 +215,21 @@ const getModifyIndexScriptDto = ({ newIndex, oldIndex, collection, ddlProvider } ddlProvider, }); scripts.push(deleteIndexScriptDto, createIndexScriptDto); - } else if (oldIndex.indxName !== newIndex.indxName) { + + if (newIndex.indxDescription) { + const commentDtos = getIndexCommentsScriptDtos({ + index: newIndex, + collection, + }); + scripts.push(...commentDtos); + } + + return scripts; + } + + if (oldIndex.indxName !== newIndex.indxName) { const schemaName = getSchemaNameFromCollection({ collection }); - const renameScript = alterIndexRenameSto({ + const renameScript = alterIndexRenameDto({ schemaName, oldIndexName: oldIndex.indxName, newIndexName: newIndex.indxName, diff --git a/forward_engineering/ddlProvider/ddlProvider.js b/forward_engineering/ddlProvider/ddlProvider.js index fe6afb6..52050cc 100644 --- a/forward_engineering/ddlProvider/ddlProvider.js +++ b/forward_engineering/ddlProvider/ddlProvider.js @@ -1,4 +1,4 @@ -const { toUpper, isEmpty, trim } = require('lodash'); +const { toUpper, isEmpty, trim, get } = require('lodash'); const templates = require('./templates'); const defaultTypes = require('../configs/defaultTypes.js'); const descriptors = require('../configs/descriptors.js'); @@ -10,6 +10,7 @@ const { toArray, hasType, setTab, + isEntityActivated, } = require('../utils/general.js'); const { assignTemplates } = require('../utils/assignTemplates'); const keyHelper = require('./ddlHelpers/key/keyHelper.js'); @@ -424,7 +425,8 @@ module.exports = (baseProvider, options, app) => { }, hydrateIndex(indexData, tableData, schemaData) { - return { ...indexData, schemaName: schemaData.schemaName }; + const isParentActivated = get(tableData, '[0].isActivated', true); + return { ...indexData, schemaName: schemaData.schemaName, isParentActivated }; }, createIndex(tableName, index) { @@ -442,11 +444,22 @@ module.exports = (baseProvider, options, app) => { templateData: { indexType, indexName, indexOptions, indexTableName }, }); const commentStatement = getIndexCommentStatement({ indexName, description: index.indxDescription }); - const createIndexStatement = statement + commentStatement; - return commentIfDeactivated(createIndexStatement, { - isActivated: index.isActivated, + let finalStatement = commentIfDeactivated(statement, { + isActivated: index.isActivated && index.isParentActivated, }); + + if (commentStatement) { + finalStatement += + '\n' + + commentIfDeactivated(commentStatement, { + isPartOfLine: true, + isActivated: index.isActivated && index.isParentActivated, + }) + + '\n'; + } + + return finalStatement; }, dropIndex(name) { From c24374491c597eb809aecd1a4578c3d51e6504f7 Mon Sep 17 00:00:00 2001 From: yevhenii-moroziuk Date: Thu, 29 Jan 2026 16:13:04 +0200 Subject: [PATCH 6/7] Fix column names in a view script --- .../ddlProvider/ddlHelpers/view/getViewData.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/forward_engineering/ddlProvider/ddlHelpers/view/getViewData.js b/forward_engineering/ddlProvider/ddlHelpers/view/getViewData.js index 9b9d2d5..ba3bc3c 100644 --- a/forward_engineering/ddlProvider/ddlHelpers/view/getViewData.js +++ b/forward_engineering/ddlProvider/ddlHelpers/view/getViewData.js @@ -1,4 +1,4 @@ -const { wrapInQuotes } = require('../../../utils/general'); +const { wrapInQuotes, getNamePrefixedWithSchemaName } = require('../../../utils/general'); /** * @param {{ key?: object }} @@ -37,7 +37,10 @@ const getViewData = ({ keys }) => { return result; } - const tableName = `${wrapInQuotes(key.dbName)}.${wrapInQuotes(key.tableName)}`; + const tableName = getNamePrefixedWithSchemaName({ + name: key.tableName, + schemaName: key.dbName, + }); if (!result.tables.includes(tableName)) { result.tables.push(tableName); From aea867dfa6d9f180cf4718da451eb918ff6af1ef Mon Sep 17 00:00:00 2001 From: yevhenii-moroziuk Date: Thu, 29 Jan 2026 17:22:57 +0200 Subject: [PATCH 7/7] HCK-14450: Code clean up --- api/fe.js | 2 + .../entityHelpers/indexesHelper.js | 248 +++++++++--------- .../indexHelpers/addNameToIndexKey.js | 57 ++++ .../indexHelpers/commentsHelper.js | 14 +- .../ddlProvider/ddlProvider.js | 1 - forward_engineering/utils/general.js | 11 - 6 files changed, 184 insertions(+), 149 deletions(-) create mode 100644 forward_engineering/alterScript/alterScriptHelpers/indexHelpers/addNameToIndexKey.js diff --git a/api/fe.js b/api/fe.js index 64f1b6f..f970853 100644 --- a/api/fe.js +++ b/api/fe.js @@ -1,7 +1,9 @@ const { generateContainerScript } = require('../forward_engineering/api/generateContainerScript'); const { isDropInStatements } = require('../forward_engineering/api/isDropInStatements'); +const { generateScript } = require('../forward_engineering/api/generateScript'); module.exports = { + generateScript, generateContainerScript, isDropInStatements, }; diff --git a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js index 1e85a12..f6b4715 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/entityHelpers/indexesHelper.js @@ -1,4 +1,4 @@ -const _ = require('lodash'); +const { isEqual } = require('lodash'); const { AlterScriptDto } = require('../../types/AlterScriptDto'); const { getSchemaNameFromCollection, @@ -7,94 +7,55 @@ const { getSchemaOfAlterCollection, getFullCollectionName, getEntityName, - isEntityActivated, + isObjectInDeltaModelActivated, } = require('../../../utils/general'); const { assignTemplates } = require('../../../utils/assignTemplates'); const templates = require('../../../ddlProvider/templates'); const { getIndexCommentsScriptDtos, getModifyIndexCommentsScriptDtos } = require('../indexHelpers/commentsHelper'); +const { addNameToIndexKey } = require('../indexHelpers/addNameToIndexKey'); -/** - * @param {string} columnId - * @param {Object} collection - * @return {string | undefined} - * */ -const getColumnNameById = ({ columnId, collection }) => { - const collectionProperties = _.toPairs(collection?.role?.properties || collection?.properties || {}).map( - ([name, value]) => ({ ...value, name }), - ); - const oldProperties = (collection?.role?.compMod?.oldProperties || []).map(property => ({ - ...property, - GUID: property.id, - })); - const properties = collectionProperties.length > 0 ? collectionProperties : oldProperties; - const propertySchema = properties.find(fieldJsonSchema => fieldJsonSchema.GUID === columnId); - - if (propertySchema) { - return propertySchema.name; - } - - return undefined; -}; - -/** - * @param {AlterIndexDto} index - * @param {Object} collection - * @return {Object} - * */ -const addNameToIndexKey = ({ index, collection }) => { - if (!index?.indxKey?.length) { - return index; - } - - const schemaName = getSchemaNameFromCollection({ collection }); - - const columnsWithNames = index.indxKey - .map(column => { - return { - ...column, - name: getColumnNameById({ columnId: column.keyId, collection }), - }; - }) - .filter(column => Boolean(column.name)); - - return { - ...index, - schemaName, - indxKey: columnsWithNames, - }; -}; - -const alterIndexRebuildProperties = ['indxCompress']; +const alterIndexProperties = ['indxCompress']; const columnProperties = ['indxKey', 'indxIncludeKey']; // Temporary always drop and recreate index if any of these properties changed const dropAndRecreateIndexProperties = [ 'indxType', 'indxTablespace', 'indxNullKeys', - ...alterIndexRebuildProperties, + ...alterIndexProperties, ...columnProperties, ]; +/** + * @param {{ + * oldIndex: Object, + * newIndex: Object + * }} param + * @return {boolean} + */ const shouldDropAndRecreateIndex = ({ oldIndex, newIndex }) => { - return dropAndRecreateIndexProperties.some(property => !_.isEqual(oldIndex[property], newIndex[property])); + return dropAndRecreateIndexProperties.some(property => !isEqual(oldIndex[property], newIndex[property])); }; /** - * @param {AlterIndexDto} oldIndex - * @param {AlterIndexDto} newIndex + * @param {{ + * oldIndex: Object, + * newIndex: Object + * }} param * @return {boolean} - * */ + */ const areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex = ({ oldIndex, newIndex }) => { return oldIndex.id === newIndex.id || oldIndex.indxName === newIndex.indxName; }; /** - * @param {string} schemaName - * @param {string} oldIndexName - * @param {string} newIndexName - * @param {boolean} isActivated - * @return {string} - * */ + * @param {{ + * schemaName: string, + * oldIndexName: string, + * newIndexName: string, + * isActivated: boolean + * }} param + * @return {AlterScriptDto} + */ const alterIndexRenameDto = ({ schemaName, oldIndexName, newIndexName, isActivated }) => { const ddlOldIndexName = getNamePrefixedWithSchemaName({ name: oldIndexName, @@ -114,11 +75,13 @@ const alterIndexRenameDto = ({ schemaName, oldIndexName, newIndexName, isActivat }; /** - * @param {AlterIndexDto} index - * @param {Object} collection - * @param {Object} additionalDataForDdlProvider + * @param {{ + * index: Object, + * collection: Object, + * ddlProvider: Object + * }} param * @return {AlterScriptDto | undefined} - * */ + */ const getCreateIndexScriptDto = ({ index, collection, ddlProvider }) => { const indexWithAddedKeyNames = addNameToIndexKey({ index, collection }); const collectionSchema = getSchemaOfAlterCollection(collection); @@ -129,76 +92,90 @@ const getCreateIndexScriptDto = ({ index, collection, ddlProvider }) => { }; /** - * @param {Object} collection - * @param {Object} additionalDataForDdlProvider + * @param {{ + * collection: Object, + * ddlProvider: Object + * }} param * @return {Array} - * */ -const getAddedIndexesScriptDtos = - ddlProvider => - ({ collection }) => { - const newIndexes = collection?.role?.Indxs || []; - const oldIndexes = collection?.role?.compMod?.Indxs?.old || []; + */ +const getAddedIndexesScriptDtos = ({ collection, ddlProvider }) => { + const newIndexes = collection?.role?.Indxs || []; + const oldIndexes = collection?.role?.compMod?.Indxs?.old || []; - return newIndexes - .filter(newIndex => { - const correspondingOldIndex = oldIndexes.find(oldIndex => - areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex({ - oldIndex, - newIndex, - }), - ); - return !correspondingOldIndex; - }) - .map(newIndex => { - return getCreateIndexScriptDto({ - index: newIndex, - collection, - ddlProvider, - }); - }) - .filter(Boolean); - }; + return newIndexes + .filter(newIndex => { + const correspondingOldIndex = oldIndexes.find(oldIndex => + areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex({ + oldIndex, + newIndex, + }), + ); + return !correspondingOldIndex; + }) + .map(newIndex => { + return getCreateIndexScriptDto({ + index: newIndex, + collection, + ddlProvider, + }); + }) + .filter(Boolean); +}; +/** + * @param {{ + * index: Object, + * collection: Object, + * ddlProvider: Object + * }} param + * @return {AlterScriptDto | undefined} + */ const getDeleteIndexScriptDto = ({ index, collection, ddlProvider }) => { const schemaName = getSchemaNameFromCollection({ collection }); - const isParentActivated = isEntityActivated(collection); - const fullIndexName = getNamePrefixedWithSchemaName({ name: index.indxName, schemaName, }); const script = ddlProvider.dropIndex(fullIndexName); - const isIndexActivated = index.isActivated && isParentActivated; - return AlterScriptDto.getInstance([script], isIndexActivated, true); + return AlterScriptDto.getInstance([script], index.isActivated && isObjectInDeltaModelActivated(collection), true); }; /** - * @param {Object} collection - * @param {Object} additionalDataForDdlProvider + * @param {{ + * collection: Object, + * ddlProvider: Object + * }} param * @return {Array} - * */ -const getDeletedIndexesScriptDtos = - ddlProvider => - ({ collection }) => { - const newIndexes = collection?.role?.compMod?.Indxs?.new || []; - const oldIndexes = collection?.role?.compMod?.Indxs?.old || []; + */ +const getDeletedIndexesScriptDtos = ({ collection, ddlProvider }) => { + const newIndexes = collection?.role?.compMod?.Indxs?.new || []; + const oldIndexes = collection?.role?.compMod?.Indxs?.old || []; - return oldIndexes - .filter(oldIndex => { - const correspondingNewIndex = newIndexes.find(newIndex => - areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex({ - oldIndex, - newIndex, - }), - ); - return !correspondingNewIndex; - }) - .map(oldIndex => { - return getDeleteIndexScriptDto({ index: oldIndex, collection, ddlProvider }); - }) - .filter(Boolean); - }; + return oldIndexes + .filter(oldIndex => { + const correspondingNewIndex = newIndexes.find(newIndex => + areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex({ + oldIndex, + newIndex, + }), + ); + return !correspondingNewIndex; + }) + .map(oldIndex => { + return getDeleteIndexScriptDto({ index: oldIndex, collection, ddlProvider }); + }) + .filter(Boolean); +}; +/** + * @param {{ + * newIndex: Object, + * oldIndex: Object, + * collection: Object, + * ddlProvider: Object + * }} param + * @return {Array} + */ const getModifyIndexScriptDto = ({ newIndex, oldIndex, collection, ddlProvider }) => { const scripts = []; @@ -214,6 +191,8 @@ const getModifyIndexScriptDto = ({ newIndex, oldIndex, collection, ddlProvider } collection, ddlProvider, }); + // if an index was recreated, and comment was removed, + // no need to generate separate script to drop comment scripts.push(deleteIndexScriptDto, createIndexScriptDto); if (newIndex.indxDescription) { @@ -233,7 +212,7 @@ const getModifyIndexScriptDto = ({ newIndex, oldIndex, collection, ddlProvider } schemaName, oldIndexName: oldIndex.indxName, newIndexName: newIndex.indxName, - isActivated: isEntityActivated(collection) && newIndex.isActivated, + isActivated: isObjectInDeltaModelActivated(collection) && newIndex.isActivated, }); scripts.push(renameScript); @@ -249,10 +228,12 @@ const getModifyIndexScriptDto = ({ newIndex, oldIndex, collection, ddlProvider } }; /** - * @param {Object} collection - * @param {Object} additionalDataForDdlProvider + * @param {{ + * collection: Object, + * ddlProvider: Object + * }} param * @return {Array} - * */ + */ const getModifiedIndexesScriptDtos = ({ collection, ddlProvider }) => { const newIndexes = collection?.role?.compMod?.Indxs?.new || []; const oldIndexes = collection?.role?.compMod?.Indxs?.old || []; @@ -286,15 +267,20 @@ const getModifiedIndexesScriptDtos = ({ collection, ddlProvider }) => { }; /** - * @param {Object} collection + * @param {{ + * ddlProvider: Object, + * collection: Object + * }} param * @return {Array} - * */ + */ const getModifyIndexesScriptDtos = ({ ddlProvider, collection }) => { - const deletedIndexesScriptDtos = getDeletedIndexesScriptDtos(ddlProvider)({ + const deletedIndexesScriptDtos = getDeletedIndexesScriptDtos({ collection, + ddlProvider, }); - const addedIndexesScriptDtos = getAddedIndexesScriptDtos(ddlProvider)({ + const addedIndexesScriptDtos = getAddedIndexesScriptDtos({ collection, + ddlProvider, }); const modifiedIndexesScriptDtos = getModifiedIndexesScriptDtos({ collection, diff --git a/forward_engineering/alterScript/alterScriptHelpers/indexHelpers/addNameToIndexKey.js b/forward_engineering/alterScript/alterScriptHelpers/indexHelpers/addNameToIndexKey.js new file mode 100644 index 0000000..1140ce4 --- /dev/null +++ b/forward_engineering/alterScript/alterScriptHelpers/indexHelpers/addNameToIndexKey.js @@ -0,0 +1,57 @@ +const { toPairs } = require('lodash'); +const { getSchemaNameFromCollection } = require('../../../utils/general'); + +/** + * @param {string} columnId + * @param {Object} collection + * @return {string | undefined} + * */ +const getColumnNameById = ({ columnId, collection }) => { + const collectionProperties = toPairs(collection?.role?.properties || collection?.properties || {}).map( + ([name, value]) => ({ ...value, name }), + ); + const oldProperties = (collection?.role?.compMod?.oldProperties || []).map(property => ({ + ...property, + GUID: property.id, + })); + const properties = collectionProperties.length > 0 ? collectionProperties : oldProperties; + const propertySchema = properties.find(fieldJsonSchema => fieldJsonSchema.GUID === columnId); + + if (propertySchema) { + return propertySchema.name; + } + + return undefined; +}; + +/** + * @param {AlterIndexDto} index + * @param {Object} collection + * @return {Object} + * */ +const addNameToIndexKey = ({ index, collection }) => { + if (!index?.indxKey?.length) { + return index; + } + + const schemaName = getSchemaNameFromCollection({ collection }); + + const columnsWithNames = index.indxKey + .map(column => { + return { + ...column, + name: getColumnNameById({ columnId: column.keyId, collection }), + }; + }) + .filter(column => Boolean(column.name)); + + return { + ...index, + schemaName, + indxKey: columnsWithNames, + }; +}; + +module.exports = { + addNameToIndexKey, +}; diff --git a/forward_engineering/alterScript/alterScriptHelpers/indexHelpers/commentsHelper.js b/forward_engineering/alterScript/alterScriptHelpers/indexHelpers/commentsHelper.js index 3993c54..4fa0526 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/indexHelpers/commentsHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/indexHelpers/commentsHelper.js @@ -3,7 +3,7 @@ const { getSchemaNameFromCollection, getNamePrefixedWithSchemaName, wrapInQuotes, - isEntityActivated, + isObjectInDeltaModelActivated, } = require('../../../utils/general'); const { getIndexCommentStatement, @@ -11,10 +11,12 @@ const { } = require('../../../ddlProvider/ddlHelpers/comment/commentHelper'); /** - * @param {Object} newIndex - * @param {Object} oldIndex - * @param {Object} collection - * @return {AlterScriptDto | undefined} + * @param {{ + * newIndex: Object, + * oldIndex: Object, + * collection: Object + * }} param + * @returns {AlterScriptDto|undefined} */ const getModifyIndexCommentsScriptDtos = ({ newIndex, oldIndex, collection }) => { const newDescription = newIndex.indxDescription; @@ -25,7 +27,7 @@ const getModifyIndexCommentsScriptDtos = ({ newIndex, oldIndex, collection }) => schemaName, }); - const isActivated = isEntityActivated(collection) && newIndex.isActivated; + const isActivated = isObjectInDeltaModelActivated(collection) && newIndex.isActivated; if (newDescription && newDescription !== oldDescription) { const script = getIndexCommentStatement({ diff --git a/forward_engineering/ddlProvider/ddlProvider.js b/forward_engineering/ddlProvider/ddlProvider.js index 52050cc..5dca1a6 100644 --- a/forward_engineering/ddlProvider/ddlProvider.js +++ b/forward_engineering/ddlProvider/ddlProvider.js @@ -10,7 +10,6 @@ const { toArray, hasType, setTab, - isEntityActivated, } = require('../utils/general.js'); const { assignTemplates } = require('../utils/assignTemplates'); const keyHelper = require('./ddlHelpers/key/keyHelper.js'); diff --git a/forward_engineering/utils/general.js b/forward_engineering/utils/general.js index 05e86b9..37aa491 100644 --- a/forward_engineering/utils/general.js +++ b/forward_engineering/utils/general.js @@ -150,16 +150,6 @@ const checkFieldPropertiesChanged = (compMod, propertiesToCheck) => { return propertiesToCheck.some(prop => compMod?.oldField[prop] !== compMod?.newField[prop]); }; -/** - * @param {object} collection - * @returns {boolean} - */ -const isEntityActivated = collection => { - const isContainerActivated = isParentContainerActivated(collection); - const isCollectionActivated = isObjectInDeltaModelActivated(collection); - return isContainerActivated && isCollectionActivated; -}; - /** * * @template {object} T @@ -208,5 +198,4 @@ module.exports = { getSchemaNameFromCollection, getUpdatedProperties, checkFieldPropertiesChanged, - isEntityActivated, };