diff --git a/forward_engineering/alterScript/alterScriptFromDeltaHelper.js b/forward_engineering/alterScript/alterScriptFromDeltaHelper.js index a21f122..bd839ad 100644 --- a/forward_engineering/alterScript/alterScriptFromDeltaHelper.js +++ b/forward_engineering/alterScript/alterScriptFromDeltaHelper.js @@ -58,6 +58,57 @@ const getAlterContainersScriptDtos = ({ collection, app, scriptFormat }) => { return [...addContainersScriptDtos, ...deleteContainersScriptDtos].filter(Boolean); }; +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]); +}; + /** * @param dto {{ * collection: Object, @@ -78,6 +129,7 @@ const getAlterCollectionsScriptDtos = ({ internalDefinitions, externalDefinitions, scriptFormat, + inlineDeltaRelationships = [], }) => { const createScriptsData = [] .concat(collection.properties?.entities?.properties?.added?.items) @@ -94,18 +146,20 @@ const getAlterCollectionsScriptDtos = ({ .filter(Boolean) .map(item => Object.values(item.properties)[0]); - const createCollectionsScriptDtos = createScriptsData - .filter(collection => collection.compMod?.created) - .map( - getAddCollectionScriptDto({ - app, - dbVersion, - modelDefinitions, - internalDefinitions, - externalDefinitions, - scriptFormat, - }), - ); + const createCollectionsScriptDtos = sortCollectionsByRelationships( + createScriptsData.filter(collection => collection.compMod?.created), + inlineDeltaRelationships, + ).map( + getAddCollectionScriptDto({ + app, + dbVersion, + modelDefinitions, + internalDefinitions, + externalDefinitions, + scriptFormat, + inlineDeltaRelationships, + }), + ); const deleteCollectionScriptDtos = deleteScriptsData .filter(collection => collection.compMod?.deleted) .map(getDeleteCollectionScriptDto(app, scriptFormat)); @@ -291,7 +345,7 @@ const getAlterModelDefinitionsScriptDtos = ({ /** * @return Array * */ -const getAlterRelationshipsScriptDtos = ({ collection, app, scriptFormat }) => { +const getAlterRelationshipsScriptDtos = ({ collection, app, scriptFormat, ignoreRelationshipIDs = [] }) => { const ddlProvider = require('../ddlProvider/ddlProvider')( null, { targetScriptOptions: { keyword: scriptFormat } }, @@ -302,19 +356,28 @@ const getAlterRelationshipsScriptDtos = ({ collection, app, scriptFormat }) => { .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, scriptFormat)(deletedRelationships); const addFkScriptDtos = getAddForeignKeyScriptDtos(ddlProvider)(addedRelationships); @@ -383,6 +446,24 @@ const getAlterContainersSequencesScriptDtos = ({ collection, app, dbVersion }) = ); }; +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; +}; + /** * @param data {CoreData} * @param app {App} @@ -404,6 +485,9 @@ const getAlterScriptDtos = (data, app) => { const dbVersion = data.modelData[0]?.dbVersion; + const inlineDeltaRelationships = getInlineRelationships({ collection, options: data.options }); + const ignoreRelationshipIDs = inlineDeltaRelationships.map(relationship => relationship.role.id); + const containersScriptDtos = getAlterContainersScriptDtos({ collection, app, scriptFormat }); const collectionsScriptDtos = getAlterCollectionsScriptDtos({ @@ -414,6 +498,7 @@ const getAlterScriptDtos = (data, app) => { internalDefinitions, externalDefinitions, scriptFormat, + inlineDeltaRelationships, }); const viewScriptDtos = getAlterViewScriptDtos(collection, app, dbVersion, scriptFormat); @@ -428,7 +513,12 @@ const getAlterScriptDtos = (data, app) => { scriptFormat, }); - const relationshipScriptDtos = getAlterRelationshipsScriptDtos({ collection, app, scriptFormat }); + const relationshipScriptDtos = getAlterRelationshipsScriptDtos({ + collection, + app, + scriptFormat, + ignoreRelationshipIDs, + }); const containersSequencesScriptDtos = getAlterContainersSequencesScriptDtos({ collection, app, dbVersion }); diff --git a/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js b/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js index 17ce8cf..5d51d01 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js @@ -17,12 +17,21 @@ const { getModifyNonNullColumnsScriptDtos } = require('./columnHelpers/nonNullCo const { getModifiedDefaultColumnValueScriptDtos } = require('./columnHelpers/defaultValueHelper'); const { getModifyEntityCommentsScriptDtos } = require('./entityHelpers/commentsHelper'); const { getModifiedCommentOnColumnScriptDtos } = require('./columnHelpers/commentsHelper'); +const { getRelationshipName } = require('./alterRelationshipsHelper'); /** * @return {(collection: AlterCollectionDto) => AlterScriptDto | undefined} * */ const getAddCollectionScriptDto = - ({ app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions, scriptFormat }) => + ({ + app, + dbVersion, + modelDefinitions, + internalDefinitions, + externalDefinitions, + scriptFormat, + inlineDeltaRelationships, + }) => collection => { const { createColumnDefinitionBySchema } = require('./createColumnDefinition')(app); const ddlProvider = require('../../ddlProvider/ddlProvider')( @@ -55,11 +64,31 @@ const getAddCollectionScriptDto = 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: getEntityName(jsonSchema), columns: columnDefinitions.map(data => ddlProvider.convertColumnDefinition(data)), checkConstraints: checkConstraints, - foreignKeyConstraints: [], + foreignKeyConstraints, schemaData, columnDefinitions, }; diff --git a/forward_engineering/alterScript/alterScriptHelpers/alterRelationshipsHelper.js b/forward_engineering/alterScript/alterScriptHelpers/alterRelationshipsHelper.js index 150ccc1..84cfe5f 100644 --- a/forward_engineering/alterScript/alterScriptHelpers/alterRelationshipsHelper.js +++ b/forward_engineering/alterScript/alterScriptHelpers/alterRelationshipsHelper.js @@ -157,4 +157,5 @@ module.exports = { getDeleteForeignKeyScriptDtos, getModifyForeignKeyScriptDtos, getAddForeignKeyScriptDtos, + getRelationshipName, };