Skip to content

Commit 29f6a6f

Browse files
authored
HCK-14450: Added logic to alter indexes (Part 1) + minor fixes (#84)
<!--do not remove this marker, its needed to replace info when ticket title is updated --> <!--jira-description-action-hidden-marker-start--> <table> <td> <a href="https://hackolade.atlassian.net/browse/HCK-14450" title="HCK-14450" target="_blank"><img alt="Sub-task" src="https://hackolade.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10316?size=medium" />HCK-14450</a> [DB2][Alter]: Implement logic for indexes (Part 1) </td></table> <br /> <!--jira-description-action-hidden-marker-end--> ## Content - Added logic to alter indexes - Added missing API method - Fixed creation of view without schema ## Note Currently I assume that all changed properties require index recreation. In the next part, I will either recreate or alter the indexes based on the modified properties.
1 parent 3425247 commit 29f6a6f

File tree

12 files changed

+484
-15
lines changed

12 files changed

+484
-15
lines changed

api/fe.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
const { generateContainerScript } = require('../forward_engineering/api/generateContainerScript');
22
const { isDropInStatements } = require('../forward_engineering/api/isDropInStatements');
3+
const { generateScript } = require('../forward_engineering/api/generateScript');
34

45
module.exports = {
6+
generateScript,
57
generateContainerScript,
68
isDropInStatements,
79
};

forward_engineering/alterScript/alterScriptBuilder.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ const mapCoreDataForContainerLevelScripts = data => {
4444
};
4545
};
4646

