diff --git a/forward_engineering/ddlProvider.js b/forward_engineering/ddlProvider.js index 17c87b97..99a178ec 100644 --- a/forward_engineering/ddlProvider.js +++ b/forward_engineering/ddlProvider.js @@ -299,7 +299,7 @@ module.exports = (baseProvider, options, app) => { return { statement: assignTemplates(templates.createForeignKeyConstraint, { - primaryTable: getTableName(primaryTable, primarySchemaName || schemaData.schemaName, true), + primaryTable: getTableName(primaryTable, primarySchemaName || schemaData?.schemaName, true), name: wrapInBrackets(relationshipName), foreignKey: isActivated ? foreignKeysToString(foreignKey) : foreignActiveKeysToString(foreignKey), primaryKey: isActivated ? foreignKeysToString(primaryKey) : foreignActiveKeysToString(primaryKey), diff --git a/forward_engineering/helpers/alterScriptFromDeltaHelper.js b/forward_engineering/helpers/alterScriptFromDeltaHelper.js index df89e30a..a9604d68 100644 --- a/forward_engineering/helpers/alterScriptFromDeltaHelper.js +++ b/forward_engineering/helpers/alterScriptFromDeltaHelper.js @@ -52,10 +52,61 @@ module.exports = _ => { return { addContainersScriptsDtos, deleteContainersScriptsDtos }; }; + const sortCollectionsByRelationships = (collections, relationships) => { + const collectionToChildren = new Map(); // Map of collection IDs to their children + const collectionParentCount = new Map(); // Track how many parents each collection has + + // Initialize maps + for (const collection of collections) { + collectionToChildren.set(collection.role.id, []); + collectionParentCount.set(collection.role.id, 0); + } + + for (const relationship of relationships) { + const parent = relationship.role.parentCollection; + const child = relationship.role.childCollection; + if (collectionToChildren.has(parent)) { + collectionToChildren.get(parent).push(child); + } + collectionParentCount.set(child, (collectionParentCount.get(child) || 0) + 1); + } + + // Find collections with no parents + const queue = collections + .filter(collection => collectionParentCount.get(collection.role.id) === 0) + .map(collection => collection.role.id); + + const sortedIds = []; + + // Sort collections + while (queue.length > 0) { + const current = queue.shift(); + sortedIds.push(current); + + for (const child of collectionToChildren.get(current) || []) { + collectionParentCount.set(child, collectionParentCount.get(child) - 1); + if (collectionParentCount.get(child) <= 0) { + queue.push(child); + } + } + } + + // Add any unvisited collection + for (const collection of collections) { + if (!sortedIds.includes(collection.role.id)) { + sortedIds.unshift(collection.role.id); + } + } + + // Map back to collection objects in sorted order + const idToCollection = Object.fromEntries(collections.map(c => [c.role.id, c])); + return sortedIds.map(id => idToCollection[id]); + }; + /** * @return {{ [key: string]: Array}}} * */ - const getAlterCollectionsScriptsDtos = (collection, app, options) => { + const getAlterCollectionsScriptsDtos = (collection, app, options, inlineDeltaRelationships = []) => { const { getAddCollectionScriptDto, getDeleteCollectionScriptDto, @@ -80,9 +131,10 @@ module.exports = _ => { .filter(Boolean) .map(item => Object.values(item.properties)[0]); - const createCollectionsScriptsDtos = createScriptsData - .filter(collection => collection.compMod?.created) - .flatMap(getAddCollectionScriptDto); + const createCollectionsScriptsDtos = sortCollectionsByRelationships( + createScriptsData.filter(collection => collection.compMod?.created), + inlineDeltaRelationships, + ).flatMap(collection => getAddCollectionScriptDto(collection, inlineDeltaRelationships)); const deleteCollectionScriptsDtos = deleteScriptsData .filter(collection => collection.compMod?.deleted) .flatMap(getDeleteCollectionScriptDto); @@ -175,7 +227,7 @@ module.exports = _ => { return { deleteUdtScriptsDtos, createUdtScriptsDtos }; }; - const getAlterRelationshipsScriptDtos = (collection, app) => { + const getAlterRelationshipsScriptDtos = (collection, app, ignoreRelationshipIDs = []) => { const _ = app.require('lodash'); const ddlProvider = require('../ddlProvider')(null, null, app); const { @@ -188,17 +240,26 @@ module.exports = _ => { .concat(collection.properties?.relationships?.properties?.added?.items) .filter(Boolean) .map(item => Object.values(item.properties)[0]) - .filter(relationship => relationship?.role?.compMod?.created); + .filter( + relationship => + relationship?.role?.compMod?.created && !ignoreRelationshipIDs.includes(relationship?.role?.id), + ); const deletedRelationships = [] .concat(collection.properties?.relationships?.properties?.deleted?.items) .filter(Boolean) .map(item => Object.values(item.properties)[0]) - .filter(relationship => relationship?.role?.compMod?.deleted); + .filter( + relationship => + relationship?.role?.compMod?.deleted && !ignoreRelationshipIDs.includes(relationship?.role?.id), + ); const modifiedRelationships = [] .concat(collection.properties?.relationships?.properties?.modified?.items) .filter(Boolean) .map(item => Object.values(item.properties)[0]) - .filter(relationship => relationship?.role?.compMod?.modified); + .filter( + relationship => + relationship?.role?.compMod?.modified && !ignoreRelationshipIDs.includes(relationship?.role?.id), + ); const deleteFkScriptDtos = getDeleteForeignKeyScriptDtos(ddlProvider, _)(deletedRelationships); const addFkScriptDtos = getAddForeignKeyScriptDtos(ddlProvider, _)(addedRelationships); @@ -349,19 +410,39 @@ module.exports = _ => { return assertNoEmptyStatements(scripts); }; + const getInlineRelationships = ({ collection, options }) => { + if (options?.scriptGenerationOptions?.feActiveOptions?.foreignKeys !== 'inline') { + return []; + } + + const addedCollectionIDs = [] + .concat(collection.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(collection.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; + }; + /** * @return Array * */ const getAlterScriptDtos = (collection, app, options) => { + const inlineDeltaRelationships = getInlineRelationships({ collection, options }); + const ignoreRelationshipIDs = inlineDeltaRelationships.map(relationship => relationship.role.id); const script = { - ...getAlterCollectionsScriptsDtos(collection, app, options), + ...getAlterCollectionsScriptsDtos(collection, app, options, inlineDeltaRelationships), ...getAlterContainersScriptsDtos(collection, app, options), ...getAlterViewScriptsDtos(collection, app, options), ...getAlterModelDefinitionsScriptsDtos(collection, app, options), ...getContainersCommentsAlterScriptsDtos(collection, app, options), ...getCollectionsCommentsAlterScriptsDtos(collection, app, options), ...getViewsCommentsAlterScriptsDtos(collection, app, options), - ...getAlterRelationshipsScriptDtos(collection, app), + ...getAlterRelationshipsScriptDtos(collection, app, ignoreRelationshipIDs), }; return [ diff --git a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js index 8837a4d2..dee40dae 100644 --- a/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/alterEntityHelper.js @@ -20,12 +20,13 @@ module.exports = (app, options) => { const { getModifyPkConstraintsScriptDtos } = require('./entityHelpers/primaryKeyHelper'); const { getModifyNonNullColumnsScriptDtos } = require('./columnHelpers/notNullConstraintsHelper'); const { getModifyUniqueConstraintsScriptDtos } = require('./entityHelpers/uniqueConstraintHelper'); + const { getRelationshipName } = require('./alterRelationshipsHelper'); /** * @param {Collection} collection * @return Array * */ - const getAddCollectionScriptDto = collection => { + const getAddCollectionScriptDto = (collection, inlineDeltaRelationships) => { //done but need clean up const schemaName = collection.compMod.keyspaceName; const schemaData = { schemaName }; @@ -45,11 +46,33 @@ module.exports = (app, options) => { const checkConstraints = (jsonSchema.chkConstr || []).map(check => ddlProvider.createCheckConstraint(ddlProvider.hydrateCheckConstraint(check)), ); + + const foreignKeyConstraints = inlineDeltaRelationships + .filter(relationship => relationship.role.childCollection === collection.role.id) + .map(relationship => { + const compMod = relationship.role.compMod; + const relationshipName = + compMod.code?.new || compMod.name?.new || getRelationshipName(relationship) || ''; + return ddlProvider.createForeignKeyConstraint({ + name: relationshipName, + foreignKey: compMod.child.collection.fkFields, + primaryKey: compMod.parent.collection.fkFields, + customProperties: compMod.customProperties?.new, + foreignTable: compMod.child.collection.name, + foreignSchemaName: compMod.child.bucket.name, + foreignTableActivated: compMod.child.collection.isActivated, + primaryTable: compMod.parent.collection.name, + primarySchemaName: compMod.parent.bucket.name, + primaryTableActivated: compMod.parent.collection.isActivated, + isActivated: Boolean(relationship.role?.compMod?.isActivated?.new), + }); + }); + const tableData = { name: tableName, columns: columnDefinitions.map(ddlProvider.convertColumnDefinition), checkConstraints: checkConstraints, - foreignKeyConstraints: [], + foreignKeyConstraints, schemaData, columnDefinitions, }; diff --git a/forward_engineering/helpers/alterScriptHelpers/alterRelationshipsHelper.js b/forward_engineering/helpers/alterScriptHelpers/alterRelationshipsHelper.js index a5c7f297..02989d8e 100644 --- a/forward_engineering/helpers/alterScriptHelpers/alterRelationshipsHelper.js +++ b/forward_engineering/helpers/alterScriptHelpers/alterRelationshipsHelper.js @@ -164,4 +164,5 @@ module.exports = { getDeleteForeignKeyScriptDtos, getModifyForeignKeyScriptDtos, getAddForeignKeyScriptDtos, + getRelationshipName, };