sqlmorpheus 0.1.2 → 0.1.3
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 +16 -0
- package/dist/index.d.ts +126 -9
- package/dist/index.js +947 -47
- package/dist/index.mjs +3 -1
- package/package.json +2 -2
- package/dist/lib/Logger.d.ts +0 -10
- package/dist/lib/Logger.js +0 -24
- package/dist/lib/MigrationHistoryManager.d.ts +0 -12
- package/dist/lib/MigrationHistoryManager.js +0 -47
- package/dist/lib/MigrationManager.d.ts +0 -27
- package/dist/lib/MigrationManager.js +0 -331
- package/dist/lib/TableStructureGenerator.d.ts +0 -10
- package/dist/lib/TableStructureGenerator.js +0 -69
- package/dist/lib/dialects/DefaultSql.d.ts +0 -34
- package/dist/lib/dialects/DefaultSql.js +0 -79
- package/dist/lib/dialects/MsSqlDialect.d.ts +0 -18
- package/dist/lib/dialects/MsSqlDialect.js +0 -53
- package/dist/lib/dialects/MySqlDialect.d.ts +0 -18
- package/dist/lib/dialects/MySqlDialect.js +0 -53
- package/dist/lib/dialects/PostgresDialect.d.ts +0 -16
- package/dist/lib/dialects/PostgresDialect.js +0 -42
- package/dist/lib/dialects/SqliteDialect.d.ts +0 -16
- package/dist/lib/dialects/SqliteDialect.js +0 -53
- package/dist/lib/exceptions/NotAllowedException.d.ts +0 -4
- package/dist/lib/exceptions/NotAllowedException.js +0 -31
- package/dist/lib/tableInfo/TableInfo.d.ts +0 -9
- package/dist/lib/tableInfo/TableInfo.js +0 -20
- package/dist/lib/tableInfo/TableObjects.d.ts +0 -6
- package/dist/lib/tableInfo/TableObjects.js +0 -2
- package/dist/lib/tableInfo/decorators/DbTable.d.ts +0 -2
- package/dist/lib/tableInfo/decorators/DbTable.js +0 -16
- package/dist/lib/tableInfo/decorators/ForeignKey.d.ts +0 -4
- package/dist/lib/tableInfo/decorators/ForeignKey.js +0 -20
- package/dist/lib/typings/AllowedMigrations.d.ts +0 -9
- package/dist/lib/typings/AllowedMigrations.js +0 -2
- package/dist/lib/typings/BackendTable.d.ts +0 -7
- package/dist/lib/typings/BackendTable.js +0 -2
- package/dist/lib/typings/ColumnInfo.d.ts +0 -6
- package/dist/lib/typings/ColumnInfo.js +0 -2
- package/dist/lib/typings/DatabaseAccess.d.ts +0 -5
- package/dist/lib/typings/DatabaseAccess.js +0 -2
- package/dist/lib/typings/DatabaseInstructions.d.ts +0 -26
- package/dist/lib/typings/DatabaseInstructions.js +0 -2
- package/dist/lib/typings/ForeignKeyInfo.d.ts +0 -9
- package/dist/lib/typings/ForeignKeyInfo.js +0 -2
- package/dist/lib/typings/MigrationHistory.d.ts +0 -7
- package/dist/lib/typings/MigrationHistory.js +0 -15
- package/dist/lib/typings/MigrationInstructions.d.ts +0 -10
- package/dist/lib/typings/MigrationInstructions.js +0 -2
- package/dist/lib/typings/Migrations.d.ts +0 -20
- package/dist/lib/typings/Migrations.js +0 -83
- package/dist/lib/typings/SqlChanges.d.ts +0 -4
- package/dist/lib/typings/SqlChanges.js +0 -2
- package/dist/lib/typings/TableStructure.d.ts +0 -8
- package/dist/lib/typings/TableStructure.js +0 -2
package/dist/index.mjs
CHANGED
|
@@ -218,7 +218,7 @@ var MigrationHistoryManager = class {
|
|
|
218
218
|
lastVersion = 0;
|
|
219
219
|
constructor(configPath) {
|
|
220
220
|
this.configPath = configPath;
|
|
221
|
-
this.migrationsPath = `${configPath}/migrations
|
|
221
|
+
this.migrationsPath = `${configPath}/migrations`;
|
|
222
222
|
mkdirSync(this.configPath, { recursive: true });
|
|
223
223
|
mkdirSync(this.migrationsPath, { recursive: true });
|
|
224
224
|
}
|
|
@@ -240,6 +240,7 @@ var MigrationHistoryManager = class {
|
|
|
240
240
|
throw new Error(`Migration ${upPath} already exists!`);
|
|
241
241
|
else if (existsSync(downPath) && !overwriteExisting)
|
|
242
242
|
throw new Error(`Migration ${downPath} already exists!`);
|
|
243
|
+
Logger.log(`Save migrations to ${this.migrationsPath}`);
|
|
243
244
|
writeFileSync(`${this.migrationsPath}/${FILENAME_UP_PREFIX}${toVersion}.sql`, `-- From: Version ${fromVersion}
|
|
244
245
|
-- To: Version ${toVersion}
|
|
245
246
|
${changes.up}`, { encoding: "utf-8" });
|
|
@@ -840,6 +841,7 @@ ${foreignKeyOnQuery}`;
|
|
|
840
841
|
};
|
|
841
842
|
|
|
842
843
|
// src/lib/tableInfo/decorators/DbTable.ts
|
|
844
|
+
import "polyfill-symbol-metadata";
|
|
843
845
|
function DbTable(tableName, primaryKey) {
|
|
844
846
|
return (table, context) => {
|
|
845
847
|
Object.defineProperty(table, "name", { value: tableName, writable: false });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sqlmorpheus",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"author": "JodliDev",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"dev": "tsup --watch",
|
|
24
24
|
"test": "vitest run",
|
|
25
25
|
"test:watch": "vitest",
|
|
26
|
-
"publish": "
|
|
26
|
+
"publish": "npm publish"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/better-sqlite3": "^7.6.13",
|
package/dist/lib/Logger.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export type LoggerMode = "silent" | "noLog" | "normal" | "debug";
|
|
2
|
-
declare class LoggerClass {
|
|
3
|
-
mode: LoggerMode;
|
|
4
|
-
setMode(mode?: LoggerMode): void;
|
|
5
|
-
debug(text: string): void;
|
|
6
|
-
log(text: string): void;
|
|
7
|
-
warn(text: string): void;
|
|
8
|
-
}
|
|
9
|
-
export declare const Logger: LoggerClass;
|
|
10
|
-
export {};
|
package/dist/lib/Logger.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Logger = void 0;
|
|
4
|
-
class LoggerClass {
|
|
5
|
-
mode = "normal";
|
|
6
|
-
setMode(mode) {
|
|
7
|
-
this.mode = mode ?? "normal";
|
|
8
|
-
}
|
|
9
|
-
debug(text) {
|
|
10
|
-
if (this.mode == "debug")
|
|
11
|
-
console.log(text);
|
|
12
|
-
}
|
|
13
|
-
log(text) {
|
|
14
|
-
if (this.mode == "silent" || this.mode == "noLog")
|
|
15
|
-
return;
|
|
16
|
-
console.log(text);
|
|
17
|
-
}
|
|
18
|
-
warn(text) {
|
|
19
|
-
if (this.mode == "silent")
|
|
20
|
-
return;
|
|
21
|
-
console.warn(text);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
exports.Logger = new LoggerClass();
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { SqlChanges } from "./typings/SqlChanges";
|
|
2
|
-
export default class MigrationHistoryManager {
|
|
3
|
-
private readonly configPath;
|
|
4
|
-
private readonly migrationsPath;
|
|
5
|
-
private lastVersion;
|
|
6
|
-
constructor(configPath: string);
|
|
7
|
-
getLastHistoryVersion(): number;
|
|
8
|
-
setLastHistoryVersion(version: number): void;
|
|
9
|
-
createMigrationHistory(toVersion: number, changes: SqlChanges, overwriteExisting?: boolean): void;
|
|
10
|
-
getUpMigration(toVersion?: number): string;
|
|
11
|
-
getDownMigration(version: number): string;
|
|
12
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const node_fs_1 = require("node:fs");
|
|
4
|
-
const fs_1 = require("fs");
|
|
5
|
-
const FILENAME_UP_PREFIX = "up_to_";
|
|
6
|
-
const FILENAME_DOWN_PREFIX = "down_to_";
|
|
7
|
-
class MigrationHistoryManager {
|
|
8
|
-
configPath;
|
|
9
|
-
migrationsPath;
|
|
10
|
-
lastVersion = 0;
|
|
11
|
-
constructor(configPath) {
|
|
12
|
-
this.configPath = configPath;
|
|
13
|
-
this.migrationsPath = `${configPath}/migrations/`;
|
|
14
|
-
(0, node_fs_1.mkdirSync)(this.configPath, { recursive: true });
|
|
15
|
-
(0, node_fs_1.mkdirSync)(this.migrationsPath, { recursive: true });
|
|
16
|
-
}
|
|
17
|
-
getLastHistoryVersion() {
|
|
18
|
-
if (this.lastVersion)
|
|
19
|
-
return this.lastVersion;
|
|
20
|
-
const path = `${this.configPath}/last_version.txt`;
|
|
21
|
-
this.lastVersion = (0, node_fs_1.existsSync)(path)
|
|
22
|
-
? parseInt((0, fs_1.readFileSync)(`${this.configPath}/last_version.txt`, { encoding: 'utf-8' })) ?? 0
|
|
23
|
-
: 0;
|
|
24
|
-
return this.lastVersion;
|
|
25
|
-
}
|
|
26
|
-
setLastHistoryVersion(version) {
|
|
27
|
-
(0, node_fs_1.writeFileSync)(`${this.configPath}/last_version.txt`, version.toString(), { encoding: 'utf-8' });
|
|
28
|
-
}
|
|
29
|
-
createMigrationHistory(toVersion, changes, overwriteExisting) {
|
|
30
|
-
const fromVersion = this.getLastHistoryVersion();
|
|
31
|
-
const upPath = `${this.migrationsPath}/${FILENAME_UP_PREFIX}${toVersion}.sql`;
|
|
32
|
-
const downPath = `${this.migrationsPath}/${FILENAME_DOWN_PREFIX}${fromVersion}.sql`;
|
|
33
|
-
if ((0, node_fs_1.existsSync)(upPath) && !overwriteExisting)
|
|
34
|
-
throw new Error(`Migration ${upPath} already exists!`);
|
|
35
|
-
else if ((0, node_fs_1.existsSync)(downPath) && !overwriteExisting)
|
|
36
|
-
throw new Error(`Migration ${downPath} already exists!`);
|
|
37
|
-
(0, node_fs_1.writeFileSync)(`${this.migrationsPath}/${FILENAME_UP_PREFIX}${toVersion}.sql`, `-- From: Version ${fromVersion}\n-- To: Version ${toVersion}\n${changes.up}`, { encoding: 'utf-8' });
|
|
38
|
-
(0, node_fs_1.writeFileSync)(`${this.migrationsPath}/${FILENAME_DOWN_PREFIX}${fromVersion}.sql`, `-- From: Version ${toVersion}\n-- To: Version ${fromVersion}\n${changes.down}`, { encoding: 'utf-8' });
|
|
39
|
-
}
|
|
40
|
-
getUpMigration(toVersion) {
|
|
41
|
-
return (0, fs_1.readFileSync)(`${this.migrationsPath}/${FILENAME_UP_PREFIX}${toVersion ?? this.getLastHistoryVersion()}.sql`, { encoding: 'utf-8' });
|
|
42
|
-
}
|
|
43
|
-
getDownMigration(version) {
|
|
44
|
-
return (0, fs_1.readFileSync)(`${this.migrationsPath}/${FILENAME_DOWN_PREFIX}${version}.sql`, { encoding: 'utf-8' });
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
exports.default = MigrationHistoryManager;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import DatabaseInstructions from "./typings/DatabaseInstructions";
|
|
2
|
-
import { DatabaseAccess } from "./typings/DatabaseAccess";
|
|
3
|
-
import { SqlChanges } from "./typings/SqlChanges";
|
|
4
|
-
export declare class MigrationManager {
|
|
5
|
-
private migrations;
|
|
6
|
-
private readonly tableStructureGenerator;
|
|
7
|
-
private existingTables;
|
|
8
|
-
private readonly db;
|
|
9
|
-
private readonly dbInstructions;
|
|
10
|
-
private readonly migrationHistoryManager;
|
|
11
|
-
private readonly dialect;
|
|
12
|
-
constructor(db: DatabaseAccess, dbInstructions: DatabaseInstructions);
|
|
13
|
-
getMigrateSql(): Promise<SqlChanges | null>;
|
|
14
|
-
prepareMigration(overwriteExisting?: boolean): Promise<void>;
|
|
15
|
-
private createAndDropTables;
|
|
16
|
-
private createTableSql;
|
|
17
|
-
private tableDoesNotExists;
|
|
18
|
-
private recreateTables;
|
|
19
|
-
private migrateForeignKeys;
|
|
20
|
-
/**
|
|
21
|
-
* Checks all columns of all tables, creates them if they do not exist in the database and modifies them if needed.
|
|
22
|
-
* If types, default values or primary key change, the table is recreated
|
|
23
|
-
*/
|
|
24
|
-
private migrateColumns;
|
|
25
|
-
private getPrimaryKeyColumn;
|
|
26
|
-
private renameColumns;
|
|
27
|
-
}
|
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.MigrationManager = void 0;
|
|
7
|
-
const TableStructureGenerator_1 = __importDefault(require("./TableStructureGenerator"));
|
|
8
|
-
const Migrations_1 = require("./typings/Migrations");
|
|
9
|
-
const MigrationHistoryManager_1 = __importDefault(require("./MigrationHistoryManager"));
|
|
10
|
-
const SqliteDialect_1 = __importDefault(require("./dialects/SqliteDialect"));
|
|
11
|
-
const PostgresDialect_1 = __importDefault(require("./dialects/PostgresDialect"));
|
|
12
|
-
const MsSqlDialect_1 = __importDefault(require("./dialects/MsSqlDialect"));
|
|
13
|
-
const MySqlDialect_1 = __importDefault(require("./dialects/MySqlDialect"));
|
|
14
|
-
const Logger_1 = require("./Logger");
|
|
15
|
-
class MigrationManager {
|
|
16
|
-
migrations = new Migrations_1.Migrations();
|
|
17
|
-
tableStructureGenerator;
|
|
18
|
-
existingTables = [];
|
|
19
|
-
db;
|
|
20
|
-
dbInstructions;
|
|
21
|
-
migrationHistoryManager;
|
|
22
|
-
dialect;
|
|
23
|
-
constructor(db, dbInstructions) {
|
|
24
|
-
switch (dbInstructions.dialect) {
|
|
25
|
-
case "Sqlite":
|
|
26
|
-
this.dialect = new SqliteDialect_1.default();
|
|
27
|
-
break;
|
|
28
|
-
case "Postgres":
|
|
29
|
-
this.dialect = new PostgresDialect_1.default();
|
|
30
|
-
break;
|
|
31
|
-
case "MsSql":
|
|
32
|
-
this.dialect = new MsSqlDialect_1.default();
|
|
33
|
-
break;
|
|
34
|
-
case "MySql":
|
|
35
|
-
this.dialect = new MySqlDialect_1.default();
|
|
36
|
-
break;
|
|
37
|
-
default:
|
|
38
|
-
throw new Error(`Unknown dialect ${dbInstructions.dialect}`);
|
|
39
|
-
}
|
|
40
|
-
this.db = db;
|
|
41
|
-
this.dbInstructions = dbInstructions;
|
|
42
|
-
this.tableStructureGenerator = new TableStructureGenerator_1.default(dbInstructions, this.dialect);
|
|
43
|
-
this.migrationHistoryManager = new MigrationHistoryManager_1.default(this.dbInstructions.configPath);
|
|
44
|
-
}
|
|
45
|
-
async getMigrateSql() {
|
|
46
|
-
if (this.dbInstructions.version <= 0)
|
|
47
|
-
throw new Error("Cannot migrate to version 0 or lower");
|
|
48
|
-
const fromVersion = this.migrationHistoryManager.getLastHistoryVersion();
|
|
49
|
-
if (fromVersion == 0) {
|
|
50
|
-
Logger_1.Logger.log(`Creating initial migration to version ${this.dbInstructions.version}`);
|
|
51
|
-
return this.createAndDropTables();
|
|
52
|
-
}
|
|
53
|
-
if (fromVersion == this.dbInstructions.version) {
|
|
54
|
-
Logger_1.Logger.log("Version has not changed. No migrations needed.");
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
if (fromVersion > this.dbInstructions.version)
|
|
58
|
-
throw new Error(`You cannot create new migrations with a lower version (from ${fromVersion} to ${this.dbInstructions.version})`);
|
|
59
|
-
Logger_1.Logger.log(`Creating migration SQL from version ${fromVersion} to ${this.dbInstructions.version}`);
|
|
60
|
-
const db = this.db;
|
|
61
|
-
await db.createBackup?.(`from_${fromVersion}_to_${this.dbInstructions.version}`);
|
|
62
|
-
this.existingTables = await this.dialect.getTableNames(this.db);
|
|
63
|
-
const foreignKeyOffQuery = this.dialect.changeForeignKeysState(false);
|
|
64
|
-
const changes = {
|
|
65
|
-
up: foreignKeyOffQuery,
|
|
66
|
-
down: foreignKeyOffQuery
|
|
67
|
-
};
|
|
68
|
-
//Run pre-migrations:
|
|
69
|
-
const preSQL = this.dbInstructions.preMigration?.(this.migrations, fromVersion, this.dbInstructions.version);
|
|
70
|
-
if (preSQL) {
|
|
71
|
-
changes.up += `\n\n-- Custom SQL from preMigration()\n${preSQL.up}`;
|
|
72
|
-
changes.down += `\n\n-- Custom SQL from preMigration()\n${preSQL.down}`;
|
|
73
|
-
}
|
|
74
|
-
[
|
|
75
|
-
await this.createAndDropTables(),
|
|
76
|
-
await this.migrateForeignKeys(),
|
|
77
|
-
await this.migrateColumns(),
|
|
78
|
-
this.renameColumns(),
|
|
79
|
-
await this.recreateTables()
|
|
80
|
-
].forEach(entry => {
|
|
81
|
-
changes.up += entry.up;
|
|
82
|
-
changes.down += entry.down;
|
|
83
|
-
});
|
|
84
|
-
//Run post-migrations:
|
|
85
|
-
const postSql = this.dbInstructions.postMigration?.(fromVersion, this.dbInstructions.version);
|
|
86
|
-
if (postSql) {
|
|
87
|
-
changes.up += `\n\n-- Custom SQL from postMigration()\n${postSql.up}`;
|
|
88
|
-
changes.down += `\n\n-- Custom SQL from postMigration()\n${postSql.down}`;
|
|
89
|
-
}
|
|
90
|
-
//Enable foreign key constraints again:
|
|
91
|
-
const foreignKeyOnQuery = this.dialect.changeForeignKeysState(true);
|
|
92
|
-
changes.up += `\n\n${foreignKeyOnQuery}`;
|
|
93
|
-
changes.down += `\n\n${foreignKeyOnQuery}`;
|
|
94
|
-
return changes;
|
|
95
|
-
}
|
|
96
|
-
async prepareMigration(overwriteExisting) {
|
|
97
|
-
const changes = await this.getMigrateSql();
|
|
98
|
-
if (!changes)
|
|
99
|
-
return;
|
|
100
|
-
this.migrationHistoryManager.createMigrationHistory(this.dbInstructions.version, changes, overwriteExisting);
|
|
101
|
-
}
|
|
102
|
-
async createAndDropTables() {
|
|
103
|
-
let changes = {
|
|
104
|
-
up: "\n\n-- Create tables\n",
|
|
105
|
-
down: "\n\n-- Create tables\n"
|
|
106
|
-
};
|
|
107
|
-
for (const tableName in this.tableStructureGenerator.tables) {
|
|
108
|
-
if (this.tableDoesNotExists(tableName)) {
|
|
109
|
-
const structure = this.tableStructureGenerator.tables[tableName];
|
|
110
|
-
changes.up += `${this.createTableSql(tableName, structure.columns, structure.foreignKeys)}\n`;
|
|
111
|
-
changes.down += `${this.dialect.dropTable(tableName)}\n`;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
for (const tableName of this.existingTables) {
|
|
115
|
-
if (!this.tableStructureGenerator.tables[tableName]) {
|
|
116
|
-
this.migrations.throwIfNotAllowed(this.dbInstructions.version, tableName, "dropTable");
|
|
117
|
-
if (!this.dialect.canInspectForeignKeys || !this.dialect.canInspectPrimaryKey)
|
|
118
|
-
this.migrations.throwIfNotAllowed(this.dbInstructions.version, tableName, "continueWithoutRollback");
|
|
119
|
-
changes.up += `${this.dialect.dropTable(tableName)}\n`;
|
|
120
|
-
changes.down += this.dialect.canInspectForeignKeys && this.dialect.canInspectPrimaryKey
|
|
121
|
-
? this.createTableSql(tableName, await this.dialect.getColumnInformation(tableName, this.db), await this.dialect.getForeignKeys(tableName, this.db))
|
|
122
|
-
: "\n\n-- Cannot recreate foreign keys or load primary keys with this database! Table will not be recreated!\n";
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
return changes;
|
|
126
|
-
}
|
|
127
|
-
createTableSql(tableName, columns, foreignKeys) {
|
|
128
|
-
//columns:
|
|
129
|
-
const queryLines = [];
|
|
130
|
-
for (const columnInfo of columns) {
|
|
131
|
-
queryLines.push(this.dialect.columnDefinition(columnInfo.name, columnInfo.type, columnInfo.defaultValue, columnInfo.isPrimaryKey));
|
|
132
|
-
}
|
|
133
|
-
//foreign keys:
|
|
134
|
-
if (foreignKeys) {
|
|
135
|
-
for (const foreignKeyInfo of foreignKeys) {
|
|
136
|
-
queryLines.push(this.dialect.foreignKey(foreignKeyInfo.fromColumn, foreignKeyInfo.toTable, foreignKeyInfo.toColumn.toString(), foreignKeyInfo.onUpdate, foreignKeyInfo.onDelete));
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return this.dialect.createTable(tableName, queryLines);
|
|
140
|
-
}
|
|
141
|
-
tableDoesNotExists(tableName) {
|
|
142
|
-
return this.existingTables.indexOf(tableName) == -1;
|
|
143
|
-
}
|
|
144
|
-
async recreateTables() {
|
|
145
|
-
const changes = {
|
|
146
|
-
up: "\n\n-- Recreate tables\n",
|
|
147
|
-
down: "\n\n-- Recreate tables\n"
|
|
148
|
-
};
|
|
149
|
-
const migrationData = this.migrations.getMigrationData();
|
|
150
|
-
for (const tableName in migrationData) {
|
|
151
|
-
const migrationEntry = migrationData[tableName];
|
|
152
|
-
if (!migrationEntry.recreate)
|
|
153
|
-
continue;
|
|
154
|
-
this.migrations.throwIfNotAllowed(this.dbInstructions.version, tableName, "recreateTable");
|
|
155
|
-
if (!this.dialect.canInspectForeignKeys || !this.dialect.canInspectPrimaryKey)
|
|
156
|
-
this.migrations.throwIfNotAllowed(this.dbInstructions.version, tableName, "continueWithoutRollback");
|
|
157
|
-
const oldColumnList = await this.dialect.getColumnInformation(tableName, this.db);
|
|
158
|
-
const newColumnList = this.tableStructureGenerator.tables[tableName].columns;
|
|
159
|
-
const moveableColumns = newColumnList
|
|
160
|
-
.filter(entry => oldColumnList.find(oldEntry => oldEntry.name == entry.name) != undefined)
|
|
161
|
-
.map(entry => entry.name);
|
|
162
|
-
const backupTableName = `${tableName}__backup`;
|
|
163
|
-
const insertQuery = this.dialect.insert(backupTableName, this.dialect.insertValues(moveableColumns, this.dialect.select(tableName, moveableColumns)));
|
|
164
|
-
const moveDataQuery = insertQuery
|
|
165
|
-
+ "\n"
|
|
166
|
-
+ this.dialect.dropTable(tableName)
|
|
167
|
-
+ "\n"
|
|
168
|
-
+ this.dialect.renameTable(backupTableName, tableName);
|
|
169
|
-
const structure = this.tableStructureGenerator.tables[tableName];
|
|
170
|
-
changes.up += this.createTableSql(backupTableName, structure.columns, structure.foreignKeys)
|
|
171
|
-
+ "\n"
|
|
172
|
-
+ moveDataQuery;
|
|
173
|
-
changes.down += this.dialect.canInspectForeignKeys && this.dialect.canInspectPrimaryKey
|
|
174
|
-
? this.createTableSql(backupTableName, await this.dialect.getColumnInformation(tableName, this.db), await this.dialect.getForeignKeys(tableName, this.db))
|
|
175
|
-
+ "\n"
|
|
176
|
-
+ moveDataQuery
|
|
177
|
-
: "\n\n-- Cannot recreate foreign keys or load primary keys with this database! Table will not be recreated!\n";
|
|
178
|
-
}
|
|
179
|
-
return changes;
|
|
180
|
-
}
|
|
181
|
-
async migrateForeignKeys() {
|
|
182
|
-
if (!this.dialect.canAlterForeignKeys)
|
|
183
|
-
return { up: "", down: "" };
|
|
184
|
-
let changes = {
|
|
185
|
-
up: "\n\n-- Foreign keys\n",
|
|
186
|
-
down: "\n\n-- Foreign keys\n"
|
|
187
|
-
};
|
|
188
|
-
for (const tableName in this.tableStructureGenerator.tables) {
|
|
189
|
-
if (this.migrations.willBeRecreated(tableName) || this.tableDoesNotExists(tableName))
|
|
190
|
-
continue;
|
|
191
|
-
const structure = this.tableStructureGenerator.tables[tableName];
|
|
192
|
-
const newForeignKeys = structure.foreignKeys ?? [];
|
|
193
|
-
const oldForeignKeys = await this.dialect.getForeignKeys(tableName, this.db);
|
|
194
|
-
let checkForNewForeignKeys = true;
|
|
195
|
-
for (const oldForeignKey of oldForeignKeys) {
|
|
196
|
-
const newForeignKey = newForeignKeys.find(entry => entry.fromColumn == oldForeignKey.fromColumn);
|
|
197
|
-
//Check for removed foreign key:
|
|
198
|
-
if (!newForeignKey) {
|
|
199
|
-
Logger_1.Logger.log(`Foreign key ${oldForeignKey.toTable}.${oldForeignKey.toColumn} to ${oldForeignKey.toTable}.${oldForeignKey.toColumn} was removed!`);
|
|
200
|
-
this.migrations.throwIfNotAllowed(this.dbInstructions.version, tableName, "removeForeignKey");
|
|
201
|
-
if (this.dialect.canAlterForeignKeys) {
|
|
202
|
-
changes.up += this.dialect.removeForeignKey(oldForeignKey.fromTable, oldForeignKey.fromColumn);
|
|
203
|
-
changes.down += this.dialect.addForeignKey(oldForeignKey.fromTable, this.dialect.foreignKey(oldForeignKey.fromColumn, oldForeignKey.toTable, oldForeignKey.toColumn, oldForeignKey.onUpdate, oldForeignKey.onDelete));
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
this.migrations.recreateTable(structure.table);
|
|
207
|
-
checkForNewForeignKeys = false;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
//Check for altered foreign key:
|
|
211
|
-
else {
|
|
212
|
-
if (!newForeignKey
|
|
213
|
-
|| oldForeignKey.toColumn != newForeignKey.toColumn
|
|
214
|
-
|| ((oldForeignKey.onUpdate ?? "NO ACTION") != (newForeignKey.onUpdate ?? "NO ACTION"))
|
|
215
|
-
|| ((oldForeignKey.onDelete ?? "NO ACTION") != (newForeignKey.onDelete ?? "NO ACTION"))) {
|
|
216
|
-
Logger_1.Logger.log(`Foreign key ${oldForeignKey.toTable}.${oldForeignKey.toColumn} to ${oldForeignKey.toTable}.${oldForeignKey.toColumn} was changed!`);
|
|
217
|
-
this.migrations.throwIfNotAllowed(this.dbInstructions.version, tableName, "alterForeignKey");
|
|
218
|
-
if (this.dialect.canAlterForeignKeys) {
|
|
219
|
-
changes.up += this.dialect.removeForeignKey(oldForeignKey.fromTable, oldForeignKey.fromColumn)
|
|
220
|
-
+ this.dialect.addForeignKey(newForeignKey.fromTable, this.dialect.foreignKey(newForeignKey.fromColumn, newForeignKey.toTable, newForeignKey.toColumn, newForeignKey.onUpdate, newForeignKey.onDelete));
|
|
221
|
-
changes.down += this.dialect.addForeignKey(oldForeignKey.fromTable, this.dialect.foreignKey(oldForeignKey.fromColumn, oldForeignKey.toTable, oldForeignKey.toColumn, oldForeignKey.onUpdate, oldForeignKey.onDelete)) + this.dialect.removeForeignKey(newForeignKey.fromTable, newForeignKey.fromColumn);
|
|
222
|
-
}
|
|
223
|
-
else {
|
|
224
|
-
this.migrations.recreateTable(structure.table);
|
|
225
|
-
checkForNewForeignKeys = false;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
//Check for new foreign keys:
|
|
231
|
-
if (checkForNewForeignKeys) {
|
|
232
|
-
for (const newForeignKey of newForeignKeys) {
|
|
233
|
-
const oldForeignKey = oldForeignKeys.find(entry => entry.fromColumn == newForeignKey.fromColumn);
|
|
234
|
-
if (oldForeignKey)
|
|
235
|
-
continue;
|
|
236
|
-
Logger_1.Logger.log(`Foreign key ${newForeignKey.toTable}.${newForeignKey.toColumn} to ${newForeignKey.toTable}.${newForeignKey.toColumn} is new!`);
|
|
237
|
-
if (this.dialect.canAlterForeignKeys) {
|
|
238
|
-
changes.up += this.dialect.addForeignKey(newForeignKey.toTable, this.dialect.foreignKey(newForeignKey.fromColumn, newForeignKey.toTable, newForeignKey.toColumn, newForeignKey.onUpdate, newForeignKey.onDelete));
|
|
239
|
-
changes.down += this.dialect.removeForeignKey(newForeignKey.fromTable, newForeignKey.fromColumn);
|
|
240
|
-
}
|
|
241
|
-
else {
|
|
242
|
-
this.migrations.recreateTable(structure.table);
|
|
243
|
-
break;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
return changes;
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Checks all columns of all tables, creates them if they do not exist in the database and modifies them if needed.
|
|
252
|
-
* If types, default values or primary key change, the table is recreated
|
|
253
|
-
*/
|
|
254
|
-
async migrateColumns() {
|
|
255
|
-
const changes = {
|
|
256
|
-
up: "\n\n-- Migrate columns\n",
|
|
257
|
-
down: "\n\n-- Migrate columns\n"
|
|
258
|
-
};
|
|
259
|
-
for (const tableName in this.tableStructureGenerator.tables) {
|
|
260
|
-
if (this.migrations.willBeRecreated(tableName) || this.tableDoesNotExists(tableName))
|
|
261
|
-
continue;
|
|
262
|
-
const newTableDefinition = this.tableStructureGenerator.tables[tableName];
|
|
263
|
-
const oldColumnList = await this.dialect.getColumnInformation(tableName, this.db);
|
|
264
|
-
const oldPrimaryKey = this.dialect.canInspectPrimaryKey ? this.getPrimaryKeyColumn(oldColumnList) : false;
|
|
265
|
-
const newColumnList = newTableDefinition.columns;
|
|
266
|
-
const newPrimaryKey = newTableDefinition.primaryKey;
|
|
267
|
-
//Search for changed primary key:
|
|
268
|
-
if (this.dialect.canInspectPrimaryKey && oldPrimaryKey != newPrimaryKey) {
|
|
269
|
-
Logger_1.Logger.log(`Primary key in ${tableName} was changed from ${oldPrimaryKey} to ${newPrimaryKey}!`);
|
|
270
|
-
this.migrations.throwIfNotAllowed(this.dbInstructions.version, tableName, "alterPrimaryKey");
|
|
271
|
-
if (this.dialect.canAlterPrimaryKey) {
|
|
272
|
-
if (oldPrimaryKey) {
|
|
273
|
-
changes.up += this.dialect.removePrimaryKey(tableName, oldPrimaryKey);
|
|
274
|
-
changes.down += this.dialect.addPrimaryKey(tableName, oldPrimaryKey);
|
|
275
|
-
}
|
|
276
|
-
if (newPrimaryKey) {
|
|
277
|
-
changes.up += this.dialect.addPrimaryKey(tableName, newPrimaryKey.toString());
|
|
278
|
-
changes.down += this.dialect.removePrimaryKey(tableName, newPrimaryKey.toString());
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
else
|
|
282
|
-
this.migrations.recreateTable(newTableDefinition.table);
|
|
283
|
-
continue;
|
|
284
|
-
}
|
|
285
|
-
//Search for added or changed columns:
|
|
286
|
-
for (const newColumn of newColumnList) {
|
|
287
|
-
const oldColumn = oldColumnList.find(entry => entry.name == newColumn.name);
|
|
288
|
-
if (oldColumn == undefined) {
|
|
289
|
-
changes.up += this.dialect.createColumn(tableName, this.dialect.columnDefinition(newColumn.name, newColumn.type, newColumn.defaultValue, newColumn.isPrimaryKey)) + "\n";
|
|
290
|
-
changes.down += this.dialect.dropColumn(tableName, newColumn.name) + "\n";
|
|
291
|
-
}
|
|
292
|
-
else if (newColumn.type != oldColumn.type || newColumn.defaultValue != oldColumn.defaultValue) {
|
|
293
|
-
this.migrations.recreateTable(newTableDefinition.table);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
//Search for removed columns:
|
|
297
|
-
for (const oldColumn of oldColumnList) {
|
|
298
|
-
const newColumn = newColumnList.find(entry => entry.name == oldColumn.name);
|
|
299
|
-
if (newColumn == undefined) {
|
|
300
|
-
this.migrations.throwIfNotAllowed(this.dbInstructions.version, tableName, "dropColumn");
|
|
301
|
-
changes.up += this.dialect.dropColumn(tableName, oldColumn.name) + "\n";
|
|
302
|
-
changes.down += this.dialect.createColumn(tableName, this.dialect.columnDefinition(oldColumn.name, oldColumn.type, oldColumn.defaultValue, oldColumn.isPrimaryKey)) + "\n";
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
return changes;
|
|
307
|
-
}
|
|
308
|
-
getPrimaryKeyColumn(columnInfoList) {
|
|
309
|
-
for (const columnInfo of columnInfoList) {
|
|
310
|
-
if (columnInfo.isPrimaryKey)
|
|
311
|
-
return columnInfo.name;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
renameColumns() {
|
|
315
|
-
const changes = {
|
|
316
|
-
up: "\n\n-- Rename columns\n",
|
|
317
|
-
down: "\n\n-- Rename columns\n"
|
|
318
|
-
};
|
|
319
|
-
const migrationData = this.migrations.getMigrationData();
|
|
320
|
-
for (const tableName in migrationData) {
|
|
321
|
-
if (migrationData[tableName].recreate)
|
|
322
|
-
continue;
|
|
323
|
-
this.migrations.loopRenamedColumns(tableName, (oldColumnName, newColumnName) => {
|
|
324
|
-
changes.up += this.dialect.renameColumn(tableName, oldColumnName, newColumnName);
|
|
325
|
-
changes.down += this.dialect.renameColumn(tableName, newColumnName, oldColumnName);
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
return changes;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
exports.MigrationManager = MigrationManager;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import DatabaseInstructions from "./typings/DatabaseInstructions";
|
|
2
|
-
import { TableStructure } from "./typings/TableStructure";
|
|
3
|
-
import DefaultSql from "./dialects/DefaultSql";
|
|
4
|
-
export default class TableStructureGenerator {
|
|
5
|
-
private readonly dialect;
|
|
6
|
-
readonly tables: Record<string, TableStructure>;
|
|
7
|
-
constructor(dbContext: DatabaseInstructions, dialect: DefaultSql);
|
|
8
|
-
private getExpectedStructure;
|
|
9
|
-
private getColumns;
|
|
10
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const Logger_1 = require("./Logger");
|
|
4
|
-
const TableInfo_1 = require("./tableInfo/TableInfo");
|
|
5
|
-
class TableStructureGenerator {
|
|
6
|
-
dialect;
|
|
7
|
-
tables = {};
|
|
8
|
-
constructor(dbContext, dialect) {
|
|
9
|
-
this.dialect = dialect;
|
|
10
|
-
if (dbContext.tables.length) {
|
|
11
|
-
const tableObjects = {};
|
|
12
|
-
for (const table of dbContext.tables) {
|
|
13
|
-
tableObjects[table.name] = { columns: new table, tableInfo: (0, TableInfo_1.getTableInfo)(table) };
|
|
14
|
-
}
|
|
15
|
-
this.getExpectedStructure(tableObjects);
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
18
|
-
const tableObjects = dbContext.tables;
|
|
19
|
-
this.getExpectedStructure(tableObjects);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
getExpectedStructure(tableObjects) {
|
|
23
|
-
for (const tableName in tableObjects) {
|
|
24
|
-
const obj = tableObjects[tableName];
|
|
25
|
-
const tableInfo = obj.tableInfo;
|
|
26
|
-
this.tables[tableName] = {
|
|
27
|
-
table: tableName,
|
|
28
|
-
primaryKey: tableInfo?.primaryKey,
|
|
29
|
-
columns: this.getColumns(obj.columns, tableInfo?.primaryKey),
|
|
30
|
-
foreignKeys: tableInfo?.foreignKeys
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
getColumns(obj, primaryKey) {
|
|
35
|
-
const columns = [];
|
|
36
|
-
for (const property in obj) {
|
|
37
|
-
const propertyKey = property;
|
|
38
|
-
const value = obj[propertyKey];
|
|
39
|
-
const columnData = {
|
|
40
|
-
name: property,
|
|
41
|
-
isPrimaryKey: property == primaryKey,
|
|
42
|
-
type: "TEXT",
|
|
43
|
-
defaultValue: this.dialect.typeNull
|
|
44
|
-
};
|
|
45
|
-
switch (typeof value) {
|
|
46
|
-
case "string":
|
|
47
|
-
columnData.type = this.dialect.typeString;
|
|
48
|
-
columnData.defaultValue = value === null ? this.dialect.typeNull : `"${this.dialect.formatValueToSql(value)}"`;
|
|
49
|
-
break;
|
|
50
|
-
case "number":
|
|
51
|
-
columnData.type = this.dialect.typeNumber;
|
|
52
|
-
columnData.defaultValue = value === null ? this.dialect.typeNull : this.dialect.formatValueToSql(value);
|
|
53
|
-
break;
|
|
54
|
-
case "boolean":
|
|
55
|
-
columnData.type = this.dialect.typeBoolean;
|
|
56
|
-
columnData.defaultValue = value === null ? this.dialect.typeNull : this.dialect.formatValueToSql(value);
|
|
57
|
-
break;
|
|
58
|
-
case "function":
|
|
59
|
-
continue;
|
|
60
|
-
default:
|
|
61
|
-
Logger_1.Logger.warn(`${obj.constructor.name}.${property} was skipped because its type is not supported (${typeof value})`);
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
columns.push(columnData);
|
|
65
|
-
}
|
|
66
|
-
return columns;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
exports.default = TableStructureGenerator;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { ForeignKeyInfo } from "../typings/ForeignKeyInfo";
|
|
2
|
-
import { DatabaseAccess } from "../typings/DatabaseAccess";
|
|
3
|
-
import { ColumnInfo } from "../typings/ColumnInfo";
|
|
4
|
-
export default abstract class DefaultSql {
|
|
5
|
-
canAlterForeignKeys: boolean;
|
|
6
|
-
canAlterPrimaryKey: boolean;
|
|
7
|
-
canInspectForeignKeys: boolean;
|
|
8
|
-
canInspectPrimaryKey: boolean;
|
|
9
|
-
typeString: string;
|
|
10
|
-
typeNumber: string;
|
|
11
|
-
typeBoolean: string;
|
|
12
|
-
typeNull: string;
|
|
13
|
-
formatValueToSql(value: string | number | boolean): string;
|
|
14
|
-
changeForeignKeysState(enabled: boolean): string;
|
|
15
|
-
getForeignKeys(tableName: string, db: DatabaseAccess): Promise<ForeignKeyInfo[]>;
|
|
16
|
-
addForeignKey(fromTableName: string, foreignKey: string): string;
|
|
17
|
-
removeForeignKey(tableName: string, foreignKeyName: string): string;
|
|
18
|
-
addPrimaryKey(tableName: string, columnName: string): string;
|
|
19
|
-
removePrimaryKey(tableName: string, columnName: string): string;
|
|
20
|
-
foreignKey(column: string, foreignTable: string, foreignColumn: string, onUpdate?: string, onDelete?: string): string;
|
|
21
|
-
createTable(tableName: string, entries: string[]): string;
|
|
22
|
-
renameTable(tableName: string, newTableName: string): string;
|
|
23
|
-
dropTable(tableName: string): string;
|
|
24
|
-
abstract getColumnInformation(tableName: string, db: DatabaseAccess): Promise<ColumnInfo[]>;
|
|
25
|
-
abstract getTableNames(db: DatabaseAccess): Promise<string[]>;
|
|
26
|
-
columnDefinition(tableName: string, type: string, defaultValue: string, isPrimaryKey: boolean): string;
|
|
27
|
-
createColumn(columnTable: string, entry: string): string;
|
|
28
|
-
renameColumn(tableName: string, oldColumnName: string, newColumnName: string): string;
|
|
29
|
-
copyColumn(tableName: string, oldColumnName: string, newColumnName: string): string;
|
|
30
|
-
dropColumn(tableName: string, columnName: string): string;
|
|
31
|
-
select(tableName: string, select: string[], where?: string): string;
|
|
32
|
-
insert(tableName: string, content: string): string;
|
|
33
|
-
insertValues(keys: string[], valueString?: string): string;
|
|
34
|
-
}
|