Skip to content

Commit c0c0417

Browse files
Feature/hck 4513 indexes alter script (#92)
* - started to work on index alter script * - Added support for adding indexes with Alter Script * - Fixed a problem with INCLUDE clause when adding indexes - Added ability to delete indexes * - Added support for index drop-and-recreate modifications * - Added support for index modifications with ALTER INDEX syntax * - Removed unused import * - Fixed a lot of issues with index name formatting * - Fixed a regression with generating names for DDL --------- Co-authored-by: unknown <unknown> Co-authored-by: chulanovskyi-bs <[email protected]>
1 parent b5dacf1 commit c0c0417

File tree

9 files changed

+594
-8
lines changed

9 files changed

+594
-8
lines changed

forward_engineering/alterScript/alterScriptFromDeltaHelper.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ const getAlterCollectionsScriptDtos = ({
102102
.concat(collection.properties?.entities?.properties?.modified?.items)
103103
.filter(Boolean)
104104
.map(item => Object.values(item.properties)[0])
105-
.flatMap(getModifyCollectionScriptDtos(app));
105+
.flatMap(getModifyCollectionScriptDtos({app, dbVersion}));
106106
const addColumnScriptDtos = []
107107
.concat(collection.properties?.entities?.properties?.added?.items)
108108
.filter(Boolean)

forward_engineering/alterScript/alterScriptHelpers/alterEntityHelper.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const {getRenameColumnScriptDtos} = require("./columnHelpers/renameColumnHelper"
77
const {AlterScriptDto} = require("../types/AlterScriptDto");
88
const {AlterCollectionDto} = require('../types/AlterCollectionDto');
99
const {getModifyPkConstraintsScriptDtos} = require("./entityHelpers/primaryKeyHelper");
10+
const {getModifyIndexesScriptDtos} = require("./entityHelpers/indexesHelper");
1011

1112

1213
/**
@@ -75,17 +76,19 @@ const getDeleteCollectionScriptDto = app => collection => {
7576
/**
7677
* @return {(collection: AlterCollectionDto) => AlterScriptDto[]}
7778
* */
78-
const getModifyCollectionScriptDtos = (app) => (collection) => {
79+
const getModifyCollectionScriptDtos = ({app, dbVersion}) => (collection) => {
7980
const _ = app.require('lodash');
8081
const ddlProvider = require('../../ddlProvider/ddlProvider')(null, null, app);
8182

8283
const modifyCheckConstraintScriptDtos = getModifyCheckConstraintScriptDtos(_, ddlProvider)(collection);
8384
const modifyCommentScriptDtos = getModifyEntityCommentsScriptDtos(_, ddlProvider)(collection);
8485
const modifyPKConstraintDtos = getModifyPkConstraintsScriptDtos(_, ddlProvider)(collection);
86+
const modifyIndexesScriptDtos = getModifyIndexesScriptDtos({ _, ddlProvider })({ collection, dbVersion });
8587
return [
8688
...modifyCheckConstraintScriptDtos,
8789
...modifyCommentScriptDtos,
88-
...modifyPKConstraintDtos
90+
...modifyPKConstraintDtos,
91+
...modifyIndexesScriptDtos,
8992
].filter(Boolean);
9093
}
9194

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
const {AlterCollectionDto} = require('../../types/AlterCollectionDto');
2+
const {AlterIndexDto} = require('../../types/AlterIndexDto');
3+
const {AlterScriptDto} = require("../../types/AlterScriptDto");
4+
5+
/**
6+
* @typedef {{
7+
* oldIndex: AlterIndexDto,
8+
* newIndex: AlterIndexDto,
9+
* }} ModifiedIndexDto
10+
* */
11+
12+
/**
13+
* @return {({ columnId: string, collection: AlterCollectionDto }) => string | undefined}
14+
* */
15+
const getColumnNameById = ({_}) => ({columnId, collection}) => {
16+
const nameToSchemaInProperties = _.toPairs(collection.role.properties || {})
17+
.find(([fieldName, fieldJsonSchema]) => {
18+
return fieldJsonSchema.GUID === columnId;
19+
});
20+
if (nameToSchemaInProperties?.length) {
21+
return nameToSchemaInProperties[0];
22+
}
23+
return undefined;
24+
}
25+
26+
/**
27+
* @return {({
28+
* columns?: Array<{keyId: string}>,
29+
* collection: AlterCollectionDto
30+
* }) => Object}
31+
* */
32+
const setNamesToColumns = ({_}) => ({columns, collection}) => {
33+
return (columns || [])
34+
.map(column => {
35+
return {
36+
...column, name: getColumnNameById({_})({columnId: column.keyId, collection}),
37+
}
38+
})
39+
.filter(column => Boolean(column.name));
40+
}
41+
42+
/**
43+
* @return {({ index: AlterIndexDto, collection: AlterCollectionDto }) => Object}
44+
* */
45+
const mapIndexToFeIndexDto = ({_}) => ({
46+
index, collection,
47+
}) => {
48+
const {getSchemaNameFromCollection} = require('../../../utils/general')(_);
49+
50+
const schemaName = getSchemaNameFromCollection({collection});
51+
52+
const columnsWithNamesSet = setNamesToColumns({_})({
53+
columns: index.columns,
54+
collection
55+
});
56+
57+
const includeColumnsWithNameSet = setNamesToColumns({_})({
58+
columns: index.include,
59+
collection
60+
});
61+
62+
return {
63+
...index,
64+
schemaName,
65+
columns: columnsWithNamesSet,
66+
include: includeColumnsWithNameSet,
67+
}
68+
}
69+
70+
/**
71+
* @return {({
72+
* oldIndex: AlterIndexDto,
73+
* newIndex: AlterIndexDto,
74+
* indexPropertiesToCompare: Array<string>,
75+
* }) => boolean}
76+
* */
77+
const areIndexesDifferent = ({_}) => ({oldIndex, newIndex, indexPropertiesToCompare}) => {
78+
const newIndexWithRelevantProperties = _.pick(newIndex, indexPropertiesToCompare);
79+
const oldIndexWithRelevantProperties = _.pick(oldIndex, indexPropertiesToCompare);
80+
return !_.isEqual(newIndexWithRelevantProperties, oldIndexWithRelevantProperties);
81+
}
82+
83+
/**
84+
* @return {({ oldIndex: AlterIndexDto, newIndex: AlterIndexDto }) => boolean}
85+
* */
86+
const shouldDropAndRecreateIndex = ({_}) => ({oldIndex, newIndex}) => {
87+
const indexPropertiesToCompare = [
88+
'index_method',
89+
'columns',
90+
'include',
91+
'nullsDistinct',
92+
'where',
93+
];
94+
return areIndexesDifferent({_})({oldIndex, newIndex, indexPropertiesToCompare});
95+
}
96+
97+
/**
98+
* @return {({ oldIndex: AlterIndexDto, newIndex: AlterIndexDto }) => boolean}
99+
* */
100+
const shouldAlterIndex = ({_}) => ({oldIndex, newIndex}) => {
101+
const indexPropertiesToCompare = [
102+
'indxName',
103+
'index_tablespace_name',
104+
'index_storage_parameter'
105+
];
106+
return areIndexesDifferent({_})({oldIndex, newIndex, indexPropertiesToCompare});
107+
}
108+
109+
/**
110+
* @param oldIndex {AlterIndexDto}
111+
* @param newIndex {AlterIndexDto}
112+
* @return {boolean}
113+
* */
114+
const areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex = ({oldIndex, newIndex}) => {
115+
return (oldIndex.id === newIndex.id) || (oldIndex.indxName === oldIndex.indxName);
116+
}
117+
118+
/**
119+
* @return {({
120+
* index: AlterIndexDto,
121+
* collection: AlterCollectionDto,
122+
* additionalDataForDdlProvider: Object,
123+
* }) => AlterScriptDto | undefined}
124+
* */
125+
const getCreateIndexScriptDto = ({_, ddlProvider}) => ({index, collection, additionalDataForDdlProvider}) => {
126+
const {dbData, tableName, isParentActivated} = additionalDataForDdlProvider;
127+
128+
const indexForFeScript = mapIndexToFeIndexDto({_})({index, collection});
129+
130+
const script = ddlProvider.createIndex(tableName, indexForFeScript, dbData, isParentActivated);
131+
const isIndexActivated = indexForFeScript.isActivated && isParentActivated;
132+
return AlterScriptDto.getInstance([script], isIndexActivated, false);
133+
}
134+
135+
/**
136+
* @return {({
137+
* collection: AlterCollectionDto,
138+
* additionalDataForDdlProvider: Object,
139+
* }) => Array<AlterScriptDto>}
140+
* */
141+
const getAddedIndexesScriptDtos = ({_, ddlProvider}) => ({collection, additionalDataForDdlProvider}) => {
142+
const newIndexes = collection?.role?.compMod?.Indxs?.new || [];
143+
const oldIndexes = collection?.role?.compMod?.Indxs?.old || [];
144+
145+
return newIndexes
146+
.filter(newIndex => {
147+
const correspondingOldIndex = oldIndexes.find(oldIndex => areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex({
148+
oldIndex, newIndex
149+
}));
150+
return !Boolean(correspondingOldIndex);
151+
})
152+
.map(newIndex => {
153+
return getCreateIndexScriptDto({_, ddlProvider})({
154+
index: newIndex,
155+
collection,
156+
additionalDataForDdlProvider
157+
});
158+
})
159+
.filter(Boolean);
160+
}
161+
162+
/**
163+
* @return {({
164+
* index: AlterIndexDto,
165+
* additionalDataForDdlProvider: Object,
166+
* }) => AlterScriptDto | undefined}
167+
* */
168+
const getDeleteIndexScriptDto = ({_, ddlProvider}) => ({index, additionalDataForDdlProvider}) => {
169+
const {getNamePrefixedWithSchemaName} = require('../../../utils/general')(_);
170+
171+
const {isParentActivated, schemaName} = additionalDataForDdlProvider;
172+
173+
const fullIndexName = getNamePrefixedWithSchemaName(index.indxName, schemaName);
174+
const script = ddlProvider.dropIndex({indexName: fullIndexName});
175+
const isIndexActivated = index.isActivated && isParentActivated;
176+
return AlterScriptDto.getInstance([script], isIndexActivated, true);
177+
}
178+
179+
/**
180+
* @return {({
181+
* collection: AlterCollectionDto,
182+
* additionalDataForDdlProvider: Object,
183+
* }) => Array<AlterScriptDto>}
184+
* */
185+
const getDeletedIndexesScriptDtos = ({_, ddlProvider}) => ({collection, additionalDataForDdlProvider}) => {
186+
const newIndexes = collection?.role?.compMod?.Indxs?.new || [];
187+
const oldIndexes = collection?.role?.compMod?.Indxs?.old || [];
188+
189+
return oldIndexes
190+
.filter(oldIndex => {
191+
const correspondingNewIndex = newIndexes.find(newIndex => areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex({
192+
oldIndex, newIndex
193+
}));
194+
return !Boolean(correspondingNewIndex);
195+
})
196+
.map(oldIndex => {
197+
return getDeleteIndexScriptDto({_, ddlProvider})({index: oldIndex, additionalDataForDdlProvider});
198+
})
199+
.filter(Boolean);
200+
}
201+
202+
/**
203+
* @return {({
204+
* additionalDataForDdlProvider: Object,
205+
* newIndex: AlterIndexDto,
206+
* oldIndex: AlterIndexDto,
207+
* }) => Array<AlterScriptDto>}
208+
* */
209+
const getAlterIndexScriptDtos = ({_, ddlProvider}) => ({
210+
newIndex,
211+
oldIndex,
212+
additionalDataForDdlProvider
213+
}) => {
214+
const alterIndexScriptDtos = [];
215+
216+
const {isParentActivated, schemaName} = additionalDataForDdlProvider;
217+
const isNewIndexActivated = newIndex.isActivated && isParentActivated;
218+
219+
const shouldRename = !_.isEqual(newIndex.indxName, oldIndex.indxName);
220+
if (shouldRename) {
221+
const script = ddlProvider.alterIndexRename({
222+
schemaName,
223+
oldIndexName: oldIndex.indxName,
224+
newIndexName: newIndex.indxName,
225+
});
226+
const renameScriptDto = AlterScriptDto.getInstance([script], isNewIndexActivated, false);
227+
alterIndexScriptDtos.push(renameScriptDto);
228+
}
229+
230+
const shouldUpdateTablespace = !_.isEqual(newIndex.index_tablespace_name, oldIndex.index_tablespace_name);
231+
if (shouldUpdateTablespace) {
232+
const script = ddlProvider.alterIndexTablespace({
233+
schemaName,
234+
indexName: newIndex.indxName,
235+
tablespaceName: newIndex.index_tablespace_name,
236+
});
237+
const changeTablespaceScriptDto = AlterScriptDto.getInstance([script], isNewIndexActivated, false);
238+
alterIndexScriptDtos.push(changeTablespaceScriptDto);
239+
}
240+
241+
const shouldUpdateStorageParams = !_.isEqual(newIndex.index_storage_parameter, oldIndex.index_storage_parameter);
242+
if (shouldUpdateStorageParams) {
243+
const updateStorageParamsScript = ddlProvider.alterIndexStorageParams({
244+
schemaName,
245+
indexName: newIndex.indxName,
246+
index: newIndex,
247+
});
248+
const updateStorageParamsScriptDto = AlterScriptDto.getInstance([updateStorageParamsScript], isNewIndexActivated, false);
249+
alterIndexScriptDtos.push(updateStorageParamsScriptDto);
250+
251+
const reindexScript = ddlProvider.reindexIndex({
252+
schemaName,
253+
indexName: newIndex.indxName,
254+
});
255+
const reindexScriptDto = AlterScriptDto.getInstance([reindexScript], isNewIndexActivated, false);
256+
alterIndexScriptDtos.push(reindexScriptDto);
257+
}
258+
259+
return alterIndexScriptDtos
260+
.filter(Boolean);
261+
};
262+
263+
/**
264+
* @return {({
265+
* collection: AlterCollectionDto,
266+
* additionalDataForDdlProvider: Object,
267+
* }) => Array<AlterScriptDto>}
268+
* */
269+
const getModifiedIndexesScriptDtos = ({_, ddlProvider}) => ({collection, additionalDataForDdlProvider}) => {
270+
const newIndexes = collection?.role?.compMod?.Indxs?.new || [];
271+
const oldIndexes = collection?.role?.compMod?.Indxs?.old || [];
272+
273+
return newIndexes
274+
.map(newIndex => {
275+
const correspondingOldIndex = oldIndexes.find(oldIndex => areOldIndexDtoAndNewIndexDtoDescribingSameDatabaseIndex({
276+
oldIndex, newIndex
277+
}));
278+
if (correspondingOldIndex) {
279+
return {
280+
newIndex,
281+
oldIndex: correspondingOldIndex,
282+
};
283+
}
284+
return undefined;
285+
})
286+
.filter(Boolean)
287+
.flatMap(({newIndex, oldIndex}) => {
288+
const shouldDropAndRecreate = shouldDropAndRecreateIndex({_})({newIndex, oldIndex});
289+
if (shouldDropAndRecreate) {
290+
const deleteIndexScriptDto = getDeleteIndexScriptDto({_, ddlProvider})({
291+
index: oldIndex,
292+
additionalDataForDdlProvider
293+
});
294+
const createIndexScriptDto = getCreateIndexScriptDto({_, ddlProvider})({
295+
index: newIndex,
296+
collection,
297+
additionalDataForDdlProvider
298+
});
299+
return [deleteIndexScriptDto, createIndexScriptDto];
300+
}
301+
302+
const shouldAlter = shouldAlterIndex({_})({oldIndex, newIndex});
303+
if (shouldAlter) {
304+
return getAlterIndexScriptDtos({_, ddlProvider})({
305+
oldIndex,
306+
newIndex,
307+
additionalDataForDdlProvider,
308+
});
309+
}
310+
311+
return [];
312+
})
313+
.filter(Boolean);
314+
}
315+
316+
/**
317+
* @return {({ collection: AlterCollectionDto, dbVersion: string }) => Array<AlterScriptDto>}
318+
* */
319+
const getModifyIndexesScriptDtos = ({_, ddlProvider}) => ({collection, dbVersion}) => {
320+
const {getSchemaNameFromCollection} = require('../../../utils/general')(_);
321+
const additionalDataForDdlProvider = {
322+
dbData: {dbVersion},
323+
tableName: collection?.compMod?.collectionName?.new || '',
324+
schemaName: getSchemaNameFromCollection({collection}) || '',
325+
isParentActivated: collection.isActivated,
326+
}
327+
328+
const deletedIndexesScriptDtos = getDeletedIndexesScriptDtos({_, ddlProvider})({
329+
collection, additionalDataForDdlProvider
330+
});
331+
const addedIndexesScriptDtos = getAddedIndexesScriptDtos({_, ddlProvider})({
332+
collection, additionalDataForDdlProvider
333+
});
334+
const modifyIndexesScriptDtos = getModifiedIndexesScriptDtos({_, ddlProvider})({
335+
collection, additionalDataForDdlProvider
336+
})
337+
338+
return [
339+
...deletedIndexesScriptDtos,
340+
...addedIndexesScriptDtos,
341+
...modifyIndexesScriptDtos,
342+
]
343+
.filter(Boolean);
344+
}
345+
346+
module.exports = {
347+
getModifyIndexesScriptDtos,
348+
}

0 commit comments

Comments
 (0)