sqlmorpheus 0.1.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.
Files changed (55) hide show
  1. package/dist/index.d.mts +110 -0
  2. package/dist/index.d.ts +6 -0
  3. package/dist/index.js +51 -0
  4. package/dist/index.mjs +884 -0
  5. package/dist/lib/Logger.d.ts +10 -0
  6. package/dist/lib/Logger.js +24 -0
  7. package/dist/lib/MigrationHistoryManager.d.ts +12 -0
  8. package/dist/lib/MigrationHistoryManager.js +47 -0
  9. package/dist/lib/MigrationManager.d.ts +27 -0
  10. package/dist/lib/MigrationManager.js +331 -0
  11. package/dist/lib/TableStructureGenerator.d.ts +10 -0
  12. package/dist/lib/TableStructureGenerator.js +69 -0
  13. package/dist/lib/dialects/DefaultSql.d.ts +34 -0
  14. package/dist/lib/dialects/DefaultSql.js +79 -0
  15. package/dist/lib/dialects/MsSqlDialect.d.ts +18 -0
  16. package/dist/lib/dialects/MsSqlDialect.js +53 -0
  17. package/dist/lib/dialects/MySqlDialect.d.ts +18 -0
  18. package/dist/lib/dialects/MySqlDialect.js +53 -0
  19. package/dist/lib/dialects/PostgresDialect.d.ts +16 -0
  20. package/dist/lib/dialects/PostgresDialect.js +42 -0
  21. package/dist/lib/dialects/SqliteDialect.d.ts +16 -0
  22. package/dist/lib/dialects/SqliteDialect.js +53 -0
  23. package/dist/lib/exceptions/NotAllowedException.d.ts +4 -0
  24. package/dist/lib/exceptions/NotAllowedException.js +31 -0
  25. package/dist/lib/tableInfo/TableInfo.d.ts +9 -0
  26. package/dist/lib/tableInfo/TableInfo.js +16 -0
  27. package/dist/lib/tableInfo/TableObjects.d.ts +6 -0
  28. package/dist/lib/tableInfo/TableObjects.js +2 -0
  29. package/dist/lib/tableInfo/decorators/DbTable.d.ts +2 -0
  30. package/dist/lib/tableInfo/decorators/DbTable.js +16 -0
  31. package/dist/lib/tableInfo/decorators/ForeignKey.d.ts +4 -0
  32. package/dist/lib/tableInfo/decorators/ForeignKey.js +20 -0
  33. package/dist/lib/typings/AllowedMigrations.d.ts +9 -0
  34. package/dist/lib/typings/AllowedMigrations.js +2 -0
  35. package/dist/lib/typings/BackendTable.d.ts +7 -0
  36. package/dist/lib/typings/BackendTable.js +2 -0
  37. package/dist/lib/typings/ColumnInfo.d.ts +6 -0
  38. package/dist/lib/typings/ColumnInfo.js +2 -0
  39. package/dist/lib/typings/DatabaseAccess.d.ts +5 -0
  40. package/dist/lib/typings/DatabaseAccess.js +2 -0
  41. package/dist/lib/typings/DatabaseInstructions.d.ts +26 -0
  42. package/dist/lib/typings/DatabaseInstructions.js +2 -0
  43. package/dist/lib/typings/ForeignKeyInfo.d.ts +9 -0
  44. package/dist/lib/typings/ForeignKeyInfo.js +2 -0
  45. package/dist/lib/typings/MigrationHistory.d.ts +7 -0
  46. package/dist/lib/typings/MigrationHistory.js +15 -0
  47. package/dist/lib/typings/MigrationInstructions.d.ts +10 -0
  48. package/dist/lib/typings/MigrationInstructions.js +2 -0
  49. package/dist/lib/typings/Migrations.d.ts +20 -0
  50. package/dist/lib/typings/Migrations.js +83 -0
  51. package/dist/lib/typings/SqlChanges.d.ts +4 -0
  52. package/dist/lib/typings/SqlChanges.js +2 -0
  53. package/dist/lib/typings/TableStructure.d.ts +8 -0
  54. package/dist/lib/typings/TableStructure.js +2 -0
  55. package/package.json +39 -0
