Skip to content

Commit 270b333

Browse files
HCK-13093: generate FK in delta models inline or separate (#202)
1 parent d7a8405 commit 270b333

File tree

3 files changed

+139
-19
lines changed

3 files changed

+139
-19
lines changed

forward_engineering/alterScript/alterScriptFromDeltaHelper.js

Lines changed: 107 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,57 @@ const getAlterContainersScriptDtos = ({ collection, app, scriptFormat }) => {
5858
return [...addContainersScriptDtos, ...deleteContainersScriptDtos].filter(Boolean);
5959
};
6060

61+
const sortCollectionsByRelationships = (collections, relationships) => {
62+
const collectionToChildren = new Map(); // Map of collection IDs to their children
63+
const collectionParentCount = new Map(); // Track how many parents each collection has
64+
65+
// Initialize maps
66+
for (const collection of collections) {
67+
collectionToChildren.set(collection.role.id, []);
68+
collectionParentCount.set(collection.role.id, 0);
69+
}
70+
71+
for (const relationship of relationships) {
72+
const parent = relationship.role.parentCollection;
73+
const child = relationship.role.childCollection;
74+
if (collectionToChildren.has(parent)) {
75+
collectionToChildren.get(parent).push(child);
76+
}
77+
collectionParentCount.set(child, (collectionParentCount.get(child) || 0) + 1);
78+
}
79+
80+
// Find collections with no parents
81+
const queue = collections
82+
.filter(collection => collectionParentCount.get(collection.role.id) === 0)
83+
.map(collection => collection.role.id);
84+
85+
const sortedIds = [];
86+
87+
// Sort collections
88+
while (queue.length > 0) {
89+
const current = queue.shift();
90+
sortedIds.push(current);
91+
92+
for (const child of collectionToChildren.get(current) || []) {
93+
collectionParentCount.set(child, collectionParentCount.get(child) - 1);
94+
if (collectionParentCount.get(child) <= 0) {
95+
queue.push(child);
96+
}
97+
}
98+
}
99+
100+
// Add any unvisited collection
101+
for (const collection of collections) {
102+
if (!sortedIds.includes(collection.role.id)) {
103+
sortedIds.unshift(collection.role.id);
104+
}
105+
}
106+
107+
// Map back to collection objects in sorted order
108+
const idToCollection = Object.fromEntries(collections.map(c => [c.role.id, c]));
109+
return sortedIds.map(id => idToCollection[id]);
110+
};
111+
61112
/**
62113
* @param dto {{
63114
* collection: Object,
@@ -78,6 +129,7 @@ const getAlterCollectionsScriptDtos = ({
78129
internalDefinitions,
79130
externalDefinitions,
80131
scriptFormat,
132+
inlineDeltaRelationships = [],
81133
}) => {
82134
const createScriptsData = []
83135
.concat(collection.properties?.entities?.properties?.added?.items)
@@ -94,18 +146,20 @@ const getAlterCollectionsScriptDtos = ({
94146
.filter(Boolean)
95147
.map(item => Object.values(item.properties)[0]);
96148

97-
const createCollectionsScriptDtos = createScriptsData
98-
.filter(collection => collection.compMod?.created)
99-
.map(
100-
getAddCollectionScriptDto({
101-
app,
102-
dbVersion,
103-
modelDefinitions,
104-
internalDefinitions,
105-
externalDefinitions,
106-
scriptFormat,
107-
}),
108-
);
149+
const createCollectionsScriptDtos = sortCollectionsByRelationships(
150+
createScriptsData.filter(collection => collection.compMod?.created),
151+
inlineDeltaRelationships,
152+
).map(
153+
getAddCollectionScriptDto({
154+
app,
155+
dbVersion,
156+
modelDefinitions,
157+
internalDefinitions,
158+
externalDefinitions,
159+
scriptFormat,
160+
inlineDeltaRelationships,
161+
}),
162+
);
109163
const deleteCollectionScriptDtos = deleteScriptsData
110164
.filter(collection => collection.compMod?.deleted)
111165
.map(getDeleteCollectionScriptDto(app, scriptFormat));
@@ -291,7 +345,7 @@ const getAlterModelDefinitionsScriptDtos = ({
291345
/**
292346
* @return Array<AlterScriptDto>
293347
* */
294-
const getAlterRelationshipsScriptDtos = ({ collection, app, scriptFormat }) => {
348+
const getAlterRelationshipsScriptDtos = ({ collection, app, scriptFormat, ignoreRelationshipIDs = [] }) => {
295349
const ddlProvider = require('../ddlProvider/ddlProvider')(
296350
null,
297351
{ targetScriptOptions: { keyword: scriptFormat } },
@@ -302,19 +356,28 @@ const getAlterRelationshipsScriptDtos = ({ collection, app, scriptFormat }) => {
302356
.concat(collection.properties?.relationships?.properties?.added?.items)
303357
.filter(Boolean)
304358
.map(item => Object.values(item.properties)[0])
305-
.filter(relationship => relationship?.role?.compMod?.created);
359+
.filter(
360+
relationship =>
361+
relationship?.role?.compMod?.created && !ignoreRelationshipIDs.includes(relationship?.role?.id),
362+
);
306363

307364
const deletedRelationships = []
308365
.concat(collection.properties?.relationships?.properties?.deleted?.items)
309366
.filter(Boolean)
310367
.map(item => Object.values(item.properties)[0])
311-
.filter(relationship => relationship?.role?.compMod?.deleted);
368+
.filter(
369+
relationship =>
370+
relationship?.role?.compMod?.deleted && !ignoreRelationshipIDs.includes(relationship?.role?.id),
371+
);
312372

313373
const modifiedRelationships = []
314374
.concat(collection.properties?.relationships?.properties?.modified?.items)
315375
.filter(Boolean)
316376
.map(item => Object.values(item.properties)[0])
317-
.filter(relationship => relationship?.role?.compMod?.modified);
377+
.filter(
378+
relationship =>
379+
relationship?.role?.compMod?.modified && !ignoreRelationshipIDs.includes(relationship?.role?.id),
380+
);
318381

319382
const deleteFkScriptDtos = getDeleteForeignKeyScriptDtos(ddlProvider, scriptFormat)(deletedRelationships);
320383
const addFkScriptDtos = getAddForeignKeyScriptDtos(ddlProvider)(addedRelationships);
@@ -383,6 +446,24 @@ const getAlterContainersSequencesScriptDtos = ({ collection, app, dbVersion }) =
383446
);
384447
};
385448

449+
const getInlineRelationships = ({ collection, options }) => {
450+
if (options?.scriptGenerationOptions?.feActiveOptions?.foreignKeys !== 'inline') {
451+
return [];
452+
}
453+
454+
const addedCollectionIDs = []
455+
.concat(collection.properties?.entities?.properties?.added?.items)
456+
.filter(item => item && Object.values(item.properties)?.[0]?.compMod?.created)
457+
.map(item => Object.values(item.properties)[0].role.id);
458+
459+
const addedRelationships = []
460+
.concat(collection.properties?.relationships?.properties?.added?.items)
461+
.map(item => item && Object.values(item.properties)[0])
462+
.filter(r => r?.role?.compMod?.created && addedCollectionIDs.includes(r?.role?.childCollection));
463+
464+
return addedRelationships;
465+
};
466+
386467
/**
387468
* @param data {CoreData}
388469
* @param app {App}
@@ -404,6 +485,9 @@ const getAlterScriptDtos = (data, app) => {
404485

405486
const dbVersion = data.modelData[0]?.dbVersion;
406487

488+
const inlineDeltaRelationships = getInlineRelationships({ collection, options: data.options });
489+
const ignoreRelationshipIDs = inlineDeltaRelationships.map(relationship => relationship.role.id);
490+
407491
const containersScriptDtos = getAlterContainersScriptDtos({ collection, app, scriptFormat });
408492

409493
const collectionsScriptDtos = getAlterCollectionsScriptDtos({
@@ -414,6 +498,7 @@ const getAlterScriptDtos = (data, app) => {
414498
internalDefinitions,
415499
externalDefinitions,
416500
scriptFormat,
501+
inlineDeltaRelationships,
417502
});
418503

419504
const viewScriptDtos = getAlterViewScriptDtos(collection, app, dbVersion, scriptFormat);
@@ -428,7 +513,12 @@ const getAlterScriptDtos = (data, app) => {
428513
scriptFormat,
429514
});
430515

431-
const relationshipScriptDtos = getAlterRelationshipsScriptDtos({ collection, app, scriptFormat });
516+
const relationshipScriptDtos = getAlterRelationshipsScriptDtos({
517+
collection,
518+
app,
519+
scriptFormat,
520+
ignoreRelationshipIDs,
521+
});
432522

433523
const containersSequencesScriptDtos = getAlterContainersSequencesScriptDtos({ collection, app, dbVersion });
434524

forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,21 @@ const { getModifyNonNullColumnsScriptDtos } = require('./columnHelpers/nonNullCo
1717
const { getModifiedDefaultColumnValueScriptDtos } = require('./columnHelpers/defaultValueHelper');
1818
const { getModifyEntityCommentsScriptDtos } = require('./entityHelpers/commentsHelper');
1919
const { getModifiedCommentOnColumnScriptDtos } = require('./columnHelpers/commentsHelper');
20+
const { getRelationshipName } = require('./alterRelationshipsHelper');
2021

2122
/**
2223
* @return {(collection: AlterCollectionDto) => AlterScriptDto | undefined}
2324
* */
2425
const getAddCollectionScriptDto =
25-
({ app, dbVersion, modelDefinitions, internalDefinitions, externalDefinitions, scriptFormat }) =>
26+
({
27+
app,
28+
dbVersion,
29+
modelDefinitions,
30+
internalDefinitions,
31+
externalDefinitions,
32+
scriptFormat,
33+
inlineDeltaRelationships,
34+
}) =>
2635
collection => {
2736
const { createColumnDefinitionBySchema } = require('./createColumnDefinition')(app);
2837
const ddlProvider = require('../../ddlProvider/ddlProvider')(
@@ -55,11 +64,31 @@ const getAddCollectionScriptDto =
5564
const checkConstraints = (jsonSchema.chkConstr || []).map(check =>
5665
ddlProvider.createCheckConstraint(ddlProvider.hydrateCheckConstraint(check)),
5766
);
67+
const foreignKeyConstraints = inlineDeltaRelationships
68+
.filter(relationship => relationship.role.childCollection === collection.role.id)
69+
.map(relationship => {
70+
const compMod = relationship.role.compMod;
71+
const relationshipName =
72+
compMod.code?.new || compMod.name?.new || getRelationshipName(relationship) || '';
73+
return ddlProvider.createForeignKeyConstraint({
74+
name: relationshipName,
75+
foreignKey: compMod.child.collection.fkFields,
76+
primaryKey: compMod.parent.collection.fkFields,
77+
customProperties: compMod.customProperties?.new,
78+
foreignTable: compMod.child.collection.name,
79+
foreignSchemaName: compMod.child.bucket.name,
80+
foreignTableActivated: compMod.child.collection.isActivated,
81+
primaryTable: compMod.parent.collection.name,
82+
primarySchemaName: compMod.parent.bucket.name,
83+
primaryTableActivated: compMod.parent.collection.isActivated,
84+
isActivated: Boolean(relationship.role?.compMod?.isActivated?.new),
85+
});
86+
});
5887
const tableData = {
5988
name: getEntityName(jsonSchema),
6089
columns: columnDefinitions.map(data => ddlProvider.convertColumnDefinition(data)),
6190
checkConstraints: checkConstraints,
62-
foreignKeyConstraints: [],
91+
foreignKeyConstraints,
6392
schemaData,
6493
columnDefinitions,
6594
};

forward_engineering/alterScript/alterScriptHelpers/alterRelationshipsHelper.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,5 @@ module.exports = {
157157
getDeleteForeignKeyScriptDtos,
158158
getModifyForeignKeyScriptDtos,
159159
getAddForeignKeyScriptDtos,
160+
getRelationshipName,
160161
};

0 commit comments

Comments
 (0)