sqlmorpheus 0.2.1 → 0.2.2
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/README.md +3 -0
- package/dist/index.d.mts +178 -17
- package/dist/index.d.ts +178 -17
- package/dist/index.js +467 -163
- package/dist/index.mjs +467 -163
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -21,42 +21,65 @@ var LoggerClass = class {
|
|
|
21
21
|
};
|
|
22
22
|
var Logger = new LoggerClass();
|
|
23
23
|
|
|
24
|
-
// src/lib/tableInfo/TableInfo.ts
|
|
25
|
-
var TABLE_INFO_PROPERTY_NAME = Symbol("tableInfo");
|
|
26
|
-
function getTableInfo(table) {
|
|
27
|
-
let metadata = table[Symbol.metadata] ?? table.prototype?.[Symbol.metadata];
|
|
28
|
-
if (!metadata) {
|
|
29
|
-
metadata = {};
|
|
30
|
-
table[Symbol.metadata] = metadata;
|
|
31
|
-
}
|
|
32
|
-
return getTableInfoFromMetadata(metadata);
|
|
33
|
-
}
|
|
34
|
-
function getTableInfoFromMetadata(metadata) {
|
|
35
|
-
if (!metadata[TABLE_INFO_PROPERTY_NAME])
|
|
36
|
-
metadata[TABLE_INFO_PROPERTY_NAME] = { primaryKey: "", foreignKeys: [] };
|
|
37
|
-
return metadata[TABLE_INFO_PROPERTY_NAME];
|
|
38
|
-
}
|
|
39
|
-
|
|
40
24
|
// src/lib/tableInfo/TableObj.ts
|
|
41
25
|
var TableObj = class _TableObj {
|
|
42
26
|
IS_TABLE_OBJ = true;
|
|
43
27
|
tableName;
|
|
44
|
-
|
|
45
|
-
|
|
28
|
+
tableStructure = {
|
|
29
|
+
table: "",
|
|
46
30
|
primaryKey: void 0,
|
|
47
|
-
|
|
48
|
-
|
|
31
|
+
columns: {},
|
|
32
|
+
foreignKeys: []
|
|
49
33
|
};
|
|
50
|
-
|
|
34
|
+
static getEmptyColumnEntry(key) {
|
|
35
|
+
return {
|
|
36
|
+
name: key,
|
|
37
|
+
type: "",
|
|
38
|
+
defaultValue: "",
|
|
39
|
+
isPrimaryKey: false
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
static getColumnEntry(key, value) {
|
|
43
|
+
let dataType = typeof value;
|
|
44
|
+
switch (typeof value) {
|
|
45
|
+
case "function":
|
|
46
|
+
return null;
|
|
47
|
+
case "object":
|
|
48
|
+
if (value instanceof Date) {
|
|
49
|
+
dataType = "date";
|
|
50
|
+
break;
|
|
51
|
+
} else {
|
|
52
|
+
Logger.warn(`${key} was skipped because its type (${typeof value}) is not supported`);
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
case "undefined":
|
|
56
|
+
case "symbol":
|
|
57
|
+
Logger.warn(`${key} was skipped because its type (${typeof value}) is not supported`);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
..._TableObj.getEmptyColumnEntry(key),
|
|
62
|
+
inputType: dataType,
|
|
63
|
+
inputDefaultValue: value
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
constructor(tableName, defaultValues) {
|
|
51
67
|
this.tableName = tableName;
|
|
52
|
-
|
|
68
|
+
for (const key in defaultValues) {
|
|
69
|
+
const value = defaultValues[key];
|
|
70
|
+
const columnEntry = _TableObj.getColumnEntry(key, value);
|
|
71
|
+
if (!columnEntry)
|
|
72
|
+
continue;
|
|
73
|
+
this.tableStructure.columns[key] = columnEntry;
|
|
74
|
+
}
|
|
53
75
|
}
|
|
54
76
|
primaryKey(key) {
|
|
55
|
-
this.
|
|
77
|
+
this.tableStructure.primaryKey = key.toString();
|
|
78
|
+
this.tableStructure.columns[key.toString()].isPrimaryKey = true;
|
|
56
79
|
return this;
|
|
57
80
|
}
|
|
58
81
|
foreignKey(fromColumn, toTable, toColumn, options) {
|
|
59
|
-
this.
|
|
82
|
+
this.tableStructure.foreignKeys.push({
|
|
60
83
|
fromTable: this.tableName,
|
|
61
84
|
fromColumn: fromColumn.toString(),
|
|
62
85
|
toTable: toTable.tableName,
|
|
@@ -67,17 +90,44 @@ var TableObj = class _TableObj {
|
|
|
67
90
|
return this;
|
|
68
91
|
}
|
|
69
92
|
dataType(column, type) {
|
|
70
|
-
this.
|
|
93
|
+
this.tableStructure.columns[column.toString()].type = type;
|
|
94
|
+
return this;
|
|
95
|
+
}
|
|
96
|
+
maxCharacterLength(column, max) {
|
|
97
|
+
this.tableStructure.columns[column.toString()].maxLength = max;
|
|
71
98
|
return this;
|
|
72
99
|
}
|
|
73
100
|
static create(tableName, columns) {
|
|
74
101
|
return new _TableObj(tableName, columns);
|
|
75
102
|
}
|
|
76
|
-
static
|
|
103
|
+
static isTableObj(obj) {
|
|
77
104
|
return !!obj?.IS_TABLE_OBJ;
|
|
78
105
|
}
|
|
79
106
|
};
|
|
80
107
|
|
|
108
|
+
// src/lib/tableInfo/getTableStructure.ts
|
|
109
|
+
var TABLE_INFO_PROPERTY_NAME = Symbol("tableInfo");
|
|
110
|
+
function getInputColumnInfo(table, context) {
|
|
111
|
+
const metadata = context?.metadata ? getTableStructureFromMetadata(context.metadata) : getTableStructure(table);
|
|
112
|
+
const key = context.name ?? context;
|
|
113
|
+
if (!metadata.columns.hasOwnProperty(key))
|
|
114
|
+
metadata.columns[key] = TableObj.getEmptyColumnEntry(key);
|
|
115
|
+
return metadata.columns[key];
|
|
116
|
+
}
|
|
117
|
+
function getTableStructure(table) {
|
|
118
|
+
let metadata = table[Symbol.metadata] ?? table.prototype?.[Symbol.metadata];
|
|
119
|
+
if (!metadata) {
|
|
120
|
+
metadata = {};
|
|
121
|
+
table[Symbol.metadata] = metadata;
|
|
122
|
+
}
|
|
123
|
+
return getTableStructureFromMetadata(metadata);
|
|
124
|
+
}
|
|
125
|
+
function getTableStructureFromMetadata(metadata) {
|
|
126
|
+
if (!metadata[TABLE_INFO_PROPERTY_NAME])
|
|
127
|
+
metadata[TABLE_INFO_PROPERTY_NAME] = { table: "", primaryKey: "", foreignKeys: [], columns: {} };
|
|
128
|
+
return metadata[TABLE_INFO_PROPERTY_NAME];
|
|
129
|
+
}
|
|
130
|
+
|
|
81
131
|
// src/lib/TableStructureGenerator.ts
|
|
82
132
|
var TableStructureGenerator = class {
|
|
83
133
|
dialect;
|
|
@@ -92,75 +142,29 @@ var TableStructureGenerator = class {
|
|
|
92
142
|
* @return An object where keys are table names, and values are their corresponding table structures.
|
|
93
143
|
*/
|
|
94
144
|
generateTableStructure() {
|
|
95
|
-
const
|
|
145
|
+
const tables = {};
|
|
96
146
|
for (const table of this.dbInstructions.tables) {
|
|
97
|
-
if (TableObj.
|
|
98
|
-
|
|
99
|
-
else {
|
|
147
|
+
if (TableObj.isTableObj(table)) {
|
|
148
|
+
tables[table.tableName] = table.tableStructure;
|
|
149
|
+
} else {
|
|
100
150
|
const classTable = table;
|
|
101
|
-
|
|
151
|
+
const structure = getTableStructure(classTable);
|
|
152
|
+
tables[classTable.name] = structure;
|
|
153
|
+
for (const key in structure.columns) {
|
|
154
|
+
const entry = structure.columns[key];
|
|
155
|
+
entry.defaultValue = entry.defaultValue === null ? this.dialect.types.null : this.dialect.formatValueToSql(entry.inputDefaultValue, entry.inputType);
|
|
156
|
+
entry.type = this.dialect.getSqlType(entry.inputType, entry);
|
|
157
|
+
}
|
|
102
158
|
}
|
|
103
159
|
}
|
|
104
|
-
const tables = {};
|
|
105
|
-
for (const tableName in tableObjects) {
|
|
106
|
-
const obj = tableObjects[tableName];
|
|
107
|
-
const tableInfo = obj.tableInfo;
|
|
108
|
-
tables[tableName] = {
|
|
109
|
-
table: tableName,
|
|
110
|
-
primaryKey: tableInfo?.primaryKey,
|
|
111
|
-
columns: this.getColumns(obj.columns, tableInfo),
|
|
112
|
-
foreignKeys: tableInfo?.foreignKeys
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
160
|
return tables;
|
|
116
161
|
}
|
|
117
|
-
/**
|
|
118
|
-
* Retrieves the columns for a table
|
|
119
|
-
*
|
|
120
|
-
* @param obj - The table class interface object containing properties that represent the table's fields.
|
|
121
|
-
* @param tableInfo - Optional metadata about the table. Can be undefined.
|
|
122
|
-
* @return An array of {@link ColumnInfo} representing the detailed column information.
|
|
123
|
-
*/
|
|
124
|
-
getColumns(obj, tableInfo) {
|
|
125
|
-
const columns = [];
|
|
126
|
-
for (const property in obj) {
|
|
127
|
-
const propertyKey = property;
|
|
128
|
-
const value = obj[propertyKey];
|
|
129
|
-
const columnData = {
|
|
130
|
-
name: property,
|
|
131
|
-
isPrimaryKey: property == tableInfo?.primaryKey,
|
|
132
|
-
type: this.dialect.types.string,
|
|
133
|
-
defaultValue: this.dialect.types.null
|
|
134
|
-
};
|
|
135
|
-
let dataType = tableInfo?.dataTypes?.[property] ?? typeof value;
|
|
136
|
-
switch (dataType) {
|
|
137
|
-
case "function":
|
|
138
|
-
continue;
|
|
139
|
-
case "object":
|
|
140
|
-
if (value instanceof Date) {
|
|
141
|
-
dataType = "date";
|
|
142
|
-
break;
|
|
143
|
-
} else {
|
|
144
|
-
Logger.warn(`${property} was skipped because its type (${typeof value}) is not supported`);
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
case "undefined":
|
|
148
|
-
case "symbol":
|
|
149
|
-
Logger.warn(`${property} was skipped because its type (${typeof value}) is not supported`);
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
columnData.defaultValue = value === null ? this.dialect.types.null : this.dialect.formatValueToSql(value, dataType);
|
|
153
|
-
columnData.type = this.dialect.types[dataType];
|
|
154
|
-
columns.push(columnData);
|
|
155
|
-
}
|
|
156
|
-
return columns;
|
|
157
|
-
}
|
|
158
162
|
};
|
|
159
163
|
|
|
160
164
|
// src/lib/exceptions/NotAllowedException.ts
|
|
161
165
|
var NotAllowedException = class extends Error {
|
|
162
166
|
constructor(entries) {
|
|
163
|
-
let message = "Some destructive changes need to be confirmed.
|
|
167
|
+
let message = "Some destructive changes need to be confirmed. To confirm, add to preMigration():\n";
|
|
164
168
|
for (const entry of entries) {
|
|
165
169
|
message += ` migrations.allowMigration(${entry.version}, ${entry.tableName}, "${entry.type}");
|
|
166
170
|
`;
|
|
@@ -178,6 +182,13 @@ var Migrations = class {
|
|
|
178
182
|
migrationDataForOldTableNames = {};
|
|
179
183
|
alwaysAllowed = {};
|
|
180
184
|
notAllowedChanges = [];
|
|
185
|
+
/**
|
|
186
|
+
* Resets the migration state to its initial values.
|
|
187
|
+
* Only used internally.
|
|
188
|
+
*
|
|
189
|
+
* @param dbInstructions - The instructions containing database metadata and migration details.
|
|
190
|
+
* @param fromVersion - The version of the actual database.
|
|
191
|
+
*/
|
|
181
192
|
reset(dbInstructions, fromVersion) {
|
|
182
193
|
this.fromVersion = fromVersion;
|
|
183
194
|
this.toVersion = dbInstructions.version;
|
|
@@ -186,10 +197,23 @@ var Migrations = class {
|
|
|
186
197
|
this.alwaysAllowed = dbInstructions.alwaysAllowedMigrations ?? {};
|
|
187
198
|
this.notAllowedChanges = [];
|
|
188
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Retrieves the migration instructions for the specified table.
|
|
202
|
+
* @see getEntryFromTableName
|
|
203
|
+
*
|
|
204
|
+
* @param table - The {@link TableInput} object from which the table name will be retrieved.
|
|
205
|
+
* @return The migration instructions corresponding to the given table input.
|
|
206
|
+
*/
|
|
189
207
|
getEntry(table) {
|
|
190
208
|
const tableName = this.getTableName(table);
|
|
191
209
|
return this.getEntryFromTableName(tableName);
|
|
192
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* Retrieves the migration instructions for the specified table.
|
|
213
|
+
*
|
|
214
|
+
* @param tableName - The name of the table for which the entry is to be retrieved or created.
|
|
215
|
+
* @return The migration instructions corresponding to the given table input.
|
|
216
|
+
*/
|
|
193
217
|
getEntryFromTableName(tableName) {
|
|
194
218
|
if (!this.migrationData.hasOwnProperty(tableName)) {
|
|
195
219
|
this.migrationData[tableName] = {
|
|
@@ -201,17 +225,39 @@ var Migrations = class {
|
|
|
201
225
|
}
|
|
202
226
|
return this.migrationData[tableName];
|
|
203
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Retrieves the table name from the given table input.
|
|
230
|
+
*
|
|
231
|
+
* @param table - The {@link TableInput} object.
|
|
232
|
+
* @return The name of the table derived from either {@link TableObj} or a class.
|
|
233
|
+
*/
|
|
204
234
|
getTableName(table) {
|
|
205
|
-
return TableObj.
|
|
235
|
+
return TableObj.isTableObj(table) ? table.tableName : table.name;
|
|
206
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Checks whether a provided version is relevant based on database version ({@link fromVersion}) and target version ({@link toVersion}).
|
|
239
|
+
* Also makes sure that version checks happen in order.
|
|
240
|
+
*
|
|
241
|
+
* @param version - The version to check for relevance.
|
|
242
|
+
* @return Returns true if the version is relevant, otherwise false.
|
|
243
|
+
* @throws Error if versions are not properly ordered
|
|
244
|
+
*/
|
|
207
245
|
versionIsRelevant(version) {
|
|
208
|
-
if (version
|
|
246
|
+
if (version <= this.fromVersion || version > this.toVersion)
|
|
209
247
|
return false;
|
|
210
248
|
if (version < this.lastUsedVersion)
|
|
211
249
|
throw new Error("Migrations in preMigration() have to be ordered by version (beginning with the lowest version).");
|
|
212
250
|
this.lastUsedVersion = version;
|
|
213
251
|
return true;
|
|
214
252
|
}
|
|
253
|
+
/**
|
|
254
|
+
* Verifies the renaming tasks specified in {@link DatabaseInstructions.preMigration} that were considered are valid.
|
|
255
|
+
* Called after all SQL queries have been generated.
|
|
256
|
+
* Only used internally.
|
|
257
|
+
*
|
|
258
|
+
* @param newTables - The table structures extracted from {@link DatabaseInstructions.tables}.
|
|
259
|
+
* @throws Error if a renaming task is invalid.
|
|
260
|
+
*/
|
|
215
261
|
verifyRenamingTasks(newTables) {
|
|
216
262
|
for (const tableName in this.migrationData) {
|
|
217
263
|
const migrationEntry = this.migrationData[tableName];
|
|
@@ -228,11 +274,18 @@ var Migrations = class {
|
|
|
228
274
|
const newColumnName = renamingData.newName;
|
|
229
275
|
if (oldColumnName == newColumnName)
|
|
230
276
|
return new Error(`You set column ${tableName}.${oldColumnName} to be renamed to itself!`);
|
|
231
|
-
else if (!newTables[tableName]?.columns
|
|
277
|
+
else if (!newTables[tableName]?.columns[newColumnName])
|
|
232
278
|
return new Error(`You set column ${tableName}.${oldColumnName} to be renamed to ${tableName}.${newColumnName}. But ${tableName}.${newColumnName} does not exist in your structure.`);
|
|
233
279
|
}
|
|
234
280
|
}
|
|
235
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* Making sure all considered calls to {@link allowMigration()} where necessary to prevent input mistakes.
|
|
284
|
+
* Called after all SQL queries have been generated.
|
|
285
|
+
* Only used internally.
|
|
286
|
+
*
|
|
287
|
+
* @throws Error if unnecessary calls were discovered. All discovered calls are collected and thrown as one Error.
|
|
288
|
+
*/
|
|
236
289
|
verifyAllowedMigrations() {
|
|
237
290
|
if (this.notAllowedChanges.length)
|
|
238
291
|
return new NotAllowedException(this.notAllowedChanges);
|
|
@@ -248,6 +301,14 @@ var Migrations = class {
|
|
|
248
301
|
if (errorMsg)
|
|
249
302
|
return new Error(errorMsg);
|
|
250
303
|
}
|
|
304
|
+
/**
|
|
305
|
+
* Called by {@link MigrationManager} to check if a specific destructive query is allowed.
|
|
306
|
+
* Only used internally.
|
|
307
|
+
*
|
|
308
|
+
* @see allowMigration()
|
|
309
|
+
* @param tableName - The name of the table to check the migration against.
|
|
310
|
+
* @param type - The type of destructive migration being checked.
|
|
311
|
+
*/
|
|
251
312
|
compareWithAllowedMigration(tableName, type) {
|
|
252
313
|
const migrationEntry = this.migrationData[tableName];
|
|
253
314
|
if (!migrationEntry?.allowedMigrations[type]) {
|
|
@@ -256,41 +317,114 @@ var Migrations = class {
|
|
|
256
317
|
} else if (migrationEntry)
|
|
257
318
|
migrationEntry.usedMigrations[type] = true;
|
|
258
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* Retrieves the migration data containing instructions for data migration.
|
|
322
|
+
* Only used internally.
|
|
323
|
+
*
|
|
324
|
+
* @return An object where each key corresponds to the table name,
|
|
325
|
+
* and the value is the associated migration instructions.
|
|
326
|
+
*/
|
|
259
327
|
getMigrationData() {
|
|
260
328
|
return this.migrationData;
|
|
261
329
|
}
|
|
330
|
+
/**
|
|
331
|
+
* Iterates over renamed columns for the specified table and executes a callback for each pair of old and new column names.
|
|
332
|
+
* Only used internally.
|
|
333
|
+
*
|
|
334
|
+
* @param tableName - Name of the table whose renamed columns should be processed.
|
|
335
|
+
* @param callback - A function to execute for each renamed column, receiving the old and new column names as arguments.
|
|
336
|
+
*/
|
|
262
337
|
loopRenamedColumns(tableName, callback) {
|
|
263
338
|
const migrationEntry = this.migrationData[tableName];
|
|
264
339
|
for (const renamingData of migrationEntry.renamedColumns) {
|
|
265
340
|
callback(renamingData.oldName, renamingData.newName);
|
|
266
341
|
}
|
|
267
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* Considers the renaming of a table and returns its (newest) name after the migration or
|
|
345
|
+
* the original name if no renaming is queued.
|
|
346
|
+
* Only used internally.
|
|
347
|
+
*
|
|
348
|
+
* @see getOldTableName()
|
|
349
|
+
* @param tableName - The current table name in the database.
|
|
350
|
+
* @return The newest table name if available, otherwise the current table name.
|
|
351
|
+
*/
|
|
268
352
|
getNewestTableName(tableName) {
|
|
269
353
|
return this.migrationDataForOldTableNames[tableName]?.tableRenaming?.newName ?? tableName;
|
|
270
354
|
}
|
|
355
|
+
/**
|
|
356
|
+
* Retrieves the current table name in the database.
|
|
357
|
+
* Only used internally.
|
|
358
|
+
*
|
|
359
|
+
* @see getNewestTableName()
|
|
360
|
+
* @param tableName - The name of the newest table name.
|
|
361
|
+
* @return The current table name in the database.
|
|
362
|
+
*/
|
|
271
363
|
getOldTableName(tableName) {
|
|
272
364
|
return this.migrationData[tableName]?.tableRenaming?.oldName ?? tableName;
|
|
273
365
|
}
|
|
366
|
+
/**
|
|
367
|
+
* Considers the renaming of a column in a table and returns its (newest) name after the migration or
|
|
368
|
+
* the original name if no renaming is queued.
|
|
369
|
+
* Only used internally.
|
|
370
|
+
*
|
|
371
|
+
* @param tableName - The name of the table containing the column.
|
|
372
|
+
* @param oldColumnName - The current name of the column in the database.
|
|
373
|
+
* @return The newest column name if available, otherwise the original column name.
|
|
374
|
+
*/
|
|
274
375
|
getNewestColumnName(tableName, oldColumnName) {
|
|
275
376
|
const columnNames = this.migrationData[tableName]?.renamedColumns.find((columns) => columns.oldName == oldColumnName);
|
|
276
377
|
return columnNames ? columnNames.newName : oldColumnName;
|
|
277
378
|
}
|
|
379
|
+
/**
|
|
380
|
+
* Determines if the specified table is marked to be recreated.
|
|
381
|
+
* Only used internally.
|
|
382
|
+
*
|
|
383
|
+
* @param tableName The name of the table to check.
|
|
384
|
+
* @return Returns true if the table will be recreated, false otherwise.
|
|
385
|
+
*/
|
|
278
386
|
willBeRecreated(tableName) {
|
|
279
387
|
return this.migrationData[tableName]?.recreate;
|
|
280
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* Marks a table to be recreated and logs the recreation reason for the user.
|
|
391
|
+
* Only used internally.
|
|
392
|
+
*
|
|
393
|
+
* @param tableName - The name of the table to be marked for recreation.
|
|
394
|
+
* @param reason - The reason why the table is being marked for recreation.
|
|
395
|
+
*/
|
|
281
396
|
internalRecreate(tableName, reason) {
|
|
282
397
|
const entry = this.getEntryFromTableName(tableName);
|
|
283
398
|
entry.recreate = true;
|
|
284
399
|
Logger.log(`Table ${tableName} will be recreated(${reason})!`);
|
|
285
400
|
}
|
|
401
|
+
/**
|
|
402
|
+
* SqlMorpheus only allows destructive statements if it was specifically allowed in {@link DatabaseInstructions.preMigration()}.
|
|
403
|
+
* Use this method to allow a destructive statement for a specific version.
|
|
404
|
+
* This method will be ignored if {@link version} is smaller than the current database version or higher than the target version of {@link DatabaseInstructions}.
|
|
405
|
+
*
|
|
406
|
+
* @param version - The target version for which the specific migration is allowed. Must be provided to make sure this method will only have an effect when specified.
|
|
407
|
+
* @param table - Either a {@link TableObj} or a class decorated with @TableClass.
|
|
408
|
+
* @param allowedMigrations - The keys representing the migrations to be allowed. Multiple migrations can be provided
|
|
409
|
+
*/
|
|
286
410
|
allowMigration(version, table, ...allowedMigrations) {
|
|
287
|
-
if (
|
|
411
|
+
if (!this.versionIsRelevant(version))
|
|
288
412
|
return;
|
|
289
413
|
const entry = this.getEntry(table);
|
|
290
414
|
for (const key of allowedMigrations) {
|
|
291
415
|
entry.allowedMigrations[key] = true;
|
|
292
416
|
}
|
|
293
417
|
}
|
|
418
|
+
/**
|
|
419
|
+
* When you change the name of a table, SqlMorpheus will assume the original table was meant to be dropped
|
|
420
|
+
* and the new table was meant to be added, which would lead to data loss.
|
|
421
|
+
* Use this method to mark a table to be renamed instead.
|
|
422
|
+
* This method will be ignored if {@link version} is smaller than the current database version or higher than the target version of {@link DatabaseInstructions}.
|
|
423
|
+
*
|
|
424
|
+
* @param version - The target version for which the table should be renamed. Must be provided to make sure this method will only have an effect when specified.
|
|
425
|
+
* @param oldTableName - The current name in the database at the time of the migration.
|
|
426
|
+
* @param newTableName - The new table name or its equivalent input format.
|
|
427
|
+
*/
|
|
294
428
|
renameTable(version, oldTableName, newTableName) {
|
|
295
429
|
if (!this.versionIsRelevant(version))
|
|
296
430
|
return;
|
|
@@ -302,6 +436,17 @@ var Migrations = class {
|
|
|
302
436
|
else
|
|
303
437
|
entry.tableRenaming.newName = newTableNameString;
|
|
304
438
|
}
|
|
439
|
+
/**
|
|
440
|
+
* When you change the name of a column, SqlMorpheus will assume the original column was meant to be removed
|
|
441
|
+
* and the new column was meant to be added, which would lead to data loss.
|
|
442
|
+
* Use this method to mark a column to be renamed instead.
|
|
443
|
+
* This method will be ignored if {@link version} is smaller than the current database version or higher than the target version of {@link DatabaseInstructions}.
|
|
444
|
+
*
|
|
445
|
+
* @param version - The target version for which the table should be renamed. Must be provided to make sure this method will only have an effect when specified.
|
|
446
|
+
* @param table Either a {@link TableObj} or a class decorated with @TableClass containing the column to be renamed.
|
|
447
|
+
* @param oldColumn The current name in the database at the time of the migration.
|
|
448
|
+
* @param newColumn The new name to assign to the column.
|
|
449
|
+
*/
|
|
305
450
|
renameColumn(version, table, oldColumn, newColumn) {
|
|
306
451
|
if (!this.versionIsRelevant(version))
|
|
307
452
|
return;
|
|
@@ -312,6 +457,15 @@ var Migrations = class {
|
|
|
312
457
|
else
|
|
313
458
|
entry.renamedColumns.push({ oldName: oldColumn, newName: newColumn });
|
|
314
459
|
}
|
|
460
|
+
/**
|
|
461
|
+
* Should not be needed most of the time.
|
|
462
|
+
* Marks a table to be recreated
|
|
463
|
+
* (a copy of the table will be created, all data will be moved over, the original table will be dropped and the new table will be renamed to the original name).
|
|
464
|
+
* This method will be ignored if {@link version} is smaller than the current database version or higher than the target version of {@link DatabaseInstructions}.
|
|
465
|
+
*
|
|
466
|
+
* @param version - The target version for which the table should be renamed. Must be provided to make sure this method will only have an effect when specified.
|
|
467
|
+
* @param table Either a {@link TableObj} or a class decorated with @TableClass.
|
|
468
|
+
*/
|
|
315
469
|
recreateTable(version, table) {
|
|
316
470
|
if (!this.versionIsRelevant(version))
|
|
317
471
|
return;
|
|
@@ -500,8 +654,9 @@ ${changes.up}
|
|
|
500
654
|
*/
|
|
501
655
|
createTableSql(tableName, columns, foreignKeys) {
|
|
502
656
|
const queryLines = [];
|
|
503
|
-
for (const
|
|
504
|
-
|
|
657
|
+
for (const key in columns) {
|
|
658
|
+
const columnInfo = columns[key];
|
|
659
|
+
queryLines.push(this.dialect.columnDefinition(columnInfo.name, columnInfo.type, columnInfo.isPrimaryKey, columnInfo.defaultValue));
|
|
505
660
|
}
|
|
506
661
|
if (foreignKeys) {
|
|
507
662
|
for (const foreignKeyInfo of foreignKeys) {
|
|
@@ -539,7 +694,11 @@ ${changes.up}
|
|
|
539
694
|
this.migrations.compareWithAllowedMigration(tableName, "continueWithoutRollback");
|
|
540
695
|
const oldColumnList = await this.dialect.getColumnInformation(this.migrations.getOldTableName(tableName));
|
|
541
696
|
const newColumnList = this.newTables[tableName].columns;
|
|
542
|
-
const moveableColumns =
|
|
697
|
+
const moveableColumns = [];
|
|
698
|
+
for (const key in newColumnList) {
|
|
699
|
+
if (oldColumnList.hasOwnProperty(key))
|
|
700
|
+
moveableColumns.push(newColumnList[key].name);
|
|
701
|
+
}
|
|
543
702
|
const backupTableName = `${tableName}__backup`;
|
|
544
703
|
const insertQuery = this.dialect.insert(
|
|
545
704
|
backupTableName,
|
|
@@ -547,7 +706,7 @@ ${changes.up}
|
|
|
547
706
|
);
|
|
548
707
|
const moveDataQuery = insertQuery + "\n" + this.dialect.dropTable(tableName) + "\n" + this.dialect.renameTable(backupTableName, tableName);
|
|
549
708
|
const structure = this.newTables[tableName];
|
|
550
|
-
changes.up += this.createTableSql(backupTableName, structure.columns, structure.foreignKeys) + "\n" + moveDataQuery + "\n";
|
|
709
|
+
changes.up += this.createTableSql(backupTableName, structure.columns, structure.foreignKeys) + "\n" + moveDataQuery + "\n\n";
|
|
551
710
|
const dbTableName = this.migrations.getOldTableName(tableName);
|
|
552
711
|
changes.down += this.dialect.canInspectForeignKeys && this.dialect.canInspectPrimaryKey ? this.createTableSql(backupTableName, await this.dialect.getColumnInformation(dbTableName), await this.dialect.getForeignKeys(dbTableName)) + "\n" + moveDataQuery : "\n\n-- Cannot recreate foreign keys or load primary keys with this database! Table will not be recreated!\n";
|
|
553
712
|
}
|
|
@@ -639,6 +798,10 @@ ${changes.up}
|
|
|
639
798
|
const newTableDefinition = this.newTables[tableName];
|
|
640
799
|
const oldColumnList = await this.dialect.getColumnInformation(this.migrations.getOldTableName(tableName));
|
|
641
800
|
const oldPrimaryKey = this.dialect.canInspectPrimaryKey ? this.getPrimaryKeyColumn(oldColumnList) : false;
|
|
801
|
+
const oldColumnNewNameIndex = {};
|
|
802
|
+
for (const key in oldColumnList) {
|
|
803
|
+
oldColumnNewNameIndex[this.migrations.getNewestColumnName(tableName, key)] = oldColumnList[key];
|
|
804
|
+
}
|
|
642
805
|
const newColumnList = newTableDefinition.columns;
|
|
643
806
|
const newPrimaryKey = newTableDefinition.primaryKey;
|
|
644
807
|
if (this.dialect.canInspectPrimaryKey && oldPrimaryKey != newPrimaryKey) {
|
|
@@ -657,25 +820,23 @@ ${changes.up}
|
|
|
657
820
|
this.migrations.internalRecreate(newTableDefinition.table, "Dialect does not support altering primary keys");
|
|
658
821
|
continue;
|
|
659
822
|
}
|
|
660
|
-
for (const
|
|
661
|
-
const
|
|
662
|
-
|
|
663
|
-
);
|
|
823
|
+
for (const key in newColumnList) {
|
|
824
|
+
const newColumn = newColumnList[key];
|
|
825
|
+
const oldColumn = oldColumnNewNameIndex[newColumn.name];
|
|
664
826
|
if (oldColumn == void 0) {
|
|
665
|
-
changes.up += this.dialect.createColumn(tableName, this.dialect.columnDefinition(newColumn.name, newColumn.type, newColumn.
|
|
827
|
+
changes.up += this.dialect.createColumn(tableName, this.dialect.columnDefinition(newColumn.name, newColumn.type, newColumn.isPrimaryKey, newColumn.defaultValue)) + "\n";
|
|
666
828
|
changes.down += this.dialect.dropColumn(tableName, newColumn.name) + "\n";
|
|
667
829
|
} else if (newColumn.type != oldColumn.type || newColumn.defaultValue != oldColumn.defaultValue) {
|
|
668
830
|
this.migrations.internalRecreate(newTableDefinition.table, "Table structure was changed");
|
|
669
831
|
}
|
|
670
832
|
}
|
|
671
|
-
for (const
|
|
672
|
-
const
|
|
673
|
-
|
|
674
|
-
);
|
|
833
|
+
for (const key in oldColumnList) {
|
|
834
|
+
const oldColumn = oldColumnList[key];
|
|
835
|
+
const newColumn = newColumnList[this.migrations.getNewestColumnName(tableName, oldColumn.name)];
|
|
675
836
|
if (newColumn == void 0) {
|
|
676
837
|
this.migrations.compareWithAllowedMigration(tableName, "dropColumn");
|
|
677
838
|
changes.up += this.dialect.dropColumn(tableName, oldColumn.name) + "\n";
|
|
678
|
-
changes.down += this.dialect.createColumn(tableName, this.dialect.columnDefinition(oldColumn.name, oldColumn.type, oldColumn.
|
|
839
|
+
changes.down += this.dialect.createColumn(tableName, this.dialect.columnDefinition(oldColumn.name, oldColumn.type, oldColumn.isPrimaryKey, oldColumn.defaultValue)) + "\n";
|
|
679
840
|
}
|
|
680
841
|
}
|
|
681
842
|
}
|
|
@@ -684,11 +845,12 @@ ${changes.up}
|
|
|
684
845
|
/**
|
|
685
846
|
* Retrieves the name of the primary key column from a list of column information.
|
|
686
847
|
*
|
|
687
|
-
* @param
|
|
848
|
+
* @param columnInfoEntries - An array of ColumnInfo objects containing details about each column.
|
|
688
849
|
* @return The name of the primary key column if found; otherwise, undefined.
|
|
689
850
|
*/
|
|
690
|
-
getPrimaryKeyColumn(
|
|
691
|
-
for (const
|
|
851
|
+
getPrimaryKeyColumn(columnInfoEntries) {
|
|
852
|
+
for (const key in columnInfoEntries) {
|
|
853
|
+
const columnInfo = columnInfoEntries[key];
|
|
692
854
|
if (columnInfo.isPrimaryKey)
|
|
693
855
|
return columnInfo.name;
|
|
694
856
|
}
|
|
@@ -778,15 +940,27 @@ ${changes.down}`, { encoding: "utf-8" });
|
|
|
778
940
|
import "polyfill-symbol-metadata";
|
|
779
941
|
function TableClass(tableName, primaryKey) {
|
|
780
942
|
return (table, context) => {
|
|
781
|
-
const
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
943
|
+
const tableStructure = context?.metadata ? getTableStructureFromMetadata(context.metadata) : getTableStructure(table);
|
|
944
|
+
tableStructure.primaryKey = primaryKey?.toString();
|
|
945
|
+
tableStructure.table = tableName;
|
|
946
|
+
if (tableStructure.foreignKeys) {
|
|
947
|
+
for (const foreignKey of tableStructure.foreignKeys) {
|
|
785
948
|
foreignKey.fromTable = tableName;
|
|
786
949
|
if (foreignKey.toTable == table.name)
|
|
787
950
|
foreignKey.toTable = tableName;
|
|
788
951
|
}
|
|
789
952
|
}
|
|
953
|
+
for (const key in table) {
|
|
954
|
+
const value = table[key];
|
|
955
|
+
const existingEntry = tableStructure.columns[key];
|
|
956
|
+
const defaultEntry = TableObj.getColumnEntry(key, value);
|
|
957
|
+
if (!defaultEntry)
|
|
958
|
+
continue;
|
|
959
|
+
tableStructure.columns[key] = {
|
|
960
|
+
...defaultEntry,
|
|
961
|
+
...existingEntry
|
|
962
|
+
};
|
|
963
|
+
}
|
|
790
964
|
Object.defineProperty(table, "name", { value: tableName, writable: false });
|
|
791
965
|
};
|
|
792
966
|
}
|
|
@@ -795,10 +969,8 @@ function TableClass(tableName, primaryKey) {
|
|
|
795
969
|
import "polyfill-symbol-metadata";
|
|
796
970
|
function DataType(type) {
|
|
797
971
|
return (table, context) => {
|
|
798
|
-
const
|
|
799
|
-
|
|
800
|
-
metadata.dataTypes = {};
|
|
801
|
-
metadata.dataTypes[context.name ?? context] = type;
|
|
972
|
+
const entry = getInputColumnInfo(table, context);
|
|
973
|
+
entry.inputType = type;
|
|
802
974
|
};
|
|
803
975
|
}
|
|
804
976
|
|
|
@@ -806,7 +978,7 @@ function DataType(type) {
|
|
|
806
978
|
import "polyfill-symbol-metadata";
|
|
807
979
|
function ForeignKey(toTable, toColumn, options) {
|
|
808
980
|
return (table, context) => {
|
|
809
|
-
const metadata = context?.metadata ?
|
|
981
|
+
const metadata = context?.metadata ? getTableStructureFromMetadata(context.metadata) : getTableStructure(table);
|
|
810
982
|
if (!metadata.foreignKeys)
|
|
811
983
|
metadata.foreignKeys = [];
|
|
812
984
|
metadata.foreignKeys.push({
|
|
@@ -846,7 +1018,7 @@ var DefaultSql = class {
|
|
|
846
1018
|
* Formats a given value to a SQL-equivalent string based on the provided data type.
|
|
847
1019
|
*
|
|
848
1020
|
* @param value - The value to be formatted.
|
|
849
|
-
* @param type - The data type of the value. Either determined through typeof or {@link
|
|
1021
|
+
* @param type - The data type of the value. Either determined through typeof or {@link TableStructure} setting
|
|
850
1022
|
* @return A string representation of the value formatted for SQL.
|
|
851
1023
|
*/
|
|
852
1024
|
formatValueToSql(value, type) {
|
|
@@ -857,65 +1029,68 @@ var DefaultSql = class {
|
|
|
857
1029
|
case "string":
|
|
858
1030
|
return `"${value}"`;
|
|
859
1031
|
case "time":
|
|
860
|
-
return toDate(value).toISOString().slice(11, 19)
|
|
1032
|
+
return `"${toDate(value).toISOString().slice(11, 19)}"`;
|
|
861
1033
|
case "date":
|
|
862
|
-
return toDate(value).toISOString().slice(0, 10)
|
|
1034
|
+
return `"${toDate(value).toISOString().slice(0, 10)}"`;
|
|
863
1035
|
case "dateTime":
|
|
864
|
-
return toDate(value).toISOString().slice(0, 19).replace("T", " ")
|
|
1036
|
+
return `"${toDate(value).toISOString().slice(0, 19).replace("T", " ")}"`;
|
|
865
1037
|
default:
|
|
866
1038
|
return value.toString();
|
|
867
1039
|
}
|
|
868
1040
|
}
|
|
1041
|
+
getSqlType(dataType, _) {
|
|
1042
|
+
return this.types[dataType];
|
|
1043
|
+
}
|
|
869
1044
|
/**
|
|
870
|
-
*
|
|
1045
|
+
* Statement to enable / disable foreign keys in the database.
|
|
871
1046
|
* Is dialect specific.
|
|
872
1047
|
*
|
|
873
1048
|
* @param enabled - A boolean indicating whether to enable or disable foreign key constraints.
|
|
874
|
-
* @return The
|
|
1049
|
+
* @return The SQL statement as a string.
|
|
875
1050
|
*/
|
|
876
1051
|
changeForeignKeysState(enabled) {
|
|
877
1052
|
return "";
|
|
878
1053
|
}
|
|
879
1054
|
/**
|
|
880
|
-
*
|
|
1055
|
+
* Statement to add a foreign key to a specified table.
|
|
881
1056
|
* Is only used if {@link canAlterForeignKeys} is true.
|
|
882
1057
|
*
|
|
883
1058
|
* @param fromTableName - The name of the table to which the foreign key will be added.
|
|
884
1059
|
* @param foreignKey - The foreign key definition to be added, see {@link foreignKey()}.
|
|
885
|
-
* @return The SQL statement
|
|
1060
|
+
* @return The SQL statement as a string.
|
|
886
1061
|
*/
|
|
887
1062
|
addForeignKey(fromTableName, foreignKey) {
|
|
888
1063
|
throw new Error("Adding foreign keys is not supported!");
|
|
889
1064
|
}
|
|
890
1065
|
/**
|
|
891
|
-
*
|
|
1066
|
+
* Statement to remove a foreign key from a specified table.
|
|
892
1067
|
* Is only used if {@link canAlterForeignKeys} is true.
|
|
893
1068
|
*
|
|
894
1069
|
* @param tableName - The name of the table to which the foreign key will be added.
|
|
895
1070
|
* @param foreignKeyName - The name of the foreign key definition.
|
|
896
|
-
* @return The SQL statement
|
|
1071
|
+
* @return The SQL statement as a string.
|
|
897
1072
|
*/
|
|
898
1073
|
removeForeignKey(tableName, foreignKeyName) {
|
|
899
1074
|
throw new Error("Foreign key removal is not supported!");
|
|
900
1075
|
}
|
|
901
1076
|
/**
|
|
902
|
-
*
|
|
1077
|
+
* Statement to add a primary key to the specified table.
|
|
903
1078
|
* Is only used if {@link canAlterPrimaryKey} is true.
|
|
904
1079
|
*
|
|
905
1080
|
* @param tableName - The name of the table to which the primary key will be added.
|
|
906
1081
|
* @param columnName - The name of the column that will be set as the primary key.
|
|
907
|
-
* @return
|
|
1082
|
+
* @return The SQL statement as a string.
|
|
908
1083
|
*/
|
|
909
1084
|
addPrimaryKey(tableName, columnName) {
|
|
910
1085
|
throw new Error("Adding foreign keys is not supported!");
|
|
911
1086
|
}
|
|
912
1087
|
/**
|
|
913
|
-
*
|
|
1088
|
+
* Statement to remove a primary key from the specified table.
|
|
914
1089
|
* Is only used if {@link canAlterPrimaryKey} is true.
|
|
915
1090
|
*
|
|
916
1091
|
* @param tableName - The name of the table to which the primary key will be added.
|
|
917
1092
|
* @param columnName - The name of the column that will be set as the primary key.
|
|
918
|
-
* @return
|
|
1093
|
+
* @return The SQL statement as a string.
|
|
919
1094
|
*/
|
|
920
1095
|
removePrimaryKey(tableName, columnName) {
|
|
921
1096
|
throw new Error("Foreign key removal is not supported!");
|
|
@@ -939,64 +1114,164 @@ var DefaultSql = class {
|
|
|
939
1114
|
query += ` ON DELETE ${onDelete}`;
|
|
940
1115
|
return query;
|
|
941
1116
|
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Statement to create a table if it does not already exist.
|
|
1119
|
+
*
|
|
1120
|
+
* @param tableName - The name of the table to be created.
|
|
1121
|
+
* @param entries - An array containing the column definitions for the table.
|
|
1122
|
+
* @return The SQL statement as a string.
|
|
1123
|
+
*/
|
|
942
1124
|
createTable(tableName, entries) {
|
|
943
1125
|
return `CREATE TABLE IF NOT EXISTS ${tableName} (
|
|
944
1126
|
${entries.join(",\n ")}
|
|
945
1127
|
);`;
|
|
946
1128
|
}
|
|
1129
|
+
/**
|
|
1130
|
+
* Statement to rename a table.
|
|
1131
|
+
*
|
|
1132
|
+
* @param tableName - The name of the existing table to be renamed.
|
|
1133
|
+
* @param newTableName - The new name for the table.
|
|
1134
|
+
* @return The SQL statement as a string.
|
|
1135
|
+
*/
|
|
947
1136
|
renameTable(tableName, newTableName) {
|
|
948
1137
|
return `ALTER TABLE ${tableName} RENAME TO ${newTableName};`;
|
|
949
1138
|
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Statement to drop a table if it exists.
|
|
1141
|
+
*
|
|
1142
|
+
* @param tableName - The name of the table to be dropped.
|
|
1143
|
+
* @return The SQL statement as a string.
|
|
1144
|
+
*/
|
|
950
1145
|
dropTable(tableName) {
|
|
951
1146
|
return `DROP TABLE IF EXISTS ${tableName};`;
|
|
952
1147
|
}
|
|
953
|
-
|
|
954
|
-
|
|
1148
|
+
/**
|
|
1149
|
+
* Constructs a SQL column definition based on the provided parameters.
|
|
1150
|
+
*
|
|
1151
|
+
* @param columnName - The name of the column.
|
|
1152
|
+
* @param type - The data type of the column.
|
|
1153
|
+
* @param defaultValue - The default value for the column.
|
|
1154
|
+
* @param isPrimaryKey - Indicates whether the column is a primary key.
|
|
1155
|
+
* @return The constructed SQL column definition string.
|
|
1156
|
+
*/
|
|
1157
|
+
columnDefinition(columnName, type, isPrimaryKey, defaultValue) {
|
|
1158
|
+
const query = `${columnName} ${type}${defaultValue ? ` DEFAULT ${defaultValue}` : ""}`;
|
|
955
1159
|
return isPrimaryKey ? `${query} PRIMARY KEY` : query;
|
|
956
1160
|
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Statement to add a new column to a specified table.
|
|
1163
|
+
*
|
|
1164
|
+
* @param columnTable - The name of the table to which the column will be added.
|
|
1165
|
+
* @param entry - The column definition including the column name and its data type. See {@link columnDefinition()}
|
|
1166
|
+
* @return The SQL statement as a string.
|
|
1167
|
+
*/
|
|
957
1168
|
createColumn(columnTable, entry) {
|
|
958
1169
|
return `ALTER TABLE ${columnTable} ADD ${entry};`;
|
|
959
1170
|
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Statement to rename a column in an existing table.
|
|
1173
|
+
*
|
|
1174
|
+
* @param tableName - The name of the table containing the column to rename.
|
|
1175
|
+
* @param oldColumnName - The current name of the column to be renamed.
|
|
1176
|
+
* @param newColumnName - The new name for the column.
|
|
1177
|
+
* @return The SQL statement as a string.
|
|
1178
|
+
*/
|
|
960
1179
|
renameColumn(tableName, oldColumnName, newColumnName) {
|
|
961
1180
|
return `ALTER TABLE ${tableName} RENAME COLUMN ${oldColumnName} TO ${newColumnName};`;
|
|
962
1181
|
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1182
|
+
/**
|
|
1183
|
+
* Statement to drop a column from a specified table.
|
|
1184
|
+
*
|
|
1185
|
+
* @param tableName - The name of the table from which the column will be dropped.
|
|
1186
|
+
* @param columnName - The name of the column to be dropped.
|
|
1187
|
+
* @return The SQL statement as a string.
|
|
1188
|
+
*/
|
|
966
1189
|
dropColumn(tableName, columnName) {
|
|
967
1190
|
return `ALTER TABLE ${tableName} DROP COLUMN ${columnName};`;
|
|
968
1191
|
}
|
|
1192
|
+
/**
|
|
1193
|
+
* Statement to return data from a table.
|
|
1194
|
+
*
|
|
1195
|
+
* @param tableName - The name of the database table to select data from.
|
|
1196
|
+
* @param select - An array of column names to include in the SELECT clause.
|
|
1197
|
+
* @param where - An optional condition.
|
|
1198
|
+
* @return The SQL statement as a string.
|
|
1199
|
+
*/
|
|
969
1200
|
select(tableName, select, where) {
|
|
970
1201
|
let query = `SELECT ${select.join(",")} FROM ${tableName}`;
|
|
971
1202
|
if (where)
|
|
972
1203
|
query += ` WHERE ${where}`;
|
|
973
1204
|
return `${query};`;
|
|
974
1205
|
}
|
|
1206
|
+
/**
|
|
1207
|
+
* Statement to insert data into a table.
|
|
1208
|
+
*
|
|
1209
|
+
* @param tableName - The name of the table where the data will be inserted.
|
|
1210
|
+
* @param content - The value query. See {@link insertValues()}.
|
|
1211
|
+
* @return The SQL statement as a string.
|
|
1212
|
+
*/
|
|
975
1213
|
insert(tableName, content) {
|
|
976
1214
|
return `INSERT INTO ${tableName} ${content};`;
|
|
977
1215
|
}
|
|
1216
|
+
/**
|
|
1217
|
+
* A SQL insert query string. See {@link insert()}.
|
|
1218
|
+
*
|
|
1219
|
+
* @param keys - An array of column names to be used in the query.
|
|
1220
|
+
* @param [valueString] - An optional preformatted value string to be included in the query.
|
|
1221
|
+
* If not provided, the method generates a default placeholder string with "?" for each key.
|
|
1222
|
+
* @return The SQL statement as a string.
|
|
1223
|
+
*/
|
|
978
1224
|
insertValues(keys, valueString) {
|
|
979
1225
|
return `(${keys}) ${valueString ?? `VALUES (${keys.map(() => "?").join(",")})`}`;
|
|
980
1226
|
}
|
|
1227
|
+
/**
|
|
1228
|
+
* Returns a SQL query string to create a migration table.
|
|
1229
|
+
* The table is used to store migration data, specifically the version of the migration.
|
|
1230
|
+
*
|
|
1231
|
+
* @return The SQL query string for creating the migration table.
|
|
1232
|
+
*/
|
|
981
1233
|
migrationTableQuery() {
|
|
982
1234
|
return this.createTable(MIGRATION_DATA_TABLE_NAME, [
|
|
983
|
-
this.columnDefinition("version", this.types.number, "0"
|
|
1235
|
+
this.columnDefinition("version", this.types.number, false, "0")
|
|
984
1236
|
]);
|
|
985
1237
|
}
|
|
1238
|
+
/**
|
|
1239
|
+
* Fetches the foreign keys for the specified table.
|
|
1240
|
+
* This method is only used if {@link canInspectForeignKeys} is true
|
|
1241
|
+
*
|
|
1242
|
+
* @param tableName - The name of the table for which to retrieve foreign key information.
|
|
1243
|
+
* @return {Promise<ForeignKeyInfo[]>} A promise that resolves to an array of {@link ForeignKeyInfo}.
|
|
1244
|
+
*/
|
|
986
1245
|
async getForeignKeys(tableName) {
|
|
987
1246
|
throw new Error("Inspecting foreign keys is not supported!");
|
|
988
1247
|
}
|
|
1248
|
+
/**
|
|
1249
|
+
* Ensures that the migration table exists in the database.
|
|
1250
|
+
* If the table does not exist, it creates the table using the defined migration table query.
|
|
1251
|
+
*
|
|
1252
|
+
* @return A promise that resolves when the migration table is created successfully.
|
|
1253
|
+
*/
|
|
989
1254
|
async createMigrationTableIfNeeded() {
|
|
990
1255
|
await this.db.runMultipleWriteStatements(this.migrationTableQuery());
|
|
991
1256
|
}
|
|
992
|
-
|
|
1257
|
+
/**
|
|
1258
|
+
* Retrieves the current version from the migration data table.
|
|
1259
|
+
*
|
|
1260
|
+
* @return A promise that resolves to the current version number. Returns 0 if no version is found.
|
|
1261
|
+
*/
|
|
993
1262
|
async getVersion() {
|
|
994
1263
|
await this.createMigrationTableIfNeeded();
|
|
995
1264
|
const query = this.select(MIGRATION_DATA_TABLE_NAME, ["version"]);
|
|
996
1265
|
const data = await this.db.runGetStatement(query);
|
|
997
1266
|
return data.length ? data[0].version : 0;
|
|
998
1267
|
}
|
|
999
|
-
|
|
1268
|
+
/**
|
|
1269
|
+
* Updates the migration version in the database. If the version entry does not exist, it inserts a new one;
|
|
1270
|
+
* if it exists, it updates the version to the specified value.
|
|
1271
|
+
*
|
|
1272
|
+
* @param newVersion - The new migration version to set in the database.
|
|
1273
|
+
* @return A promise that resolves when the operation is complete.
|
|
1274
|
+
*/
|
|
1000
1275
|
async setVersion(newVersion) {
|
|
1001
1276
|
const query = `${this.migrationTableQuery()};
|
|
1002
1277
|
INSERT INTO ${MIGRATION_DATA_TABLE_NAME} (version) VALUES ${newVersion} WHERE NOT EXISTS (SELECT 1 FROM ${MIGRATION_DATA_TABLE_NAME})
|
|
@@ -1014,9 +1289,9 @@ var SqliteDialect = class extends DefaultSql {
|
|
|
1014
1289
|
number: "INTEGER",
|
|
1015
1290
|
bigint: "INTEGER",
|
|
1016
1291
|
boolean: "INTEGER",
|
|
1017
|
-
date: "
|
|
1018
|
-
time: "
|
|
1019
|
-
dateTime: "
|
|
1292
|
+
date: "INTEGER",
|
|
1293
|
+
time: "INTEGER",
|
|
1294
|
+
dateTime: "INTEGER",
|
|
1020
1295
|
null: "NULL"
|
|
1021
1296
|
};
|
|
1022
1297
|
canAlterForeignKeys = false;
|
|
@@ -1031,14 +1306,16 @@ var SqliteDialect = class extends DefaultSql {
|
|
|
1031
1306
|
}
|
|
1032
1307
|
async getColumnInformation(tableName) {
|
|
1033
1308
|
const data = await this.db.runGetStatement(`PRAGMA table_info(${tableName})`);
|
|
1034
|
-
|
|
1035
|
-
|
|
1309
|
+
const output = {};
|
|
1310
|
+
for (const entry of data) {
|
|
1311
|
+
output[entry["name"]] = {
|
|
1036
1312
|
name: entry["name"],
|
|
1037
1313
|
type: entry["type"],
|
|
1038
1314
|
defaultValue: entry["dflt_value"],
|
|
1039
1315
|
isPrimaryKey: entry["pk"] == "1"
|
|
1040
1316
|
};
|
|
1041
|
-
}
|
|
1317
|
+
}
|
|
1318
|
+
return output;
|
|
1042
1319
|
}
|
|
1043
1320
|
formatValueToSql(value, type) {
|
|
1044
1321
|
function toDate(value2) {
|
|
@@ -1063,8 +1340,8 @@ var SqliteDialect = class extends DefaultSql {
|
|
|
1063
1340
|
fromColumn: entry["from"],
|
|
1064
1341
|
toTable: entry["table"],
|
|
1065
1342
|
toColumn: entry["to"],
|
|
1066
|
-
|
|
1067
|
-
|
|
1343
|
+
onUpdate: entry["on_update"] ?? "NO ACTION",
|
|
1344
|
+
onDelete: entry["on_delete"] ?? "NO ACTION"
|
|
1068
1345
|
};
|
|
1069
1346
|
});
|
|
1070
1347
|
}
|
|
@@ -1097,14 +1374,17 @@ var PostgresDialect = class extends DefaultSql {
|
|
|
1097
1374
|
}
|
|
1098
1375
|
async getColumnInformation(tableName) {
|
|
1099
1376
|
const data = await this.db.runGetStatement(`SELECT column_name, data_type, column_default FROM information_schema.columns WHERE table_schema = 'public' AND table_name = '${tableName}';`);
|
|
1100
|
-
|
|
1101
|
-
|
|
1377
|
+
const output = {};
|
|
1378
|
+
for (const entry of data) {
|
|
1379
|
+
output[entry["name"]] = {
|
|
1102
1380
|
name: entry["column_name"],
|
|
1103
1381
|
type: entry["data_type"],
|
|
1382
|
+
maxLength: 0,
|
|
1104
1383
|
defaultValue: entry["column_default"],
|
|
1105
1384
|
isPrimaryKey: false
|
|
1106
1385
|
};
|
|
1107
|
-
}
|
|
1386
|
+
}
|
|
1387
|
+
return output;
|
|
1108
1388
|
}
|
|
1109
1389
|
addPrimaryKey(tableName, columnName) {
|
|
1110
1390
|
return `ALTER TABLE ${tableName} ADD PRIMARY KEY (${columnName});
|
|
@@ -1149,18 +1429,21 @@ var MsSqlDialect = class extends DefaultSql {
|
|
|
1149
1429
|
});
|
|
1150
1430
|
}
|
|
1151
1431
|
async getTableNames() {
|
|
1152
|
-
return await this.db.runGetStatement("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'");
|
|
1432
|
+
return (await this.db.runGetStatement("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'")).map((entry) => entry.name);
|
|
1153
1433
|
}
|
|
1154
1434
|
async getColumnInformation(tableName) {
|
|
1155
1435
|
const data = await this.db.runGetStatement(`SELECT COLUMN_NAME, DATA_TYPE, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = N'${tableName};'`);
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1436
|
+
const output = {};
|
|
1437
|
+
for (const entry of data) {
|
|
1438
|
+
output[entry["name"]] = {
|
|
1439
|
+
name: entry["name"],
|
|
1159
1440
|
type: entry["DATA_TYPE"],
|
|
1441
|
+
maxLength: 0,
|
|
1160
1442
|
defaultValue: entry["COLUMN_DEFAULT"],
|
|
1161
|
-
isPrimaryKey:
|
|
1443
|
+
isPrimaryKey: entry["pk"] == "1"
|
|
1162
1444
|
};
|
|
1163
|
-
}
|
|
1445
|
+
}
|
|
1446
|
+
return output;
|
|
1164
1447
|
}
|
|
1165
1448
|
};
|
|
1166
1449
|
|
|
@@ -1170,9 +1453,26 @@ var MySqlDialect = class extends DefaultSql {
|
|
|
1170
1453
|
canAlterPrimaryKey = true;
|
|
1171
1454
|
canInspectForeignKeys = true;
|
|
1172
1455
|
canInspectPrimaryKey = true;
|
|
1456
|
+
types = {
|
|
1457
|
+
string: "VARCHAR",
|
|
1458
|
+
number: "INT",
|
|
1459
|
+
bigint: "BIGINT",
|
|
1460
|
+
boolean: "BOOLEAN",
|
|
1461
|
+
date: "DATE",
|
|
1462
|
+
time: "TIME",
|
|
1463
|
+
dateTime: "DATETIME",
|
|
1464
|
+
null: "NULL"
|
|
1465
|
+
};
|
|
1466
|
+
getSqlType(dataType, columnInfo) {
|
|
1467
|
+
switch (dataType) {
|
|
1468
|
+
case "string":
|
|
1469
|
+
return this.types[dataType] + `(${columnInfo?.maxLength})`;
|
|
1470
|
+
default:
|
|
1471
|
+
return super.getSqlType(dataType, columnInfo);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1173
1474
|
changeForeignKeysState(enabled) {
|
|
1174
|
-
return `SET FOREIGN_KEY_CHECKS ${enabled ? "1" : "0"}
|
|
1175
|
-
;`;
|
|
1475
|
+
return `SET FOREIGN_KEY_CHECKS ${enabled ? "1" : "0"};`;
|
|
1176
1476
|
}
|
|
1177
1477
|
addForeignKey(fromTableName, foreignKey) {
|
|
1178
1478
|
return `ALTER TABLE ${fromTableName} ADD ${foreignKey};`;
|
|
@@ -1198,18 +1498,22 @@ var MySqlDialect = class extends DefaultSql {
|
|
|
1198
1498
|
});
|
|
1199
1499
|
}
|
|
1200
1500
|
async getTableNames() {
|
|
1201
|
-
|
|
1501
|
+
const t = await this.db.runGetStatement("SELECT table_name FROM information_schema.tables;");
|
|
1502
|
+
return (await this.db.runGetStatement("SELECT table_name FROM information_schema.tables;")).map((entry) => entry.name);
|
|
1202
1503
|
}
|
|
1203
1504
|
async getColumnInformation(tableName) {
|
|
1204
1505
|
const data = await this.db.runGetStatement(`SHOW COLUMNS FROM ${tableName};`);
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1506
|
+
const output = {};
|
|
1507
|
+
for (const entry of data) {
|
|
1508
|
+
output[entry["name"]] = {
|
|
1509
|
+
name: entry["name"],
|
|
1510
|
+
type: entry["type"],
|
|
1511
|
+
maxLength: 0,
|
|
1512
|
+
defaultValue: entry["dflt_value"],
|
|
1513
|
+
isPrimaryKey: entry["pk"] == "1"
|
|
1211
1514
|
};
|
|
1212
|
-
}
|
|
1515
|
+
}
|
|
1516
|
+
return output;
|
|
1213
1517
|
}
|
|
1214
1518
|
};
|
|
1215
1519
|
|