47+
const buildEntityLevelAlterScript = (data, app) => {
48+
const alterScriptDtos = getAlterScriptDtos(data, app);
49+
const shouldApplyDropStatements = data.options?.additionalOptions?.some(
50+
option => option.id === 'applyDropStatements' && option.value,
51+
);
52+
53+
return joinAlterScriptDtosIntoScript(alterScriptDtos, shouldApplyDropStatements);
54+
};
55+
4756
const buildContainerLevelAlterScript = (data, app) => {
4857
const preparedData = mapCoreDataForContainerLevelScripts(data);
4958
const alterScriptDtos = getAlterScriptDtos(preparedData, app);
@@ -66,6 +75,7 @@ const doesContainerLevelAlterScriptContainDropStatements = (data, app) => {
6675

6776
module.exports = {
6877
doesEntityLevelAlterScriptContainDropStatements,
78+
buildEntityLevelAlterScript,
6979
buildContainerLevelAlterScript,
7080
doesContainerLevelAlterScriptContainDropStatements,
7181
};

forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const { getRenameColumnScriptDtos } = require('./columnHelpers/alterColumnNameHe
1111
const { getModifyEntityCommentsScriptDtos } = require('./entityHelpers/commentsHelper');
1212
const { getModifyPkConstraintsScriptDtos } = require('./entityHelpers/primaryKeyHelper');
1313
const { getModifyUkConstraintsScriptDtos } = require('./entityHelpers/uniqueKeyHelper');
14+
const { getModifyIndexesScriptDtos } = require('./entityHelpers/indexesHelper');
1415
const { getModifiedDefaultColumnValueScriptDtos } = require('./columnHelpers/defaultValueHelper');
1516
const {
1617
getEntityName,
@@ -109,13 +110,14 @@ const getModifyCollectionScriptDtos = collection => {
109110
};
110111

111112
/**
112-
* @param {Object} collection
113-
* @returns {Array<AlterScriptDto>}
113+
* @param {Object} ddlProvider
114+
* @returns {(collection: Object) => Array<AlterScriptDto>}
114115
*/
115-
const getModifyCollectionKeysScriptDtos = collection => {
116+
const getModifyCollectionKeysScriptDtos = ddlProvider => collection => {
116117
const modifyPkConstraintDtos = getModifyPkConstraintsScriptDtos(collection);
117118
const modifyUkConstraintDtos = getModifyUkConstraintsScriptDtos(collection);
118-
return [...modifyPkConstraintDtos, ...modifyUkConstraintDtos].filter(Boolean);
119+
const modifyIndexesScriptDtos = getModifyIndexesScriptDtos({ ddlProvider, collection });
120+
return [...modifyPkConstraintDtos, ...modifyUkConstraintDtos, ...modifyIndexesScriptDtos].filter(Boolean);
119121
};
120122

121123
/**
@@ -197,7 +199,7 @@ const getEntitiesScripts = (app, inlineDeltaRelationships) => {
197199
getDeleteCollectionScriptDto: getDeleteCollectionScriptDto(ddlProvider),
198200
getModifyCollectionScriptDtos,
199201
getModifyColumnScriptDtos: getModifyColumnScriptDtos(ddlProvider),
200-
getModifyCollectionKeysScriptDtos,
202+
getModifyCollectionKeysScriptDtos: getModifyCollectionKeysScriptDtos(ddlProvider),
201203
getAddColumnScriptDtos: getAddColumnScriptDtos(ddlProvider),
202204
getDeleteColumnScriptDtos: getDeleteColumnScriptDtos(ddlProvider),
203205
};
Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
const { isEqual } = require('lodash');
2+
const { AlterScriptDto } = require('../../types/AlterScriptDto');
3+
const {
4+
getSchemaNameFromCollection,
5+
getNamePrefixedWithSchemaName,
6+
wrapInQuotes,
7+
getSchemaOfAlterCollection,
8+
getFullCollectionName,
9+
getEntityName,
10+
isObjectInDeltaModelActivated,
11+
} = require('../../../utils/general');
12+
const { assignTemplates } = require('../../../utils/assignTemplates');
13+
const templates = require('../../../ddlProvider/templates');
14+
const { getIndexCommentsScriptDtos, getModifyIndexCommentsScriptDtos } = require('../indexHelpers/commentsHelper');
15+
const { addNameToIndexKey } = require('../indexHelpers/addNameToIndexKey');
16+
17+
const alterIndexProperties = ['indxCompress'];
18+
const columnProperties = ['indxKey', 'indxIncludeKey'];
19+
// Temporary always drop and recreate index if any of these properties changed
20+
const dropAndRecreateIndexProperties = [
21+
'indxType',
22+
'indxTablespace',
23+
'indxNullKeys',
24+
...alterIndexProperties,
25+
...columnProperties,
26+
];
27+
28+
/**
29+
* @param {{
30+
* oldIndex: Object,
31+
* newIndex: Object
32+
* }} param
33+
* @return {boolean}
34+
*/
35+
const shouldDropAndRecreateIndex = ({ oldIndex, newIndex }) => {
36+
return dropAndRecreateIndexProperties.some(property => !isEqual(oldIndex[property], newIndex[property]));
37+
};
38+
39+
/**
40+
* @param {{
41+
* oldIndex: Object,
42+
* newIndex: Object
43+
* }} param
44+
* @return {boolean}
45+
*/
46+
const areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex = ({ oldIndex, newIndex }) => {
47+
return oldIndex.id === newIndex.id || oldIndex.indxName === newIndex.indxName;
48+
};
49+
50+
/**
51+
* @param {{
52+
* schemaName: string,
53+
* oldIndexName: string,
54+
* newIndexName: string,
55+
* isActivated: boolean
56+
* }} param
57+
* @return {AlterScriptDto}
58+
*/
59+
const alterIndexRenameDto = ({ schemaName, oldIndexName, newIndexName, isActivated }) => {
60+
const ddlOldIndexName = getNamePrefixedWithSchemaName({
61+
name: oldIndexName,
62+
schemaName,
63+
});
64+
const ddlNewIndexName = wrapInQuotes(newIndexName);
65+
66+
const script = assignTemplates({
67+
template: templates.renameIndex,
68+
templateData: {
69+
oldIndexName: ddlOldIndexName,
70+
newIndexName: ddlNewIndexName,
71+
},
72+
});
73+
74+
return AlterScriptDto.getInstance([script], isActivated, false);
75+
};
76+
77+
/**
78+
* @param {{
79+
* index: Object,
80+
* collection: Object,
81+
* ddlProvider: Object
82+
* }} param
83+
* @return {AlterScriptDto | undefined}
84+
*/
85+
const getCreateIndexScriptDto = ({ index, collection, ddlProvider }) => {
86+
const indexWithAddedKeyNames = addNameToIndexKey({ index, collection });
87+
const collectionSchema = getSchemaOfAlterCollection(collection);
88+
const tableName = getEntityName(collectionSchema);
89+
90+
const script = ddlProvider.createIndex(tableName, indexWithAddedKeyNames);
91+
return AlterScriptDto.getInstance([script], true, false);
92+
};
93+
94+
/**
95+
* @param {{
96+
* collection: Object,
97+
* ddlProvider: Object
98+
* }} param
99+
* @return {Array<AlterScriptDto>}
100+
*/
101+
const getAddedIndexesScriptDtos = ({ collection, ddlProvider }) => {
102+
const newIndexes = collection?.role?.Indxs || [];
103+
const oldIndexes = collection?.role?.compMod?.Indxs?.old || [];
104+
105+
return newIndexes
106+
.filter(newIndex => {
107+
const correspondingOldIndex = oldIndexes.find(oldIndex =>
108+
areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex({
109+
oldIndex,
110+
newIndex,
111+
}),
112+
);
113+
return !correspondingOldIndex;
114+
})
115+
.map(newIndex => {
116+
return getCreateIndexScriptDto({
117+
index: newIndex,
118+
collection,
119+
ddlProvider,
120+
});
121+
})
122+
.filter(Boolean);
123+
};
124+
125+
/**
126+
* @param {{
127+
* index: Object,
128+
* collection: Object,
129+
* ddlProvider: Object
130+
* }} param
131+
* @return {AlterScriptDto | undefined}
132+
*/
133+
const getDeleteIndexScriptDto = ({ index, collection, ddlProvider }) => {
134+
const schemaName = getSchemaNameFromCollection({ collection });
135+
const fullIndexName = getNamePrefixedWithSchemaName({
136+
name: index.indxName,
137+
schemaName,
138+
});
139+
const script = ddlProvider.dropIndex(fullIndexName);
140+
return AlterScriptDto.getInstance([script], index.isActivated && isObjectInDeltaModelActivated(collection), true);
141+
};
142+
143+
/**
144+
* @param {{
145+
* collection: Object,
146+
* ddlProvider: Object
147+
* }} param
148+
* @return {Array<AlterScriptDto>}
149+
*/
150+
const getDeletedIndexesScriptDtos = ({ collection, ddlProvider }) => {
151+
const newIndexes = collection?.role?.compMod?.Indxs?.new || [];
152+
const oldIndexes = collection?.role?.compMod?.Indxs?.old || [];
153+
154+
return oldIndexes
155+
.filter(oldIndex => {
156+
const correspondingNewIndex = newIndexes.find(newIndex =>
157+
areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex({
158+
oldIndex,
159+
newIndex,
160+
}),
161+
);
162+
return !correspondingNewIndex;
163+
})
164+
.map(oldIndex => {
165+
return getDeleteIndexScriptDto({ index: oldIndex, collection, ddlProvider });
166+
})
167+
.filter(Boolean);
168+
};
169+
170+
/**
171+
* @param {{
172+
* newIndex: Object,
173+
* oldIndex: Object,
174+
* collection: Object,
175+
* ddlProvider: Object
176+
* }} param
177+
* @return {Array<AlterScriptDto>}
178+
*/
179+
const getModifyIndexScriptDto = ({ newIndex, oldIndex, collection, ddlProvider }) => {
180+
const scripts = [];
181+
182+
const shouldDropAndRecreate = shouldDropAndRecreateIndex({ newIndex, oldIndex });
183+
if (shouldDropAndRecreate) {
184+
const deleteIndexScriptDto = getDeleteIndexScriptDto({
185+
index: oldIndex,
186+
collection,
187+
ddlProvider,
188+
});
189+
const createIndexScriptDto = getCreateIndexScriptDto({
190+
index: newIndex,
191+
collection,
192+
ddlProvider,
193+
});
194+
// if an index was recreated, and comment was removed,
195+
// no need to generate separate script to drop comment
196+
scripts.push(deleteIndexScriptDto, createIndexScriptDto);
197+
198+
if (newIndex.indxDescription) {
199+
const commentDtos = getIndexCommentsScriptDtos({
200+
index: newIndex,
201+
collection,
202+
});
203+
scripts.push(...commentDtos);
204+
}
205+
206+
return scripts;
207+
}
208+
209+
if (oldIndex.indxName !== newIndex.indxName) {
210+
const schemaName = getSchemaNameFromCollection({ collection });
211+
const renameScript = alterIndexRenameDto({
212+
schemaName,
213+
oldIndexName: oldIndex.indxName,
214+
newIndexName: newIndex.indxName,
215+
isActivated: isObjectInDeltaModelActivated(collection) && newIndex.isActivated,
216+
});
217+
218+
scripts.push(renameScript);
219+
}
220+
221+
const commentDtos = getModifyIndexCommentsScriptDtos({ newIndex, oldIndex, collection });
222+
223+
if (commentDtos) {
224+
scripts.push(commentDtos);
225+
}
226+
227+
return scripts;
228+
};
229+
230+
/**
231+
* @param {{
232+
* collection: Object,
233+
* ddlProvider: Object
234+
* }} param
235+
* @return {Array<AlterScriptDto>}
236+
*/
237+
const getModifiedIndexesScriptDtos = ({ collection, ddlProvider }) => {
238+
const newIndexes = collection?.role?.compMod?.Indxs?.new || [];
239+
const oldIndexes = collection?.role?.compMod?.Indxs?.old || [];
240+
241+
return newIndexes
242+
.map(newIndex => {
243+
const correspondingOldIndex = oldIndexes.find(oldIndex =>
244+
areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex({
245+
oldIndex,
246+
newIndex,
247+
}),
248+
);
249+
if (correspondingOldIndex) {
250+
return {
251+
newIndex,
252+
oldIndex: correspondingOldIndex,
253+
};
254+
}
255+
return undefined;
256+
})
257+
.filter(Boolean)
258+
.flatMap(({ newIndex, oldIndex }) => {
259+
return getModifyIndexScriptDto({
260+
newIndex,
261+
oldIndex,
262+
collection,
263+
ddlProvider,
264+
});
265+
})
266+
.filter(Boolean);
267+
};
268+
269+
/**
270+
* @param {{
271+
* ddlProvider: Object,
272+
* collection: Object
273+
* }} param
274+
* @return {Array<AlterScriptDto>}
275+
*/
276+
const getModifyIndexesScriptDtos = ({ ddlProvider, collection }) => {
277+
const deletedIndexesScriptDtos = getDeletedIndexesScriptDtos({
278+
collection,
279+
ddlProvider,
280+
});
281+
const addedIndexesScriptDtos = getAddedIndexesScriptDtos({
282+
collection,
283+
ddlProvider,
284+
});
285+
const modifiedIndexesScriptDtos = getModifiedIndexesScriptDtos({
286+
collection,
287+
ddlProvider,
288+
});
289+
290+
return [...deletedIndexesScriptDtos, ...addedIndexesScriptDtos, ...modifiedIndexesScriptDtos].filter(Boolean);
291+
};
292+
293+
module.exports = {
294+
getModifyIndexesScriptDtos,
295+
};

0 commit comments

Comments
 (0)