sqlmorpheus 0.2.5 → 0.2.6
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 +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +136 -102
- package/dist/index.mjs +126 -102
- package/package.json +2 -1
package/dist/index.d.mts
CHANGED
|
@@ -39,7 +39,7 @@ interface MigrationInstructions {
|
|
|
39
39
|
|
|
40
40
|
interface ColumnInfo {
|
|
41
41
|
name: string;
|
|
42
|
-
|
|
42
|
+
sqlType: string;
|
|
43
43
|
maxLength?: number;
|
|
44
44
|
defaultValue?: string;
|
|
45
45
|
isPrimaryKey: boolean;
|
|
@@ -251,7 +251,7 @@ interface SqlChanges {
|
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
type NativeDataTypeOptions = "boolean" | "number" | "bigint" | "string";
|
|
254
|
-
type AddedDataTypeOptions = "date" | "time" | "dateTime";
|
|
254
|
+
type AddedDataTypeOptions = "date" | "time" | "dateTime" | "text";
|
|
255
255
|
type DataTypeOptions = NativeDataTypeOptions | AddedDataTypeOptions;
|
|
256
256
|
|
|
257
257
|
interface InputColumnInfo extends ColumnInfo {
|
|
@@ -348,6 +348,6 @@ declare function ForeignKey<TOther extends TableClassInterface>(toTable: Class<T
|
|
|
348
348
|
}): (table: any, context: any) => void;
|
|
349
349
|
|
|
350
350
|
declare function runMigration(db: DatabaseAccess, dbInstructions: DatabaseInstructions): Promise<void>;
|
|
351
|
-
declare function rollback(db: DatabaseAccess, dbInstructions: DatabaseInstructions, toVersion: number): Promise<
|
|
351
|
+
declare function rollback(db: DatabaseAccess, dbInstructions: DatabaseInstructions, toVersion: number): Promise<number>;
|
|
352
352
|
|
|
353
353
|
export { DataType, type DatabaseAccess, type DatabaseInstructions, ForeignKey, type PublicMigrations, type SqlChanges, TableClass, TableObj, rollback, runMigration };
|
package/dist/index.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ interface MigrationInstructions {
|
|
|
39
39
|
|
|
40
40
|
interface ColumnInfo {
|
|
41
41
|
name: string;
|
|
42
|
-
|
|
42
|
+
sqlType: string;
|
|
43
43
|
maxLength?: number;
|
|
44
44
|
defaultValue?: string;
|
|
45
45
|
isPrimaryKey: boolean;
|
|
@@ -251,7 +251,7 @@ interface SqlChanges {
|
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
type NativeDataTypeOptions = "boolean" | "number" | "bigint" | "string";
|
|
254
|
-
type AddedDataTypeOptions = "date" | "time" | "dateTime";
|
|
254
|
+
type AddedDataTypeOptions = "date" | "time" | "dateTime" | "text";
|
|
255
255
|
type DataTypeOptions = NativeDataTypeOptions | AddedDataTypeOptions;
|
|
256
256
|
|
|
257
257
|
interface InputColumnInfo extends ColumnInfo {
|
|
@@ -348,6 +348,6 @@ declare function ForeignKey<TOther extends TableClassInterface>(toTable: Class<T
|
|
|
348
348
|
}): (table: any, context: any) => void;
|
|
349
349
|
|
|
350
350
|
declare function runMigration(db: DatabaseAccess, dbInstructions: DatabaseInstructions): Promise<void>;
|
|
351
|
-
declare function rollback(db: DatabaseAccess, dbInstructions: DatabaseInstructions, toVersion: number): Promise<
|
|
351
|
+
declare function rollback(db: DatabaseAccess, dbInstructions: DatabaseInstructions, toVersion: number): Promise<number>;
|
|
352
352
|
|
|
353
353
|
export { DataType, type DatabaseAccess, type DatabaseInstructions, ForeignKey, type PublicMigrations, type SqlChanges, TableClass, TableObj, rollback, runMigration };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -65,7 +75,7 @@ var TableObj = class _TableObj {
|
|
|
65
75
|
static getEmptyColumnEntry(key) {
|
|
66
76
|
return {
|
|
67
77
|
name: key,
|
|
68
|
-
|
|
78
|
+
sqlType: "",
|
|
69
79
|
defaultValue: "",
|
|
70
80
|
isPrimaryKey: false
|
|
71
81
|
};
|
|
@@ -192,8 +202,8 @@ var TableStructureGenerator = class {
|
|
|
192
202
|
}
|
|
193
203
|
for (const key in structure.columns) {
|
|
194
204
|
const entry = structure.columns[key];
|
|
195
|
-
entry.defaultValue = entry.inputDefaultValue === null ? this.dialect.
|
|
196
|
-
entry.
|
|
205
|
+
entry.defaultValue = entry.inputDefaultValue === null ? this.dialect.nullType : this.dialect.formatValueToSql(entry.inputDefaultValue, entry.inputType);
|
|
206
|
+
entry.sqlType = this.dialect.getSqlType(entry.inputType, entry);
|
|
197
207
|
}
|
|
198
208
|
}
|
|
199
209
|
return tables;
|
|
@@ -698,7 +708,7 @@ ${changes.up}
|
|
|
698
708
|
const queryLines = [];
|
|
699
709
|
for (const key in columns) {
|
|
700
710
|
const columnInfo = columns[key];
|
|
701
|
-
queryLines.push(this.dialect.columnDefinition(columnInfo.name, columnInfo.
|
|
711
|
+
queryLines.push(this.dialect.columnDefinition(columnInfo.name, columnInfo.sqlType, columnInfo.isPrimaryKey, columnInfo.defaultValue));
|
|
702
712
|
}
|
|
703
713
|
if (foreignKeys) {
|
|
704
714
|
for (const foreignKeyInfo of foreignKeys) {
|
|
@@ -870,9 +880,9 @@ ${changes.up}
|
|
|
870
880
|
if (willBeRenamed)
|
|
871
881
|
continue;
|
|
872
882
|
if (oldColumn == void 0) {
|
|
873
|
-
changes.up += this.dialect.createColumn(tableName, this.dialect.columnDefinition(newColumn.name, newColumn.
|
|
883
|
+
changes.up += this.dialect.createColumn(tableName, this.dialect.columnDefinition(newColumn.name, newColumn.sqlType, newColumn.isPrimaryKey, newColumn.defaultValue)) + "\n";
|
|
874
884
|
changes.down += this.dialect.dropColumn(tableName, newColumn.name) + "\n";
|
|
875
|
-
} else if (newColumn.
|
|
885
|
+
} else if (newColumn.sqlType != oldColumn.sqlType || newColumn.defaultValue != oldColumn.defaultValue) {
|
|
876
886
|
this.migrations.internalRecreate(newTableDefinition.table, "Table structure was changed");
|
|
877
887
|
}
|
|
878
888
|
}
|
|
@@ -882,7 +892,7 @@ ${changes.up}
|
|
|
882
892
|
if (newColumn == void 0) {
|
|
883
893
|
this.migrations.compareWithAllowedMigration(tableName, "dropColumn");
|
|
884
894
|
changes.up += this.dialect.dropColumn(tableName, oldColumn.name) + "\n";
|
|
885
|
-
changes.down += this.dialect.createColumn(tableName, this.dialect.columnDefinition(oldColumn.name, oldColumn.
|
|
895
|
+
changes.down += this.dialect.createColumn(tableName, this.dialect.columnDefinition(oldColumn.name, oldColumn.sqlType, oldColumn.isPrimaryKey, oldColumn.defaultValue)) + "\n";
|
|
886
896
|
}
|
|
887
897
|
}
|
|
888
898
|
}
|
|
@@ -924,59 +934,6 @@ ${changes.up}
|
|
|
924
934
|
}
|
|
925
935
|
};
|
|
926
936
|
|
|
927
|
-
// src/lib/MigrationHistoryManager.ts
|
|
928
|
-
var import_node_fs = require("fs");
|
|
929
|
-
var import_fs = require("fs");
|
|
930
|
-
var FILENAME_UP_PREFIX = "up_to_";
|
|
931
|
-
var FILENAME_DOWN_PREFIX = "down_to_";
|
|
932
|
-
var MigrationHistoryManager = class {
|
|
933
|
-
configPath;
|
|
934
|
-
migrationsPath;
|
|
935
|
-
constructor(configPath) {
|
|
936
|
-
this.configPath = configPath;
|
|
937
|
-
this.migrationsPath = `${configPath}/migrations`;
|
|
938
|
-
(0, import_node_fs.mkdirSync)(this.configPath, { recursive: true });
|
|
939
|
-
(0, import_node_fs.mkdirSync)(this.migrationsPath, { recursive: true });
|
|
940
|
-
}
|
|
941
|
-
/**
|
|
942
|
-
* Creates migration history files for upgrading and downgrading database schemas.
|
|
943
|
-
*
|
|
944
|
-
* @param fromVersion - The current version number of the database.
|
|
945
|
-
* @param toVersion - The target version number for the migration.
|
|
946
|
-
* @param changes - An object containing the SQL changes for upgrading (`changes.up`) and downgrading (`changes.down`).
|
|
947
|
-
* @param overwriteExisting - A flag that determines if existing migration files should be overwritten. Defaults to `false`.
|
|
948
|
-
*/
|
|
949
|
-
createMigrationHistory(fromVersion, toVersion, changes, overwriteExisting) {
|
|
950
|
-
const upPath = `${this.migrationsPath}/${FILENAME_UP_PREFIX}${toVersion}.sql`;
|
|
951
|
-
const downPath = `${this.migrationsPath}/${FILENAME_DOWN_PREFIX}${fromVersion}.sql`;
|
|
952
|
-
if ((0, import_node_fs.existsSync)(upPath) && !overwriteExisting)
|
|
953
|
-
throw new Error(`Migration ${upPath} already exists!`);
|
|
954
|
-
else if ((0, import_node_fs.existsSync)(downPath) && !overwriteExisting)
|
|
955
|
-
throw new Error(`Migration ${downPath} already exists!`);
|
|
956
|
-
Logger.log(`Save migrations to ${this.migrationsPath}`);
|
|
957
|
-
return changes;
|
|
958
|
-
}
|
|
959
|
-
/**
|
|
960
|
-
* Retrieves the SQL migration script for upgrading to the specified version.
|
|
961
|
-
* If no version is provided, it retrieves the migration script for the latest version in the history.
|
|
962
|
-
*
|
|
963
|
-
* @param toVersion - The version of the migration script to retrieve. If not specified, the latest version is used.
|
|
964
|
-
* @return The content of the SQL migration script as a string.
|
|
965
|
-
*/
|
|
966
|
-
getUpMigration(toVersion) {
|
|
967
|
-
return (0, import_fs.readFileSync)(`${this.migrationsPath}/${FILENAME_UP_PREFIX}${toVersion}.sql`, { encoding: "utf-8" });
|
|
968
|
-
}
|
|
969
|
-
/**
|
|
970
|
-
* Retrieves the SQL migration script for downgrading to the specified version.
|
|
971
|
-
*
|
|
972
|
-
* @param version - The version number of the migration to retrieve.
|
|
973
|
-
* @return The SQL script for the down migration.
|
|
974
|
-
*/
|
|
975
|
-
getDownMigration(version) {
|
|
976
|
-
return (0, import_fs.readFileSync)(`${this.migrationsPath}/${FILENAME_DOWN_PREFIX}${version}.sql`, { encoding: "utf-8" });
|
|
977
|
-
}
|
|
978
|
-
};
|
|
979
|
-
|
|
980
937
|
// src/lib/tableInfo/decorators/TableClass.ts
|
|
981
938
|
var import_polyfill_symbol_metadata = require("polyfill-symbol-metadata");
|
|
982
939
|
function TableClass(tableName, primaryKey) {
|
|
@@ -1038,6 +995,7 @@ function ForeignKey(toTable, toColumn, options) {
|
|
|
1038
995
|
}
|
|
1039
996
|
|
|
1040
997
|
// src/lib/dialects/DefaultSql.ts
|
|
998
|
+
var import_escape_sql_string = __toESM(require("escape-sql-string"));
|
|
1041
999
|
var MIGRATION_DATA_TABLE_NAME = "__sqlmorpheus_migrations";
|
|
1042
1000
|
var DefaultSql = class {
|
|
1043
1001
|
db;
|
|
@@ -1046,15 +1004,16 @@ var DefaultSql = class {
|
|
|
1046
1004
|
canInspectForeignKeys = false;
|
|
1047
1005
|
canInspectPrimaryKey = false;
|
|
1048
1006
|
types = {
|
|
1007
|
+
text: "TEXT",
|
|
1049
1008
|
string: "TEXT",
|
|
1050
1009
|
number: "INTEGER",
|
|
1051
1010
|
bigint: "BIGINT",
|
|
1052
1011
|
boolean: "BOOLEAN",
|
|
1053
1012
|
date: "DATE",
|
|
1054
1013
|
time: "TIME",
|
|
1055
|
-
dateTime: "DATETIME"
|
|
1056
|
-
null: "NULL"
|
|
1014
|
+
dateTime: "DATETIME"
|
|
1057
1015
|
};
|
|
1016
|
+
nullType = "NULL";
|
|
1058
1017
|
constructor(db) {
|
|
1059
1018
|
this.db = db;
|
|
1060
1019
|
}
|
|
@@ -1070,6 +1029,7 @@ var DefaultSql = class {
|
|
|
1070
1029
|
return value2 instanceof Date ? value2 : new Date(value2);
|
|
1071
1030
|
}
|
|
1072
1031
|
switch (type) {
|
|
1032
|
+
case "text":
|
|
1073
1033
|
case "string":
|
|
1074
1034
|
return `"${value}"`;
|
|
1075
1035
|
case "time":
|
|
@@ -1239,12 +1199,17 @@ var DefaultSql = class {
|
|
|
1239
1199
|
* @param tableName - The name of the database table to select data from.
|
|
1240
1200
|
* @param select - An array of column names to include in the SELECT clause.
|
|
1241
1201
|
* @param where - An optional condition.
|
|
1202
|
+
* @param orderBy - Optional. the column to sort by
|
|
1242
1203
|
* @return The SQL statement as a string.
|
|
1243
1204
|
*/
|
|
1244
|
-
select(tableName, select, where) {
|
|
1205
|
+
select(tableName, select, where, orderBy) {
|
|
1245
1206
|
let query = `SELECT ${select.join(",")} FROM ${tableName}`;
|
|
1246
|
-
if (where)
|
|
1207
|
+
if (where) {
|
|
1247
1208
|
query += ` WHERE ${where}`;
|
|
1209
|
+
}
|
|
1210
|
+
if (orderBy) {
|
|
1211
|
+
query += ` ORDER BY ${orderBy}`;
|
|
1212
|
+
}
|
|
1248
1213
|
return `${query};`;
|
|
1249
1214
|
}
|
|
1250
1215
|
/**
|
|
@@ -1276,7 +1241,10 @@ var DefaultSql = class {
|
|
|
1276
1241
|
*/
|
|
1277
1242
|
migrationTableQuery() {
|
|
1278
1243
|
return this.createTable(MIGRATION_DATA_TABLE_NAME, [
|
|
1279
|
-
this.columnDefinition("
|
|
1244
|
+
this.columnDefinition("fromVersion", this.getSqlType("number"), false, "0"),
|
|
1245
|
+
this.columnDefinition("toVersion", this.getSqlType("number"), true, "0"),
|
|
1246
|
+
this.columnDefinition("upChanges", this.getSqlType("text"), false),
|
|
1247
|
+
this.columnDefinition("downChanges", this.getSqlType("text"), false)
|
|
1280
1248
|
]);
|
|
1281
1249
|
}
|
|
1282
1250
|
/**
|
|
@@ -1305,23 +1273,44 @@ var DefaultSql = class {
|
|
|
1305
1273
|
*/
|
|
1306
1274
|
async getVersion() {
|
|
1307
1275
|
await this.createMigrationTableIfNeeded();
|
|
1308
|
-
const query = this.select(MIGRATION_DATA_TABLE_NAME, ["
|
|
1276
|
+
const query = this.select(MIGRATION_DATA_TABLE_NAME, ["toVersion"], void 0, "toVersion DESC");
|
|
1309
1277
|
const data = await this.db.runGetStatement(query);
|
|
1310
|
-
return data.length ? data[0].
|
|
1278
|
+
return data.length ? data[0].toVersion : 0;
|
|
1311
1279
|
}
|
|
1312
1280
|
/**
|
|
1313
1281
|
* Updates the migration version in the database. If the version entry does not exist, it inserts a new one;
|
|
1314
1282
|
* if it exists, it updates the version to the specified value.
|
|
1315
1283
|
*
|
|
1316
|
-
* @param
|
|
1284
|
+
* @param toVersion - The new migration version to set in the database.
|
|
1317
1285
|
* @return A promise that resolves when the operation is complete.
|
|
1318
1286
|
*/
|
|
1319
|
-
async
|
|
1320
|
-
const query = `${this.migrationTableQuery()};
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1287
|
+
async rollbackHistory(toVersion) {
|
|
1288
|
+
const query = `${this.migrationTableQuery()}; DELETE FROM ${MIGRATION_DATA_TABLE_NAME} WHERE toVersion > ${toVersion};`;
|
|
1289
|
+
await this.db.runMultipleWriteStatements(query);
|
|
1290
|
+
}
|
|
1291
|
+
async getChanges(version) {
|
|
1292
|
+
await this.createMigrationTableIfNeeded();
|
|
1293
|
+
const query = this.select(MIGRATION_DATA_TABLE_NAME, ["fromVersion", "upChanges", "downChanges"], `toVersion = ${version}`);
|
|
1294
|
+
const data = await this.db.runGetStatement(query);
|
|
1295
|
+
return data ? { up: data[0].upChanges, down: data[0].downChanges, fromVersion: data[0].fromVersion } : null;
|
|
1296
|
+
}
|
|
1297
|
+
async hasChanges(version) {
|
|
1298
|
+
await this.createMigrationTableIfNeeded();
|
|
1299
|
+
const query = this.select(MIGRATION_DATA_TABLE_NAME, ["toVersion"], `toVersion = ${version}`);
|
|
1300
|
+
const data = await this.db.runGetStatement(query);
|
|
1301
|
+
return !!data.length;
|
|
1302
|
+
}
|
|
1303
|
+
/**
|
|
1304
|
+
* Saves the change history to the SQLMorpheus table in the database
|
|
1305
|
+
* Since we save SQL queries in the database, we need to make sure that they are properly escaped.
|
|
1306
|
+
* @param fromVersion
|
|
1307
|
+
* @param toVersion
|
|
1308
|
+
* @param changes
|
|
1309
|
+
*/
|
|
1310
|
+
async setChanges(fromVersion, toVersion, changes) {
|
|
1311
|
+
const downChanges = (0, import_escape_sql_string.default)(changes.down);
|
|
1312
|
+
const upChanges = (0, import_escape_sql_string.default)(changes.up);
|
|
1313
|
+
const query = `${this.migrationTableQuery()} ${await this.hasChanges(toVersion) ? `UPDATE ${MIGRATION_DATA_TABLE_NAME} SET fromVersion = '${fromVersion}', upChanges = ${upChanges}, downChanges = ${downChanges} WHERE toVersion = '${toVersion}';` : `INSERT INTO ${MIGRATION_DATA_TABLE_NAME} (fromVersion, toVersion, upChanges, downChanges) VALUES ('${fromVersion}', '${toVersion}', ${upChanges}, ${downChanges})`}`;
|
|
1325
1314
|
await this.db.runMultipleWriteStatements(query);
|
|
1326
1315
|
}
|
|
1327
1316
|
};
|
|
@@ -1329,14 +1318,14 @@ UPDATE ${MIGRATION_DATA_TABLE_NAME} SET version = ${newVersion} WHERE EXISTS (SE
|
|
|
1329
1318
|
// src/lib/dialects/SqliteDialect.ts
|
|
1330
1319
|
var SqliteDialect = class extends DefaultSql {
|
|
1331
1320
|
types = {
|
|
1321
|
+
text: "TEXT",
|
|
1332
1322
|
string: "TEXT",
|
|
1333
1323
|
number: "INTEGER",
|
|
1334
1324
|
bigint: "INTEGER",
|
|
1335
1325
|
boolean: "INTEGER",
|
|
1336
1326
|
date: "INTEGER",
|
|
1337
1327
|
time: "INTEGER",
|
|
1338
|
-
dateTime: "INTEGER"
|
|
1339
|
-
null: "NULL"
|
|
1328
|
+
dateTime: "INTEGER"
|
|
1340
1329
|
};
|
|
1341
1330
|
canAlterForeignKeys = false;
|
|
1342
1331
|
canAlterPrimaryKey = false;
|
|
@@ -1354,8 +1343,8 @@ var SqliteDialect = class extends DefaultSql {
|
|
|
1354
1343
|
for (const entry of data) {
|
|
1355
1344
|
output[entry["name"]] = {
|
|
1356
1345
|
name: entry["name"],
|
|
1357
|
-
|
|
1358
|
-
defaultValue: entry["dflt_value"],
|
|
1346
|
+
sqlType: entry["type"],
|
|
1347
|
+
defaultValue: entry["dflt_value"] ?? this.nullType,
|
|
1359
1348
|
isPrimaryKey: entry["pk"] == "1"
|
|
1360
1349
|
};
|
|
1361
1350
|
}
|
|
@@ -1389,12 +1378,17 @@ var SqliteDialect = class extends DefaultSql {
|
|
|
1389
1378
|
};
|
|
1390
1379
|
});
|
|
1391
1380
|
}
|
|
1381
|
+
async setChanges(fromVersion, toVersion, changes) {
|
|
1382
|
+
await this.db.runMultipleWriteStatements(`PRAGMA user_version = ${toVersion};`);
|
|
1383
|
+
await super.setChanges(fromVersion, toVersion, changes);
|
|
1384
|
+
}
|
|
1392
1385
|
async getVersion() {
|
|
1393
1386
|
const output = await this.db.runGetStatement(`PRAGMA user_version;`);
|
|
1394
1387
|
return output[0].user_version;
|
|
1395
1388
|
}
|
|
1396
|
-
async
|
|
1397
|
-
await this.db.runMultipleWriteStatements(`PRAGMA user_version = ${
|
|
1389
|
+
async rollbackHistory(toVersion) {
|
|
1390
|
+
await this.db.runMultipleWriteStatements(`PRAGMA user_version = ${toVersion};`);
|
|
1391
|
+
await super.rollbackHistory(toVersion);
|
|
1398
1392
|
}
|
|
1399
1393
|
};
|
|
1400
1394
|
|
|
@@ -1422,7 +1416,7 @@ var PostgresDialect = class extends DefaultSql {
|
|
|
1422
1416
|
for (const entry of data) {
|
|
1423
1417
|
output[entry["name"]] = {
|
|
1424
1418
|
name: entry["column_name"],
|
|
1425
|
-
|
|
1419
|
+
sqlType: entry["data_type"],
|
|
1426
1420
|
maxLength: 0,
|
|
1427
1421
|
defaultValue: entry["column_default"],
|
|
1428
1422
|
isPrimaryKey: false
|
|
@@ -1481,7 +1475,7 @@ var MsSqlDialect = class extends DefaultSql {
|
|
|
1481
1475
|
for (const entry of data) {
|
|
1482
1476
|
output[entry["name"]] = {
|
|
1483
1477
|
name: entry["name"],
|
|
1484
|
-
|
|
1478
|
+
sqlType: entry["DATA_TYPE"],
|
|
1485
1479
|
maxLength: 0,
|
|
1486
1480
|
defaultValue: entry["COLUMN_DEFAULT"],
|
|
1487
1481
|
isPrimaryKey: entry["pk"] == "1"
|
|
@@ -1498,19 +1492,27 @@ var MySqlDialect = class extends DefaultSql {
|
|
|
1498
1492
|
canInspectForeignKeys = true;
|
|
1499
1493
|
canInspectPrimaryKey = true;
|
|
1500
1494
|
types = {
|
|
1495
|
+
text: "TEXT",
|
|
1501
1496
|
string: "VARCHAR",
|
|
1502
1497
|
number: "INT",
|
|
1503
1498
|
bigint: "BIGINT",
|
|
1504
|
-
boolean: "
|
|
1499
|
+
boolean: "TINYINT(1)",
|
|
1505
1500
|
date: "DATE",
|
|
1506
1501
|
time: "TIME",
|
|
1507
|
-
dateTime: "DATETIME"
|
|
1508
|
-
null: "NULL"
|
|
1502
|
+
dateTime: "DATETIME"
|
|
1509
1503
|
};
|
|
1504
|
+
formatValueToSql(value, type) {
|
|
1505
|
+
switch (type) {
|
|
1506
|
+
case "boolean":
|
|
1507
|
+
return value ? "1" : "0";
|
|
1508
|
+
default:
|
|
1509
|
+
return super.formatValueToSql(value, type);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1510
1512
|
getSqlType(dataType, columnInfo) {
|
|
1511
1513
|
switch (dataType) {
|
|
1512
1514
|
case "string":
|
|
1513
|
-
return this.types[dataType] + `(${columnInfo?.maxLength})`;
|
|
1515
|
+
return this.types[dataType] + `(${columnInfo?.maxLength ?? 100})`;
|
|
1514
1516
|
default:
|
|
1515
1517
|
return super.getSqlType(dataType, columnInfo);
|
|
1516
1518
|
}
|
|
@@ -1531,13 +1533,27 @@ var MySqlDialect = class extends DefaultSql {
|
|
|
1531
1533
|
return `ALTER TABLE ${tableName} PRIMARY KEY;`;
|
|
1532
1534
|
}
|
|
1533
1535
|
async getForeignKeys(tableName) {
|
|
1534
|
-
const
|
|
1536
|
+
const data3 = await this.db.runGetStatement(
|
|
1537
|
+
`SELECT
|
|
1538
|
+
*
|
|
1539
|
+
FROM information_schema.KEY_COLUMN_USAGE AS info
|
|
1540
|
+
INNER JOIN information_schema.REFERENTIAL_CONSTRAINTS AS constr ON info.CONSTRAINT_NAME = constr.CONSTRAINT_NAME
|
|
1541
|
+
WHERE info.REFERENCED_TABLE_SCHEMA = (SELECT DATABASE()) AND info.TABLE_NAME = '${tableName}';`
|
|
1542
|
+
);
|
|
1543
|
+
const data = await this.db.runGetStatement(
|
|
1544
|
+
`SELECT
|
|
1545
|
+
info.TABLE_NAME, info.COLUMN_NAME, info.REFERENCED_TABLE_NAME, info.REFERENCED_COLUMN_NAME, constr.UPDATE_RULE, constr.DELETE_RULE
|
|
1546
|
+
FROM information_schema.KEY_COLUMN_USAGE AS info INNER JOIN information_schema.REFERENTIAL_CONSTRAINTS AS constr ON info.CONSTRAINT_NAME = constr.CONSTRAINT_NAME
|
|
1547
|
+
WHERE info.REFERENCED_TABLE_SCHEMA = (SELECT DATABASE()) AND info.TABLE_NAME = '${tableName}';`
|
|
1548
|
+
);
|
|
1535
1549
|
return data.map((entry) => {
|
|
1536
1550
|
return {
|
|
1537
1551
|
fromTable: tableName,
|
|
1538
1552
|
fromColumn: entry["COLUMN_NAME"],
|
|
1539
1553
|
toTable: entry["REFERENCED_TABLE_NAME"],
|
|
1540
|
-
toColumn: entry["REFERENCED_COLUMN_NAME"]
|
|
1554
|
+
toColumn: entry["REFERENCED_COLUMN_NAME"],
|
|
1555
|
+
onUpdate: entry["UPDATE_RULE"],
|
|
1556
|
+
onDelete: entry["DELETE_RULE"]
|
|
1541
1557
|
};
|
|
1542
1558
|
});
|
|
1543
1559
|
}
|
|
@@ -1549,14 +1565,23 @@ var MySqlDialect = class extends DefaultSql {
|
|
|
1549
1565
|
const data = await this.db.runGetStatement(`SHOW COLUMNS FROM ${tableName};`);
|
|
1550
1566
|
const output = {};
|
|
1551
1567
|
for (const entry of data) {
|
|
1552
|
-
const
|
|
1553
|
-
|
|
1568
|
+
const sqlType = entry["Type"].toUpperCase();
|
|
1569
|
+
const info = {
|
|
1554
1570
|
name: entry["Field"],
|
|
1555
|
-
|
|
1556
|
-
maxLength: lengthMatch ? parseInt(lengthMatch[1]) ?? 0 : 0,
|
|
1557
|
-
defaultValue: entry["Default"],
|
|
1571
|
+
sqlType,
|
|
1558
1572
|
isPrimaryKey: entry["Key"] == "PRI"
|
|
1559
1573
|
};
|
|
1574
|
+
switch (sqlType.substring(0, 4)) {
|
|
1575
|
+
case "TEXT":
|
|
1576
|
+
case "VARC":
|
|
1577
|
+
case "DATE":
|
|
1578
|
+
case "TIME":
|
|
1579
|
+
info.defaultValue = entry["Default"] ? `"${entry["Default"]}"` : this.nullType;
|
|
1580
|
+
break;
|
|
1581
|
+
default:
|
|
1582
|
+
info.defaultValue = entry["Default"] ?? this.nullType;
|
|
1583
|
+
}
|
|
1584
|
+
output[entry["Field"]] = info;
|
|
1560
1585
|
}
|
|
1561
1586
|
return output;
|
|
1562
1587
|
}
|
|
@@ -1585,8 +1610,7 @@ async function runMigration(db, dbInstructions) {
|
|
|
1585
1610
|
const mm = new MigrationManager(dialect);
|
|
1586
1611
|
const migration = await mm.generateSqlChanges(dbInstructions);
|
|
1587
1612
|
if (migration) {
|
|
1588
|
-
|
|
1589
|
-
migrationHistoryManager.createMigrationHistory(migration.fromVersion, dbInstructions.version, migration.changes);
|
|
1613
|
+
await dialect.setChanges(migration.fromVersion, dbInstructions.version, migration.changes);
|
|
1590
1614
|
await db.createBackup?.(`from_${migration.fromVersion}_to_${dbInstructions.version}`);
|
|
1591
1615
|
await db.runMultipleWriteStatements(migration.changes.up);
|
|
1592
1616
|
}
|
|
@@ -1595,16 +1619,26 @@ async function rollback(db, dbInstructions, toVersion) {
|
|
|
1595
1619
|
Logger.setMode(dbInstructions.loggerMode);
|
|
1596
1620
|
const dialect = getDialect(db, dbInstructions);
|
|
1597
1621
|
const fromVersion = await dialect.getVersion();
|
|
1598
|
-
const historyManager = new MigrationHistoryManager(dbInstructions.configPath);
|
|
1599
1622
|
await db.createBackup?.(`from_${fromVersion}_to_${dbInstructions.version}`);
|
|
1600
1623
|
Logger.log(`Rolling back from ${fromVersion} to ${toVersion}`);
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1624
|
+
let version = fromVersion;
|
|
1625
|
+
while (version > toVersion) {
|
|
1626
|
+
const changes = await dialect.getChanges(version);
|
|
1627
|
+
if (!changes) {
|
|
1628
|
+
throw new Error(`No changes found for version ${version}`);
|
|
1629
|
+
} else if (changes.fromVersion == version) {
|
|
1630
|
+
throw new Error(`Saved changes do not change the database version (${version})`);
|
|
1631
|
+
}
|
|
1632
|
+
Logger.debug(changes.down);
|
|
1633
|
+
await db.runMultipleWriteStatements(changes.down);
|
|
1634
|
+
dbInstructions.version = changes.fromVersion;
|
|
1635
|
+
version = changes.fromVersion;
|
|
1636
|
+
}
|
|
1637
|
+
if (version < toVersion) {
|
|
1638
|
+
Logger.warn(`There was no entry for version ${toVersion}. Rolled back to version ${version}`);
|
|
1606
1639
|
}
|
|
1607
|
-
await dialect.
|
|
1640
|
+
await dialect.rollbackHistory(version);
|
|
1641
|
+
return version;
|
|
1608
1642
|
}
|
|
1609
1643
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1610
1644
|
0 && (module.exports = {
|
package/dist/index.mjs
CHANGED
|
@@ -34,7 +34,7 @@ var TableObj = class _TableObj {
|
|
|
34
34
|
static getEmptyColumnEntry(key) {
|
|
35
35
|
return {
|
|
36
36
|
name: key,
|
|
37
|
-
|
|
37
|
+
sqlType: "",
|
|
38
38
|
defaultValue: "",
|
|
39
39
|
isPrimaryKey: false
|
|
40
40
|
};
|
|
@@ -161,8 +161,8 @@ var TableStructureGenerator = class {
|
|
|
161
161
|
}
|
|
162
162
|
for (const key in structure.columns) {
|
|
163
163
|
const entry = structure.columns[key];
|
|
164
|
-
entry.defaultValue = entry.inputDefaultValue === null ? this.dialect.
|
|
165
|
-
entry.
|
|
164
|
+
entry.defaultValue = entry.inputDefaultValue === null ? this.dialect.nullType : this.dialect.formatValueToSql(entry.inputDefaultValue, entry.inputType);
|
|
165
|
+
entry.sqlType = this.dialect.getSqlType(entry.inputType, entry);
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
return tables;
|
|
@@ -667,7 +667,7 @@ ${changes.up}
|
|
|
667
667
|
const queryLines = [];
|
|
668
668
|
for (const key in columns) {
|
|
669
669
|
const columnInfo = columns[key];
|
|
670
|
-
queryLines.push(this.dialect.columnDefinition(columnInfo.name, columnInfo.
|
|
670
|
+
queryLines.push(this.dialect.columnDefinition(columnInfo.name, columnInfo.sqlType, columnInfo.isPrimaryKey, columnInfo.defaultValue));
|
|
671
671
|
}
|
|
672
672
|
if (foreignKeys) {
|
|
673
673
|
for (const foreignKeyInfo of foreignKeys) {
|
|
@@ -839,9 +839,9 @@ ${changes.up}
|
|
|
839
839
|
if (willBeRenamed)
|
|
840
840
|
continue;
|
|
841
841
|
if (oldColumn == void 0) {
|
|
842
|
-
changes.up += this.dialect.createColumn(tableName, this.dialect.columnDefinition(newColumn.name, newColumn.
|
|
842
|
+
changes.up += this.dialect.createColumn(tableName, this.dialect.columnDefinition(newColumn.name, newColumn.sqlType, newColumn.isPrimaryKey, newColumn.defaultValue)) + "\n";
|
|
843
843
|
changes.down += this.dialect.dropColumn(tableName, newColumn.name) + "\n";
|
|
844
|
-
} else if (newColumn.
|
|
844
|
+
} else if (newColumn.sqlType != oldColumn.sqlType || newColumn.defaultValue != oldColumn.defaultValue) {
|
|
845
845
|
this.migrations.internalRecreate(newTableDefinition.table, "Table structure was changed");
|
|
846
846
|
}
|
|
847
847
|
}
|
|
@@ -851,7 +851,7 @@ ${changes.up}
|
|
|
851
851
|
if (newColumn == void 0) {
|
|
852
852
|
this.migrations.compareWithAllowedMigration(tableName, "dropColumn");
|
|
853
853
|
changes.up += this.dialect.dropColumn(tableName, oldColumn.name) + "\n";
|
|
854
|
-
changes.down += this.dialect.createColumn(tableName, this.dialect.columnDefinition(oldColumn.name, oldColumn.
|
|
854
|
+
changes.down += this.dialect.createColumn(tableName, this.dialect.columnDefinition(oldColumn.name, oldColumn.sqlType, oldColumn.isPrimaryKey, oldColumn.defaultValue)) + "\n";
|
|
855
855
|
}
|
|
856
856
|
}
|
|
857
857
|
}
|
|
@@ -893,59 +893,6 @@ ${changes.up}
|
|
|
893
893
|
}
|
|
894
894
|
};
|
|
895
895
|
|
|
896
|
-
// src/lib/MigrationHistoryManager.ts
|
|
897
|
-
import { existsSync, mkdirSync } from "fs";
|
|
898
|
-
import { readFileSync } from "fs";
|
|
899
|
-
var FILENAME_UP_PREFIX = "up_to_";
|
|
900
|
-
var FILENAME_DOWN_PREFIX = "down_to_";
|
|
901
|
-
var MigrationHistoryManager = class {
|
|
902
|
-
configPath;
|
|
903
|
-
migrationsPath;
|
|
904
|
-
constructor(configPath) {
|
|
905
|
-
this.configPath = configPath;
|
|
906
|
-
this.migrationsPath = `${configPath}/migrations`;
|
|
907
|
-
mkdirSync(this.configPath, { recursive: true });
|
|
908
|
-
mkdirSync(this.migrationsPath, { recursive: true });
|
|
909
|
-
}
|
|
910
|
-
/**
|
|
911
|
-
* Creates migration history files for upgrading and downgrading database schemas.
|
|
912
|
-
*
|
|
913
|
-
* @param fromVersion - The current version number of the database.
|
|
914
|
-
* @param toVersion - The target version number for the migration.
|
|
915
|
-
* @param changes - An object containing the SQL changes for upgrading (`changes.up`) and downgrading (`changes.down`).
|
|
916
|
-
* @param overwriteExisting - A flag that determines if existing migration files should be overwritten. Defaults to `false`.
|
|
917
|
-
*/
|
|
918
|
-
createMigrationHistory(fromVersion, toVersion, changes, overwriteExisting) {
|
|
919
|
-
const upPath = `${this.migrationsPath}/${FILENAME_UP_PREFIX}${toVersion}.sql`;
|
|
920
|
-
const downPath = `${this.migrationsPath}/${FILENAME_DOWN_PREFIX}${fromVersion}.sql`;
|
|
921
|
-
if (existsSync(upPath) && !overwriteExisting)
|
|
922
|
-
throw new Error(`Migration ${upPath} already exists!`);
|
|
923
|
-
else if (existsSync(downPath) && !overwriteExisting)
|
|
924
|
-
throw new Error(`Migration ${downPath} already exists!`);
|
|
925
|
-
Logger.log(`Save migrations to ${this.migrationsPath}`);
|
|
926
|
-
return changes;
|
|
927
|
-
}
|
|
928
|
-
/**
|
|
929
|
-
* Retrieves the SQL migration script for upgrading to the specified version.
|
|
930
|
-
* If no version is provided, it retrieves the migration script for the latest version in the history.
|
|
931
|
-
*
|
|
932
|
-
* @param toVersion - The version of the migration script to retrieve. If not specified, the latest version is used.
|
|
933
|
-
* @return The content of the SQL migration script as a string.
|
|
934
|
-
*/
|
|
935
|
-
getUpMigration(toVersion) {
|
|
936
|
-
return readFileSync(`${this.migrationsPath}/${FILENAME_UP_PREFIX}${toVersion}.sql`, { encoding: "utf-8" });
|
|
937
|
-
}
|
|
938
|
-
/**
|
|
939
|
-
* Retrieves the SQL migration script for downgrading to the specified version.
|
|
940
|
-
*
|
|
941
|
-
* @param version - The version number of the migration to retrieve.
|
|
942
|
-
* @return The SQL script for the down migration.
|
|
943
|
-
*/
|
|
944
|
-
getDownMigration(version) {
|
|
945
|
-
return readFileSync(`${this.migrationsPath}/${FILENAME_DOWN_PREFIX}${version}.sql`, { encoding: "utf-8" });
|
|
946
|
-
}
|
|
947
|
-
};
|
|
948
|
-
|
|
949
896
|
// src/lib/tableInfo/decorators/TableClass.ts
|
|
950
897
|
import "polyfill-symbol-metadata";
|
|
951
898
|
function TableClass(tableName, primaryKey) {
|
|
@@ -1007,6 +954,7 @@ function ForeignKey(toTable, toColumn, options) {
|
|
|
1007
954
|
}
|
|
1008
955
|
|
|
1009
956
|
// src/lib/dialects/DefaultSql.ts
|
|
957
|
+
import escapeString from "escape-sql-string";
|
|
1010
958
|
var MIGRATION_DATA_TABLE_NAME = "__sqlmorpheus_migrations";
|
|
1011
959
|
var DefaultSql = class {
|
|
1012
960
|
db;
|
|
@@ -1015,15 +963,16 @@ var DefaultSql = class {
|
|
|
1015
963
|
canInspectForeignKeys = false;
|
|
1016
964
|
canInspectPrimaryKey = false;
|
|
1017
965
|
types = {
|
|
966
|
+
text: "TEXT",
|
|
1018
967
|
string: "TEXT",
|
|
1019
968
|
number: "INTEGER",
|
|
1020
969
|
bigint: "BIGINT",
|
|
1021
970
|
boolean: "BOOLEAN",
|
|
1022
971
|
date: "DATE",
|
|
1023
972
|
time: "TIME",
|
|
1024
|
-
dateTime: "DATETIME"
|
|
1025
|
-
null: "NULL"
|
|
973
|
+
dateTime: "DATETIME"
|
|
1026
974
|
};
|
|
975
|
+
nullType = "NULL";
|
|
1027
976
|
constructor(db) {
|
|
1028
977
|
this.db = db;
|
|
1029
978
|
}
|
|
@@ -1039,6 +988,7 @@ var DefaultSql = class {
|
|
|
1039
988
|
return value2 instanceof Date ? value2 : new Date(value2);
|
|
1040
989
|
}
|
|
1041
990
|
switch (type) {
|
|
991
|
+
case "text":
|
|
1042
992
|
case "string":
|
|
1043
993
|
return `"${value}"`;
|
|
1044
994
|
case "time":
|
|
@@ -1208,12 +1158,17 @@ var DefaultSql = class {
|
|
|
1208
1158
|
* @param tableName - The name of the database table to select data from.
|
|
1209
1159
|
* @param select - An array of column names to include in the SELECT clause.
|
|
1210
1160
|
* @param where - An optional condition.
|
|
1161
|
+
* @param orderBy - Optional. the column to sort by
|
|
1211
1162
|
* @return The SQL statement as a string.
|
|
1212
1163
|
*/
|
|
1213
|
-
select(tableName, select, where) {
|
|
1164
|
+
select(tableName, select, where, orderBy) {
|
|
1214
1165
|
let query = `SELECT ${select.join(",")} FROM ${tableName}`;
|
|
1215
|
-
if (where)
|
|
1166
|
+
if (where) {
|
|
1216
1167
|
query += ` WHERE ${where}`;
|
|
1168
|
+
}
|
|
1169
|
+
if (orderBy) {
|
|
1170
|
+
query += ` ORDER BY ${orderBy}`;
|
|
1171
|
+
}
|
|
1217
1172
|
return `${query};`;
|
|
1218
1173
|
}
|
|
1219
1174
|
/**
|
|
@@ -1245,7 +1200,10 @@ var DefaultSql = class {
|
|
|
1245
1200
|
*/
|
|
1246
1201
|
migrationTableQuery() {
|
|
1247
1202
|
return this.createTable(MIGRATION_DATA_TABLE_NAME, [
|
|
1248
|
-
this.columnDefinition("
|
|
1203
|
+
this.columnDefinition("fromVersion", this.getSqlType("number"), false, "0"),
|
|
1204
|
+
this.columnDefinition("toVersion", this.getSqlType("number"), true, "0"),
|
|
1205
|
+
this.columnDefinition("upChanges", this.getSqlType("text"), false),
|
|
1206
|
+
this.columnDefinition("downChanges", this.getSqlType("text"), false)
|
|
1249
1207
|
]);
|
|
1250
1208
|
}
|
|
1251
1209
|
/**
|
|
@@ -1274,23 +1232,44 @@ var DefaultSql = class {
|
|
|
1274
1232
|
*/
|
|
1275
1233
|
async getVersion() {
|
|
1276
1234
|
await this.createMigrationTableIfNeeded();
|
|
1277
|
-
const query = this.select(MIGRATION_DATA_TABLE_NAME, ["
|
|
1235
|
+
const query = this.select(MIGRATION_DATA_TABLE_NAME, ["toVersion"], void 0, "toVersion DESC");
|
|
1278
1236
|
const data = await this.db.runGetStatement(query);
|
|
1279
|
-
return data.length ? data[0].
|
|
1237
|
+
return data.length ? data[0].toVersion : 0;
|
|
1280
1238
|
}
|
|
1281
1239
|
/**
|
|
1282
1240
|
* Updates the migration version in the database. If the version entry does not exist, it inserts a new one;
|
|
1283
1241
|
* if it exists, it updates the version to the specified value.
|
|
1284
1242
|
*
|
|
1285
|
-
* @param
|
|
1243
|
+
* @param toVersion - The new migration version to set in the database.
|
|
1286
1244
|
* @return A promise that resolves when the operation is complete.
|
|
1287
1245
|
*/
|
|
1288
|
-
async
|
|
1289
|
-
const query = `${this.migrationTableQuery()};
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1246
|
+
async rollbackHistory(toVersion) {
|
|
1247
|
+
const query = `${this.migrationTableQuery()}; DELETE FROM ${MIGRATION_DATA_TABLE_NAME} WHERE toVersion > ${toVersion};`;
|
|
1248
|
+
await this.db.runMultipleWriteStatements(query);
|
|
1249
|
+
}
|
|
1250
|
+
async getChanges(version) {
|
|
1251
|
+
await this.createMigrationTableIfNeeded();
|
|
1252
|
+
const query = this.select(MIGRATION_DATA_TABLE_NAME, ["fromVersion", "upChanges", "downChanges"], `toVersion = ${version}`);
|
|
1253
|
+
const data = await this.db.runGetStatement(query);
|
|
1254
|
+
return data ? { up: data[0].upChanges, down: data[0].downChanges, fromVersion: data[0].fromVersion } : null;
|
|
1255
|
+
}
|
|
1256
|
+
async hasChanges(version) {
|
|
1257
|
+
await this.createMigrationTableIfNeeded();
|
|
1258
|
+
const query = this.select(MIGRATION_DATA_TABLE_NAME, ["toVersion"], `toVersion = ${version}`);
|
|
1259
|
+
const data = await this.db.runGetStatement(query);
|
|
1260
|
+
return !!data.length;
|
|
1261
|
+
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Saves the change history to the SQLMorpheus table in the database
|
|
1264
|
+
* Since we save SQL queries in the database, we need to make sure that they are properly escaped.
|
|
1265
|
+
* @param fromVersion
|
|
1266
|
+
* @param toVersion
|
|
1267
|
+
* @param changes
|
|
1268
|
+
*/
|
|
1269
|
+
async setChanges(fromVersion, toVersion, changes) {
|
|
1270
|
+
const downChanges = escapeString(changes.down);
|
|
1271
|
+
const upChanges = escapeString(changes.up);
|
|
1272
|
+
const query = `${this.migrationTableQuery()} ${await this.hasChanges(toVersion) ? `UPDATE ${MIGRATION_DATA_TABLE_NAME} SET fromVersion = '${fromVersion}', upChanges = ${upChanges}, downChanges = ${downChanges} WHERE toVersion = '${toVersion}';` : `INSERT INTO ${MIGRATION_DATA_TABLE_NAME} (fromVersion, toVersion, upChanges, downChanges) VALUES ('${fromVersion}', '${toVersion}', ${upChanges}, ${downChanges})`}`;
|
|
1294
1273
|
await this.db.runMultipleWriteStatements(query);
|
|
1295
1274
|
}
|
|
1296
1275
|
};
|
|
@@ -1298,14 +1277,14 @@ UPDATE ${MIGRATION_DATA_TABLE_NAME} SET version = ${newVersion} WHERE EXISTS (SE
|
|
|
1298
1277
|
// src/lib/dialects/SqliteDialect.ts
|
|
1299
1278
|
var SqliteDialect = class extends DefaultSql {
|
|
1300
1279
|
types = {
|
|
1280
|
+
text: "TEXT",
|
|
1301
1281
|
string: "TEXT",
|
|
1302
1282
|
number: "INTEGER",
|
|
1303
1283
|
bigint: "INTEGER",
|
|
1304
1284
|
boolean: "INTEGER",
|
|
1305
1285
|
date: "INTEGER",
|
|
1306
1286
|
time: "INTEGER",
|
|
1307
|
-
dateTime: "INTEGER"
|
|
1308
|
-
null: "NULL"
|
|
1287
|
+
dateTime: "INTEGER"
|
|
1309
1288
|
};
|
|
1310
1289
|
canAlterForeignKeys = false;
|
|
1311
1290
|
canAlterPrimaryKey = false;
|
|
@@ -1323,8 +1302,8 @@ var SqliteDialect = class extends DefaultSql {
|
|
|
1323
1302
|
for (const entry of data) {
|
|
1324
1303
|
output[entry["name"]] = {
|
|
1325
1304
|
name: entry["name"],
|
|
1326
|
-
|
|
1327
|
-
defaultValue: entry["dflt_value"],
|
|
1305
|
+
sqlType: entry["type"],
|
|
1306
|
+
defaultValue: entry["dflt_value"] ?? this.nullType,
|
|
1328
1307
|
isPrimaryKey: entry["pk"] == "1"
|
|
1329
1308
|
};
|
|
1330
1309
|
}
|
|
@@ -1358,12 +1337,17 @@ var SqliteDialect = class extends DefaultSql {
|
|
|
1358
1337
|
};
|
|
1359
1338
|
});
|
|
1360
1339
|
}
|
|
1340
|
+
async setChanges(fromVersion, toVersion, changes) {
|
|
1341
|
+
await this.db.runMultipleWriteStatements(`PRAGMA user_version = ${toVersion};`);
|
|
1342
|
+
await super.setChanges(fromVersion, toVersion, changes);
|
|
1343
|
+
}
|
|
1361
1344
|
async getVersion() {
|
|
1362
1345
|
const output = await this.db.runGetStatement(`PRAGMA user_version;`);
|
|
1363
1346
|
return output[0].user_version;
|
|
1364
1347
|
}
|
|
1365
|
-
async
|
|
1366
|
-
await this.db.runMultipleWriteStatements(`PRAGMA user_version = ${
|
|
1348
|
+
async rollbackHistory(toVersion) {
|
|
1349
|
+
await this.db.runMultipleWriteStatements(`PRAGMA user_version = ${toVersion};`);
|
|
1350
|
+
await super.rollbackHistory(toVersion);
|
|
1367
1351
|
}
|
|
1368
1352
|
};
|
|
1369
1353
|
|
|
@@ -1391,7 +1375,7 @@ var PostgresDialect = class extends DefaultSql {
|
|
|
1391
1375
|
for (const entry of data) {
|
|
1392
1376
|
output[entry["name"]] = {
|
|
1393
1377
|
name: entry["column_name"],
|
|
1394
|
-
|
|
1378
|
+
sqlType: entry["data_type"],
|
|
1395
1379
|
maxLength: 0,
|
|
1396
1380
|
defaultValue: entry["column_default"],
|
|
1397
1381
|
isPrimaryKey: false
|
|
@@ -1450,7 +1434,7 @@ var MsSqlDialect = class extends DefaultSql {
|
|
|
1450
1434
|
for (const entry of data) {
|
|
1451
1435
|
output[entry["name"]] = {
|
|
1452
1436
|
name: entry["name"],
|
|
1453
|
-
|
|
1437
|
+
sqlType: entry["DATA_TYPE"],
|
|
1454
1438
|
maxLength: 0,
|
|
1455
1439
|
defaultValue: entry["COLUMN_DEFAULT"],
|
|
1456
1440
|
isPrimaryKey: entry["pk"] == "1"
|
|
@@ -1467,19 +1451,27 @@ var MySqlDialect = class extends DefaultSql {
|
|
|
1467
1451
|
canInspectForeignKeys = true;
|
|
1468
1452
|
canInspectPrimaryKey = true;
|
|
1469
1453
|
types = {
|
|
1454
|
+
text: "TEXT",
|
|
1470
1455
|
string: "VARCHAR",
|
|
1471
1456
|
number: "INT",
|
|
1472
1457
|
bigint: "BIGINT",
|
|
1473
|
-
boolean: "
|
|
1458
|
+
boolean: "TINYINT(1)",
|
|
1474
1459
|
date: "DATE",
|
|
1475
1460
|
time: "TIME",
|
|
1476
|
-
dateTime: "DATETIME"
|
|
1477
|
-
null: "NULL"
|
|
1461
|
+
dateTime: "DATETIME"
|
|
1478
1462
|
};
|
|
1463
|
+
formatValueToSql(value, type) {
|
|
1464
|
+
switch (type) {
|
|
1465
|
+
case "boolean":
|
|
1466
|
+
return value ? "1" : "0";
|
|
1467
|
+
default:
|
|
1468
|
+
return super.formatValueToSql(value, type);
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1479
1471
|
getSqlType(dataType, columnInfo) {
|
|
1480
1472
|
switch (dataType) {
|
|
1481
1473
|
case "string":
|
|
1482
|
-
return this.types[dataType] + `(${columnInfo?.maxLength})`;
|
|
1474
|
+
return this.types[dataType] + `(${columnInfo?.maxLength ?? 100})`;
|
|
1483
1475
|
default:
|
|
1484
1476
|
return super.getSqlType(dataType, columnInfo);
|
|
1485
1477
|
}
|
|
@@ -1500,13 +1492,27 @@ var MySqlDialect = class extends DefaultSql {
|
|
|
1500
1492
|
return `ALTER TABLE ${tableName} PRIMARY KEY;`;
|
|
1501
1493
|
}
|
|
1502
1494
|
async getForeignKeys(tableName) {
|
|
1503
|
-
const
|
|
1495
|
+
const data3 = await this.db.runGetStatement(
|
|
1496
|
+
`SELECT
|
|
1497
|
+
*
|
|
1498
|
+
FROM information_schema.KEY_COLUMN_USAGE AS info
|
|
1499
|
+
INNER JOIN information_schema.REFERENTIAL_CONSTRAINTS AS constr ON info.CONSTRAINT_NAME = constr.CONSTRAINT_NAME
|
|
1500
|
+
WHERE info.REFERENCED_TABLE_SCHEMA = (SELECT DATABASE()) AND info.TABLE_NAME = '${tableName}';`
|
|
1501
|
+
);
|
|
1502
|
+
const data = await this.db.runGetStatement(
|
|
1503
|
+
`SELECT
|
|
1504
|
+
info.TABLE_NAME, info.COLUMN_NAME, info.REFERENCED_TABLE_NAME, info.REFERENCED_COLUMN_NAME, constr.UPDATE_RULE, constr.DELETE_RULE
|
|
1505
|
+
FROM information_schema.KEY_COLUMN_USAGE AS info INNER JOIN information_schema.REFERENTIAL_CONSTRAINTS AS constr ON info.CONSTRAINT_NAME = constr.CONSTRAINT_NAME
|
|
1506
|
+
WHERE info.REFERENCED_TABLE_SCHEMA = (SELECT DATABASE()) AND info.TABLE_NAME = '${tableName}';`
|
|
1507
|
+
);
|
|
1504
1508
|
return data.map((entry) => {
|
|
1505
1509
|
return {
|
|
1506
1510
|
fromTable: tableName,
|
|
1507
1511
|
fromColumn: entry["COLUMN_NAME"],
|
|
1508
1512
|
toTable: entry["REFERENCED_TABLE_NAME"],
|
|
1509
|
-
toColumn: entry["REFERENCED_COLUMN_NAME"]
|
|
1513
|
+
toColumn: entry["REFERENCED_COLUMN_NAME"],
|
|
1514
|
+
onUpdate: entry["UPDATE_RULE"],
|
|
1515
|
+
onDelete: entry["DELETE_RULE"]
|
|
1510
1516
|
};
|
|
1511
1517
|
});
|
|
1512
1518
|
}
|
|
@@ -1518,14 +1524,23 @@ var MySqlDialect = class extends DefaultSql {
|
|
|
1518
1524
|
const data = await this.db.runGetStatement(`SHOW COLUMNS FROM ${tableName};`);
|
|
1519
1525
|
const output = {};
|
|
1520
1526
|
for (const entry of data) {
|
|
1521
|
-
const
|
|
1522
|
-
|
|
1527
|
+
const sqlType = entry["Type"].toUpperCase();
|
|
1528
|
+
const info = {
|
|
1523
1529
|
name: entry["Field"],
|
|
1524
|
-
|
|
1525
|
-
maxLength: lengthMatch ? parseInt(lengthMatch[1]) ?? 0 : 0,
|
|
1526
|
-
defaultValue: entry["Default"],
|
|
1530
|
+
sqlType,
|
|
1527
1531
|
isPrimaryKey: entry["Key"] == "PRI"
|
|
1528
1532
|
};
|
|
1533
|
+
switch (sqlType.substring(0, 4)) {
|
|
1534
|
+
case "TEXT":
|
|
1535
|
+
case "VARC":
|
|
1536
|
+
case "DATE":
|
|
1537
|
+
case "TIME":
|
|
1538
|
+
info.defaultValue = entry["Default"] ? `"${entry["Default"]}"` : this.nullType;
|
|
1539
|
+
break;
|
|
1540
|
+
default:
|
|
1541
|
+
info.defaultValue = entry["Default"] ?? this.nullType;
|
|
1542
|
+
}
|
|
1543
|
+
output[entry["Field"]] = info;
|
|
1529
1544
|
}
|
|
1530
1545
|
return output;
|
|
1531
1546
|
}
|
|
@@ -1554,8 +1569,7 @@ async function runMigration(db, dbInstructions) {
|
|
|
1554
1569
|
const mm = new MigrationManager(dialect);
|
|
1555
1570
|
const migration = await mm.generateSqlChanges(dbInstructions);
|
|
1556
1571
|
if (migration) {
|
|
1557
|
-
|
|
1558
|
-
migrationHistoryManager.createMigrationHistory(migration.fromVersion, dbInstructions.version, migration.changes);
|
|
1572
|
+
await dialect.setChanges(migration.fromVersion, dbInstructions.version, migration.changes);
|
|
1559
1573
|
await db.createBackup?.(`from_${migration.fromVersion}_to_${dbInstructions.version}`);
|
|
1560
1574
|
await db.runMultipleWriteStatements(migration.changes.up);
|
|
1561
1575
|
}
|
|
@@ -1564,16 +1578,26 @@ async function rollback(db, dbInstructions, toVersion) {
|
|
|
1564
1578
|
Logger.setMode(dbInstructions.loggerMode);
|
|
1565
1579
|
const dialect = getDialect(db, dbInstructions);
|
|
1566
1580
|
const fromVersion = await dialect.getVersion();
|
|
1567
|
-
const historyManager = new MigrationHistoryManager(dbInstructions.configPath);
|
|
1568
1581
|
await db.createBackup?.(`from_${fromVersion}_to_${dbInstructions.version}`);
|
|
1569
1582
|
Logger.log(`Rolling back from ${fromVersion} to ${toVersion}`);
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1583
|
+
let version = fromVersion;
|
|
1584
|
+
while (version > toVersion) {
|
|
1585
|
+
const changes = await dialect.getChanges(version);
|
|
1586
|
+
if (!changes) {
|
|
1587
|
+
throw new Error(`No changes found for version ${version}`);
|
|
1588
|
+
} else if (changes.fromVersion == version) {
|
|
1589
|
+
throw new Error(`Saved changes do not change the database version (${version})`);
|
|
1590
|
+
}
|
|
1591
|
+
Logger.debug(changes.down);
|
|
1592
|
+
await db.runMultipleWriteStatements(changes.down);
|
|
1593
|
+
dbInstructions.version = changes.fromVersion;
|
|
1594
|
+
version = changes.fromVersion;
|
|
1595
|
+
}
|
|
1596
|
+
if (version < toVersion) {
|
|
1597
|
+
Logger.warn(`There was no entry for version ${toVersion}. Rolled back to version ${version}`);
|
|
1575
1598
|
}
|
|
1576
|
-
await dialect.
|
|
1599
|
+
await dialect.rollbackHistory(version);
|
|
1600
|
+
return version;
|
|
1577
1601
|
}
|
|
1578
1602
|
export {
|
|
1579
1603
|
DataType,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sqlmorpheus",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"author": "JodliDev",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"vitest": "^3.2.4"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
+
"escape-sql-string": "^1.2.2",
|
|
39
40
|
"polyfill-symbol-metadata": "^0.0.2"
|
|
40
41
|
}
|
|
41
42
|
}
|