sqlmorpheus 0.1.10 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +41 -17
- package/dist/index.d.ts +41 -17
- package/dist/index.js +133 -64
- package/dist/index.mjs +133 -64
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -22,14 +22,44 @@ interface AllowedMigrations {
|
|
|
22
22
|
continueWithoutRollback?: boolean;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
interface RenameData {
|
|
26
|
+
oldName: string;
|
|
27
|
+
newName: string;
|
|
28
|
+
}
|
|
25
29
|
interface MigrationInstructions {
|
|
26
|
-
|
|
30
|
+
tableRenaming?: RenameData;
|
|
27
31
|
recreate: boolean;
|
|
28
32
|
/**
|
|
29
|
-
* Stores changes to column
|
|
33
|
+
* Stores changes to column. One entry per column.
|
|
34
|
+
* Each entry is an array (0: name in the database, last: current name in code)
|
|
30
35
|
*/
|
|
31
|
-
renamedColumns:
|
|
36
|
+
renamedColumns: RenameData[];
|
|
32
37
|
allowedMigrations: AllowedMigrations;
|
|
38
|
+
usedMigrations: Record<string, boolean>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface ColumnInfo {
|
|
42
|
+
name: string;
|
|
43
|
+
type: string;
|
|
44
|
+
defaultValue: string;
|
|
45
|
+
isPrimaryKey: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type ForeignKeyActions = "SET NULL" | "SET DEFAULT" | "RESTRICT" | "NO ACTION" | "CASCADE";
|
|
49
|
+
interface ForeignKeyInfo {
|
|
50
|
+
fromTable: string;
|
|
51
|
+
fromColumn: string;
|
|
52
|
+
toTable: string;
|
|
53
|
+
toColumn: string;
|
|
54
|
+
onUpdate?: ForeignKeyActions;
|
|
55
|
+
onDelete?: ForeignKeyActions;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface TableStructure {
|
|
59
|
+
table: string;
|
|
60
|
+
primaryKey?: string;
|
|
61
|
+
columns: ColumnInfo[];
|
|
62
|
+
foreignKeys?: ForeignKeyInfo[];
|
|
33
63
|
}
|
|
34
64
|
|
|
35
65
|
declare class Migrations {
|
|
@@ -37,20 +67,24 @@ declare class Migrations {
|
|
|
37
67
|
private alwaysAllowed;
|
|
38
68
|
private fromVersion;
|
|
39
69
|
private migrationData;
|
|
70
|
+
private migrationDataForOldTableNames;
|
|
40
71
|
private notAllowedChanges;
|
|
41
72
|
reset(dbInstructions: DatabaseInstructions, fromVersion: number): void;
|
|
42
73
|
private getEntry;
|
|
43
74
|
private getTableName;
|
|
44
|
-
|
|
45
|
-
|
|
75
|
+
verifyRenamingTasks(newTables: Record<string, TableStructure>): Error | void;
|
|
76
|
+
verifyAllowedMigrations(): Error | void;
|
|
77
|
+
compareWithAllowedMigration(tableName: string, type: keyof AllowedMigrations): void;
|
|
46
78
|
allowMigration(version: number, table: string | Class<BackendTable>, ...allowedMigrations: (keyof AllowedMigrations)[]): void;
|
|
47
|
-
renameTable(version: number, oldTableName: string,
|
|
79
|
+
renameTable(version: number, oldTableName: string, newTableName: string | Class<BackendTable>): void;
|
|
48
80
|
renameColumn(version: number, table: string | Class<BackendTable>, oldColumn: string, newColumn: string): void;
|
|
49
81
|
recreateTableImp(table: Class<BackendTable> | string): void;
|
|
50
82
|
recreateTable(version: number, table: Class<BackendTable> | string): void;
|
|
51
83
|
getMigrationData(): Record<string, MigrationInstructions>;
|
|
52
84
|
loopRenamedColumns(tableName: string, callback: (oldColumnName: string, newColumnName: string) => void): void;
|
|
53
|
-
|
|
85
|
+
getNewestTableName(tableName: string): string;
|
|
86
|
+
getOldTableName(tableName: string): string;
|
|
87
|
+
getNewestColumnName(tableName: string, oldColumnName: string): string;
|
|
54
88
|
willBeRecreated(tableName: string): boolean;
|
|
55
89
|
}
|
|
56
90
|
type PublicMigrations = Pick<Migrations, "recreateTable" | "renameTable" | "renameColumn" | "allowMigration">;
|
|
@@ -60,16 +94,6 @@ interface SqlChanges {
|
|
|
60
94
|
down: string;
|
|
61
95
|
}
|
|
62
96
|
|
|
63
|
-
type ForeignKeyActions = "SET NULL" | "SET DEFAULT" | "RESTRICT" | "NO ACTION" | "CASCADE";
|
|
64
|
-
interface ForeignKeyInfo {
|
|
65
|
-
fromTable: string;
|
|
66
|
-
fromColumn: string;
|
|
67
|
-
toTable: string;
|
|
68
|
-
toColumn: string;
|
|
69
|
-
onUpdate?: ForeignKeyActions;
|
|
70
|
-
onDelete?: ForeignKeyActions;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
97
|
interface TableInfo {
|
|
74
98
|
primaryKey?: string;
|
|
75
99
|
foreignKeys?: ForeignKeyInfo[];
|
package/dist/index.d.ts
CHANGED
|
@@ -22,14 +22,44 @@ interface AllowedMigrations {
|
|
|
22
22
|
continueWithoutRollback?: boolean;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
interface RenameData {
|
|
26
|
+
oldName: string;
|
|
27
|
+
newName: string;
|
|
28
|
+
}
|
|
25
29
|
interface MigrationInstructions {
|
|
26
|
-
|
|
30
|
+
tableRenaming?: RenameData;
|
|
27
31
|
recreate: boolean;
|
|
28
32
|
/**
|
|
29
|
-
* Stores changes to column
|
|
33
|
+
* Stores changes to column. One entry per column.
|
|
34
|
+
* Each entry is an array (0: name in the database, last: current name in code)
|
|
30
35
|
*/
|
|
31
|
-
renamedColumns:
|
|
36
|
+
renamedColumns: RenameData[];
|
|
32
37
|
allowedMigrations: AllowedMigrations;
|
|
38
|
+
usedMigrations: Record<string, boolean>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface ColumnInfo {
|
|
42
|
+
name: string;
|
|
43
|
+
type: string;
|
|
44
|
+
defaultValue: string;
|
|
45
|
+
isPrimaryKey: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type ForeignKeyActions = "SET NULL" | "SET DEFAULT" | "RESTRICT" | "NO ACTION" | "CASCADE";
|
|
49
|
+
interface ForeignKeyInfo {
|
|
50
|
+
fromTable: string;
|
|
51
|
+
fromColumn: string;
|
|
52
|
+
toTable: string;
|
|
53
|
+
toColumn: string;
|
|
54
|
+
onUpdate?: ForeignKeyActions;
|
|
55
|
+
onDelete?: ForeignKeyActions;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface TableStructure {
|
|
59
|
+
table: string;
|
|
60
|
+
primaryKey?: string;
|
|
61
|
+
columns: ColumnInfo[];
|
|
62
|
+
foreignKeys?: ForeignKeyInfo[];
|
|
33
63
|
}
|
|
34
64
|
|
|
35
65
|
declare class Migrations {
|
|
@@ -37,20 +67,24 @@ declare class Migrations {
|
|
|
37
67
|
private alwaysAllowed;
|
|
38
68
|
private fromVersion;
|
|
39
69
|
private migrationData;
|
|
70
|
+
private migrationDataForOldTableNames;
|
|
40
71
|
private notAllowedChanges;
|
|
41
72
|
reset(dbInstructions: DatabaseInstructions, fromVersion: number): void;
|
|
42
73
|
private getEntry;
|
|
43
74
|
private getTableName;
|
|
44
|
-
|
|
45
|
-
|
|
75
|
+
verifyRenamingTasks(newTables: Record<string, TableStructure>): Error | void;
|
|
76
|
+
verifyAllowedMigrations(): Error | void;
|
|
77
|
+
compareWithAllowedMigration(tableName: string, type: keyof AllowedMigrations): void;
|
|
46
78
|
allowMigration(version: number, table: string | Class<BackendTable>, ...allowedMigrations: (keyof AllowedMigrations)[]): void;
|
|
47
|
-
renameTable(version: number, oldTableName: string,
|
|
79
|
+
renameTable(version: number, oldTableName: string, newTableName: string | Class<BackendTable>): void;
|
|
48
80
|
renameColumn(version: number, table: string | Class<BackendTable>, oldColumn: string, newColumn: string): void;
|
|
49
81
|
recreateTableImp(table: Class<BackendTable> | string): void;
|
|
50
82
|
recreateTable(version: number, table: Class<BackendTable> | string): void;
|
|
51
83
|
getMigrationData(): Record<string, MigrationInstructions>;
|
|
52
84
|
loopRenamedColumns(tableName: string, callback: (oldColumnName: string, newColumnName: string) => void): void;
|
|
53
|
-
|
|
85
|
+
getNewestTableName(tableName: string): string;
|
|
86
|
+
getOldTableName(tableName: string): string;
|
|
87
|
+
getNewestColumnName(tableName: string, oldColumnName: string): string;
|
|
54
88
|
willBeRecreated(tableName: string): boolean;
|
|
55
89
|
}
|
|
56
90
|
type PublicMigrations = Pick<Migrations, "recreateTable" | "renameTable" | "renameColumn" | "allowMigration">;
|
|
@@ -60,16 +94,6 @@ interface SqlChanges {
|
|
|
60
94
|
down: string;
|
|
61
95
|
}
|
|
62
96
|
|
|
63
|
-
type ForeignKeyActions = "SET NULL" | "SET DEFAULT" | "RESTRICT" | "NO ACTION" | "CASCADE";
|
|
64
|
-
interface ForeignKeyInfo {
|
|
65
|
-
fromTable: string;
|
|
66
|
-
fromColumn: string;
|
|
67
|
-
toTable: string;
|
|
68
|
-
toColumn: string;
|
|
69
|
-
onUpdate?: ForeignKeyActions;
|
|
70
|
-
onDelete?: ForeignKeyActions;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
97
|
interface TableInfo {
|
|
74
98
|
primaryKey?: string;
|
|
75
99
|
foreignKeys?: ForeignKeyInfo[];
|
package/dist/index.js
CHANGED
|
@@ -146,14 +146,12 @@ var TableStructureGenerator = class {
|
|
|
146
146
|
// src/lib/exceptions/NotAllowedException.ts
|
|
147
147
|
var NotAllowedException = class extends Error {
|
|
148
148
|
constructor(entries) {
|
|
149
|
-
let message = "Some destructive changes need to be confirmed
|
|
149
|
+
let message = "Some destructive changes need to be confirmed.\n In preMigration() run:\n";
|
|
150
150
|
for (const entry of entries) {
|
|
151
|
-
message += `
|
|
152
|
-
|
|
151
|
+
message += ` migrations.allowMigration(${entry.version}, "${entry.tableName}", "${entry.type}");
|
|
152
|
+
`;
|
|
153
153
|
}
|
|
154
|
-
super(
|
|
155
|
-
|
|
156
|
-
`);
|
|
154
|
+
super(message);
|
|
157
155
|
}
|
|
158
156
|
};
|
|
159
157
|
|
|
@@ -163,6 +161,7 @@ var Migrations = class {
|
|
|
163
161
|
alwaysAllowed = {};
|
|
164
162
|
fromVersion = 0;
|
|
165
163
|
migrationData = {};
|
|
164
|
+
migrationDataForOldTableNames = {};
|
|
166
165
|
notAllowedChanges = [];
|
|
167
166
|
reset(dbInstructions, fromVersion) {
|
|
168
167
|
this.fromVersion = fromVersion;
|
|
@@ -177,7 +176,8 @@ var Migrations = class {
|
|
|
177
176
|
this.migrationData[tableName] = {
|
|
178
177
|
recreate: false,
|
|
179
178
|
renamedColumns: [],
|
|
180
|
-
allowedMigrations: {}
|
|
179
|
+
allowedMigrations: {},
|
|
180
|
+
usedMigrations: {}
|
|
181
181
|
};
|
|
182
182
|
}
|
|
183
183
|
return this.migrationData[tableName];
|
|
@@ -185,20 +185,47 @@ var Migrations = class {
|
|
|
185
185
|
getTableName(table) {
|
|
186
186
|
return typeof table == "string" ? table : table.name;
|
|
187
187
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
188
|
+
verifyRenamingTasks(newTables) {
|
|
189
|
+
for (const tableName in this.migrationData) {
|
|
190
|
+
const migrationEntry = this.migrationData[tableName];
|
|
191
|
+
if (migrationEntry.tableRenaming?.oldName == tableName)
|
|
192
|
+
return new Error(`You set table "${tableName}" to be renamed to itself!`);
|
|
193
|
+
if (migrationEntry.tableRenaming && migrationEntry.tableRenaming.newName != tableName)
|
|
194
|
+
return new Error(`You set table "${tableName}" to be renamed to a different name than the one in your structure (${migrationEntry.tableRenaming.newName})!`);
|
|
195
|
+
else if (!newTables[tableName])
|
|
196
|
+
return new Error(`You set table "${migrationEntry.tableRenaming}" migrations for "${tableName}". But "${tableName}" does not exist in your structure.`);
|
|
197
|
+
for (const renamingData of migrationEntry.renamedColumns) {
|
|
198
|
+
const oldColumnName = renamingData.oldName;
|
|
199
|
+
const newColumnName = renamingData.newName;
|
|
200
|
+
if (oldColumnName == newColumnName)
|
|
201
|
+
return new Error(`You set column ${tableName}.${oldColumnName} to be renamed to itself!`);
|
|
202
|
+
else if (!newTables[tableName]?.columns.find((column) => column.name == newColumnName))
|
|
203
|
+
return new Error(`You set column ${tableName}.${oldColumnName} to be renamed to ${tableName}.${newColumnName}. But ${tableName}.${newColumnName} does not exist in your structure.`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
verifyAllowedMigrations() {
|
|
208
|
+
if (this.notAllowedChanges.length)
|
|
209
|
+
return new NotAllowedException(this.notAllowedChanges);
|
|
210
|
+
let errorMsg = "";
|
|
211
|
+
for (const tableName in this.migrationData) {
|
|
212
|
+
const migration = this.migrationData[tableName];
|
|
213
|
+
for (const type in migration.allowedMigrations) {
|
|
214
|
+
if (!migration.usedMigrations[type])
|
|
215
|
+
errorMsg += `Migration "${type}" for ${tableName} was allowed but not needed.
|
|
216
|
+
`;
|
|
217
|
+
}
|
|
201
218
|
}
|
|
219
|
+
if (errorMsg)
|
|
220
|
+
return new Error(errorMsg);
|
|
221
|
+
}
|
|
222
|
+
compareWithAllowedMigration(tableName, type) {
|
|
223
|
+
const migrationEntry = this.migrationData[tableName];
|
|
224
|
+
if (!migrationEntry?.allowedMigrations[type]) {
|
|
225
|
+
if (!this.alwaysAllowed[type])
|
|
226
|
+
this.notAllowedChanges.push({ version: this.toVersion, tableName, type });
|
|
227
|
+
} else if (migrationEntry)
|
|
228
|
+
migrationEntry.usedMigrations[type] = true;
|
|
202
229
|
}
|
|
203
230
|
allowMigration(version, table, ...allowedMigrations) {
|
|
204
231
|
if (version < this.fromVersion || version > this.toVersion)
|
|
@@ -208,23 +235,30 @@ var Migrations = class {
|
|
|
208
235
|
entry.allowedMigrations[key] = true;
|
|
209
236
|
}
|
|
210
237
|
}
|
|
211
|
-
renameTable(version, oldTableName,
|
|
238
|
+
renameTable(version, oldTableName, newTableName) {
|
|
212
239
|
if (version < this.fromVersion || version > this.toVersion)
|
|
213
240
|
return;
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
241
|
+
const newTableNameString = this.getTableName(newTableName);
|
|
242
|
+
if (this.migrationData.hasOwnProperty(oldTableName)) {
|
|
243
|
+
this.migrationData[newTableNameString] = this.getEntry(oldTableName);
|
|
244
|
+
delete this.migrationData[oldTableName];
|
|
245
|
+
}
|
|
246
|
+
const entry = this.getEntry(newTableName);
|
|
247
|
+
this.migrationDataForOldTableNames[oldTableName] = entry;
|
|
248
|
+
if (!entry.tableRenaming)
|
|
249
|
+
entry.tableRenaming = { oldName: oldTableName, newName: newTableNameString };
|
|
250
|
+
else
|
|
251
|
+
entry.tableRenaming.newName = newTableNameString;
|
|
218
252
|
}
|
|
219
253
|
renameColumn(version, table, oldColumn, newColumn) {
|
|
220
254
|
if (version < this.fromVersion || version > this.toVersion)
|
|
221
255
|
return;
|
|
222
256
|
const entry = this.getEntry(table);
|
|
223
|
-
const existingColumnEntry = entry.renamedColumns.find((entry2) => entry2
|
|
257
|
+
const existingColumnEntry = entry.renamedColumns.find((entry2) => entry2.newName == oldColumn);
|
|
224
258
|
if (existingColumnEntry)
|
|
225
|
-
existingColumnEntry.
|
|
259
|
+
existingColumnEntry.newName = newColumn;
|
|
226
260
|
else
|
|
227
|
-
entry.renamedColumns.push(
|
|
261
|
+
entry.renamedColumns.push({ oldName: oldColumn, newName: newColumn });
|
|
228
262
|
}
|
|
229
263
|
recreateTableImp(table) {
|
|
230
264
|
const entry = this.getEntry(table);
|
|
@@ -240,17 +274,19 @@ var Migrations = class {
|
|
|
240
274
|
}
|
|
241
275
|
loopRenamedColumns(tableName, callback) {
|
|
242
276
|
const migrationEntry = this.migrationData[tableName];
|
|
243
|
-
for (const
|
|
244
|
-
|
|
245
|
-
continue;
|
|
246
|
-
const oldColumnName = renamingArray[0];
|
|
247
|
-
const newColumnName = renamingArray[renamingArray.length - 1];
|
|
248
|
-
callback(oldColumnName, newColumnName);
|
|
277
|
+
for (const renamingData of migrationEntry.renamedColumns) {
|
|
278
|
+
callback(renamingData.oldName, renamingData.newName);
|
|
249
279
|
}
|
|
250
280
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
281
|
+
getNewestTableName(tableName) {
|
|
282
|
+
return this.migrationDataForOldTableNames[tableName]?.tableRenaming?.newName ?? tableName;
|
|
283
|
+
}
|
|
284
|
+
getOldTableName(tableName) {
|
|
285
|
+
return this.migrationData[tableName]?.tableRenaming?.oldName ?? tableName;
|
|
286
|
+
}
|
|
287
|
+
getNewestColumnName(tableName, oldColumnName) {
|
|
288
|
+
const columnNames = this.migrationData[tableName]?.renamedColumns.find((columns) => columns.oldName == oldColumnName);
|
|
289
|
+
return columnNames ? columnNames.newName : oldColumnName;
|
|
254
290
|
}
|
|
255
291
|
willBeRecreated(tableName) {
|
|
256
292
|
return this.migrationData[tableName]?.recreate;
|
|
@@ -261,6 +297,10 @@ var Migrations = class {
|
|
|
261
297
|
var MigrationManager = class {
|
|
262
298
|
migrations = new Migrations();
|
|
263
299
|
newTables = {};
|
|
300
|
+
/**
|
|
301
|
+
* Table names that currently exist in the database
|
|
302
|
+
* Note: If tables are set to be renamed, then names in this array will be corrected to their future name.
|
|
303
|
+
*/
|
|
264
304
|
existingTables = [];
|
|
265
305
|
dialect;
|
|
266
306
|
constructor(dialect) {
|
|
@@ -318,8 +358,9 @@ ${preSQL.down}`;
|
|
|
318
358
|
changes.down += initialChanges.down;
|
|
319
359
|
} else {
|
|
320
360
|
Logger.log(`Creating migration SQL from version ${fromVersion} to ${toVersion}`);
|
|
321
|
-
this.existingTables = await this.dialect.getTableNames();
|
|
361
|
+
this.existingTables = (await this.dialect.getTableNames()).map((oldTableName) => this.migrations.getNewestTableName(oldTableName));
|
|
322
362
|
[
|
|
363
|
+
this.renameTables(),
|
|
323
364
|
await this.createAndDropTables(),
|
|
324
365
|
await this.migrateForeignKeys(),
|
|
325
366
|
await this.migrateColumns(),
|
|
@@ -348,8 +389,18 @@ ${foreignKeyOnQuery}`;
|
|
|
348
389
|
changes.down += `
|
|
349
390
|
|
|
350
391
|
${foreignKeyOnQuery}`;
|
|
351
|
-
|
|
352
|
-
|
|
392
|
+
const exception = this.migrations.verifyRenamingTasks(this.newTables) ?? this.migrations.verifyAllowedMigrations();
|
|
393
|
+
if (exception) {
|
|
394
|
+
Logger.debug(`
|
|
395
|
+
Canceled changes:
|
|
396
|
+
${changes.up}
|
|
397
|
+
`);
|
|
398
|
+
if (dbInstructions.throwIfNotAllowed)
|
|
399
|
+
throw exception;
|
|
400
|
+
else {
|
|
401
|
+
console.error(exception.message);
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
353
404
|
}
|
|
354
405
|
return {
|
|
355
406
|
fromVersion,
|
|
@@ -357,6 +408,22 @@ ${foreignKeyOnQuery}`;
|
|
|
357
408
|
changes
|
|
358
409
|
};
|
|
359
410
|
}
|
|
411
|
+
renameTables() {
|
|
412
|
+
const changes = {
|
|
413
|
+
up: "\n\n-- Rename tables\n",
|
|
414
|
+
down: "\n\n-- Rename tables\n"
|
|
415
|
+
};
|
|
416
|
+
const data = this.migrations.getMigrationData();
|
|
417
|
+
for (const tableName in data) {
|
|
418
|
+
const migrationEntry = data[tableName];
|
|
419
|
+
if (migrationEntry.tableRenaming) {
|
|
420
|
+
Logger.log(`Table "${migrationEntry.tableRenaming.oldName}" will be renamed to "${tableName}"!`);
|
|
421
|
+
changes.up += this.dialect.renameTable(migrationEntry.tableRenaming.oldName, tableName);
|
|
422
|
+
changes.down += this.dialect.renameTable(tableName, migrationEntry.tableRenaming.oldName);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return changes;
|
|
426
|
+
}
|
|
360
427
|
/**
|
|
361
428
|
* Generates SQL change statements for creating and dropping tables based on the current table structure
|
|
362
429
|
* and existing table configurations in the database. The `up` changes include SQL statements for creating
|
|
@@ -368,8 +435,8 @@ ${foreignKeyOnQuery}`;
|
|
|
368
435
|
*/
|
|
369
436
|
async createAndDropTables() {
|
|
370
437
|
let changes = {
|
|
371
|
-
up: "\n\n-- Create tables\n",
|
|
372
|
-
down: "\n\n-- Create tables\n"
|
|
438
|
+
up: "\n\n-- Create and drop tables\n",
|
|
439
|
+
down: "\n\n-- Create and drop tables\n"
|
|
373
440
|
};
|
|
374
441
|
for (const tableName in this.newTables) {
|
|
375
442
|
if (this.tableDoesNotExists(tableName)) {
|
|
@@ -382,12 +449,13 @@ ${foreignKeyOnQuery}`;
|
|
|
382
449
|
}
|
|
383
450
|
for (const tableName of this.existingTables) {
|
|
384
451
|
if (!this.newTables[tableName]) {
|
|
385
|
-
this.migrations.
|
|
452
|
+
this.migrations.compareWithAllowedMigration(tableName, "dropTable");
|
|
386
453
|
if (!this.dialect.canInspectForeignKeys || !this.dialect.canInspectPrimaryKey)
|
|
387
|
-
this.migrations.
|
|
454
|
+
this.migrations.compareWithAllowedMigration(tableName, "continueWithoutRollback");
|
|
455
|
+
const dbTableName = this.migrations.getOldTableName(tableName);
|
|
388
456
|
changes.up += `${this.dialect.dropTable(tableName)}
|
|
389
457
|
`;
|
|
390
|
-
changes.down += this.dialect.canInspectForeignKeys && this.dialect.canInspectPrimaryKey ? this.createTableSql(tableName, await this.dialect.getColumnInformation(
|
|
458
|
+
changes.down += this.dialect.canInspectForeignKeys && this.dialect.canInspectPrimaryKey ? this.createTableSql(tableName, await this.dialect.getColumnInformation(dbTableName), await this.dialect.getForeignKeys(dbTableName)) : "\n\n-- Cannot recreate foreign keys or load primary keys with this database! Table will not be recreated!\n";
|
|
391
459
|
}
|
|
392
460
|
}
|
|
393
461
|
return changes;
|
|
@@ -438,10 +506,11 @@ ${foreignKeyOnQuery}`;
|
|
|
438
506
|
const migrationEntry = migrationData[tableName];
|
|
439
507
|
if (!migrationEntry.recreate)
|
|
440
508
|
continue;
|
|
441
|
-
|
|
509
|
+
Logger.log(`Table ${tableName} will be recreated!`);
|
|
510
|
+
this.migrations.compareWithAllowedMigration(tableName, "recreateTable");
|
|
442
511
|
if (!this.dialect.canInspectForeignKeys || !this.dialect.canInspectPrimaryKey)
|
|
443
|
-
this.migrations.
|
|
444
|
-
const oldColumnList = await this.dialect.getColumnInformation(tableName);
|
|
512
|
+
this.migrations.compareWithAllowedMigration(tableName, "continueWithoutRollback");
|
|
513
|
+
const oldColumnList = await this.dialect.getColumnInformation(this.migrations.getOldTableName(tableName));
|
|
445
514
|
const newColumnList = this.newTables[tableName].columns;
|
|
446
515
|
const moveableColumns = newColumnList.filter((entry) => oldColumnList.find((oldEntry) => oldEntry.name == entry.name) != void 0).map((entry) => entry.name);
|
|
447
516
|
const backupTableName = `${tableName}__backup`;
|
|
@@ -451,8 +520,9 @@ ${foreignKeyOnQuery}`;
|
|
|
451
520
|
);
|
|
452
521
|
const moveDataQuery = insertQuery + "\n" + this.dialect.dropTable(tableName) + "\n" + this.dialect.renameTable(backupTableName, tableName);
|
|
453
522
|
const structure = this.newTables[tableName];
|
|
454
|
-
changes.up += this.createTableSql(backupTableName, structure.columns, structure.foreignKeys) + "\n" + moveDataQuery;
|
|
455
|
-
|
|
523
|
+
changes.up += this.createTableSql(backupTableName, structure.columns, structure.foreignKeys) + "\n" + moveDataQuery + "\n";
|
|
524
|
+
const dbTableName = this.migrations.getOldTableName(tableName);
|
|
525
|
+
changes.down += this.dialect.canInspectForeignKeys && this.dialect.canInspectPrimaryKey ? this.createTableSql(backupTableName, await this.dialect.getColumnInformation(dbTableName), await this.dialect.getForeignKeys(dbTableName)) + "\n" + moveDataQuery : "\n\n-- Cannot recreate foreign keys or load primary keys with this database! Table will not be recreated!\n";
|
|
456
526
|
}
|
|
457
527
|
return changes;
|
|
458
528
|
}
|
|
@@ -460,8 +530,6 @@ ${foreignKeyOnQuery}`;
|
|
|
460
530
|
* Migrates foreign key constraints for all defined tables.
|
|
461
531
|
*/
|
|
462
532
|
async migrateForeignKeys() {
|
|
463
|
-
if (!this.dialect.canAlterForeignKeys)
|
|
464
|
-
return { up: "", down: "" };
|
|
465
533
|
let changes = {
|
|
466
534
|
up: "\n\n-- Foreign keys\n",
|
|
467
535
|
down: "\n\n-- Foreign keys\n"
|
|
@@ -471,13 +539,13 @@ ${foreignKeyOnQuery}`;
|
|
|
471
539
|
continue;
|
|
472
540
|
const structure = this.newTables[tableName];
|
|
473
541
|
const newForeignKeys = structure.foreignKeys ?? [];
|
|
474
|
-
const oldForeignKeys = await this.dialect.getForeignKeys(tableName);
|
|
542
|
+
const oldForeignKeys = await this.dialect.getForeignKeys(this.migrations.getOldTableName(tableName));
|
|
475
543
|
let checkForNewForeignKeys = true;
|
|
476
544
|
for (const oldForeignKey of oldForeignKeys) {
|
|
477
545
|
const newForeignKey = newForeignKeys.find((entry) => entry.fromColumn == oldForeignKey.fromColumn);
|
|
478
546
|
if (!newForeignKey) {
|
|
479
|
-
Logger.log(`Foreign key ${oldForeignKey.
|
|
480
|
-
this.migrations.
|
|
547
|
+
Logger.log(`Foreign key ${oldForeignKey.fromTable}.${oldForeignKey.fromColumn} to ${oldForeignKey.toTable}.${oldForeignKey.toColumn} will be removed!`);
|
|
548
|
+
this.migrations.compareWithAllowedMigration(tableName, "removeForeignKey");
|
|
481
549
|
if (this.dialect.canAlterForeignKeys) {
|
|
482
550
|
changes.up += this.dialect.removeForeignKey(oldForeignKey.fromTable, oldForeignKey.fromColumn);
|
|
483
551
|
changes.down += this.dialect.addForeignKey(
|
|
@@ -490,8 +558,8 @@ ${foreignKeyOnQuery}`;
|
|
|
490
558
|
}
|
|
491
559
|
} else {
|
|
492
560
|
if (!newForeignKey || oldForeignKey.toColumn != newForeignKey.toColumn || (oldForeignKey.onUpdate ?? "NO ACTION") != (newForeignKey.onUpdate ?? "NO ACTION") || (oldForeignKey.onDelete ?? "NO ACTION") != (newForeignKey.onDelete ?? "NO ACTION")) {
|
|
493
|
-
Logger.log(`Foreign key ${oldForeignKey.
|
|
494
|
-
this.migrations.
|
|
561
|
+
Logger.log(`Foreign key ${oldForeignKey.fromTable}.${oldForeignKey.fromColumn} to ${oldForeignKey.toTable}.${oldForeignKey.toColumn} will be changed!`);
|
|
562
|
+
this.migrations.compareWithAllowedMigration(tableName, "alterForeignKey");
|
|
495
563
|
if (this.dialect.canAlterForeignKeys) {
|
|
496
564
|
changes.up += this.dialect.removeForeignKey(oldForeignKey.fromTable, oldForeignKey.fromColumn) + this.dialect.addForeignKey(
|
|
497
565
|
newForeignKey.fromTable,
|
|
@@ -513,7 +581,7 @@ ${foreignKeyOnQuery}`;
|
|
|
513
581
|
const oldForeignKey = oldForeignKeys.find((entry) => entry.fromColumn == newForeignKey.fromColumn);
|
|
514
582
|
if (oldForeignKey)
|
|
515
583
|
continue;
|
|
516
|
-
Logger.log(`Foreign key ${newForeignKey.
|
|
584
|
+
Logger.log(`Foreign key ${newForeignKey.fromTable}.${newForeignKey.fromColumn} to ${newForeignKey.toTable}.${newForeignKey.toColumn} will be added!`);
|
|
517
585
|
if (this.dialect.canAlterForeignKeys) {
|
|
518
586
|
changes.up += this.dialect.addForeignKey(
|
|
519
587
|
newForeignKey.toTable,
|
|
@@ -542,13 +610,13 @@ ${foreignKeyOnQuery}`;
|
|
|
542
610
|
if (this.migrations.willBeRecreated(tableName) || this.tableDoesNotExists(tableName))
|
|
543
611
|
continue;
|
|
544
612
|
const newTableDefinition = this.newTables[tableName];
|
|
545
|
-
const oldColumnList = await this.dialect.getColumnInformation(tableName);
|
|
613
|
+
const oldColumnList = await this.dialect.getColumnInformation(this.migrations.getOldTableName(tableName));
|
|
546
614
|
const oldPrimaryKey = this.dialect.canInspectPrimaryKey ? this.getPrimaryKeyColumn(oldColumnList) : false;
|
|
547
615
|
const newColumnList = newTableDefinition.columns;
|
|
548
616
|
const newPrimaryKey = newTableDefinition.primaryKey;
|
|
549
617
|
if (this.dialect.canInspectPrimaryKey && oldPrimaryKey != newPrimaryKey) {
|
|
550
|
-
Logger.log(`Primary key in ${tableName}
|
|
551
|
-
this.migrations.
|
|
618
|
+
Logger.log(`Primary key in ${tableName} will be changed from ${oldPrimaryKey} to ${newPrimaryKey}!`);
|
|
619
|
+
this.migrations.compareWithAllowedMigration(tableName, "alterPrimaryKey");
|
|
552
620
|
if (this.dialect.canAlterPrimaryKey) {
|
|
553
621
|
if (oldPrimaryKey) {
|
|
554
622
|
changes.up += this.dialect.removePrimaryKey(tableName, oldPrimaryKey);
|
|
@@ -564,7 +632,7 @@ ${foreignKeyOnQuery}`;
|
|
|
564
632
|
}
|
|
565
633
|
for (const newColumn of newColumnList) {
|
|
566
634
|
const oldColumn = oldColumnList.find(
|
|
567
|
-
(entry) => this.migrations.
|
|
635
|
+
(entry) => this.migrations.getNewestColumnName(tableName, entry.name) == newColumn.name
|
|
568
636
|
);
|
|
569
637
|
if (oldColumn == void 0) {
|
|
570
638
|
changes.up += this.dialect.createColumn(tableName, this.dialect.columnDefinition(newColumn.name, newColumn.type, newColumn.defaultValue, newColumn.isPrimaryKey)) + "\n";
|
|
@@ -575,10 +643,10 @@ ${foreignKeyOnQuery}`;
|
|
|
575
643
|
}
|
|
576
644
|
for (const oldColumn of oldColumnList) {
|
|
577
645
|
const newColumn = newColumnList.find(
|
|
578
|
-
(entry) => entry.name == this.migrations.
|
|
646
|
+
(entry) => entry.name == this.migrations.getNewestColumnName(tableName, oldColumn.name)
|
|
579
647
|
);
|
|
580
648
|
if (newColumn == void 0) {
|
|
581
|
-
this.migrations.
|
|
649
|
+
this.migrations.compareWithAllowedMigration(tableName, "dropColumn");
|
|
582
650
|
changes.up += this.dialect.dropColumn(tableName, oldColumn.name) + "\n";
|
|
583
651
|
changes.down += this.dialect.createColumn(tableName, this.dialect.columnDefinition(oldColumn.name, oldColumn.type, oldColumn.defaultValue, oldColumn.isPrimaryKey)) + "\n";
|
|
584
652
|
}
|
|
@@ -612,6 +680,7 @@ ${foreignKeyOnQuery}`;
|
|
|
612
680
|
if (migrationData[tableName].recreate)
|
|
613
681
|
continue;
|
|
614
682
|
this.migrations.loopRenamedColumns(tableName, (oldColumnName, newColumnName) => {
|
|
683
|
+
Logger.log(`Column ${tableName}.${oldColumnName} will be renamed to ${tableName}.${newColumnName}!`);
|
|
615
684
|
changes.up += this.dialect.renameColumn(tableName, oldColumnName, newColumnName);
|
|
616
685
|
changes.down += this.dialect.renameColumn(tableName, newColumnName, oldColumnName);
|
|
617
686
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -114,14 +114,12 @@ var TableStructureGenerator = class {
|
|
|
114
114
|
// src/lib/exceptions/NotAllowedException.ts
|
|
115
115
|
var NotAllowedException = class extends Error {
|
|
116
116
|
constructor(entries) {
|
|
117
|
-
let message = "Some destructive changes need to be confirmed
|
|
117
|
+
let message = "Some destructive changes need to be confirmed.\n In preMigration() run:\n";
|
|
118
118
|
for (const entry of entries) {
|
|
119
|
-
message += `
|
|
120
|
-
|
|
119
|
+
message += ` migrations.allowMigration(${entry.version}, "${entry.tableName}", "${entry.type}");
|
|
120
|
+
`;
|
|
121
121
|
}
|
|
122
|
-
super(
|
|
123
|
-
|
|
124
|
-
`);
|
|
122
|
+
super(message);
|
|
125
123
|
}
|
|
126
124
|
};
|
|
127
125
|
|
|
@@ -131,6 +129,7 @@ var Migrations = class {
|
|
|
131
129
|
alwaysAllowed = {};
|
|
132
130
|
fromVersion = 0;
|
|
133
131
|
migrationData = {};
|
|
132
|
+
migrationDataForOldTableNames = {};
|
|
134
133
|
notAllowedChanges = [];
|
|
135
134
|
reset(dbInstructions, fromVersion) {
|
|
136
135
|
this.fromVersion = fromVersion;
|
|
@@ -145,7 +144,8 @@ var Migrations = class {
|
|
|
145
144
|
this.migrationData[tableName] = {
|
|
146
145
|
recreate: false,
|
|
147
146
|
renamedColumns: [],
|
|
148
|
-
allowedMigrations: {}
|
|
147
|
+
allowedMigrations: {},
|
|
148
|
+
usedMigrations: {}
|
|
149
149
|
};
|
|
150
150
|
}
|
|
151
151
|
return this.migrationData[tableName];
|
|
@@ -153,20 +153,47 @@ var Migrations = class {
|
|
|
153
153
|
getTableName(table) {
|
|
154
154
|
return typeof table == "string" ? table : table.name;
|
|
155
155
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
156
|
+
verifyRenamingTasks(newTables) {
|
|
157
|
+
for (const tableName in this.migrationData) {
|
|
158
|
+
const migrationEntry = this.migrationData[tableName];
|
|
159
|
+
if (migrationEntry.tableRenaming?.oldName == tableName)
|
|
160
|
+
return new Error(`You set table "${tableName}" to be renamed to itself!`);
|
|
161
|
+
if (migrationEntry.tableRenaming && migrationEntry.tableRenaming.newName != tableName)
|
|
162
|
+
return new Error(`You set table "${tableName}" to be renamed to a different name than the one in your structure (${migrationEntry.tableRenaming.newName})!`);
|
|
163
|
+
else if (!newTables[tableName])
|
|
164
|
+
return new Error(`You set table "${migrationEntry.tableRenaming}" migrations for "${tableName}". But "${tableName}" does not exist in your structure.`);
|
|
165
|
+
for (const renamingData of migrationEntry.renamedColumns) {
|
|
166
|
+
const oldColumnName = renamingData.oldName;
|
|
167
|
+
const newColumnName = renamingData.newName;
|
|
168
|
+
if (oldColumnName == newColumnName)
|
|
169
|
+
return new Error(`You set column ${tableName}.${oldColumnName} to be renamed to itself!`);
|
|
170
|
+
else if (!newTables[tableName]?.columns.find((column) => column.name == newColumnName))
|
|
171
|
+
return new Error(`You set column ${tableName}.${oldColumnName} to be renamed to ${tableName}.${newColumnName}. But ${tableName}.${newColumnName} does not exist in your structure.`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
verifyAllowedMigrations() {
|
|
176
|
+
if (this.notAllowedChanges.length)
|
|
177
|
+
return new NotAllowedException(this.notAllowedChanges);
|
|
178
|
+
let errorMsg = "";
|
|
179
|
+
for (const tableName in this.migrationData) {
|
|
180
|
+
const migration = this.migrationData[tableName];
|
|
181
|
+
for (const type in migration.allowedMigrations) {
|
|
182
|
+
if (!migration.usedMigrations[type])
|
|
183
|
+
errorMsg += `Migration "${type}" for ${tableName} was allowed but not needed.
|
|
184
|
+
`;
|
|
185
|
+
}
|
|
169
186
|
}
|
|
187
|
+
if (errorMsg)
|
|
188
|
+
return new Error(errorMsg);
|
|
189
|
+
}
|
|
190
|
+
compareWithAllowedMigration(tableName, type) {
|
|
191
|
+
const migrationEntry = this.migrationData[tableName];
|
|
192
|
+
if (!migrationEntry?.allowedMigrations[type]) {
|
|
193
|
+
if (!this.alwaysAllowed[type])
|
|
194
|
+
this.notAllowedChanges.push({ version: this.toVersion, tableName, type });
|
|
195
|
+
} else if (migrationEntry)
|
|
196
|
+
migrationEntry.usedMigrations[type] = true;
|
|
170
197
|
}
|
|
171
198
|
allowMigration(version, table, ...allowedMigrations) {
|
|
172
199
|
if (version < this.fromVersion || version > this.toVersion)
|
|
@@ -176,23 +203,30 @@ var Migrations = class {
|
|
|
176
203
|
entry.allowedMigrations[key] = true;
|
|
177
204
|
}
|
|
178
205
|
}
|
|
179
|
-
renameTable(version, oldTableName,
|
|
206
|
+
renameTable(version, oldTableName, newTableName) {
|
|
180
207
|
if (version < this.fromVersion || version > this.toVersion)
|
|
181
208
|
return;
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
209
|
+
const newTableNameString = this.getTableName(newTableName);
|
|
210
|
+
if (this.migrationData.hasOwnProperty(oldTableName)) {
|
|
211
|
+
this.migrationData[newTableNameString] = this.getEntry(oldTableName);
|
|
212
|
+
delete this.migrationData[oldTableName];
|
|
213
|
+
}
|
|
214
|
+
const entry = this.getEntry(newTableName);
|
|
215
|
+
this.migrationDataForOldTableNames[oldTableName] = entry;
|
|
216
|
+
if (!entry.tableRenaming)
|
|
217
|
+
entry.tableRenaming = { oldName: oldTableName, newName: newTableNameString };
|
|
218
|
+
else
|
|
219
|
+
entry.tableRenaming.newName = newTableNameString;
|
|
186
220
|
}
|
|
187
221
|
renameColumn(version, table, oldColumn, newColumn) {
|
|
188
222
|
if (version < this.fromVersion || version > this.toVersion)
|
|
189
223
|
return;
|
|
190
224
|
const entry = this.getEntry(table);
|
|
191
|
-
const existingColumnEntry = entry.renamedColumns.find((entry2) => entry2
|
|
225
|
+
const existingColumnEntry = entry.renamedColumns.find((entry2) => entry2.newName == oldColumn);
|
|
192
226
|
if (existingColumnEntry)
|
|
193
|
-
existingColumnEntry.
|
|
227
|
+
existingColumnEntry.newName = newColumn;
|
|
194
228
|
else
|
|
195
|
-
entry.renamedColumns.push(
|
|
229
|
+
entry.renamedColumns.push({ oldName: oldColumn, newName: newColumn });
|
|
196
230
|
}
|
|
197
231
|
recreateTableImp(table) {
|
|
198
232
|
const entry = this.getEntry(table);
|
|
@@ -208,17 +242,19 @@ var Migrations = class {
|
|
|
208
242
|
}
|
|
209
243
|
loopRenamedColumns(tableName, callback) {
|
|
210
244
|
const migrationEntry = this.migrationData[tableName];
|
|
211
|
-
for (const
|
|
212
|
-
|
|
213
|
-
continue;
|
|
214
|
-
const oldColumnName = renamingArray[0];
|
|
215
|
-
const newColumnName = renamingArray[renamingArray.length - 1];
|
|
216
|
-
callback(oldColumnName, newColumnName);
|
|
245
|
+
for (const renamingData of migrationEntry.renamedColumns) {
|
|
246
|
+
callback(renamingData.oldName, renamingData.newName);
|
|
217
247
|
}
|
|
218
248
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
249
|
+
getNewestTableName(tableName) {
|
|
250
|
+
return this.migrationDataForOldTableNames[tableName]?.tableRenaming?.newName ?? tableName;
|
|
251
|
+
}
|
|
252
|
+
getOldTableName(tableName) {
|
|
253
|
+
return this.migrationData[tableName]?.tableRenaming?.oldName ?? tableName;
|
|
254
|
+
}
|
|
255
|
+
getNewestColumnName(tableName, oldColumnName) {
|
|
256
|
+
const columnNames = this.migrationData[tableName]?.renamedColumns.find((columns) => columns.oldName == oldColumnName);
|
|
257
|
+
return columnNames ? columnNames.newName : oldColumnName;
|
|
222
258
|
}
|
|
223
259
|
willBeRecreated(tableName) {
|
|
224
260
|
return this.migrationData[tableName]?.recreate;
|
|
@@ -229,6 +265,10 @@ var Migrations = class {
|
|
|
229
265
|
var MigrationManager = class {
|
|
230
266
|
migrations = new Migrations();
|
|
231
267
|
newTables = {};
|
|
268
|
+
/**
|
|
269
|
+
* Table names that currently exist in the database
|
|
270
|
+
* Note: If tables are set to be renamed, then names in this array will be corrected to their future name.
|
|
271
|
+
*/
|
|
232
272
|
existingTables = [];
|
|
233
273
|
dialect;
|
|
234
274
|
constructor(dialect) {
|
|
@@ -286,8 +326,9 @@ ${preSQL.down}`;
|
|
|
286
326
|
changes.down += initialChanges.down;
|
|
287
327
|
} else {
|
|
288
328
|
Logger.log(`Creating migration SQL from version ${fromVersion} to ${toVersion}`);
|
|
289
|
-
this.existingTables = await this.dialect.getTableNames();
|
|
329
|
+
this.existingTables = (await this.dialect.getTableNames()).map((oldTableName) => this.migrations.getNewestTableName(oldTableName));
|
|
290
330
|
[
|
|
331
|
+
this.renameTables(),
|
|
291
332
|
await this.createAndDropTables(),
|
|
292
333
|
await this.migrateForeignKeys(),
|
|
293
334
|
await this.migrateColumns(),
|
|
@@ -316,8 +357,18 @@ ${foreignKeyOnQuery}`;
|
|
|
316
357
|
changes.down += `
|
|
317
358
|
|
|
318
359
|
${foreignKeyOnQuery}`;
|
|
319
|
-
|
|
320
|
-
|
|
360
|
+
const exception = this.migrations.verifyRenamingTasks(this.newTables) ?? this.migrations.verifyAllowedMigrations();
|
|
361
|
+
if (exception) {
|
|
362
|
+
Logger.debug(`
|
|
363
|
+
Canceled changes:
|
|
364
|
+
${changes.up}
|
|
365
|
+
`);
|
|
366
|
+
if (dbInstructions.throwIfNotAllowed)
|
|
367
|
+
throw exception;
|
|
368
|
+
else {
|
|
369
|
+
console.error(exception.message);
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
321
372
|
}
|
|
322
373
|
return {
|
|
323
374
|
fromVersion,
|
|
@@ -325,6 +376,22 @@ ${foreignKeyOnQuery}`;
|
|
|
325
376
|
changes
|
|
326
377
|
};
|
|
327
378
|
}
|
|
379
|
+
renameTables() {
|
|
380
|
+
const changes = {
|
|
381
|
+
up: "\n\n-- Rename tables\n",
|
|
382
|
+
down: "\n\n-- Rename tables\n"
|
|
383
|
+
};
|
|
384
|
+
const data = this.migrations.getMigrationData();
|
|
385
|
+
for (const tableName in data) {
|
|
386
|
+
const migrationEntry = data[tableName];
|
|
387
|
+
if (migrationEntry.tableRenaming) {
|
|
388
|
+
Logger.log(`Table "${migrationEntry.tableRenaming.oldName}" will be renamed to "${tableName}"!`);
|
|
389
|
+
changes.up += this.dialect.renameTable(migrationEntry.tableRenaming.oldName, tableName);
|
|
390
|
+
changes.down += this.dialect.renameTable(tableName, migrationEntry.tableRenaming.oldName);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
return changes;
|
|
394
|
+
}
|
|
328
395
|
/**
|
|
329
396
|
* Generates SQL change statements for creating and dropping tables based on the current table structure
|
|
330
397
|
* and existing table configurations in the database. The `up` changes include SQL statements for creating
|
|
@@ -336,8 +403,8 @@ ${foreignKeyOnQuery}`;
|
|
|
336
403
|
*/
|
|
337
404
|
async createAndDropTables() {
|
|
338
405
|
let changes = {
|
|
339
|
-
up: "\n\n-- Create tables\n",
|
|
340
|
-
down: "\n\n-- Create tables\n"
|
|
406
|
+
up: "\n\n-- Create and drop tables\n",
|
|
407
|
+
down: "\n\n-- Create and drop tables\n"
|
|
341
408
|
};
|
|
342
409
|
for (const tableName in this.newTables) {
|
|
343
410
|
if (this.tableDoesNotExists(tableName)) {
|
|
@@ -350,12 +417,13 @@ ${foreignKeyOnQuery}`;
|
|
|
350
417
|
}
|
|
351
418
|
for (const tableName of this.existingTables) {
|
|
352
419
|
if (!this.newTables[tableName]) {
|
|
353
|
-
this.migrations.
|
|
420
|
+
this.migrations.compareWithAllowedMigration(tableName, "dropTable");
|
|
354
421
|
if (!this.dialect.canInspectForeignKeys || !this.dialect.canInspectPrimaryKey)
|
|
355
|
-
this.migrations.
|
|
422
|
+
this.migrations.compareWithAllowedMigration(tableName, "continueWithoutRollback");
|
|
423
|
+
const dbTableName = this.migrations.getOldTableName(tableName);
|
|
356
424
|
changes.up += `${this.dialect.dropTable(tableName)}
|
|
357
425
|
`;
|
|
358
|
-
changes.down += this.dialect.canInspectForeignKeys && this.dialect.canInspectPrimaryKey ? this.createTableSql(tableName, await this.dialect.getColumnInformation(
|
|
426
|
+
changes.down += this.dialect.canInspectForeignKeys && this.dialect.canInspectPrimaryKey ? this.createTableSql(tableName, await this.dialect.getColumnInformation(dbTableName), await this.dialect.getForeignKeys(dbTableName)) : "\n\n-- Cannot recreate foreign keys or load primary keys with this database! Table will not be recreated!\n";
|
|
359
427
|
}
|
|
360
428
|
}
|
|
361
429
|
return changes;
|
|
@@ -406,10 +474,11 @@ ${foreignKeyOnQuery}`;
|
|
|
406
474
|
const migrationEntry = migrationData[tableName];
|
|
407
475
|
if (!migrationEntry.recreate)
|
|
408
476
|
continue;
|
|
409
|
-
|
|
477
|
+
Logger.log(`Table ${tableName} will be recreated!`);
|
|
478
|
+
this.migrations.compareWithAllowedMigration(tableName, "recreateTable");
|
|
410
479
|
if (!this.dialect.canInspectForeignKeys || !this.dialect.canInspectPrimaryKey)
|
|
411
|
-
this.migrations.
|
|
412
|
-
const oldColumnList = await this.dialect.getColumnInformation(tableName);
|
|
480
|
+
this.migrations.compareWithAllowedMigration(tableName, "continueWithoutRollback");
|
|
481
|
+
const oldColumnList = await this.dialect.getColumnInformation(this.migrations.getOldTableName(tableName));
|
|
413
482
|
const newColumnList = this.newTables[tableName].columns;
|
|
414
483
|
const moveableColumns = newColumnList.filter((entry) => oldColumnList.find((oldEntry) => oldEntry.name == entry.name) != void 0).map((entry) => entry.name);
|
|
415
484
|
const backupTableName = `${tableName}__backup`;
|
|
@@ -419,8 +488,9 @@ ${foreignKeyOnQuery}`;
|
|
|
419
488
|
);
|
|
420
489
|
const moveDataQuery = insertQuery + "\n" + this.dialect.dropTable(tableName) + "\n" + this.dialect.renameTable(backupTableName, tableName);
|
|
421
490
|
const structure = this.newTables[tableName];
|
|
422
|
-
changes.up += this.createTableSql(backupTableName, structure.columns, structure.foreignKeys) + "\n" + moveDataQuery;
|
|
423
|
-
|
|
491
|
+
changes.up += this.createTableSql(backupTableName, structure.columns, structure.foreignKeys) + "\n" + moveDataQuery + "\n";
|
|
492
|
+
const dbTableName = this.migrations.getOldTableName(tableName);
|
|
493
|
+
changes.down += this.dialect.canInspectForeignKeys && this.dialect.canInspectPrimaryKey ? this.createTableSql(backupTableName, await this.dialect.getColumnInformation(dbTableName), await this.dialect.getForeignKeys(dbTableName)) + "\n" + moveDataQuery : "\n\n-- Cannot recreate foreign keys or load primary keys with this database! Table will not be recreated!\n";
|
|
424
494
|
}
|
|
425
495
|
return changes;
|
|
426
496
|
}
|
|
@@ -428,8 +498,6 @@ ${foreignKeyOnQuery}`;
|
|
|
428
498
|
* Migrates foreign key constraints for all defined tables.
|
|
429
499
|
*/
|
|
430
500
|
async migrateForeignKeys() {
|
|
431
|
-
if (!this.dialect.canAlterForeignKeys)
|
|
432
|
-
return { up: "", down: "" };
|
|
433
501
|
let changes = {
|
|
434
502
|
up: "\n\n-- Foreign keys\n",
|
|
435
503
|
down: "\n\n-- Foreign keys\n"
|
|
@@ -439,13 +507,13 @@ ${foreignKeyOnQuery}`;
|
|
|
439
507
|
continue;
|
|
440
508
|
const structure = this.newTables[tableName];
|
|
441
509
|
const newForeignKeys = structure.foreignKeys ?? [];
|
|
442
|
-
const oldForeignKeys = await this.dialect.getForeignKeys(tableName);
|
|
510
|
+
const oldForeignKeys = await this.dialect.getForeignKeys(this.migrations.getOldTableName(tableName));
|
|
443
511
|
let checkForNewForeignKeys = true;
|
|
444
512
|
for (const oldForeignKey of oldForeignKeys) {
|
|
445
513
|
const newForeignKey = newForeignKeys.find((entry) => entry.fromColumn == oldForeignKey.fromColumn);
|
|
446
514
|
if (!newForeignKey) {
|
|
447
|
-
Logger.log(`Foreign key ${oldForeignKey.
|
|
448
|
-
this.migrations.
|
|
515
|
+
Logger.log(`Foreign key ${oldForeignKey.fromTable}.${oldForeignKey.fromColumn} to ${oldForeignKey.toTable}.${oldForeignKey.toColumn} will be removed!`);
|
|
516
|
+
this.migrations.compareWithAllowedMigration(tableName, "removeForeignKey");
|
|
449
517
|
if (this.dialect.canAlterForeignKeys) {
|
|
450
518
|
changes.up += this.dialect.removeForeignKey(oldForeignKey.fromTable, oldForeignKey.fromColumn);
|
|
451
519
|
changes.down += this.dialect.addForeignKey(
|
|
@@ -458,8 +526,8 @@ ${foreignKeyOnQuery}`;
|
|
|
458
526
|
}
|
|
459
527
|
} else {
|
|
460
528
|
if (!newForeignKey || oldForeignKey.toColumn != newForeignKey.toColumn || (oldForeignKey.onUpdate ?? "NO ACTION") != (newForeignKey.onUpdate ?? "NO ACTION") || (oldForeignKey.onDelete ?? "NO ACTION") != (newForeignKey.onDelete ?? "NO ACTION")) {
|
|
461
|
-
Logger.log(`Foreign key ${oldForeignKey.
|
|
462
|
-
this.migrations.
|
|
529
|
+
Logger.log(`Foreign key ${oldForeignKey.fromTable}.${oldForeignKey.fromColumn} to ${oldForeignKey.toTable}.${oldForeignKey.toColumn} will be changed!`);
|
|
530
|
+
this.migrations.compareWithAllowedMigration(tableName, "alterForeignKey");
|
|
463
531
|
if (this.dialect.canAlterForeignKeys) {
|
|
464
532
|
changes.up += this.dialect.removeForeignKey(oldForeignKey.fromTable, oldForeignKey.fromColumn) + this.dialect.addForeignKey(
|
|
465
533
|
newForeignKey.fromTable,
|
|
@@ -481,7 +549,7 @@ ${foreignKeyOnQuery}`;
|
|
|
481
549
|
const oldForeignKey = oldForeignKeys.find((entry) => entry.fromColumn == newForeignKey.fromColumn);
|
|
482
550
|
if (oldForeignKey)
|
|
483
551
|
continue;
|
|
484
|
-
Logger.log(`Foreign key ${newForeignKey.
|
|
552
|
+
Logger.log(`Foreign key ${newForeignKey.fromTable}.${newForeignKey.fromColumn} to ${newForeignKey.toTable}.${newForeignKey.toColumn} will be added!`);
|
|
485
553
|
if (this.dialect.canAlterForeignKeys) {
|
|
486
554
|
changes.up += this.dialect.addForeignKey(
|
|
487
555
|
newForeignKey.toTable,
|
|
@@ -510,13 +578,13 @@ ${foreignKeyOnQuery}`;
|
|
|
510
578
|
if (this.migrations.willBeRecreated(tableName) || this.tableDoesNotExists(tableName))
|
|
511
579
|
continue;
|
|
512
580
|
const newTableDefinition = this.newTables[tableName];
|
|
513
|
-
const oldColumnList = await this.dialect.getColumnInformation(tableName);
|
|
581
|
+
const oldColumnList = await this.dialect.getColumnInformation(this.migrations.getOldTableName(tableName));
|
|
514
582
|
const oldPrimaryKey = this.dialect.canInspectPrimaryKey ? this.getPrimaryKeyColumn(oldColumnList) : false;
|
|
515
583
|
const newColumnList = newTableDefinition.columns;
|
|
516
584
|
const newPrimaryKey = newTableDefinition.primaryKey;
|
|
517
585
|
if (this.dialect.canInspectPrimaryKey && oldPrimaryKey != newPrimaryKey) {
|
|
518
|
-
Logger.log(`Primary key in ${tableName}
|
|
519
|
-
this.migrations.
|
|
586
|
+
Logger.log(`Primary key in ${tableName} will be changed from ${oldPrimaryKey} to ${newPrimaryKey}!`);
|
|
587
|
+
this.migrations.compareWithAllowedMigration(tableName, "alterPrimaryKey");
|
|
520
588
|
if (this.dialect.canAlterPrimaryKey) {
|
|
521
589
|
if (oldPrimaryKey) {
|
|
522
590
|
changes.up += this.dialect.removePrimaryKey(tableName, oldPrimaryKey);
|
|
@@ -532,7 +600,7 @@ ${foreignKeyOnQuery}`;
|
|
|
532
600
|
}
|
|
533
601
|
for (const newColumn of newColumnList) {
|
|
534
602
|
const oldColumn = oldColumnList.find(
|
|
535
|
-
(entry) => this.migrations.
|
|
603
|
+
(entry) => this.migrations.getNewestColumnName(tableName, entry.name) == newColumn.name
|
|
536
604
|
);
|
|
537
605
|
if (oldColumn == void 0) {
|
|
538
606
|
changes.up += this.dialect.createColumn(tableName, this.dialect.columnDefinition(newColumn.name, newColumn.type, newColumn.defaultValue, newColumn.isPrimaryKey)) + "\n";
|
|
@@ -543,10 +611,10 @@ ${foreignKeyOnQuery}`;
|
|
|
543
611
|
}
|
|
544
612
|
for (const oldColumn of oldColumnList) {
|
|
545
613
|
const newColumn = newColumnList.find(
|
|
546
|
-
(entry) => entry.name == this.migrations.
|
|
614
|
+
(entry) => entry.name == this.migrations.getNewestColumnName(tableName, oldColumn.name)
|
|
547
615
|
);
|
|
548
616
|
if (newColumn == void 0) {
|
|
549
|
-
this.migrations.
|
|
617
|
+
this.migrations.compareWithAllowedMigration(tableName, "dropColumn");
|
|
550
618
|
changes.up += this.dialect.dropColumn(tableName, oldColumn.name) + "\n";
|
|
551
619
|
changes.down += this.dialect.createColumn(tableName, this.dialect.columnDefinition(oldColumn.name, oldColumn.type, oldColumn.defaultValue, oldColumn.isPrimaryKey)) + "\n";
|
|
552
620
|
}
|
|
@@ -580,6 +648,7 @@ ${foreignKeyOnQuery}`;
|
|
|
580
648
|
if (migrationData[tableName].recreate)
|
|
581
649
|
continue;
|
|
582
650
|
this.migrations.loopRenamedColumns(tableName, (oldColumnName, newColumnName) => {
|
|
651
|
+
Logger.log(`Column ${tableName}.${oldColumnName} will be renamed to ${tableName}.${newColumnName}!`);
|
|
583
652
|
changes.up += this.dialect.renameColumn(tableName, oldColumnName, newColumnName);
|
|
584
653
|
changes.down += this.dialect.renameColumn(tableName, newColumnName, oldColumnName);
|
|
585
654
|
});
|