Skip to content

Commit 331d4d5

Browse files
HCK-13862: Enable script generation for FK (#130)
* HCK-13862: add config for fk script generation option * HCK-13862: implement FK alter script
1 parent d8b7030 commit 331d4d5

5 files changed

Lines changed: 255 additions & 13 deletions

File tree

forward_engineering/config.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,28 @@
8282
}
8383
]
8484
},
85+
{
86+
"keyword": "foreignKeys",
87+
"label": "FE_SCRIPT_GENERATION_OPTIONS___FOREIGN_KEYS",
88+
"disabled": false,
89+
"value": {
90+
"inline": {
91+
"default": false,
92+
"disabled": true,
93+
"disabledLabel": ""
94+
},
95+
"separate": {
96+
"default": true,
97+
"disabled": false,
98+
"disabledLabel": ""
99+
},
100+
"ignore": {
101+
"default": false,
102+
"disabled": false,
103+
"disabledLabel": ""
104+
}
105+
}
106+
},
85107
{
86108
"keyword": "uniqueConstraints",
87109
"label": "FE_SCRIPT_GENERATION_OPTIONS___UNIQUE_KEYS",

forward_engineering/helpers/alterScriptFromDeltaHelper.js

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,18 @@ const {
1111
getAddColumnsScripts,
1212
getModifyColumnsScripts,
1313
} = require('./alterScriptHelpers/alterEntityHelper');
14+
const { getAlterRelationshipsScripts } = require('./alterScriptHelpers/alterRelationshipsHelper');
1415
const {
1516
getAddViewsScripts,
1617
getDeleteViewsScripts,
1718
getModifyViewsScripts,
1819
} = require('./alterScriptHelpers/alterViewHelper');
20+
const { getItems } = require('./alterScriptHelpers/common');
21+
const { getContainerName } = require('./alterScriptHelpers/generalHelper');
1922
const { DROP_STATEMENTS } = require('./constants');
20-
const { commentDeactivatedStatements } = require('./generalHelper');
23+
const { commentDeactivatedStatements, replaceSpaceWithUnderscore, prepareName } = require('./generalHelper');
2124

22-
const getItems = (entity, nameProperty, modify) =>
23-
[]
24-
.concat(entity.properties?.[nameProperty]?.properties?.[modify]?.items)
25-
.filter(Boolean)
26-
.map(items => Object.values(items.properties)[0]);
25+
const getSchemaName = collection => replaceSpaceWithUnderscore(prepareName(getContainerName(collection.role?.compMod)));
2726

2827
const getAlterContainersScripts = (schema, provider) => {
2928
const addedContainerScripts = getItems(schema, 'containers', 'added').map(getAddContainerScript);
@@ -39,20 +38,31 @@ const getAlterContainersScripts = (schema, provider) => {
3938
};
4039

4140
const getAlterCollectionsScripts = (schema, definitions, provider, data) => {
42-
const getColumnScripts = (items, getScript) => items.filter(item => item.properties).flatMap(getScript);
41+
let currentSchemaName = '';
42+
43+
const setCurrentSchemaName = (entity, getScript) => {
44+
const script = getScript(entity);
45+
46+
currentSchemaName = getSchemaName(entity);
47+
48+
return script;
49+
};
50+
51+
const getColumnScripts = (items, getScript) =>
52+
items.filter(item => item.properties).flatMap(item => setCurrentSchemaName(item, getScript));
4353

4454
const addedCollectionsItems = getItems(schema, 'entities', 'added');
4555
const deletedCollectionsItems = getItems(schema, 'entities', 'deleted');
4656
const modifiedCollectionsItems = getItems(schema, 'entities', 'modified');
4757

4858
const addedCollectionsScripts = addedCollectionsItems
4959
.filter(item => item.compMod?.created)
50-
.flatMap(getAddCollectionsScripts(definitions, data));
60+
.flatMap(item => setCurrentSchemaName(item, getAddCollectionsScripts(definitions, data)));
5161
const deletedCollectionsScripts = deletedCollectionsItems
5262
.filter(item => item.compMod?.deleted)
5363
.flatMap(getDeleteCollectionsScripts(provider));
54-
const modifiedCollectionsScripts = modifiedCollectionsItems.flatMap(
55-
getModifyCollectionsScripts(definitions, provider, data),
64+
const modifiedCollectionsScripts = modifiedCollectionsItems.flatMap(item =>
65+
setCurrentSchemaName(item, getModifyCollectionsScripts(definitions, provider, data)),
5666
);
5767

5868
const addedColumnsItems = addedCollectionsItems.filter(item => !item.compMod?.created);
@@ -72,6 +82,7 @@ const getAlterCollectionsScripts = (schema, definitions, provider, data) => {
7282
addedColumnsScripts,
7383
deletedColumnsScripts,
7484
modifiedColumnsScripts,
85+
currentSchemaName,
7586
};
7687
};
7788

@@ -108,10 +119,16 @@ const getAlterViewsScripts = (schema, provider) => {
108119

109120
const getAlterScript = (schema, definitions, data, app, needMinify, sqlFormatter) => {
110121
const provider = require('./alterScriptHelpers/provider')(app);
122+
const containerScripts = getAlterContainersScripts(schema, provider);
123+
const { currentSchemaName, ...collectionScripts } = getAlterCollectionsScripts(schema, definitions, provider, data);
124+
const viewScripts = getAlterViewsScripts(schema, provider);
125+
const relationshipScripts = getAlterRelationshipsScripts(schema, provider, currentSchemaName);
126+
111127
let scripts = {
112-
...getAlterContainersScripts(schema, provider),
113-
...getAlterCollectionsScripts(schema, definitions, provider, data),
114-
...getAlterViewsScripts(schema, provider),
128+
...containerScripts,
129+
...collectionScripts,
130+
...viewScripts,
131+
...relationshipScripts,
115132
};
116133

117134
scripts = [
@@ -127,6 +144,9 @@ const getAlterScript = (schema, definitions, data, app, needMinify, sqlFormatter
127144
'addedViewScripts',
128145
'modifiedViewScripts',
129146
'deletedContainerScripts',
147+
'deleteFkScripts',
148+
'addFkScripts',
149+
'modifiedFkScripts',
130150
]
131151
.flatMap(name => scripts[name] || [])
132152
.filter(Boolean)
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
const {
2+
getFullEntityName,
3+
generateFullEntityName,
4+
getEntityProperties,
5+
getContainerName,
6+
getEntityData,
7+
getEntityName,
8+
prepareScript,
9+
hydrateProperty,
10+
} = require('./generalHelper');
11+
const { replaceSpaceWithUnderscore, prepareName, commentDeactivatedStatements } = require('../generalHelper');
12+
13+
const templates = require('./config/templates');
14+
const { getItems } = require('./common');
15+
16+
const getRelationshipName = relationship => {
17+
return relationship.role.code || relationship.role.name;
18+
};
19+
20+
const getFullParentTableName = relationship => {
21+
const compMod = relationship.role.compMod;
22+
23+
const parentDBName = replaceSpaceWithUnderscore(prepareName(compMod.parent.bucket.name));
24+
const parentEntityName = replaceSpaceWithUnderscore(compMod.parent.collection.name);
25+
26+
return getFullEntityName(parentDBName, parentEntityName);
27+
};
28+
29+
const getFullChildTableName = relationship => {
30+
const compMod = relationship.role.compMod;
31+
32+
const childDBName = replaceSpaceWithUnderscore(prepareName(compMod.child.bucket.name));
33+
const childEntityName = replaceSpaceWithUnderscore(compMod.child.collection.name);
34+
return getFullEntityName(childDBName, childEntityName);
35+
};
36+
37+
const getAddSingleForeignKeyScript = provider => relationship => {
38+
const compMod = relationship.role.compMod;
39+
const parentTableName = getFullParentTableName(relationship);
40+
const childTableName = getFullChildTableName(relationship);
41+
42+
const relationshipName = compMod.code?.new || compMod.name?.new || getRelationshipName(relationship) || '';
43+
const constraintName = relationshipName.includes(' ') ? `\`${relationshipName}\`` : relationshipName;
44+
const childColumns = compMod.child.collection.fkFields.map(field => prepareName(field.name));
45+
const parentColumns = compMod.parent.collection.fkFields.map(field => prepareName(field.name));
46+
const disableNoValidate = relationship.role?.compMod?.customProperties?.new?.disableNoValidate;
47+
const disableNoValidateClause = disableNoValidate ? ' DISABLE NOVALIDATE' : '';
48+
49+
return provider.assignTemplates(templates.addFkConstraint, {
50+
childTableName,
51+
constraintName,
52+
childColumns,
53+
parentTableName,
54+
parentColumns,
55+
disableNoValidate: disableNoValidateClause,
56+
});
57+
};
58+
59+
const canRelationshipBeAdded = relationship => {
60+
const compMod = relationship.role.compMod;
61+
if (!compMod) {
62+
return false;
63+
}
64+
return [
65+
compMod.code?.new || compMod.name?.new || getRelationshipName(relationship),
66+
compMod.parent?.bucket,
67+
compMod.parent?.collection,
68+
compMod.parent?.collection?.fkFields?.length,
69+
compMod.child?.bucket,
70+
compMod.child?.collection,
71+
compMod.child?.collection?.fkFields?.length,
72+
].every(property => Boolean(property));
73+
};
74+
75+
const getAddForeignKeyScript = provider => relationship => {
76+
const script = getAddSingleForeignKeyScript(provider)(relationship);
77+
const isActivated = Boolean(relationship.role?.compMod?.isActivated?.new);
78+
79+
return commentDeactivatedStatements(script, isActivated);
80+
};
81+
82+
const getDeleteSingleForeignKeyScript = provider => relationship => {
83+
const compMod = relationship.role.compMod;
84+
const tableName = getFullChildTableName(relationship);
85+
const relationshipName = compMod.code?.old || compMod.name?.old || getRelationshipName(relationship) || '';
86+
const constraintName = prepareName(relationshipName);
87+
88+
return provider.assignTemplates(templates.dropConstraint, {
89+
tableName,
90+
constraintName,
91+
});
92+
};
93+
94+
const canRelationshipBeDeleted = relationship => {
95+
const compMod = relationship.role.compMod;
96+
if (!compMod) {
97+
return false;
98+
}
99+
return [
100+
compMod.code?.old || compMod.name?.old || getRelationshipName(relationship),
101+
compMod.child?.bucket,
102+
compMod.child?.collection,
103+
].every(property => Boolean(property));
104+
};
105+
106+
const getDeleteForeignKeyScripts = provider => deletedRelationships => {
107+
return deletedRelationships
108+
.filter(relationship => canRelationshipBeDeleted(relationship))
109+
.map(relationship => {
110+
const script = getDeleteSingleForeignKeyScript(provider)(relationship);
111+
const isActivated = Boolean(relationship.role?.compMod?.isActivated?.new);
112+
113+
return commentDeactivatedStatements(script, isActivated);
114+
});
115+
};
116+
117+
const getModifyForeignKeyScript = provider => relationship => {
118+
const deleteScript = getDeleteSingleForeignKeyScript(provider)(relationship);
119+
const addScript = getAddSingleForeignKeyScript(provider)(relationship);
120+
const isActivated = Boolean(relationship.role?.compMod?.isActivated?.new);
121+
122+
return (
123+
commentDeactivatedStatements(deleteScript, isActivated) + commentDeactivatedStatements(addScript, isActivated)
124+
);
125+
};
126+
127+
const getAlterRelationshipsScripts = (schema, provider, initialSchemaName) => {
128+
let currentSchemaName = initialSchemaName;
129+
130+
const generateAddFkScripts = (addedRelationships, getScript) => {
131+
return addedRelationships.filter(relationship => canRelationshipBeAdded(relationship)).flatMap(getScript);
132+
};
133+
134+
const generateModifyFkScripts = (modifiedRelationships, getScript) => {
135+
return modifiedRelationships
136+
.filter(relationship => canRelationshipBeAdded(relationship) && canRelationshipBeDeleted(relationship))
137+
.flatMap(getScript);
138+
};
139+
140+
const getRelationshipsScriptsWithUseSchema = (relationships, processRelationships, getScript) => {
141+
return processRelationships(relationships, relationship => {
142+
const script = getScript(provider)(relationship);
143+
144+
if (!script) {
145+
return [];
146+
}
147+
148+
const schemaName = replaceSpaceWithUnderscore(
149+
prepareName(relationship.role.compMod.child.bucket?.name || ''),
150+
);
151+
152+
if (currentSchemaName === schemaName) {
153+
return [script];
154+
}
155+
156+
currentSchemaName = schemaName;
157+
158+
const useSchemaScript = provider.assignTemplates(templates.useSchema, { schemaName });
159+
160+
return [useSchemaScript, script];
161+
});
162+
};
163+
164+
const deletedRelationships = getItems(schema, 'relationships', 'deleted').filter(
165+
relationship => relationship.role?.compMod?.deleted,
166+
);
167+
const addedRelationships = getItems(schema, 'relationships', 'added').filter(
168+
relationship => relationship.role?.compMod?.created,
169+
);
170+
const modifiedRelationships = getItems(schema, 'relationships', 'modified');
171+
172+
const deleteFkScripts = getDeleteForeignKeyScripts(provider)(deletedRelationships);
173+
const addFkScripts = getRelationshipsScriptsWithUseSchema(
174+
addedRelationships,
175+
generateAddFkScripts,
176+
getAddForeignKeyScript,
177+
);
178+
const modifiedFkScripts = getRelationshipsScriptsWithUseSchema(
179+
modifiedRelationships,
180+
generateModifyFkScripts,
181+
getModifyForeignKeyScript,
182+
);
183+
return { deleteFkScripts, addFkScripts, modifiedFkScripts };
184+
};
185+
186+
module.exports = {
187+
getAlterRelationshipsScripts,
188+
};

forward_engineering/helpers/alterScriptHelpers/common.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,15 @@ const compareProperties = ({ new: newProperty, old: oldProperty }) => {
4949
const getIsChangeProperties = (compMod, properties) =>
5050
properties.some(property => compareProperties(compMod[property] || {}));
5151

52+
const getItems = (entity, nameProperty, modify) =>
53+
[]
54+
.concat(entity.properties?.[nameProperty]?.properties?.[modify]?.items)
55+
.filter(Boolean)
56+
.map(items => Object.values(items.properties)[0]);
57+
5258
module.exports = {
5359
hydrateTableProperties,
5460
getDifferentItems,
5561
getIsChangeProperties,
62+
getItems,
5663
};

forward_engineering/helpers/alterScriptHelpers/config/templates.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,9 @@ module.exports = {
6464

6565
addUkConstraint:
6666
'ALTER TABLE ${tableName} ADD CONSTRAINT ${constraintName} UNIQUE (${columnNames}) DISABLE${noValidate}${rely};',
67+
68+
addFkConstraint:
69+
'ALTER TABLE ${childTableName} ADD CONSTRAINT ${constraintName} FOREIGN KEY (${childColumns}) REFERENCES ${parentTableName}(${parentColumns})${disableNoValidate};',
70+
71+
useSchema: 'USE ${schemaName};',
6772
};

0 commit comments

Comments
 (0)