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.js
CHANGED
|
@@ -55,42 +55,65 @@ var LoggerClass = class {
|
|
|
55
55
|
};
|
|
56
56
|
var Logger = new LoggerClass();
|
|
57
57
|
|
|
58
|
-
// src/lib/tableInfo/TableInfo.ts
|
|
59
|
-
var TABLE_INFO_PROPERTY_NAME = Symbol("tableInfo");
|
|
60
|
-
function getTableInfo(table) {
|
|
61
|
-
let metadata = table[Symbol.metadata] ?? table.prototype?.[Symbol.metadata];
|
|
62
|
-
if (!metadata) {
|
|
63
|
-
metadata = {};
|
|
64
|
-
table[Symbol.metadata] = metadata;
|
|
65
|
-
}
|
|
66
|
-
return getTableInfoFromMetadata(metadata);
|
|
67
|
-
}
|
|
68
|
-
function getTableInfoFromMetadata(metadata) {
|
|
69
|
-
if (!metadata[TABLE_INFO_PROPERTY_NAME])
|
|
70
|
-
metadata[TABLE_INFO_PROPERTY_NAME] = { primaryKey: "", foreignKeys: [] };
|
|
71
|
-
return metadata[TABLE_INFO_PROPERTY_NAME];
|
|
72
|
-
}
|
|
73
|
-
|
|
74
58
|
// src/lib/tableInfo/TableObj.ts
|
|
75
59
|
var TableObj = class _TableObj {
|
|
76
60
|
IS_TABLE_OBJ = true;
|
|
77
61
|
tableName;
|
|
78
|
-
|
|
79
|
-
|
|
62
|
+
tableStructure = {
|
|
63
|
+
table: "",
|
|
80
64
|
primaryKey: void 0,
|
|
81
|
-
|
|
82
|
-
|
|
65
|
+
columns: {},
|
|
66
|
+
foreignKeys: []
|
|
83
67
|
};
|
|
84
|
-
|
|
68
|
+
static getEmptyColumnEntry(key) {
|
|
69
|
+
return {
|
|
70
|
+
name: key,
|
|
71
|
+
type: "",
|
|
72
|
+
defaultValue: "",
|
|
73
|
+
isPrimaryKey: false
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
static getColumnEntry(key, value) {
|
|
77
|
+
let dataType = typeof value;
|
|
78
|
+
switch (typeof value) {
|
|
79
|
+
case "function":
|
|
80
|
+
return null;
|
|
81
|
+
case "object":
|
|
82
|
+
if (value instanceof Date) {
|
|
83
|
+
dataType = "date";
|
|
84
|
+
break;
|
|
85
|
+
} else {
|
|
86
|
+
Logger.warn(`${key} was skipped because its type (${typeof value}) is not supported`);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
case "undefined":
|
|
90
|
+
case "symbol":
|
|
91
|
+
Logger.warn(`${key} was skipped because its type (${typeof value}) is not supported`);
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
..._TableObj.getEmptyColumnEntry(key),
|
|
96
|
+
inputType: dataType,
|
|
97
|
+
inputDefaultValue: value
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
constructor(tableName, defaultValues) {
|
|
85
101
|
this.tableName = tableName;
|
|
86
|
-
|
|
102
|
+
for (const key in defaultValues) {
|
|
103
|
+
const value = defaultValues[key];
|
|
104
|
+
const columnEntry = _TableObj.getColumnEntry(key, value);
|
|
105
|
+
if (!columnEntry)
|
|
106
|
+
continue;
|
|
107
|
+
this.tableStructure.columns[key] = columnEntry;
|
|
108
|
+
}
|
|
87
109
|
}
|
|
88
110
|
primaryKey(key) {
|
|
89
|
-
this.
|
|
111
|
+
this.tableStructure.primaryKey = key.toString();
|
|
112
|
+
this.tableStructure.columns[key.toString()].isPrimaryKey = true;
|
|
90
113
|
return this;
|
|
91
114
|
}
|
|
92
115
|
foreignKey(fromColumn, toTable, toColumn, options) {
|
|
93
|
-
this.
|
|
116
|
+
this.tableStructure.foreignKeys.push({
|
|
94
117
|
fromTable: this.tableName,
|
|
95
118
|
fromColumn: fromColumn.toString(),
|
|
96
119
|
toTable: toTable.tableName,
|
|
@@ -101,17 +124,44 @@ var TableObj = class _TableObj {
|
|
|
101
124
|
return this;
|
|
102
125
|
}
|
|
103
126
|
dataType(column, type) {
|
|
104
|
-
this.
|
|
127
|
+
this.tableStructure.columns[column.toString()].type = type;
|
|
128
|
+
return this;
|
|
129
|
+
}
|
|
130
|
+
maxCharacterLength(column, max) {
|
|
131
|
+
this.tableStructure.columns[column.toString()].maxLength = max;
|
|
105
132
|
return this;
|
|
106
133
|
}
|
|
107
134
|
static create(tableName, columns) {
|
|
108
135
|
return new _TableObj(tableName, columns);
|
|
109
136
|
}
|
|
110
|
-
static
|
|
137
|
+
static isTableObj(obj) {
|
|
111
138
|
return !!obj?.IS_TABLE_OBJ;
|
|
112
139
|
}
|
|
113
140
|
};
|
|
114
141
|
|
|
142
|
+
// src/lib/tableInfo/getTableStructure.ts
|
|
143
|
+
var TABLE_INFO_PROPERTY_NAME = Symbol("tableInfo");
|
|
144
|
+
function getInputColumnInfo(table, context) {
|
|
145
|
+
const metadata = context?.metadata ? getTableStructureFromMetadata(context.metadata) : getTableStructure(table);
|
|
146
|
+
const key = context.name ?? context;
|
|
147
|
+
if (!metadata.columns.hasOwnProperty(key))
|
|
148
|
+
metadata.columns[key] = TableObj.getEmptyColumnEntry(key);
|
|
149
|
+
return metadata.columns[key];
|
|
150
|
+
}
|
|
151
|
+
function getTableStructure(table) {
|
|
152
|
+
let metadata = table[Symbol.metadata] ?? table.prototype?.[Symbol.metadata];
|
|
153
|
+
if (!metadata) {
|
|
154
|
+
metadata = {};
|
|
155
|
+
table[Symbol.metadata] = metadata;
|
|
156
|
+
}
|
|
157
|
+
return getTableStructureFromMetadata(metadata);
|
|
158
|
+
}
|
|
159
|
+
function getTableStructureFromMetadata(metadata) {
|
|
160
|
+
if (!metadata[TABLE_INFO_PROPERTY_NAME])
|
|
161
|
+
metadata[TABLE_INFO_PROPERTY_NAME] = { table: "", primaryKey: "", foreignKeys: [], columns: {} };
|
|
162
|
+
return metadata[TABLE_INFO_PROPERTY_NAME];
|
|
163
|
+
}
|
|
164
|
+
|
|
115
165
|
// src/lib/TableStructureGenerator.ts
|
|
116
166
|
var TableStructureGenerator = class {
|
|
117
167
|
dialect;
|
|
@@ -126,75 +176,29 @@ var TableStructureGenerator = class {
|
|
|
126
176
|
* @return An object where keys are table names, and values are their corresponding table structures.
|
|
127
177
|
*/
|
|
128
178
|
generateTableStructure() {
|
|
129
|
-
const
|
|
179
|
+
const tables = {};
|
|
130
180
|
for (const table of this.dbInstructions.tables) {
|
|
131
|
-
if (TableObj.
|
|
132
|
-
|
|
133
|
-
else {
|
|
181
|
+
if (TableObj.isTableObj(table)) {
|
|
182
|
+
tables[table.tableName] = table.tableStructure;
|
|
183
|
+
} else {
|
|
134
184
|
const classTable = table;
|
|
135
|
-
|
|
185
|
+
const structure = getTableStructure(classTable);
|
|
186
|
+
tables[classTable.name] = structure;
|
|
187
|
+
for (const key in structure.columns) {
|
|
188
|
+
const entry = structure.columns[key];
|
|
189
|
+
entry.defaultValue = entry.defaultValue === null ? this.dialect.types.null : this.dialect.formatValueToSql(entry.inputDefaultValue, entry.inputType);
|
|
190
|
+
entry.type = this.dialect.getSqlType(entry.inputType, entry);
|
|
191
|
+
}
|
|
136
192
|
}
|
|
137
193
|
}
|
|
138
|
-
const tables = {};
|
|
139
|
-
for (const tableName in tableObjects) {
|
|
140
|
-
const obj = tableObjects[tableName];
|
|
141
|
-
const tableInfo = obj.tableInfo;
|
|
142
|
-
tables[tableName] = {
|
|
143
|
-
table: tableName,
|
|
144
|
-
primaryKey: tableInfo?.primaryKey,
|
|
145
|
-
columns: this.getColumns(obj.columns, tableInfo),
|
|
146
|
-
foreignKeys: tableInfo?.foreignKeys
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
194
|
return tables;
|
|
150
195
|
}
|
|
151
|
-
/**
|
|
152
|
-
* Retrieves the columns for a table
|
|
153
|
-
*
|
|
154
|
-
* @param obj - The table class interface object containing properties that represent the table's fields.
|
|
155
|
-
* @param tableInfo - Optional metadata about the table. Can be undefined.
|
|
156
|
-
* @return An array of {@link ColumnInfo} representing the detailed column information.
|
|
157
|
-
*/
|
|
158
|
-
getColumns(obj, tableInfo) {
|
|
159
|
-
const columns = [];
|
|
160
|
-
for (const property in obj) {
|
|
161
|
-
const propertyKey = property;
|
|
162
|
-
const value = obj[propertyKey];
|
|
163
|
-
const columnData = {
|
|
164
|
-
name: property,
|
|
165
|
-
isPrimaryKey: property == tableInfo?.primaryKey,
|
|
166
|
-
type: this.dialect.types.string,
|
|
167
|
-
defaultValue: this.dialect.types.null
|
|
168
|
-
};
|
|
169
|
-
let dataType = tableInfo?.dataTypes?.[property] ?? typeof value;
|
|
170
|
-
switch (dataType) {
|
|
171
|
-
case "function":
|
|
172
|
-
continue;
|
|
173
|
-
case "object":
|
|
174
|
-
if (value instanceof Date) {
|
|
175
|
-
dataType = "date";
|
|
176
|
-
break;
|
|
177
|
-
} else {
|
|
178
|
-
Logger.warn(`${property} was skipped because its type (${typeof value}) is not supported`);
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
case "undefined":
|
|
182
|
-
case "symbol":
|
|
183
|
-
Logger.warn(`${property} was skipped because its type (${typeof value}) is not supported`);
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
columnData.defaultValue = value === null ? this.dialect.types.null : this.dialect.formatValueToSql(value, dataType);
|
|
187
|
-
columnData.type = this.dialect.types[dataType];
|
|
188
|
-
columns.push(columnData);
|
|
189
|
-
}
|
|
190
|
-
return columns;
|
|
191
|
-
}
|
|
192
196
|
};
|
|
193
197
|
|
|
194
198
|
// src/lib/exceptions/NotAllowedException.ts
|
|
195
199
|
var NotAllowedException = class extends Error {
|
|
196
200
|
constructor(entries) {
|
|
197
|
-
let message = "Some destructive changes need to be confirmed.
|
|
201
|
+
let message = "Some destructive changes need to be confirmed. To confirm, add to preMigration():\n";
|
|
198
202
|
for (const entry of entries) {
|
|
199
203
|
message += ` migrations.allowMigration(${entry.version}, ${entry.tableName}, "${entry.type}");
|
|
200
204
|
`;
|
|
@@ -212,6 +216,13 @@ var Migrations = class {
|
|
|
212
216
|
migrationDataForOldTableNames = {};
|
|
213
217
|
alwaysAllowed = {};
|
|
214
218
|
notAllowedChanges = [];
|
|
219
|
+
/**
|
|
220
|
+
* Resets the migration state to its initial values.
|
|
221
|
+
* Only used internally.
|
|
222
|
+
*
|
|
223
|
+
* @param dbInstructions - The instructions containing database metadata and migration details.
|
|
224
|
+
* @param fromVersion - The version of the actual database.
|
|
225
|
+
*/
|
|
215
226
|
reset(dbInstructions, fromVersion) {
|
|
216
227
|
this.fromVersion = fromVersion;
|
|
217
228
|
this.toVersion = dbInstructions.version;
|
|
@@ -220,10 +231,23 @@ var Migrations = class {
|
|
|
220
231
|
this.alwaysAllowed = dbInstructions.alwaysAllowedMigrations ?? {};
|
|
221
232
|
this.notAllowedChanges = [];
|
|
222
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Retrieves the migration instructions for the specified table.
|
|
236
|
+
* @see getEntryFromTableName
|
|
237
|
+
*
|
|
238
|
+
* @param table - The {@link TableInput} object from which the table name will be retrieved.
|
|
239
|
+
* @return The migration instructions corresponding to the given table input.
|
|
240
|
+
*/
|
|
223
241
|
getEntry(table) {
|
|
224
242
|
const tableName = this.getTableName(table);
|
|
225
243
|
return this.getEntryFromTableName(tableName);
|
|
226
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* Retrieves the migration instructions for the specified table.
|
|
247
|
+
*
|
|
248
|
+
* @param tableName - The name of the table for which the entry is to be retrieved or created.
|
|
249
|
+
* @return The migration instructions corresponding to the given table input.
|
|
250
|
+
*/
|
|
227
251
|
getEntryFromTableName(tableName) {
|
|
228
252
|
if (!this.migrationData.hasOwnProperty(tableName)) {
|
|
229
253
|
this.migrationData[tableName] = {
|
|
@@ -235,17 +259,39 @@ var Migrations = class {
|
|
|
235
259
|
}
|
|
236
260
|
return this.migrationData[tableName];
|
|
237
261
|
}
|
|
262
|
+
/**
|
|
263
|
+
* Retrieves the table name from the given table input.
|
|
264
|
+
*
|
|
265
|
+
* @param table - The {@link TableInput} object.
|
|
266
|
+
* @return The name of the table derived from either {@link TableObj} or a class.
|
|
267
|
+
*/
|
|
238
268
|
getTableName(table) {
|
|
239
|
-
return TableObj.
|
|
269
|
+
return TableObj.isTableObj(table) ? table.tableName : table.name;
|
|
240
270
|
}
|
|
271
|
+
/**
|
|
272
|
+
* Checks whether a provided version is relevant based on database version ({@link fromVersion}) and target version ({@link toVersion}).
|
|
273
|
+
* Also makes sure that version checks happen in order.
|
|
274
|
+
*
|
|
275
|
+
* @param version - The version to check for relevance.
|
|
276
|
+
* @return Returns true if the version is relevant, otherwise false.
|
|
277
|
+
* @throws Error if versions are not properly ordered
|
|
278
|
+
*/
|
|
241
279
|
versionIsRelevant(version) {
|
|
242
|
-
if (version
|
|
280
|
+
if (version <= this.fromVersion || version > this.toVersion)
|
|
243
281
|
return false;
|
|
244
282
|
if (version < this.lastUsedVersion)
|
|
245
283
|
throw new Error("Migrations in preMigration() have to be ordered by version (beginning with the lowest version).");
|
|
246
284
|
this.lastUsedVersion = version;
|
|
247
285
|
return true;
|
|
248
286
|
}
|
|
287
|
+
/**
|
|
288
|
+
* Verifies the renaming tasks specified in {@link DatabaseInstructions.preMigration} that were considered are valid.
|
|
289
|
+
* Called after all SQL queries have been generated.
|
|
290
|
+
* Only used internally.
|
|
291
|
+
*
|
|
292
|
+
* @param newTables - The table structures extracted from {@link DatabaseInstructions.tables}.
|
|
293
|
+
* @throws Error if a renaming task is invalid.
|
|
294
|
+
*/
|
|
249
295
|
verifyRenamingTasks(newTables) {
|
|
250
296
|
for (const tableName in this.migrationData) {
|
|
251
297
|
const migrationEntry = this.migrationData[tableName];
|
|
@@ -262,11 +308,18 @@ var Migrations = class {
|
|
|
262
308
|
const newColumnName = renamingData.newName;
|
|
263
309
|
if (oldColumnName == newColumnName)
|
|
264
310
|
return new Error(`You set column ${tableName}.${oldColumnName} to be renamed to itself!`);
|
|
265
|
-
else if (!newTables[tableName]?.columns
|
|
311
|
+
else if (!newTables[tableName]?.columns[newColumnName])
|
|
266
312
|
return new Error(`You set column ${tableName}.${oldColumnName} to be renamed to ${tableName}.${newColumnName}. But ${tableName}.${newColumnName} does not exist in your structure.`);
|
|
267
313
|
}
|
|
268
314
|
}
|
|
269
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* Making sure all considered calls to {@link allowMigration()} where necessary to prevent input mistakes.
|
|
318
|
+
* Called after all SQL queries have been generated.
|
|
319
|
+
* Only used internally.
|
|
320
|
+
*
|
|
321
|
+
* @throws Error if unnecessary calls were discovered. All discovered calls are collected and thrown as one Error.
|
|
322
|
+
*/
|
|
270
323
|
verifyAllowedMigrations() {
|
|
271
324
|
if (this.notAllowedChanges.length)
|
|
272
325
|
return new NotAllowedException(this.notAllowedChanges);
|
|
@@ -282,6 +335,14 @@ var Migrations = class {
|
|
|
282
335
|
if (errorMsg)
|
|
283
336
|
return new Error(errorMsg);
|
|
284
337
|
}
|
|
338
|
+
/**
|
|
339
|
+
* Called by {@link MigrationManager} to check if a specific destructive query is allowed.
|
|
340
|
+
* Only used internally.
|
|
341
|
+
*
|
|
342
|
+
* @see allowMigration()
|
|
343
|
+
* @param tableName - The name of the table to check the migration against.
|
|
344
|
+
* @param type - The type of destructive migration being checked.
|
|
345
|
+
*/
|
|
285
346
|
compareWithAllowedMigration(tableName, type) {
|
|
286
347
|
const migrationEntry = this.migrationData[tableName];
|
|
287
348
|
if (!migrationEntry?.allowedMigrations[type]) {
|
|
@@ -290,41 +351,114 @@ var Migrations = class {
|
|
|
290
351
|
} else if (migrationEntry)
|
|
291
352
|
migrationEntry.usedMigrations[type] = true;
|
|
292
353
|
}
|
|
354
|
+
/**
|
|
355
|
+
* Retrieves the migration data containing instructions for data migration.
|
|
356
|
+
* Only used internally.
|
|
357
|
+
*
|
|
358
|
+
* @return An object where each key corresponds to the table name,
|
|
359
|
+
* and the value is the associated migration instructions.
|
|
360
|
+
*/
|
|
293
361
|
getMigrationData() {
|
|
294
362
|
return this.migrationData;
|
|
295
363
|
}
|
|
364
|
+
/**
|
|
365
|
+
* Iterates over renamed columns for the specified table and executes a callback for each pair of old and new column names.
|
|
366
|
+
* Only used internally.
|
|
367
|
+
*
|
|
368
|
+
* @param tableName - Name of the table whose renamed columns should be processed.
|
|
369
|
+
* @param callback - A function to execute for each renamed column, receiving the old and new column names as arguments.
|
|
370
|
+
*/
|
|
296
371
|
loopRenamedColumns(tableName, callback) {
|
|
297
372
|
const migrationEntry = this.migrationData[tableName];
|
|
298
373
|
for (const renamingData of migrationEntry.renamedColumns) {
|
|
299
374
|
callback(renamingData.oldName, renamingData.newName);
|
|
300
375
|
}
|
|
301
376
|
}
|
|
377
|
+
/**
|
|
378
|
+
* Considers the renaming of a table and returns its (newest) name after the migration or
|
|
379
|
+
* the original name if no renaming is queued.
|
|
380
|
+
* Only used internally.
|
|
381
|
+
*
|
|
382
|
+
* @see getOldTableName()
|
|
383
|
+
* @param tableName - The current table name in the database.
|
|
384
|
+
* @return The newest table name if available, otherwise the current table name.
|
|
385
|
+
*/
|
|
302
386
|
getNewestTableName(tableName) {
|
|
303
387
|
return this.migrationDataForOldTableNames[tableName]?.tableRenaming?.newName ?? tableName;
|
|
304
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* Retrieves the current table name in the database.
|
|
391
|
+
* Only used internally.
|
|
392
|
+
*
|
|
393
|
+
* @see getNewestTableName()
|
|
394
|
+
* @param tableName - The name of the newest table name.
|
|
395
|
+
* @return The current table name in the database.
|
|
396
|
+
*/
|
|
305
397
|
getOldTableName(tableName) {
|
|
306
398
|
return this.migrationData[tableName]?.tableRenaming?.oldName ?? tableName;
|
|
307
399
|
}
|
|
400
|
+
/**
|
|
401
|
+
* Considers the renaming of a column in a table and returns its (newest) name after the migration or
|
|
402
|
+
* the original name if no renaming is queued.
|
|
403
|
+
* Only used internally.
|
|
404
|
+
*
|
|
405
|
+
* @param tableName - The name of the table containing the column.
|
|
406
|
+
* @param oldColumnName - The current name of the column in the database.
|
|
407
|
+
* @return The newest column name if available, otherwise the original column name.
|
|
408
|
+
*/
|
|
308
409
|
getNewestColumnName(tableName, oldColumnName) {
|
|
309
410
|
const columnNames = this.migrationData[tableName]?.renamedColumns.find((columns) => columns.oldName == oldColumnName);
|
|
310
411
|
return columnNames ? columnNames.newName : oldColumnName;
|
|
311
412
|
}
|
|
413
|
+
/**
|
|
414
|
+
* Determines if the specified table is marked to be recreated.
|
|
415
|
+
* Only used internally.
|
|
416
|
+
*
|
|
417
|
+
* @param tableName The name of the table to check.
|
|
418
|
+
* @return Returns true if the table will be recreated, false otherwise.
|
|
419
|
+
*/
|
|
312
420
|
willBeRecreated(tableName) {
|
|
313
421
|
return this.migrationData[tableName]?.recreate;
|
|
314
422
|
}
|
|
423
|
+
/**
|
|
424
|
+
* Marks a table to be recreated and logs the recreation reason for the user.
|
|
425
|
+
* Only used internally.
|
|
426
|
+
*
|
|
427
|
+
* @param tableName - The name of the table to be marked for recreation.
|
|
428
|
+
* @param reason - The reason why the table is being marked for recreation.
|
|
429
|
+
*/
|
|
315
430
|
internalRecreate(tableName, reason) {
|
|
316
431
|
const entry = this.getEntryFromTableName(tableName);
|
|
317
432
|
entry.recreate = true;
|
|
318
433
|
Logger.log(`Table ${tableName} will be recreated(${reason})!`);
|
|
319
434
|
}
|
|
435
|
+
/**
|
|
436
|
+
* SqlMorpheus only allows destructive statements if it was specifically allowed in {@link DatabaseInstructions.preMigration()}.
|
|
437
|
+
* Use this method to allow a destructive statement for a specific version.
|
|
438
|
+
* This method will be ignored if {@link version} is smaller than the current database version or higher than the target version of {@link DatabaseInstructions}.
|
|
439
|
+
*
|
|
440
|
+
* @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.
|
|
441
|
+
* @param table - Either a {@link TableObj} or a class decorated with @TableClass.
|
|
442
|
+
* @param allowedMigrations - The keys representing the migrations to be allowed. Multiple migrations can be provided
|
|
443
|
+
*/
|
|
320
444
|
allowMigration(version, table, ...allowedMigrations) {
|
|
321
|
-
if (
|
|
445
|
+
if (!this.versionIsRelevant(version))
|
|
322
446
|
return;
|
|
323
447
|
const entry = this.getEntry(table);
|
|
324
448
|
for (const key of allowedMigrations) {
|
|
325
449
|
entry.allowedMigrations[key] = true;
|
|
326
450
|
}
|
|
327
451
|
}
|
|
452
|
+
/**
|
|
453
|
+
* When you change the name of a table, SqlMorpheus will assume the original table was meant to be dropped
|
|
454
|
+
* and the new table was meant to be added, which would lead to data loss.
|
|
455
|
+
* Use this method to mark a table to be renamed instead.
|
|
456
|
+
* This method will be ignored if {@link version} is smaller than the current database version or higher than the target version of {@link DatabaseInstructions}.
|
|
457
|
+
*
|
|
458
|
+
* @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.
|
|
459
|
+
* @param oldTableName - The current name in the database at the time of the migration.
|
|
460
|
+
* @param newTableName - The new table name or its equivalent input format.
|
|
461
|
+
*/
|
|
328
462
|
renameTable(version, oldTableName, newTableName) {
|
|
329
463
|
if (!this.versionIsRelevant(version))
|
|
330
464
|
return;
|
|
@@ -336,6 +470,17 @@ var Migrations = class {
|
|
|
336
470
|
else
|
|
337
471
|
entry.tableRenaming.newName = newTableNameString;
|
|
338
472
|
}
|
|
473
|
+
/**
|
|
474
|
+
* When you change the name of a column, SqlMorpheus will assume the original column was meant to be removed
|
|
475
|
+
* and the new column was meant to be added, which would lead to data loss.
|
|
476
|
+
* Use this method to mark a column to be renamed instead.
|
|
477
|
+
* This method will be ignored if {@link version} is smaller than the current database version or higher than the target version of {@link DatabaseInstructions}.
|
|
478
|
+
*
|
|
479
|
+
* @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.
|
|
480
|
+
* @param table Either a {@link TableObj} or a class decorated with @TableClass containing the column to be renamed.
|
|
481
|
+
* @param oldColumn The current name in the database at the time of the migration.
|
|
482
|
+
* @param newColumn The new name to assign to the column.
|
|
483
|
+
*/
|
|
339
484
|
renameColumn(version, table, oldColumn, newColumn) {
|
|
340
485
|
if (!this.versionIsRelevant(version))
|
|
341
486
|
return;
|
|
@@ -346,6 +491,15 @@ var Migrations = class {
|
|
|
346
491
|
else
|
|
347
492
|
entry.renamedColumns.push({ oldName: oldColumn, newName: newColumn });
|
|
348
493
|
}
|
|
494
|
+
/**
|
|
495
|
+
* Should not be needed most of the time.
|
|
496
|
+
* Marks a table to be recreated
|
|
497
|
+
* (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).
|
|
498
|
+
* This method will be ignored if {@link version} is smaller than the current database version or higher than the target version of {@link DatabaseInstructions}.
|
|
499
|
+
*
|
|
500
|
+
* @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.
|
|
501
|
+
* @param table Either a {@link TableObj} or a class decorated with @TableClass.
|
|
502
|
+
*/
|
|
349
503
|
recreateTable(version, table) {
|
|
350
504
|
if (!this.versionIsRelevant(version))
|
|
351
505
|
return;
|
|
@@ -534,8 +688,9 @@ ${changes.up}
|
|
|
534
688
|
*/
|
|
535
689
|
createTableSql(tableName, columns, foreignKeys) {
|
|
536
690
|
const queryLines = [];
|
|
537
|
-
for (const
|
|
538
|
-
|
|
691
|
+
for (const key in columns) {
|
|
692
|
+
const columnInfo = columns[key];
|
|
693
|
+
queryLines.push(this.dialect.columnDefinition(columnInfo.name, columnInfo.type, columnInfo.isPrimaryKey, columnInfo.defaultValue));
|
|
539
694
|
}
|
|
540
695
|
if (foreignKeys) {
|
|
541
696
|
for (const foreignKeyInfo of foreignKeys) {
|
|
@@ -573,7 +728,11 @@ ${changes.up}
|
|
|
573
728
|
this.migrations.compareWithAllowedMigration(tableName, "continueWithoutRollback");
|
|
574
729
|
const oldColumnList = await this.dialect.getColumnInformation(this.migrations.getOldTableName(tableName));
|
|
575
730
|
const newColumnList = this.newTables[tableName].columns;
|
|
576
|
-
const moveableColumns =
|
|
731
|
+
const moveableColumns = [];
|
|
732
|
+
for (const key in newColumnList) {
|
|
733
|
+
if (oldColumnList.hasOwnProperty(key))
|
|
734
|
+
moveableColumns.push(newColumnList[key].name);
|
|
735
|
+
}
|
|
577
736
|
const backupTableName = `${tableName}__backup`;
|
|
578
737
|
const insertQuery = this.dialect.insert(
|
|
579
738
|
backupTableName,
|
|
@@ -581,7 +740,7 @@ ${changes.up}
|
|
|
581
740
|
);
|
|
582
741
|
const moveDataQuery = insertQuery + "\n" + this.dialect.dropTable(tableName) + "\n" + this.dialect.renameTable(backupTableName, tableName);
|
|
583
742
|
const structure = this.newTables[tableName];
|
|
584
|
-
changes.up += this.createTableSql(backupTableName, structure.columns, structure.foreignKeys) + "\n" + moveDataQuery + "\n";
|
|
743
|
+
changes.up += this.createTableSql(backupTableName, structure.columns, structure.foreignKeys) + "\n" + moveDataQuery + "\n\n";
|
|
585
744
|
const dbTableName = this.migrations.getOldTableName(tableName);
|
|
586
745
|
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";
|
|
587
746
|
}
|
|
@@ -673,6 +832,10 @@ ${changes.up}
|
|
|
673
832
|
const newTableDefinition = this.newTables[tableName];
|
|
674
833
|
const oldColumnList = await this.dialect.getColumnInformation(this.migrations.getOldTableName(tableName));
|
|
675
834
|
const oldPrimaryKey = this.dialect.canInspectPrimaryKey ? this.getPrimaryKeyColumn(oldColumnList) : false;
|
|
835
|
+
const oldColumnNewNameIndex = {};
|
|
836
|
+
for (const key in oldColumnList) {
|
|
837
|
+
oldColumnNewNameIndex[this.migrations.getNewestColumnName(tableName, key)] = oldColumnList[key];
|
|
838
|
+
}
|
|
676
839
|
const newColumnList = newTableDefinition.columns;
|
|
677
840
|
const newPrimaryKey = newTableDefinition.primaryKey;
|
|
678
841
|
if (this.dialect.canInspectPrimaryKey && oldPrimaryKey != newPrimaryKey) {
|
|
@@ -691,25 +854,23 @@ ${changes.up}
|
|
|
691
854
|
this.migrations.internalRecreate(newTableDefinition.table, "Dialect does not support altering primary keys");
|
|
692
855
|
continue;
|
|
693
856
|
}
|
|
694
|
-
for (const
|
|
695
|
-
const
|
|
696
|
-
|
|
697
|
-
);
|
|
857
|
+
for (const key in newColumnList) {
|
|
858
|
+
const newColumn = newColumnList[key];
|
|
859
|
+
const oldColumn = oldColumnNewNameIndex[newColumn.name];
|
|
698
860
|
if (oldColumn == void 0) {
|
|
699
|
-
changes.up += this.dialect.createColumn(tableName, this.dialect.columnDefinition(newColumn.name, newColumn.type, newColumn.
|
|
861
|
+
changes.up += this.dialect.createColumn(tableName, this.dialect.columnDefinition(newColumn.name, newColumn.type, newColumn.isPrimaryKey, newColumn.defaultValue)) + "\n";
|
|
700
862
|
changes.down += this.dialect.dropColumn(tableName, newColumn.name) + "\n";
|
|
701
863
|
} else if (newColumn.type != oldColumn.type || newColumn.defaultValue != oldColumn.defaultValue) {
|
|
702
864
|
this.migrations.internalRecreate(newTableDefinition.table, "Table structure was changed");
|
|
703
865
|
}
|
|
704
866
|
}
|
|
705
|
-
for (const
|
|
706
|
-
const
|
|
707
|
-
|
|
708
|
-
);
|
|
867
|
+
for (const key in oldColumnList) {
|
|
868
|
+
const oldColumn = oldColumnList[key];
|
|
869
|
+
const newColumn = newColumnList[this.migrations.getNewestColumnName(tableName, oldColumn.name)];
|
|
709
870
|
if (newColumn == void 0) {
|
|
710
871
|
this.migrations.compareWithAllowedMigration(tableName, "dropColumn");
|
|
711
872
|
changes.up += this.dialect.dropColumn(tableName, oldColumn.name) + "\n";
|
|
712
|
-
changes.down += this.dialect.createColumn(tableName, this.dialect.columnDefinition(oldColumn.name, oldColumn.type, oldColumn.
|
|
873
|
+
changes.down += this.dialect.createColumn(tableName, this.dialect.columnDefinition(oldColumn.name, oldColumn.type, oldColumn.isPrimaryKey, oldColumn.defaultValue)) + "\n";
|
|
713
874
|
}
|
|
714
875
|
}
|
|
715
876
|
}
|
|
@@ -718,11 +879,12 @@ ${changes.up}
|
|
|
718
879
|
/**
|
|
719
880
|
* Retrieves the name of the primary key column from a list of column information.
|
|
720
881
|
*
|
|
721
|
-
* @param
|
|
882
|
+
* @param columnInfoEntries - An array of ColumnInfo objects containing details about each column.
|
|
722
883
|
* @return The name of the primary key column if found; otherwise, undefined.
|
|
723
884
|
*/
|
|
724
|
-
getPrimaryKeyColumn(
|
|
725
|
-
for (const
|
|
885
|
+
getPrimaryKeyColumn(columnInfoEntries) {
|
|
886
|
+
for (const key in columnInfoEntries) {
|
|
887
|
+
const columnInfo = columnInfoEntries[key];
|
|
726
888
|
if (columnInfo.isPrimaryKey)
|
|
727
889
|
return columnInfo.name;
|
|
728
890
|
}
|
|
@@ -812,15 +974,27 @@ ${changes.down}`, { encoding: "utf-8" });
|
|
|
812
974
|
var import_polyfill_symbol_metadata = require("polyfill-symbol-metadata");
|
|
813
975
|
function TableClass(tableName, primaryKey) {
|
|
814
976
|
return (table, context) => {
|
|
815
|
-
const
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
977
|
+
const tableStructure = context?.metadata ? getTableStructureFromMetadata(context.metadata) : getTableStructure(table);
|
|
978
|
+
tableStructure.primaryKey = primaryKey?.toString();
|
|
979
|
+
tableStructure.table = tableName;
|
|
980
|
+
if (tableStructure.foreignKeys) {
|
|
981
|
+
for (const foreignKey of tableStructure.foreignKeys) {
|
|
819
982
|
foreignKey.fromTable = tableName;
|
|
820
983
|
if (foreignKey.toTable == table.name)
|
|
821
984
|
foreignKey.toTable = tableName;
|
|
822
985
|
}
|
|
823
986
|
}
|
|
987
|
+
for (const key in table) {
|
|
988
|
+
const value = table[key];
|
|
989
|
+
const existingEntry = tableStructure.columns[key];
|
|
990
|
+
const defaultEntry = TableObj.getColumnEntry(key, value);
|
|
991
|
+
if (!defaultEntry)
|
|
992
|
+
continue;
|
|
993
|
+
tableStructure.columns[key] = {
|
|
994
|
+
...defaultEntry,
|
|
995
|
+
...existingEntry
|
|
996
|
+
};
|
|
997
|
+
}
|
|
824
998
|
Object.defineProperty(table, "name", { value: tableName, writable: false });
|
|
825
999
|
};
|
|
826
1000
|
}
|
|
@@ -829,10 +1003,8 @@ function TableClass(tableName, primaryKey) {
|
|
|
829
1003
|
var import_polyfill_symbol_metadata2 = require("polyfill-symbol-metadata");
|
|
830
1004
|
function DataType(type) {
|
|
831
1005
|
return (table, context) => {
|
|
832
|
-
const
|
|
833
|
-
|
|
834
|
-
metadata.dataTypes = {};
|
|
835
|
-
metadata.dataTypes[context.name ?? context] = type;
|
|
1006
|
+
const entry = getInputColumnInfo(table, context);
|
|
1007
|
+
entry.inputType = type;
|
|
836
1008
|
};
|
|
837
1009
|
}
|
|
838
1010
|
|
|
@@ -840,7 +1012,7 @@ function DataType(type) {
|
|
|
840
1012
|
var import_polyfill_symbol_metadata3 = require("polyfill-symbol-metadata");
|
|
841
1013
|
function ForeignKey(toTable, toColumn, options) {
|
|
842
1014
|
return (table, context) => {
|
|
843
|
-
const metadata = context?.metadata ?
|
|
1015
|
+
const metadata = context?.metadata ? getTableStructureFromMetadata(context.metadata) : getTableStructure(table);
|
|
844
1016
|
if (!metadata.foreignKeys)
|
|
845
1017
|
metadata.foreignKeys = [];
|
|
846
1018
|
metadata.foreignKeys.push({
|
|
@@ -880,7 +1052,7 @@ var DefaultSql = class {
|
|
|
880
1052
|
* Formats a given value to a SQL-equivalent string based on the provided data type.
|
|
881
1053
|
*
|
|
882
1054
|
* @param value - The value to be formatted.
|
|
883
|
-
* @param type - The data type of the value. Either determined through typeof or {@link
|
|
1055
|
+
* @param type - The data type of the value. Either determined through typeof or {@link TableStructure} setting
|
|
884
1056
|
* @return A string representation of the value formatted for SQL.
|
|
885
1057
|
*/
|
|
886
1058
|
formatValueToSql(value, type) {
|
|
@@ -891,65 +1063,68 @@ var DefaultSql = class {
|
|
|
891
1063
|
case "string":
|
|
892
1064
|
return `"${value}"`;
|
|
893
1065
|
case "time":
|
|
894
|
-
return toDate(value).toISOString().slice(11, 19)
|
|
1066
|
+
return `"${toDate(value).toISOString().slice(11, 19)}"`;
|
|
895
1067
|
case "date":
|
|
896
|
-
return toDate(value).toISOString().slice(0, 10)
|
|
1068
|
+
return `"${toDate(value).toISOString().slice(0, 10)}"`;
|
|
897
1069
|
case "dateTime":
|
|
898
|
-
return toDate(value).toISOString().slice(0, 19).replace("T", " ")
|
|
1070
|
+
return `"${toDate(value).toISOString().slice(0, 19).replace("T", " ")}"`;
|
|
899
1071
|
default:
|
|
900
1072
|
return value.toString();
|
|
901
1073
|
}
|
|
902
1074
|
}
|
|
1075
|
+
getSqlType(dataType, _) {
|
|
1076
|
+
return this.types[dataType];
|
|
1077
|
+
}
|
|
903
1078
|
/**
|
|
904
|
-
*
|
|
1079
|
+
* Statement to enable / disable foreign keys in the database.
|
|
905
1080
|
* Is dialect specific.
|
|
906
1081
|
*
|
|
907
1082
|
* @param enabled - A boolean indicating whether to enable or disable foreign key constraints.
|
|
908
|
-
* @return The
|
|
1083
|
+
* @return The SQL statement as a string.
|
|
909
1084
|
*/
|
|
910
1085
|
changeForeignKeysState(enabled) {
|
|
911
1086
|
return "";
|
|
912
1087
|
}
|
|
913
1088
|
/**
|
|
914
|
-
*
|
|
1089
|
+
* Statement to add a foreign key to a specified table.
|
|
915
1090
|
* Is only used if {@link canAlterForeignKeys} is true.
|
|
916
1091
|
*
|
|
917
1092
|
* @param fromTableName - The name of the table to which the foreign key will be added.
|
|
918
1093
|
* @param foreignKey - The foreign key definition to be added, see {@link foreignKey()}.
|
|
919
|
-
* @return The SQL statement
|
|
1094
|
+
* @return The SQL statement as a string.
|
|
920
1095
|
*/
|
|
921
1096
|
addForeignKey(fromTableName, foreignKey) {
|
|
922
1097
|
throw new Error("Adding foreign keys is not supported!");
|
|
923
1098
|
}
|
|
924
1099
|
/**
|
|
925
|
-
*
|
|
1100
|
+
* Statement to remove a foreign key from a specified table.
|
|
926
1101
|
* Is only used if {@link canAlterForeignKeys} is true.
|
|
927
1102
|
*
|
|
928
1103
|
* @param tableName - The name of the table to which the foreign key will be added.
|
|
929
1104
|
* @param foreignKeyName - The name of the foreign key definition.
|
|
930
|
-
* @return The SQL statement
|
|
1105
|
+
* @return The SQL statement as a string.
|
|
931
1106
|
*/
|
|
932
1107
|
removeForeignKey(tableName, foreignKeyName) {
|
|
933
1108
|
throw new Error("Foreign key removal is not supported!");
|
|
934
1109
|
}
|
|
935
1110
|
/**
|
|
936
|
-
*
|
|
1111
|
+
* Statement to add a primary key to the specified table.
|
|
937
1112
|
* Is only used if {@link canAlterPrimaryKey} is true.
|
|
938
1113
|
*
|
|
939
1114
|
* @param tableName - The name of the table to which the primary key will be added.
|
|
940
1115
|
* @param columnName - The name of the column that will be set as the primary key.
|
|
941
|
-
* @return
|
|
1116
|
+
* @return The SQL statement as a string.
|
|
942
1117
|
*/
|
|
943
1118
|
addPrimaryKey(tableName, columnName) {
|
|
944
1119
|
throw new Error("Adding foreign keys is not supported!");
|
|
945
1120
|
}
|
|
946
1121
|
/**
|
|
947
|
-
*
|
|
1122
|
+
* Statement to remove a primary key from the specified table.
|
|
948
1123
|
* Is only used if {@link canAlterPrimaryKey} is true.
|
|
949
1124
|
*
|
|
950
1125
|
* @param tableName - The name of the table to which the primary key will be added.
|
|
951
1126
|
* @param columnName - The name of the column that will be set as the primary key.
|
|
952
|
-
* @return
|
|
1127
|
+
* @return The SQL statement as a string.
|
|
953
1128
|
*/
|
|
954
1129
|
removePrimaryKey(tableName, columnName) {
|
|
955
1130
|
throw new Error("Foreign key removal is not supported!");
|
|
@@ -973,64 +1148,164 @@ var DefaultSql = class {
|
|
|
973
1148
|
query += ` ON DELETE ${onDelete}`;
|
|
974
1149
|
return query;
|
|
975
1150
|
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Statement to create a table if it does not already exist.
|
|
1153
|
+
*
|
|
1154
|
+
* @param tableName - The name of the table to be created.
|
|
1155
|
+
* @param entries - An array containing the column definitions for the table.
|
|
1156
|
+
* @return The SQL statement as a string.
|
|
1157
|
+
*/
|
|
976
1158
|
createTable(tableName, entries) {
|
|
977
1159
|
return `CREATE TABLE IF NOT EXISTS ${tableName} (
|
|
978
1160
|
${entries.join(",\n ")}
|
|
979
1161
|
);`;
|
|
980
1162
|
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Statement to rename a table.
|
|
1165
|
+
*
|
|
1166
|
+
* @param tableName - The name of the existing table to be renamed.
|
|
1167
|
+
* @param newTableName - The new name for the table.
|
|
1168
|
+
* @return The SQL statement as a string.
|
|
1169
|
+
*/
|
|
981
1170
|
renameTable(tableName, newTableName) {
|
|
982
1171
|
return `ALTER TABLE ${tableName} RENAME TO ${newTableName};`;
|
|
983
1172
|
}
|
|
1173
|
+
/**
|
|
1174
|
+
* Statement to drop a table if it exists.
|
|
1175
|
+
*
|
|
1176
|
+
* @param tableName - The name of the table to be dropped.
|
|
1177
|
+
* @return The SQL statement as a string.
|
|
1178
|
+
*/
|
|
984
1179
|
dropTable(tableName) {
|
|
985
1180
|
return `DROP TABLE IF EXISTS ${tableName};`;
|
|
986
1181
|
}
|
|
987
|
-
|
|
988
|
-
|
|
1182
|
+
/**
|
|
1183
|
+
* Constructs a SQL column definition based on the provided parameters.
|
|
1184
|
+
*
|
|
1185
|
+
* @param columnName - The name of the column.
|
|
1186
|
+
* @param type - The data type of the column.
|
|
1187
|
+
* @param defaultValue - The default value for the column.
|
|
1188
|
+
* @param isPrimaryKey - Indicates whether the column is a primary key.
|
|
1189
|
+
* @return The constructed SQL column definition string.
|
|
1190
|
+
*/
|
|
1191
|
+
columnDefinition(columnName, type, isPrimaryKey, defaultValue) {
|
|
1192
|
+
const query = `${columnName} ${type}${defaultValue ? ` DEFAULT ${defaultValue}` : ""}`;
|
|
989
1193
|
return isPrimaryKey ? `${query} PRIMARY KEY` : query;
|
|
990
1194
|
}
|
|
1195
|
+
/**
|
|
1196
|
+
* Statement to add a new column to a specified table.
|
|
1197
|
+
*
|
|
1198
|
+
* @param columnTable - The name of the table to which the column will be added.
|
|
1199
|
+
* @param entry - The column definition including the column name and its data type. See {@link columnDefinition()}
|
|
1200
|
+
* @return The SQL statement as a string.
|
|
1201
|
+
*/
|
|
991
1202
|
createColumn(columnTable, entry) {
|
|
992
1203
|
return `ALTER TABLE ${columnTable} ADD ${entry};`;
|
|
993
1204
|
}
|
|
1205
|
+
/**
|
|
1206
|
+
* Statement to rename a column in an existing table.
|
|
1207
|
+
*
|
|
1208
|
+
* @param tableName - The name of the table containing the column to rename.
|
|
1209
|
+
* @param oldColumnName - The current name of the column to be renamed.
|
|
1210
|
+
* @param newColumnName - The new name for the column.
|
|
1211
|
+
* @return The SQL statement as a string.
|
|
1212
|
+
*/
|
|
994
1213
|
renameColumn(tableName, oldColumnName, newColumnName) {
|
|
995
1214
|
return `ALTER TABLE ${tableName} RENAME COLUMN ${oldColumnName} TO ${newColumnName};`;
|
|
996
1215
|
}
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1216
|
+
/**
|
|
1217
|
+
* Statement to drop a column from a specified table.
|
|
1218
|
+
*
|
|
1219
|
+
* @param tableName - The name of the table from which the column will be dropped.
|
|
1220
|
+
* @param columnName - The name of the column to be dropped.
|
|
1221
|
+
* @return The SQL statement as a string.
|
|
1222
|
+
*/
|
|
1000
1223
|
dropColumn(tableName, columnName) {
|
|
1001
1224
|
return `ALTER TABLE ${tableName} DROP COLUMN ${columnName};`;
|
|
1002
1225
|
}
|
|
1226
|
+
/**
|
|
1227
|
+
* Statement to return data from a table.
|
|
1228
|
+
*
|
|
1229
|
+
* @param tableName - The name of the database table to select data from.
|
|
1230
|
+
* @param select - An array of column names to include in the SELECT clause.
|
|
1231
|
+
* @param where - An optional condition.
|
|
1232
|
+
* @return The SQL statement as a string.
|
|
1233
|
+
*/
|
|
1003
1234
|
select(tableName, select, where) {
|
|
1004
1235
|
let query = `SELECT ${select.join(",")} FROM ${tableName}`;
|
|
1005
1236
|
if (where)
|
|
1006
1237
|
query += ` WHERE ${where}`;
|
|
1007
1238
|
return `${query};`;
|
|
1008
1239
|
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Statement to insert data into a table.
|
|
1242
|
+
*
|
|
1243
|
+
* @param tableName - The name of the table where the data will be inserted.
|
|
1244
|
+
* @param content - The value query. See {@link insertValues()}.
|
|
1245
|
+
* @return The SQL statement as a string.
|
|
1246
|
+
*/
|
|
1009
1247
|
insert(tableName, content) {
|
|
1010
1248
|
return `INSERT INTO ${tableName} ${content};`;
|
|
1011
1249
|
}
|
|
1250
|
+
/**
|
|
1251
|
+
* A SQL insert query string. See {@link insert()}.
|
|
1252
|
+
*
|
|
1253
|
+
* @param keys - An array of column names to be used in the query.
|
|
1254
|
+
* @param [valueString] - An optional preformatted value string to be included in the query.
|
|
1255
|
+
* If not provided, the method generates a default placeholder string with "?" for each key.
|
|
1256
|
+
* @return The SQL statement as a string.
|
|
1257
|
+
*/
|
|
1012
1258
|
insertValues(keys, valueString) {
|
|
1013
1259
|
return `(${keys}) ${valueString ?? `VALUES (${keys.map(() => "?").join(",")})`}`;
|
|
1014
1260
|
}
|
|
1261
|
+
/**
|
|
1262
|
+
* Returns a SQL query string to create a migration table.
|
|
1263
|
+
* The table is used to store migration data, specifically the version of the migration.
|
|
1264
|
+
*
|
|
1265
|
+
* @return The SQL query string for creating the migration table.
|
|
1266
|
+
*/
|
|
1015
1267
|
migrationTableQuery() {
|
|
1016
1268
|
return this.createTable(MIGRATION_DATA_TABLE_NAME, [
|
|
1017
|
-
this.columnDefinition("version", this.types.number, "0"
|
|
1269
|
+
this.columnDefinition("version", this.types.number, false, "0")
|
|
1018
1270
|
]);
|
|
1019
1271
|
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Fetches the foreign keys for the specified table.
|
|
1274
|
+
* This method is only used if {@link canInspectForeignKeys} is true
|
|
1275
|
+
*
|
|
1276
|
+
* @param tableName - The name of the table for which to retrieve foreign key information.
|
|
1277
|
+
* @return {Promise<ForeignKeyInfo[]>} A promise that resolves to an array of {@link ForeignKeyInfo}.
|
|
1278
|
+
*/
|
|
1020
1279
|
async getForeignKeys(tableName) {
|
|
1021
1280
|
throw new Error("Inspecting foreign keys is not supported!");
|
|
1022
1281
|
}
|
|
1282
|
+
/**
|
|
1283
|
+
* Ensures that the migration table exists in the database.
|
|
1284
|
+
* If the table does not exist, it creates the table using the defined migration table query.
|
|
1285
|
+
*
|
|
1286
|
+
* @return A promise that resolves when the migration table is created successfully.
|
|
1287
|
+
*/
|
|
1023
1288
|
async createMigrationTableIfNeeded() {
|
|
1024
1289
|
await this.db.runMultipleWriteStatements(this.migrationTableQuery());
|
|
1025
1290
|
}
|
|
1026
|
-
|
|
1291
|
+
/**
|
|
1292
|
+
* Retrieves the current version from the migration data table.
|
|
1293
|
+
*
|
|
1294
|
+
* @return A promise that resolves to the current version number. Returns 0 if no version is found.
|
|
1295
|
+
*/
|
|
1027
1296
|
async getVersion() {
|
|
1028
1297
|
await this.createMigrationTableIfNeeded();
|
|
1029
1298
|
const query = this.select(MIGRATION_DATA_TABLE_NAME, ["version"]);
|
|
1030
1299
|
const data = await this.db.runGetStatement(query);
|
|
1031
1300
|
return data.length ? data[0].version : 0;
|
|
1032
1301
|
}
|
|
1033
|
-
|
|
1302
|
+
/**
|
|
1303
|
+
* Updates the migration version in the database. If the version entry does not exist, it inserts a new one;
|
|
1304
|
+
* if it exists, it updates the version to the specified value.
|
|
1305
|
+
*
|
|
1306
|
+
* @param newVersion - The new migration version to set in the database.
|
|
1307
|
+
* @return A promise that resolves when the operation is complete.
|
|
1308
|
+
*/
|
|
1034
1309
|
async setVersion(newVersion) {
|
|
1035
1310
|
const query = `${this.migrationTableQuery()};
|
|
1036
1311
|
INSERT INTO ${MIGRATION_DATA_TABLE_NAME} (version) VALUES ${newVersion} WHERE NOT EXISTS (SELECT 1 FROM ${MIGRATION_DATA_TABLE_NAME})
|
|
@@ -1048,9 +1323,9 @@ var SqliteDialect = class extends DefaultSql {
|
|
|
1048
1323
|
number: "INTEGER",
|
|
1049
1324
|
bigint: "INTEGER",
|
|
1050
1325
|
boolean: "INTEGER",
|
|
1051
|
-
date: "
|
|
1052
|
-
time: "
|
|
1053
|
-
dateTime: "
|
|
1326
|
+
date: "INTEGER",
|
|
1327
|
+
time: "INTEGER",
|
|
1328
|
+
dateTime: "INTEGER",
|
|
1054
1329
|
null: "NULL"
|
|
1055
1330
|
};
|
|
1056
1331
|
canAlterForeignKeys = false;
|
|
@@ -1065,14 +1340,16 @@ var SqliteDialect = class extends DefaultSql {
|
|
|
1065
1340
|
}
|
|
1066
1341
|
async getColumnInformation(tableName) {
|
|
1067
1342
|
const data = await this.db.runGetStatement(`PRAGMA table_info(${tableName})`);
|
|
1068
|
-
|
|
1069
|
-
|
|
1343
|
+
const output = {};
|
|
1344
|
+
for (const entry of data) {
|
|
1345
|
+
output[entry["name"]] = {
|
|
1070
1346
|
name: entry["name"],
|
|
1071
1347
|
type: entry["type"],
|
|
1072
1348
|
defaultValue: entry["dflt_value"],
|
|
1073
1349
|
isPrimaryKey: entry["pk"] == "1"
|
|
1074
1350
|
};
|
|
1075
|
-
}
|
|
1351
|
+
}
|
|
1352
|
+
return output;
|
|
1076
1353
|
}
|
|
1077
1354
|
formatValueToSql(value, type) {
|
|
1078
1355
|
function toDate(value2) {
|
|
@@ -1097,8 +1374,8 @@ var SqliteDialect = class extends DefaultSql {
|
|
|
1097
1374
|
fromColumn: entry["from"],
|
|
1098
1375
|
toTable: entry["table"],
|
|
1099
1376
|
toColumn: entry["to"],
|
|
1100
|
-
|
|
1101
|
-
|
|
1377
|
+
onUpdate: entry["on_update"] ?? "NO ACTION",
|
|
1378
|
+
onDelete: entry["on_delete"] ?? "NO ACTION"
|
|
1102
1379
|
};
|
|
1103
1380
|
});
|
|
1104
1381
|
}
|
|
@@ -1131,14 +1408,17 @@ var PostgresDialect = class extends DefaultSql {
|
|
|
1131
1408
|
}
|
|
1132
1409
|
async getColumnInformation(tableName) {
|
|
1133
1410
|
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}';`);
|
|
1134
|
-
|
|
1135
|
-
|
|
1411
|
+
const output = {};
|
|
1412
|
+
for (const entry of data) {
|
|
1413
|
+
output[entry["name"]] = {
|
|
1136
1414
|
name: entry["column_name"],
|
|
1137
1415
|
type: entry["data_type"],
|
|
1416
|
+
maxLength: 0,
|
|
1138
1417
|
defaultValue: entry["column_default"],
|
|
1139
1418
|
isPrimaryKey: false
|
|
1140
1419
|
};
|
|
1141
|
-
}
|
|
1420
|
+
}
|
|
1421
|
+
return output;
|
|
1142
1422
|
}
|
|
1143
1423
|
addPrimaryKey(tableName, columnName) {
|
|
1144
1424
|
return `ALTER TABLE ${tableName} ADD PRIMARY KEY (${columnName});
|
|
@@ -1183,18 +1463,21 @@ var MsSqlDialect = class extends DefaultSql {
|
|
|
1183
1463
|
});
|
|
1184
1464
|
}
|
|
1185
1465
|
async getTableNames() {
|
|
1186
|
-
return await this.db.runGetStatement("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'");
|
|
1466
|
+
return (await this.db.runGetStatement("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'")).map((entry) => entry.name);
|
|
1187
1467
|
}
|
|
1188
1468
|
async getColumnInformation(tableName) {
|
|
1189
1469
|
const data = await this.db.runGetStatement(`SELECT COLUMN_NAME, DATA_TYPE, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = N'${tableName};'`);
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1470
|
+
const output = {};
|
|
1471
|
+
for (const entry of data) {
|
|
1472
|
+
output[entry["name"]] = {
|
|
1473
|
+
name: entry["name"],
|
|
1193
1474
|
type: entry["DATA_TYPE"],
|
|
1475
|
+
maxLength: 0,
|
|
1194
1476
|
defaultValue: entry["COLUMN_DEFAULT"],
|
|
1195
|
-
isPrimaryKey:
|
|
1477
|
+
isPrimaryKey: entry["pk"] == "1"
|
|
1196
1478
|
};
|
|
1197
|
-
}
|
|
1479
|
+
}
|
|
1480
|
+
return output;
|
|
1198
1481
|
}
|
|
1199
1482
|
};
|
|
1200
1483
|
|
|
@@ -1204,9 +1487,26 @@ var MySqlDialect = class extends DefaultSql {
|
|
|
1204
1487
|
canAlterPrimaryKey = true;
|
|
1205
1488
|
canInspectForeignKeys = true;
|
|
1206
1489
|
canInspectPrimaryKey = true;
|
|
1490
|
+
types = {
|
|
1491
|
+
string: "VARCHAR",
|
|
1492
|
+
number: "INT",
|
|
1493
|
+
bigint: "BIGINT",
|
|
1494
|
+
boolean: "BOOLEAN",
|
|
1495
|
+
date: "DATE",
|
|
1496
|
+
time: "TIME",
|
|
1497
|
+
dateTime: "DATETIME",
|
|
1498
|
+
null: "NULL"
|
|
1499
|
+
};
|
|
1500
|
+
getSqlType(dataType, columnInfo) {
|
|
1501
|
+
switch (dataType) {
|
|
1502
|
+
case "string":
|
|
1503
|
+
return this.types[dataType] + `(${columnInfo?.maxLength})`;
|
|
1504
|
+
default:
|
|
1505
|
+
return super.getSqlType(dataType, columnInfo);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1207
1508
|
changeForeignKeysState(enabled) {
|
|
1208
|
-
return `SET FOREIGN_KEY_CHECKS ${enabled ? "1" : "0"}
|
|
1209
|
-
;`;
|
|
1509
|
+
return `SET FOREIGN_KEY_CHECKS ${enabled ? "1" : "0"};`;
|
|
1210
1510
|
}
|
|
1211
1511
|
addForeignKey(fromTableName, foreignKey) {
|
|
1212
1512
|
return `ALTER TABLE ${fromTableName} ADD ${foreignKey};`;
|
|
@@ -1232,18 +1532,22 @@ var MySqlDialect = class extends DefaultSql {
|
|
|
1232
1532
|
});
|
|
1233
1533
|
}
|
|
1234
1534
|
async getTableNames() {
|
|
1235
|
-
|
|
1535
|
+
const t = await this.db.runGetStatement("SELECT table_name FROM information_schema.tables;");
|
|
1536
|
+
return (await this.db.runGetStatement("SELECT table_name FROM information_schema.tables;")).map((entry) => entry.name);
|
|
1236
1537
|
}
|
|
1237
1538
|
async getColumnInformation(tableName) {
|
|
1238
1539
|
const data = await this.db.runGetStatement(`SHOW COLUMNS FROM ${tableName};`);
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1540
|
+
const output = {};
|
|
1541
|
+
for (const entry of data) {
|
|
1542
|
+
output[entry["name"]] = {
|
|
1543
|
+
name: entry["name"],
|
|
1544
|
+
type: entry["type"],
|
|
1545
|
+
maxLength: 0,
|
|
1546
|
+
defaultValue: entry["dflt_value"],
|
|
1547
|
+
isPrimaryKey: entry["pk"] == "1"
|
|
1245
1548
|
};
|
|
1246
|
-
}
|
|
1549
|
+
}
|
|
1550
|
+
return output;
|
|
1247
1551
|
}
|
|
1248
1552
|
};
|
|
1249
1553
|
|