From 1740dc3e90a2340a9a30469d24474c5c247bdc71 Mon Sep 17 00:00:00 2001 From: Alik Rakhmonov Date: Tue, 16 Dec 2025 11:39:36 +0100 Subject: [PATCH 1/4] HCK-14001: missing FK in CREATE statement --- forward_engineering/config.json | 6 ++-- .../generateContainerScript.js | 15 +++------- .../helpers/alterScriptFromDeltaHelper.js | 6 ++-- ...tionshipsHelper.js => foreignKeyHelper.js} | 4 +-- .../helpers/foreignKeyHelper.js | 28 ++----------------- 5 files changed, 15 insertions(+), 44 deletions(-) rename forward_engineering/helpers/alterScriptHelpers/{alterRelationshipsHelper.js => foreignKeyHelper.js} (98%) diff --git a/forward_engineering/config.json b/forward_engineering/config.json index 048d2d5..da24c7c 100644 --- a/forward_engineering/config.json +++ b/forward_engineering/config.json @@ -88,12 +88,12 @@ "disabled": false, "value": { "inline": { - "default": false, - "disabled": true, + "default": true, + "disabled": false, "disabledLabel": "" }, "separate": { - "default": true, + "default": false, "disabled": false, "disabledLabel": "" }, diff --git a/forward_engineering/generateContainerScript.js b/forward_engineering/generateContainerScript.js index 5b05891..ee41165 100644 --- a/forward_engineering/generateContainerScript.js +++ b/forward_engineering/generateContainerScript.js @@ -8,7 +8,6 @@ const { getTableStatement } = require('./helpers/tableHelper'); const { getIndexes } = require('./helpers/indexHelper'); const { buildScript } = require('./helpers/buildScript'); const { parseEntities } = require('./helpers/parseEntities'); -const { getForeignKeys } = require('./helpers/foreignKeyHelper'); const { getWorkloadManagementStatements } = require('./helpers/getWorkloadManagementStatements'); const { getIsPkOrFkConstraintAvailable } = require('./helpers/constraintHelper'); @@ -61,6 +60,8 @@ const generateContainerScript = (data, logger, callback, app) => { }); const entities = data.entities.reduce((result, entityId) => { + const foreignKeys = foreignKeyHelper.getForeignKeyStatementsByHashItem(foreignKeyHashTable[entityId] || {}); + const args = [ containerData, data.entityData[entityId], @@ -69,22 +70,14 @@ const generateContainerScript = (data, logger, callback, app) => { ]; return result.concat([ - getTableStatement(...args, null, areColumnConstraintsAvailable, isPkOrFkConstraintAvailable), + getTableStatement(...args, foreignKeys, areColumnConstraintsAvailable, isPkOrFkConstraintAvailable), getIndexes(...args, areColumnConstraintsAvailable), ]); }, []); - const foreignKeys = getForeignKeys(data, foreignKeyHashTable, isPkOrFkConstraintAvailable); - callback( null, - buildScript(needMinify)( - ...workloadManagementStatements, - databaseStatement, - ...entities, - ...viewsScripts, - foreignKeys, - ), + buildScript(needMinify)(...workloadManagementStatements, databaseStatement, ...entities, ...viewsScripts), ); } catch (e) { logger.log('error', { message: e.message, stack: e.stack }, 'Hive Forward-Engineering Error'); diff --git a/forward_engineering/helpers/alterScriptFromDeltaHelper.js b/forward_engineering/helpers/alterScriptFromDeltaHelper.js index 2fde392..3673904 100644 --- a/forward_engineering/helpers/alterScriptFromDeltaHelper.js +++ b/forward_engineering/helpers/alterScriptFromDeltaHelper.js @@ -11,7 +11,7 @@ const { getAddColumnsScripts, getModifyColumnsScripts, } = require('./alterScriptHelpers/alterEntityHelper'); -const { getAlterRelationshipsScripts } = require('./alterScriptHelpers/alterRelationshipsHelper'); +const { getAlterForeignKeyScripts } = require('./alterScriptHelpers/foreignKeyHelper'); const { getAddViewsScripts, getDeleteViewsScripts, @@ -122,13 +122,13 @@ const getAlterScript = (schema, definitions, data, app, needMinify, sqlFormatter const containerScripts = getAlterContainersScripts(schema, provider); const { currentSchemaName, ...collectionScripts } = getAlterCollectionsScripts(schema, definitions, provider, data); const viewScripts = getAlterViewsScripts(schema, provider); - const relationshipScripts = getAlterRelationshipsScripts(schema, provider, currentSchemaName); + const foreignKeyScripts = getAlterForeignKeyScripts(schema, provider, currentSchemaName); let scripts = { ...containerScripts, ...collectionScripts, ...viewScripts, - ...relationshipScripts, + ...foreignKeyScripts, }; scripts = [ diff --git a/forward_engineering/helpers/alterScriptHelpers/alterRelationshipsHelper.js b/forward_engineering/helpers/alterScriptHelpers/foreignKeyHelper.js similarity index 98% rename from forward_engineering/helpers/alterScriptHelpers/alterRelationshipsHelper.js rename to forward_engineering/helpers/alterScriptHelpers/foreignKeyHelper.js index 9adc447..040ee44 100644 --- a/forward_engineering/helpers/alterScriptHelpers/alterRelationshipsHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/foreignKeyHelper.js @@ -124,7 +124,7 @@ const getModifyForeignKeyScript = provider => relationship => { ); }; -const getAlterRelationshipsScripts = (schema, provider, initialSchemaName) => { +const getAlterForeignKeyScripts = (schema, provider, initialSchemaName) => { let currentSchemaName = initialSchemaName; const generateAddFkScripts = (addedRelationships, getScript) => { @@ -184,5 +184,5 @@ const getAlterRelationshipsScripts = (schema, provider, initialSchemaName) => { }; module.exports = { - getAlterRelationshipsScripts, + getAlterForeignKeyScripts, }; diff --git a/forward_engineering/helpers/foreignKeyHelper.js b/forward_engineering/helpers/foreignKeyHelper.js index 084a9ff..481498a 100644 --- a/forward_engineering/helpers/foreignKeyHelper.js +++ b/forward_engineering/helpers/foreignKeyHelper.js @@ -121,13 +121,13 @@ const getForeignKeyStatementsByHashItem = hashItem => { const keyName = firstKey.code || firstKey.name || ''; const constraintName = keyName.includes(' ') ? `\`${keyName}\`` : keyName; const parentTableName = firstKey.parentTableName; - const childTableName = firstKey.childTableName; const disableNoValidate = keys.some(item => item?.disableNoValidate); const childColumns = keys.map(item => item.childColumn).join(', '); const parentColumns = keys.map(item => item.parentColumn).join(', '); const isActivated = firstKey.isActivated; + const constraintNameStatement = constraintName ? `CONSTRAINT ${constraintName} ` : ''; - const statement = `ALTER TABLE ${childTableName} ADD CONSTRAINT ${constraintName} FOREIGN KEY (${childColumns}) REFERENCES ${parentTableName}(${parentColumns}) ${disableNoValidate ? 'DISABLE NOVALIDATE' : ''};`; + const statement = `,${constraintNameStatement}FOREIGN KEY (${childColumns}) REFERENCES ${parentTableName}(${parentColumns}) ${disableNoValidate ? 'DISABLE NOVALIDATE' : ''}`; return commentDeactivatedStatements(statement, isActivated); }) @@ -144,29 +144,7 @@ const getPreparedForeignColumns = (columnsPaths, idToNameHashTable) => { } }; -const getForeignKeys = (data, foreignKeyHashTable, areForeignPrimaryKeyConstraintsAvailable) => { - if (!areForeignPrimaryKeyConstraintsAvailable) { - return null; - } - - const dbName = replaceSpaceWithUnderscore(getName(getTab(0, data.containerData))); - - const foreignKeysStatements = data.entities - .reduce((result, entityId) => { - const foreignKeyStatement = getForeignKeyStatementsByHashItem(foreignKeyHashTable[entityId] || {}); - - if (foreignKeyStatement) { - return [...result, foreignKeyStatement]; - } - - return result; - }, []) - .join('\n'); - - return foreignKeysStatements ? `\nUSE ${dbName};${foreignKeysStatements}` : ''; -}; - module.exports = { getForeignKeyHashTable, - getForeignKeys, + getForeignKeyStatementsByHashItem, }; From a33047e4c9372fbdef12ce623677057cdeeccb93 Mon Sep 17 00:00:00 2001 From: Alik Rakhmonov Date: Tue, 16 Dec 2025 11:43:44 +0100 Subject: [PATCH 2/4] rename --- forward_engineering/helpers/alterScriptFromDeltaHelper.js | 2 +- .../{foreignKeyHelper.js => aliterForeignKeyHelper.js} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename forward_engineering/helpers/alterScriptHelpers/{foreignKeyHelper.js => aliterForeignKeyHelper.js} (100%) diff --git a/forward_engineering/helpers/alterScriptFromDeltaHelper.js b/forward_engineering/helpers/alterScriptFromDeltaHelper.js index 3673904..7b5af8a 100644 --- a/forward_engineering/helpers/alterScriptFromDeltaHelper.js +++ b/forward_engineering/helpers/alterScriptFromDeltaHelper.js @@ -11,7 +11,7 @@ const { getAddColumnsScripts, getModifyColumnsScripts, } = require('./alterScriptHelpers/alterEntityHelper'); -const { getAlterForeignKeyScripts } = require('./alterScriptHelpers/foreignKeyHelper'); +const { getAlterForeignKeyScripts } = require('./alterScriptHelpers/alterForeignKeyHelper'); const { getAddViewsScripts, getDeleteViewsScripts, diff --git a/forward_engineering/helpers/alterScriptHelpers/foreignKeyHelper.js b/forward_engineering/helpers/alterScriptHelpers/aliterForeignKeyHelper.js similarity index 100% rename from forward_engineering/helpers/alterScriptHelpers/foreignKeyHelper.js rename to forward_engineering/helpers/alterScriptHelpers/aliterForeignKeyHelper.js From 3881eb3fd3ce2478f59ca6bd8315ef6b5780337d Mon Sep 17 00:00:00 2001 From: Alik Rakhmonov Date: Tue, 16 Dec 2025 11:44:12 +0100 Subject: [PATCH 3/4] fix --- .../{aliterForeignKeyHelper.js => alterForeignKeyHelper.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename forward_engineering/helpers/alterScriptHelpers/{aliterForeignKeyHelper.js => alterForeignKeyHelper.js} (100%) diff --git a/forward_engineering/helpers/alterScriptHelpers/aliterForeignKeyHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterForeignKeyHelper.js similarity index 100% rename from forward_engineering/helpers/alterScriptHelpers/aliterForeignKeyHelper.js rename to forward_engineering/helpers/alterScriptHelpers/alterForeignKeyHelper.js From 8abb26d7db3d4a61c3a62e26ee5db84e4826da7b Mon Sep 17 00:00:00 2001 From: Alik Rakhmonov Date: Tue, 16 Dec 2025 12:33:58 +0100 Subject: [PATCH 4/4] inline in alter --- .../helpers/alterScriptFromDeltaHelper.js | 38 ++++++++++++-- .../alterScriptHelpers/alterEntityHelper.js | 51 +++++++++++++++---- .../alterForeignKeyHelper.js | 8 ++- .../helpers/foreignKeyHelper.js | 22 +++++++- 4 files changed, 99 insertions(+), 20 deletions(-) diff --git a/forward_engineering/helpers/alterScriptFromDeltaHelper.js b/forward_engineering/helpers/alterScriptFromDeltaHelper.js index 7b5af8a..68f2033 100644 --- a/forward_engineering/helpers/alterScriptFromDeltaHelper.js +++ b/forward_engineering/helpers/alterScriptFromDeltaHelper.js @@ -37,7 +37,7 @@ const getAlterContainersScripts = (schema, provider) => { }; }; -const getAlterCollectionsScripts = (schema, definitions, provider, data) => { +const getAlterCollectionsScripts = ({ schema, definitions, provider, data, inlineDeltaRelationships }) => { let currentSchemaName = ''; const setCurrentSchemaName = (entity, getScript) => { @@ -57,7 +57,9 @@ const getAlterCollectionsScripts = (schema, definitions, provider, data) => { const addedCollectionsScripts = addedCollectionsItems .filter(item => item.compMod?.created) - .flatMap(item => setCurrentSchemaName(item, getAddCollectionsScripts(definitions, data))); + .flatMap(item => + setCurrentSchemaName(item, getAddCollectionsScripts(definitions, data, inlineDeltaRelationships)), + ); const deletedCollectionsScripts = deletedCollectionsItems .filter(item => item.compMod?.deleted) .flatMap(getDeleteCollectionsScripts(provider)); @@ -117,12 +119,40 @@ const getAlterViewsScripts = (schema, provider) => { }; }; +const getInlineRelationships = ({ schema, options }) => { + if (options?.scriptGenerationOptions?.feActiveOptions?.foreignKeys !== 'inline') { + return []; + } + + const addedCollectionIDs = [] + .concat(schema.properties?.entities?.properties?.added?.items) + .filter(item => item && Object.values(item.properties)?.[0]?.compMod?.created) + .map(item => Object.values(item.properties)[0].role.id); + + const addedRelationships = [] + .concat(schema.properties?.relationships?.properties?.added?.items) + .map(item => item && Object.values(item.properties)[0]) + .filter(r => r?.role?.compMod?.created && addedCollectionIDs.includes(r?.role?.childCollection)); + + return addedRelationships; +}; + const getAlterScript = (schema, definitions, data, app, needMinify, sqlFormatter) => { const provider = require('./alterScriptHelpers/provider')(app); + + const inlineDeltaRelationships = getInlineRelationships({ schema, options: data.options }); + const ignoreRelationshipIDs = inlineDeltaRelationships.map(relationship => relationship.role.id); + const containerScripts = getAlterContainersScripts(schema, provider); - const { currentSchemaName, ...collectionScripts } = getAlterCollectionsScripts(schema, definitions, provider, data); + const { currentSchemaName, ...collectionScripts } = getAlterCollectionsScripts({ + schema, + definitions, + provider, + data, + inlineDeltaRelationships, + }); const viewScripts = getAlterViewsScripts(schema, provider); - const foreignKeyScripts = getAlterForeignKeyScripts(schema, provider, currentSchemaName); + const foreignKeyScripts = getAlterForeignKeyScripts({ schema, provider, currentSchemaName, ignoreRelationshipIDs }); let scripts = { ...containerScripts, diff --git a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js index 10e3b84..982d423 100644 --- a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js @@ -21,6 +21,7 @@ const { getModifyUkConstraintsScripts } = require('./uniqueKeyHelper'); const { getModifyNonNullColumnsScripts } = require('./nonNullConstraintHelper'); const { getModifyDefaultValueConstraintsScripts } = require('./defaultConstraintHelper'); const { getModifyCheckConstraintsScripts } = require('./checkConstraintHelper'); +const { getForeignKeyConstraint } = require('../foreignKeyHelper'); const tableProperties = [ 'compositePartitionKey', @@ -157,16 +158,48 @@ const generateModifyCollectionScript = (entity, definitions, provider) => { return { type: 'modified', script: provider.alterTable(hydratedAlterTable) }; }; -const getAddCollectionsScripts = (definitions, data) => entity => { - const properties = getEntityProperties(entity); - const indexes = _.get(entity, 'role.SecIndxs', []); - const hydratedCollection = hydrateCollection(entity, definitions); - const isPkOrFkConstraintAvailable = getIsPkOrFkConstraintAvailable(data); - const collectionScript = getTableStatement(...hydratedCollection, null, true, isPkOrFkConstraintAvailable); - const indexScript = getIndexes(...hydrateAddIndexes(entity, indexes, properties, definitions)); +const getAddCollectionsScripts = + (definitions, data, inlineDeltaRelationships = []) => + entity => { + const properties = getEntityProperties(entity); + const indexes = _.get(entity, 'role.SecIndxs', []); + const hydratedCollection = hydrateCollection(entity, definitions); + const isPkOrFkConstraintAvailable = getIsPkOrFkConstraintAvailable(data); - return prepareScript(collectionScript, indexScript); -}; + const foreignKeyConstraints = inlineDeltaRelationships + .filter(relationship => relationship.role.childCollection === entity.role.id) + .map(relationship => { + const compMod = relationship.role.compMod; + const relationshipName = + compMod.code?.new || compMod.name?.new || relationship.role.code || relationship.role.name || ''; + const constraintName = relationshipName.includes(' ') ? `\`${relationshipName}\`` : relationshipName; + const parentTableName = compMod.parent.collection.name; + const childColumns = compMod.child.collection.fkFields.map(field => field.name).join(', '); + const parentColumns = compMod.parent.collection.fkFields.map(field => field.name).join(', '); + const disableNoValidate = relationship.role?.customProperties?.disableNoValidate; + + const statement = getForeignKeyConstraint({ + constraintName, + childColumns, + parentTableName, + parentColumns, + disableNoValidate, + }); + + return statement; + }) + .join('\n'); + + const collectionScript = getTableStatement( + ...hydratedCollection, + foreignKeyConstraints, + true, + isPkOrFkConstraintAvailable, + ); + const indexScript = getIndexes(...hydrateAddIndexes(entity, indexes, properties, definitions)); + + return prepareScript(collectionScript, indexScript); + }; const getDeleteCollectionsScripts = provider => entity => { const entityData = { ...entity, ..._.get(entity, 'role', {}) }; diff --git a/forward_engineering/helpers/alterScriptHelpers/alterForeignKeyHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterForeignKeyHelper.js index 040ee44..0821f7f 100644 --- a/forward_engineering/helpers/alterScriptHelpers/alterForeignKeyHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/alterForeignKeyHelper.js @@ -124,9 +124,7 @@ const getModifyForeignKeyScript = provider => relationship => { ); }; -const getAlterForeignKeyScripts = (schema, provider, initialSchemaName) => { - let currentSchemaName = initialSchemaName; - +const getAlterForeignKeyScripts = ({ schema, provider, currentSchemaName, ignoreRelationshipIDs = [] }) => { const generateAddFkScripts = (addedRelationships, getScript) => { return addedRelationships.filter(relationship => canRelationshipBeAdded(relationship)).flatMap(getScript); }; @@ -162,10 +160,10 @@ const getAlterForeignKeyScripts = (schema, provider, initialSchemaName) => { }; const deletedRelationships = getItems(schema, 'relationships', 'deleted').filter( - relationship => relationship.role?.compMod?.deleted, + relationship => relationship.role?.compMod?.deleted && !ignoreRelationshipIDs.includes(relationship?.role?.id), ); const addedRelationships = getItems(schema, 'relationships', 'added').filter( - relationship => relationship.role?.compMod?.created, + relationship => relationship.role?.compMod?.created && !ignoreRelationshipIDs.includes(relationship?.role?.id), ); const modifiedRelationships = getItems(schema, 'relationships', 'modified'); diff --git a/forward_engineering/helpers/foreignKeyHelper.js b/forward_engineering/helpers/foreignKeyHelper.js index 481498a..c4ea3e0 100644 --- a/forward_engineering/helpers/foreignKeyHelper.js +++ b/forward_engineering/helpers/foreignKeyHelper.js @@ -113,6 +113,18 @@ const getForeignKeyHashTable = ({ }, {}); }; +const getForeignKeyConstraint = ({ + constraintName, + childColumns, + parentTableName, + parentColumns, + disableNoValidate, +}) => { + const constraintNameStatement = constraintName ? `CONSTRAINT ${constraintName} ` : ''; + const statement = `,${constraintNameStatement}FOREIGN KEY (${childColumns}) REFERENCES ${parentTableName}(${parentColumns}) ${disableNoValidate ? 'DISABLE NOVALIDATE' : ''}`; + return statement; +}; + const getForeignKeyStatementsByHashItem = hashItem => { return Object.keys(hashItem || {}) .map(groupKey => { @@ -125,9 +137,14 @@ const getForeignKeyStatementsByHashItem = hashItem => { const childColumns = keys.map(item => item.childColumn).join(', '); const parentColumns = keys.map(item => item.parentColumn).join(', '); const isActivated = firstKey.isActivated; - const constraintNameStatement = constraintName ? `CONSTRAINT ${constraintName} ` : ''; - const statement = `,${constraintNameStatement}FOREIGN KEY (${childColumns}) REFERENCES ${parentTableName}(${parentColumns}) ${disableNoValidate ? 'DISABLE NOVALIDATE' : ''}`; + const statement = getForeignKeyConstraint({ + constraintName, + childColumns, + parentTableName, + parentColumns, + disableNoValidate, + }); return commentDeactivatedStatements(statement, isActivated); }) @@ -147,4 +164,5 @@ const getPreparedForeignColumns = (columnsPaths, idToNameHashTable) => { module.exports = { getForeignKeyHashTable, getForeignKeyStatementsByHashItem, + getForeignKeyConstraint, };