@@ -0,0 +1,18 @@
1
+ import DefaultSql from "./DefaultSql";
2
+ import { ForeignKeyInfo } from "../typings/ForeignKeyInfo";
3
+ import { DatabaseAccess } from "../typings/DatabaseAccess";
4
+ import { ColumnInfo } from "../typings/ColumnInfo";
5
+ export default class MsSqlDialect extends DefaultSql {
6
+ canAlterForeignKeys: boolean;
7
+ canAlterPrimaryKey: boolean;
8
+ canInspectForeignKeys: boolean;
9
+ canInspectPrimaryKey: boolean;
10
+ changeForeignKeysState(enabled: boolean): string;
11
+ getForeignKeys(tableName: string, db: DatabaseAccess): Promise<ForeignKeyInfo[]>;
12
+ addForeignKey(fromTableName: string, foreignKey: string): string;
13
+ removeForeignKey(tableName: string, foreignKeyName: string): string;
14
+ addPrimaryKey(tableName: string, columnName: string): string;
15
+ removePrimaryKey(tableName: string, columnName: string): string;
16
+ getTableNames(db: DatabaseAccess): Promise<string[]>;
17
+ getColumnInformation(tableName: string, db: DatabaseAccess): Promise<ColumnInfo[]>;
18
+ }
@@ -0,0 +1,53 @@
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
+ const DefaultSql_1 = __importDefault(require("./DefaultSql"));
7
+ class MsSqlDialect extends DefaultSql_1.default {
8
+ canAlterForeignKeys = true;
9
+ canAlterPrimaryKey = true;
10
+ canInspectForeignKeys = true;
11
+ canInspectPrimaryKey = false;
12
+ changeForeignKeysState(enabled) {
13
+ return `EXEC sp_MSforeachtable "${enabled ? "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all" : "ALTER TABLE ? NOCHECK CONSTRAINT all"}"`;
14
+ }
15
+ async getForeignKeys(tableName, db) {
16
+ const data = await db.runGetStatement(`EXEC sp_fkeys @fktable_name = ${tableName};`);
17
+ return data.map(entry => {
18
+ return {
19
+ fromTable: entry[tableName],
20
+ fromColumn: entry["FKCOLUMN_NAME"],
21
+ toTable: entry["PKTABLE_NAME"],
22
+ toColumn: entry["PKCOLUMN_NAME"],
23
+ };
24
+ });
25
+ }
26
+ addForeignKey(fromTableName, foreignKey) {
27
+ return `ALTER TABLE ${fromTableName} ADD ${foreignKey};`;
28
+ }
29
+ removeForeignKey(tableName, foreignKeyName) {
30
+ return `ALTER TABLE ${tableName} DROP CONSTRAINT ${foreignKeyName};`;
31
+ }
32
+ addPrimaryKey(tableName, columnName) {
33
+ return `ALTER TABLE ${tableName} ADD CONSTRAINT ${tableName}_primary PRIMARY KEY (${columnName});`;
34
+ }
35
+ removePrimaryKey(tableName, columnName) {
36
+ return `ALTER TABLE ${tableName} DROP CONSTRAINT ${columnName}_primary;`;
37
+ }
38
+ async getTableNames(db) {
39
+ return await db.runGetStatement("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'");
40
+ }
41
+ async getColumnInformation(tableName, db) {
42
+ const data = await db.runGetStatement(`SELECT COLUMN_NAME, DATA_TYPE, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = N'${tableName};'`);
43
+ return data.map(entry => {
44
+ return {
45
+ name: entry["COLUMN_NAME"],
46
+ type: entry["DATA_TYPE"],
47
+ defaultValue: entry["COLUMN_DEFAULT"],
48
+ isPrimaryKey: false,
49
+ };
50
+ });
51
+ }
52
+ }
53
+ exports.default = MsSqlDialect;
@@ -0,0 +1,18 @@
1
+ import DefaultSql from "./DefaultSql";
2
+ import { ForeignKeyInfo } from "../typings/ForeignKeyInfo";
3
+ import { DatabaseAccess } from "../typings/DatabaseAccess";
4
+ import { ColumnInfo } from "../typings/ColumnInfo";
5
+ export default class MySqlDialect extends DefaultSql {
6
+ canAlterForeignKeys: boolean;
7
+ canAlterPrimaryKey: boolean;
8
+ canInspectForeignKeys: boolean;
9
+ canInspectPrimaryKey: boolean;
10
+ changeForeignKeysState(enabled: boolean): string;
11
+ getForeignKeys(tableName: string, db: DatabaseAccess): Promise<ForeignKeyInfo[]>;
12
+ addForeignKey(fromTableName: string, foreignKey: string): string;
13
+ removeForeignKey(tableName: string, foreignKeyName: string): string;
14
+ addPrimaryKey(tableName: string, columnName: string): string;
15
+ removePrimaryKey(tableName: string, _columnName: string): string;
16
+ getTableNames(db: DatabaseAccess): Promise<string[]>;
17
+ getColumnInformation(tableName: string, db: DatabaseAccess): Promise<ColumnInfo[]>;
18
+ }
@@ -0,0 +1,53 @@
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
+ const DefaultSql_1 = __importDefault(require("./DefaultSql"));
7
+ class MySqlDialect extends DefaultSql_1.default {
8
+ canAlterForeignKeys = true;
9
+ canAlterPrimaryKey = true;
10
+ canInspectForeignKeys = true;
11
+ canInspectPrimaryKey = true;
12
+ changeForeignKeysState(enabled) {
13
+ return `SET FOREIGN_KEY_CHECKS ${enabled ? "1" : "0"}\n;`;
14
+ }
15
+ async getForeignKeys(tableName, db) {
16
+ const data = await db.runGetStatement(`SELECT TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME, REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_SCHEMA = (SELECT DATABASE()) AND REFERENCED_TABLE_NAME = '${tableName}';`);
17
+ return data.map(entry => {
18
+ return {
19
+ fromTable: tableName,
20
+ fromColumn: entry["COLUMN_NAME"],
21
+ toTable: entry["REFERENCED_TABLE_NAME"],
22
+ toColumn: entry["REFERENCED_COLUMN_NAME"]
23
+ };
24
+ });
25
+ }
26
+ addForeignKey(fromTableName, foreignKey) {
27
+ return `ALTER TABLE ${fromTableName} ADD ${foreignKey};`;
28
+ }
29
+ removeForeignKey(tableName, foreignKeyName) {
30
+ return `ALTER TABLE ${tableName} DROP FOREIGN KEY ${foreignKeyName};`;
31
+ }
32
+ addPrimaryKey(tableName, columnName) {
33
+ return `ALTER TABLE ${tableName} PRIMARY KEY (${columnName});`;
34
+ }
35
+ removePrimaryKey(tableName, _columnName) {
36
+ return `ALTER TABLE ${tableName} PRIMARY KEY;`;
37
+ }
38
+ async getTableNames(db) {
39
+ return await db.runGetStatement("SHOW TABLES;");
40
+ }
41
+ async getColumnInformation(tableName, db) {
42
+ const data = await db.runGetStatement(`SHOW COLUMNS FROM ${tableName};`);
43
+ return data.map(entry => {
44
+ return {
45
+ name: entry["Field"],
46
+ type: entry["Type"],
47
+ defaultValue: entry["Default"],
48
+ isPrimaryKey: entry["Key"] == "PRI",
49
+ };
50
+ });
51
+ }
52
+ }
53
+ exports.default = MySqlDialect;
@@ -0,0 +1,16 @@
1
+ import DefaultSql from "./DefaultSql";
2
+ import { DatabaseAccess } from "../typings/DatabaseAccess";
3
+ import { ColumnInfo } from "../typings/ColumnInfo";
4
+ export default class PostgresDialect extends DefaultSql {
5
+ canAlterForeignKeys: boolean;
6
+ canAlterPrimaryKey: boolean;
7
+ canInspectForeignKeys: boolean;
8
+ canInspectPrimaryKey: boolean;
9
+ changeForeignKeysState(enabled: boolean): string;
10
+ addForeignKey(fromTableName: string, foreignKey: string): string;
11
+ removeForeignKey(tableName: string, foreignKeyName: string): string;
12
+ getTableNames(db: DatabaseAccess): Promise<string[]>;
13
+ getColumnInformation(tableName: string, db: DatabaseAccess): Promise<ColumnInfo[]>;
14
+ addPrimaryKey(tableName: string, columnName: string): string;
15
+ removePrimaryKey(tableName: string, columnName: string): string;
16
+ }
@@ -0,0 +1,42 @@
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
+ const DefaultSql_1 = __importDefault(require("./DefaultSql"));
7
+ class PostgresDialect extends DefaultSql_1.default {
8
+ canAlterForeignKeys = true;
9
+ canAlterPrimaryKey = true;
10
+ canInspectForeignKeys = false;
11
+ canInspectPrimaryKey = false;
12
+ changeForeignKeysState(enabled) {
13
+ return `SET session_replication_role = '${enabled ? "replica" : "origin"}';`;
14
+ }
15
+ addForeignKey(fromTableName, foreignKey) {
16
+ return `ALTER TABLE ${fromTableName} ADD CONSTRAINT ${fromTableName} ${foreignKey};`;
17
+ }
18
+ removeForeignKey(tableName, foreignKeyName) {
19
+ return `ALTER TABLE ${tableName} DROP CONSTRAINT ${foreignKeyName};`;
20
+ }
21
+ async getTableNames(db) {
22
+ return await db.runGetStatement("SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND table_type='BASE TABLE';");
23
+ }
24
+ async getColumnInformation(tableName, db) {
25
+ const data = await db.runGetStatement(`SELECT column_name, data_type, column_default FROM information_schema.columns WHERE table_schema = 'public' AND table_name = '${tableName}';`);
26
+ return data.map(entry => {
27
+ return {
28
+ name: entry["column_name"],
29
+ type: entry["data_type"],
30
+ defaultValue: entry["column_default"],
31
+ isPrimaryKey: false,
32
+ };
33
+ });
34
+ }
35
+ addPrimaryKey(tableName, columnName) {
36
+ return `ALTER TABLE ${tableName} ADD PRIMARY KEY (${columnName});\n`;
37
+ }
38
+ removePrimaryKey(tableName, columnName) {
39
+ return `ALTER TABLE ${tableName} DROP CONSTRAINT ${columnName};\n`;
40
+ }
41
+ }
42
+ exports.default = PostgresDialect;
@@ -0,0 +1,16 @@
1
+ import DefaultSql from "./DefaultSql";
2
+ import { ForeignKeyInfo } from "../typings/ForeignKeyInfo";
3
+ import { DatabaseAccess } from "../typings/DatabaseAccess";
4
+ import { ColumnInfo } from "../typings/ColumnInfo";
5
+ export default class SqliteDialect extends DefaultSql {
6
+ typeBoolean: string;
7
+ canAlterForeignKeys: boolean;
8
+ canAlterPrimaryKey: boolean;
9
+ canInspectForeignKeys: boolean;
10
+ canInspectPrimaryKey: boolean;
11
+ changeForeignKeysState(enabled: boolean): string;
12
+ getForeignKeys(tableName: string, db: DatabaseAccess): Promise<ForeignKeyInfo[]>;
13
+ getTableNames(db: DatabaseAccess): Promise<string[]>;
14
+ getColumnInformation(tableName: string, db: DatabaseAccess): Promise<ColumnInfo[]>;
15
+ formatValueToSql(value: string | number | boolean): string;
16
+ }
@@ -0,0 +1,53 @@
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
+ const DefaultSql_1 = __importDefault(require("./DefaultSql"));
7
+ class SqliteDialect extends DefaultSql_1.default {
8
+ typeBoolean = "INTEGER";
9
+ canAlterForeignKeys = false;
10
+ canAlterPrimaryKey = false;
11
+ canInspectForeignKeys = true;
12
+ canInspectPrimaryKey = true;
13
+ changeForeignKeysState(enabled) {
14
+ return `PRAGMA foreign_keys = ${enabled ? "ON" : "OFF"};`;
15
+ }
16
+ async getForeignKeys(tableName, db) {
17
+ const data = await db.runGetStatement(`PRAGMA foreign_key_list(${tableName});`);
18
+ return data.map(entry => {
19
+ return {
20
+ fromTable: tableName,
21
+ fromColumn: entry["from"],
22
+ toTable: entry["table"],
23
+ toColumn: entry["to"],
24
+ on_update: entry["on_update"],
25
+ on_delete: entry["on_delete"],
26
+ };
27
+ });
28
+ }
29
+ async getTableNames(db) {
30
+ return (await db.runGetStatement("SELECT name FROM sqlite_master WHERE type = 'table'"))
31
+ .map((obj) => obj.name);
32
+ }
33
+ async getColumnInformation(tableName, db) {
34
+ const data = await db.runGetStatement(`PRAGMA table_info(${tableName})`);
35
+ return data.map(entry => {
36
+ return {
37
+ name: entry["name"],
38
+ type: entry["type"],
39
+ defaultValue: entry["dflt_value"],
40
+ isPrimaryKey: entry["pk"] == "1",
41
+ };
42
+ });
43
+ }
44
+ formatValueToSql(value) {
45
+ switch (typeof value) {
46
+ case "boolean":
47
+ return value ? "1" : "0";
48
+ default:
49
+ return value.toString();
50
+ }
51
+ }
52
+ }
53
+ exports.default = SqliteDialect;
@@ -0,0 +1,4 @@
1
+ import AllowedMigrations from "../typings/AllowedMigrations";
2
+ export default class NotAllowedException extends Error {
3
+ constructor(version: number, tableName: string, type: keyof AllowedMigrations);
4
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class NotAllowedException extends Error {
4
+ constructor(version, tableName, type) {
5
+ const information = `You have to enable "${type}" for version "${version}" and table "${tableName}"`;
6
+ switch (type) {
7
+ case "continueWithoutRollback":
8
+ super(`Some changes can not be rolled back automatically. ${information}`);
9
+ break;
10
+ case "dropColumn":
11
+ super(`Not allowed to drop column. ${information}`);
12
+ break;
13
+ case "dropTable":
14
+ super(`Not allowed to drop table. ${information}`);
15
+ break;
16
+ case "recreateTable":
17
+ super(`Not allowed to recreate table. ${information}`);
18
+ break;
19
+ case "alterForeignKey":
20
+ super(`Not allowed to alter existing foreign key. ${information}`);
21
+ break;
22
+ case "alterPrimaryKey":
23
+ super(`Not allowed to alter primary key. ${information}`);
24
+ break;
25
+ case "removeForeignKey":
26
+ super(`Not allowed to remove existing foreign key. ${information}`);
27
+ break;
28
+ }
29
+ }
30
+ }
31
+ exports.default = NotAllowedException;
@@ -0,0 +1,9 @@
1
+ import { ForeignKeyInfo } from "../typings/ForeignKeyInfo";
2
+ import { BackendTable, Class } from "../typings/BackendTable";
3
+ export declare const TABLE_INFO_PROPERTY_NAME: unique symbol;
4
+ export default interface TableInfo {
5
+ primaryKey?: string;
6
+ foreignKeys?: ForeignKeyInfo[];
7
+ }
8
+ export declare function getTableInfo<T extends BackendTable>(table: Class<T>): TableInfo;
9
+ export declare function getTableInfoFromMetadata(metadata: Record<PropertyKey, unknown>): TableInfo;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TABLE_INFO_PROPERTY_NAME = void 0;
4
+ exports.getTableInfo = getTableInfo;
5
+ exports.getTableInfoFromMetadata = getTableInfoFromMetadata;
6
+ exports.TABLE_INFO_PROPERTY_NAME = Symbol("tableInfo");
7
+ function getTableInfo(table) {
8
+ if (!table.hasOwnProperty(Symbol.metadata))
9
+ table[Symbol.metadata] = {};
10
+ return getTableInfoFromMetadata(table[Symbol.metadata]);
11
+ }
12
+ function getTableInfoFromMetadata(metadata) {
13
+ if (!metadata[exports.TABLE_INFO_PROPERTY_NAME])
14
+ metadata[exports.TABLE_INFO_PROPERTY_NAME] = { primaryKey: "", foreignKeys: [] };
15
+ return metadata[exports.TABLE_INFO_PROPERTY_NAME];
16
+ }
@@ -0,0 +1,6 @@
1
+ import { BackendTable } from "../typings/BackendTable";
2
+ import TableInfo from "./TableInfo";
3
+ export type TableObjects = Record<string, {
4
+ columns: BackendTable;
5
+ tableInfo?: TableInfo;
6
+ }>;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ import { BackendTable, Class } from "../../typings/BackendTable";
2
+ export default function DbTable<T extends BackendTable>(tableName: string, primaryKey?: keyof T): (table: Class<T>, context: any) => void;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = DbTable;
4
+ const TableInfo_1 = require("../TableInfo");
5
+ function DbTable(tableName, primaryKey) {
6
+ return (table, context) => {
7
+ Object.defineProperty(table, "name", { value: tableName, writable: false });
8
+ const tableInfo = (0, TableInfo_1.getTableInfoFromMetadata)(context.metadata);
9
+ tableInfo.primaryKey = primaryKey?.toString();
10
+ if (tableInfo.foreignKeys) {
11
+ for (const foreignKey of tableInfo.foreignKeys) {
12
+ foreignKey.fromTable = tableName;
13
+ }
14
+ }
15
+ };
16
+ }
@@ -0,0 +1,4 @@
1
+ import { BackendTable, Class } from "../../typings/BackendTable";
2
+ import "polyfill-symbol-metadata";
3
+ import { ForeignKeyActions } from "../../typings/ForeignKeyInfo";
4
+ export default function ForeignKey<TOther extends BackendTable>(toTable: Class<TOther>, toColumn: keyof TOther, onDelete?: ForeignKeyActions, onUpdate?: ForeignKeyActions): (_: undefined, context: any) => void;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = ForeignKey;
4
+ const TableInfo_1 = require("../TableInfo");
5
+ require("polyfill-symbol-metadata");
6
+ function ForeignKey(toTable, toColumn, onDelete, onUpdate) {
7
+ return (_, context) => {
8
+ const metadata = (0, TableInfo_1.getTableInfoFromMetadata)(context.metadata);
9
+ if (!metadata.foreignKeys)
10
+ metadata.foreignKeys = [];
11
+ metadata.foreignKeys.push({
12
+ fromTable: "",
13
+ fromColumn: context.name,
14
+ toTable: toTable.name,
15
+ toColumn: toColumn.toString(),
16
+ onDelete: onDelete,
17
+ onUpdate: onUpdate,
18
+ });
19
+ };
20
+ }
@@ -0,0 +1,9 @@
1
+ export default interface AllowedMigrations {
2
+ recreateTable?: boolean;
3
+ dropTable?: boolean;
4
+ dropColumn?: boolean;
5
+ alterPrimaryKey?: boolean;
6
+ removeForeignKey?: boolean;
7
+ alterForeignKey?: boolean;
8
+ continueWithoutRollback?: boolean;
9
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,7 @@
1
+ export type Class<T> = new (...args: never[]) => T;
2
+ /**
3
+ * This does nothing. It mainly exists in case we want to filter class types in the future
4
+ */
5
+ export type BackendTable = {
6
+ [key: string]: any;
7
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ export interface ColumnInfo {
2
+ name: string;
3
+ type: string;
4
+ defaultValue: string;
5
+ isPrimaryKey: boolean;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ export interface DatabaseAccess {
2
+ createBackup?(name: string): Promise<void>;
3
+ runGetStatement(query: string): Promise<unknown>;
4
+ runMultipleWriteStatements(query: string): Promise<void>;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,26 @@
1
+ import { BackendTable, Class } from "./BackendTable";
2
+ import { PublicMigrations } from "./Migrations";
3
+ import { SqlChanges } from "./SqlChanges";
4
+ import { TableObjects } from "../tableInfo/TableObjects";
5
+ export default interface DatabaseInstructions {
6
+ dialect: "Sqlite" | "MsSql" | "MySql" | "Postgres";
7
+ tables: Class<BackendTable>[] | TableObjects;
8
+ version: number;
9
+ configPath: string;
10
+ loggerMode?: "silent" | "noLog" | "normal" | "debug";
11
+ /**
12
+ * Custom migrations that will run before any database changes are applied.
13
+ * @param migrations The migration object that will be validated after this.
14
+ * @param fromVersion Version of the current database.
15
+ * @param toVersion Version of the database after update.
16
+ * @return custom SQL that should be executed before migrations are executed.
17
+ */
18
+ preMigration?(migrations: PublicMigrations, fromVersion: number, toVersion: number): SqlChanges | void;
19
+ /**
20
+ * Custom migrations that will run after database changes have been applied (but before the transaction is finished)
21
+ * @param fromVersion Version of the current database.
22
+ * @param toVersion Version of the database after update.
23
+ * @return custom SQL that should be executed before migrations are executed.
24
+ */
25
+ postMigration?(fromVersion: number, toVersion: number): SqlChanges;
26
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,9 @@
1
+ export type ForeignKeyActions = "SET NULL" | "SET DEFAULT" | "RESTRICT" | "NO ACTION" | "CASCADE";
2
+ export interface ForeignKeyInfo {
3
+ fromTable: string;
4
+ fromColumn: string;
5
+ toTable: string;
6
+ toColumn: string;
7
+ onUpdate?: ForeignKeyActions;
8
+ onDelete?: ForeignKeyActions;
9
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,7 @@
1
+ export default class MigrationHistory {
2
+ fromVersion: number;
3
+ toVersion: number;
4
+ upSql: string;
5
+ downSql: string;
6
+ constructor(fromVersion: number, toVersion: number, upSql: string, downSql: string);
7
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class MigrationHistory {
4
+ fromVersion = 0;
5
+ toVersion = 1;
6
+ upSql = "";
7
+ downSql = "";
8
+ constructor(fromVersion, toVersion, upSql, downSql) {
9
+ this.fromVersion = fromVersion;
10
+ this.toVersion = toVersion;
11
+ this.upSql = upSql;
12
+ this.downSql = downSql;
13
+ }
14
+ }
15
+ exports.default = MigrationHistory;
@@ -0,0 +1,10 @@
1
+ import AllowedMigrations from "./AllowedMigrations";
2
+ export default interface MigrationInstructions {
3
+ oldTableName?: string;
4
+ recreate: boolean;
5
+ /**
6
+ * Stores changes to column (0: name in the database, last: current name in code)
7
+ */
8
+ renamedColumns: string[][];
9
+ allowedMigrations: Record<number, AllowedMigrations>;
10
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,20 @@
1
+ import { Class, BackendTable } from "./BackendTable";
2
+ import AllowedMigrations from "./AllowedMigrations";
3
+ import MigrationInstructions from "./MigrationInstructions";
4
+ export declare class Migrations {
5
+ private readonly migrationData;
6
+ private alwaysAllowed;
7
+ private getEntry;
8
+ private getTableName;
9
+ alwaysAllow(...allowedMigrations: (keyof AllowedMigrations)[]): void;
10
+ allowMigration(version: number, table: string | Class<BackendTable>, ...allowedMigrations: (keyof AllowedMigrations)[]): void;
11
+ throwIfNotAllowed(version: number, tableName: string, type: keyof AllowedMigrations): void;
12
+ renameTable(oldTableName: string, newTable: string | Class<BackendTable>): void;
13
+ renameColumn(table: string | Class<BackendTable>, oldColumn: string, newColumn: string): void;
14
+ recreateTable(table: Class<BackendTable> | string): void;
15
+ getMigrationData(): Record<string, MigrationInstructions>;
16
+ loopRenamedColumns(tableName: string, callback: (oldColumnName: string, newColumnName: string) => void): void;
17
+ getUpdatedColumnName(tableName: string, oldColumnName: string): string;
18
+ willBeRecreated(tableName: string): boolean;
19
+ }
20
+ export type PublicMigrations = Pick<Migrations, "recreateTable" | "renameTable" | "renameColumn" | "allowMigration" | "alwaysAllow">;
@@ -0,0 +1,83 @@
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.Migrations = void 0;
7
+ const NotAllowedException_1 = __importDefault(require("../exceptions/NotAllowedException"));
8
+ class Migrations {
9
+ migrationData = {};
10
+ alwaysAllowed = {};
11
+ getEntry(table) {
12
+ const tableName = this.getTableName(table);
13
+ if (!this.migrationData.hasOwnProperty(tableName)) {
14
+ this.migrationData[tableName] = {
15
+ recreate: false,
16
+ renamedColumns: [],
17
+ allowedMigrations: {}
18
+ };
19
+ }
20
+ return this.migrationData[tableName];
21
+ }
22
+ getTableName(table) {
23
+ return typeof table == "string" ? table : table.name;
24
+ }
25
+ alwaysAllow(...allowedMigrations) {
26
+ for (const key of allowedMigrations) {
27
+ this.alwaysAllowed[key] = true;
28
+ }
29
+ }
30
+ allowMigration(version, table, ...allowedMigrations) {
31
+ const entry = this.getEntry(table);
32
+ if (!entry.allowedMigrations.hasOwnProperty(version))
33
+ entry.allowedMigrations[version] = {};
34
+ for (const key of allowedMigrations) {
35
+ this.alwaysAllowed[key] = true;
36
+ }
37
+ }
38
+ throwIfNotAllowed(version, tableName, type) {
39
+ if (!(this.migrationData[tableName]?.allowedMigrations[version] ?? this.alwaysAllowed)[type])
40
+ throw new NotAllowedException_1.default(version, tableName, type);
41
+ }
42
+ renameTable(oldTableName, newTable) {
43
+ const entry = this.getEntry(newTable);
44
+ entry.recreate = true;
45
+ if (!entry.oldTableName) //entry might have already existed
46
+ entry.oldTableName = oldTableName;
47
+ }
48
+ renameColumn(table, oldColumn, newColumn) {
49
+ const entry = this.getEntry(table);
50
+ const existingColumnEntry = entry.renamedColumns.find((entry) => entry[entry.length - 1] == oldColumn);
51
+ if (existingColumnEntry)
52
+ existingColumnEntry.push(newColumn);
53
+ else
54
+ entry.renamedColumns.push([oldColumn, newColumn]);
55
+ }
56
+ recreateTable(table) {
57
+ const entry = this.getEntry(table);
58
+ entry.recreate = true;
59
+ }
60
+ getMigrationData() {
61
+ return this.migrationData;
62
+ }
63
+ loopRenamedColumns(tableName, callback) {
64
+ const migrationEntry = this.migrationData[tableName];
65
+ //We have to assume that there were multiple version changes in which the column name was changed multiple times.
66
+ //So we only rename from the original name (index 0) to the newest (last index)
67
+ for (const renamingArray of migrationEntry.renamedColumns) {
68
+ if (renamingArray.length <= 1)
69
+ continue;
70
+ const oldColumnName = renamingArray[0];
71
+ const newColumnName = renamingArray[renamingArray.length - 1];
72
+ callback(oldColumnName, newColumnName);
73
+ }
74
+ }
75
+ getUpdatedColumnName(tableName, oldColumnName) {
76
+ const columnNames = this.migrationData[tableName].renamedColumns.find((columns) => columns[0] == oldColumnName);
77
+ return columnNames ? columnNames[columnNames.length - 1] : oldColumnName;
78
+ }
79
+ willBeRecreated(tableName) {
80
+ return this.migrationData[tableName]?.recreate;
81
+ }
82
+ }
83
+ exports.Migrations = Migrations;