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