@mikro-orm/knex 6.3.5-dev.1 → 6.3.5-dev.10
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.
|
@@ -92,7 +92,7 @@ class MySqlSchemaHelper extends SchemaHelper_1.SchemaHelper {
|
|
|
92
92
|
order by ordinal_position`;
|
|
93
93
|
const allColumns = await connection.execute(sql);
|
|
94
94
|
const str = (val) => val != null ? '' + val : val;
|
|
95
|
-
const extra = (val) => val.replace(/auto_increment|default_generated|(stored|virtual) generated/i, '').trim();
|
|
95
|
+
const extra = (val) => val.replace(/auto_increment|default_generated|(stored|virtual) generated/i, '').trim() || undefined;
|
|
96
96
|
const ret = {};
|
|
97
97
|
for (const col of allColumns) {
|
|
98
98
|
const mappedType = this.platform.getMappedType(col.column_type);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/knex",
|
|
3
|
-
"version": "6.3.5-dev.
|
|
3
|
+
"version": "6.3.5-dev.10",
|
|
4
4
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"@mikro-orm/core": "^6.3.4"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"@mikro-orm/core": "6.3.5-dev.
|
|
69
|
+
"@mikro-orm/core": "6.3.5-dev.10",
|
|
70
70
|
"better-sqlite3": "*",
|
|
71
71
|
"libsql": "*",
|
|
72
72
|
"mariadb": "*"
|
package/schema/DatabaseTable.js
CHANGED
|
@@ -170,36 +170,46 @@ class DatabaseTable {
|
|
|
170
170
|
const compositeFkUniques = {};
|
|
171
171
|
const potentiallyUnmappedIndexes = this.indexes.filter(index => !index.primary // Skip primary index. Whether it's in use by scalar column or FK, it's already mapped.
|
|
172
172
|
&& (index.columnNames.length > 1 // All composite indexes are to be mapped to entity decorators or FK props.
|
|
173
|
-
|| !(index.columnNames[0] in columnFks) // Non-composite indexes for scalar props are to be mapped to the column.
|
|
174
173
|
|| skippedColumnNames.includes(index.columnNames[0]) // Non-composite indexes for skipped columns are to be mapped as entity decorators.
|
|
174
|
+
|| index.deferMode || index.expression // Non-trivial non-composite indexes will be declared at the entity's metadata, though later outputted in the property
|
|
175
|
+
|| !(index.columnNames[0] in columnFks) // Trivial non-composite indexes for scalar props are to be mapped to the column.
|
|
175
176
|
)
|
|
176
177
|
// ignore indexes that don't have all column names (this can happen in sqlite where there is no way to infer this for expressions)
|
|
177
178
|
&& !(index.columnNames.some(col => !col) && !index.expression));
|
|
178
179
|
for (const index of potentiallyUnmappedIndexes) {
|
|
179
|
-
const ret = {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
180
|
+
const ret = {
|
|
181
|
+
name: index.keyName,
|
|
182
|
+
deferMode: index.deferMode,
|
|
183
|
+
expression: index.expression,
|
|
184
|
+
};
|
|
185
|
+
const isTrivial = !index.deferMode && !index.expression;
|
|
186
|
+
if (isTrivial) {
|
|
187
|
+
// Index is for FK. Map to the FK prop and move on.
|
|
188
|
+
const fkForIndex = fkIndexes.get(index);
|
|
189
|
+
if (fkForIndex && !fkForIndex.fk.columnNames.some(col => !index.columnNames.includes(col))) {
|
|
190
|
+
ret.properties = [this.getPropertyName(namingStrategy, fkForIndex.baseName, fkForIndex.fk)];
|
|
191
|
+
const map = index.unique ? compositeFkUniques : compositeFkIndexes;
|
|
192
|
+
if (typeof map[ret.properties[0]] === 'undefined') {
|
|
193
|
+
map[ret.properties[0]] = index;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
187
197
|
}
|
|
188
|
-
const properties = this.getIndexProperties(index, columnFks, fksOnColumnProps, fksOnStandaloneProps, namingStrategy);
|
|
198
|
+
const properties = ret.properties ?? this.getIndexProperties(index, columnFks, fksOnColumnProps, fksOnStandaloneProps, namingStrategy);
|
|
189
199
|
// If there is a column that cannot be unambiguously mapped to a prop, render an expression.
|
|
190
|
-
if (
|
|
191
|
-
ret.expression
|
|
192
|
-
}
|
|
193
|
-
else if (typeof properties === 'undefined') {
|
|
194
|
-
ret.expression = schemaHelper.getCreateIndexSQL(this.name, index);
|
|
200
|
+
if (typeof properties === 'undefined') {
|
|
201
|
+
ret.expression ??= schemaHelper.getCreateIndexSQL(this.name, index);
|
|
195
202
|
}
|
|
196
203
|
else {
|
|
197
|
-
ret.properties
|
|
204
|
+
ret.properties ??= properties;
|
|
198
205
|
// If the index is for one property that is not a FK prop, map to the column prop and move on.
|
|
199
|
-
if (properties.length === 1 && !fksOnStandaloneProps.has(properties[0])) {
|
|
206
|
+
if (properties.length === 1 && isTrivial && !fksOnStandaloneProps.has(properties[0])) {
|
|
200
207
|
const map = index.unique ? compositeFkUniques : compositeFkIndexes;
|
|
201
|
-
map
|
|
202
|
-
|
|
208
|
+
// Only map one trivial index. If the same column is indexed many times over, output
|
|
209
|
+
if (typeof map[properties[0]] === 'undefined') {
|
|
210
|
+
map[properties[0]] = index;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
203
213
|
}
|
|
204
214
|
}
|
|
205
215
|
// Composite indexes that aren't exclusively mapped to FK props get an entity decorator.
|
|
@@ -216,18 +226,18 @@ class DatabaseTable {
|
|
|
216
226
|
const standaloneFkPropBasedOnColumn = fksOnStandaloneProps.get(columnName);
|
|
217
227
|
if (standaloneFkPropBasedOnColumn && !fksOnColumnProps.get(columnName)) {
|
|
218
228
|
addedStandaloneFkPropsBasedOnColumn.add(columnName);
|
|
219
|
-
const
|
|
220
|
-
const prop = this.getForeignKeyDeclaration(currentFk, namingStrategy, schemaHelper, fkIndex, nullableForeignKeys.has(currentFk), columnName);
|
|
229
|
+
const { fkIndex, currentFk } = standaloneFkPropBasedOnColumn;
|
|
230
|
+
const prop = this.getForeignKeyDeclaration(currentFk, namingStrategy, schemaHelper, fkIndex, nullableForeignKeys.has(currentFk), columnName, fksOnColumnProps);
|
|
221
231
|
schema.addProperty(prop.name, prop.type, prop);
|
|
222
232
|
}
|
|
223
233
|
const prop = this.getPropertyDeclaration(column, namingStrategy, schemaHelper, compositeFkIndexes, compositeFkUniques, columnFks, fksOnColumnProps.get(columnName));
|
|
224
234
|
schema.addProperty(prop.name, prop.type, prop);
|
|
225
235
|
}
|
|
226
|
-
for (const [propBaseName,
|
|
236
|
+
for (const [propBaseName, { fkIndex, currentFk }] of fksOnStandaloneProps.entries()) {
|
|
227
237
|
if (addedStandaloneFkPropsBasedOnColumn.has(propBaseName)) {
|
|
228
238
|
continue;
|
|
229
239
|
}
|
|
230
|
-
const prop = this.getForeignKeyDeclaration(currentFk, namingStrategy, schemaHelper, fkIndex, nullableForeignKeys.has(currentFk), propBaseName);
|
|
240
|
+
const prop = this.getForeignKeyDeclaration(currentFk, namingStrategy, schemaHelper, fkIndex, nullableForeignKeys.has(currentFk), propBaseName, fksOnColumnProps);
|
|
231
241
|
schema.addProperty(prop.name, prop.type, prop);
|
|
232
242
|
}
|
|
233
243
|
const meta = schema.init().meta;
|
|
@@ -246,6 +256,7 @@ class DatabaseTable {
|
|
|
246
256
|
const columnFks = {};
|
|
247
257
|
const fkIndexes = new Map();
|
|
248
258
|
const nullableForeignKeys = new Set();
|
|
259
|
+
const standaloneFksBasedOnColumnNames = new Map();
|
|
249
260
|
for (const currentFk of fks) {
|
|
250
261
|
const fkIndex = this.findFkIndex(currentFk);
|
|
251
262
|
if (currentFk.columnNames.length === 1 && !fks.some(fk => fk !== currentFk && fk.columnNames.length === 1 && currentFk.columnNames[0] === fk.columnNames[0])) {
|
|
@@ -258,12 +269,17 @@ class DatabaseTable {
|
|
|
258
269
|
}
|
|
259
270
|
if (scalarPropertiesForRelations === 'always') {
|
|
260
271
|
const baseName = this.getSafeBaseNameForFkProp(namingStrategy, currentFk, fks, columnName);
|
|
261
|
-
|
|
262
|
-
|
|
272
|
+
standaloneFksBasedOnColumnNames.set(baseName, currentFk);
|
|
273
|
+
fksOnStandaloneProps.set(baseName, { fkIndex, currentFk });
|
|
274
|
+
if (fkIndex) {
|
|
275
|
+
fkIndexes.set(fkIndex, { fk: currentFk, baseName });
|
|
276
|
+
}
|
|
263
277
|
}
|
|
264
278
|
else {
|
|
265
279
|
fksOnColumnProps.set(columnName, currentFk);
|
|
266
|
-
|
|
280
|
+
if (fkIndex) {
|
|
281
|
+
fkIndexes.set(fkIndex, { fk: currentFk, baseName: columnName });
|
|
282
|
+
}
|
|
267
283
|
}
|
|
268
284
|
continue;
|
|
269
285
|
}
|
|
@@ -290,12 +306,17 @@ class DatabaseTable {
|
|
|
290
306
|
const columnName = specificColumnNames[0];
|
|
291
307
|
if (scalarPropertiesForRelations === 'always') {
|
|
292
308
|
const baseName = this.getSafeBaseNameForFkProp(namingStrategy, currentFk, fks, columnName);
|
|
293
|
-
|
|
294
|
-
|
|
309
|
+
standaloneFksBasedOnColumnNames.set(baseName, currentFk);
|
|
310
|
+
fksOnStandaloneProps.set(baseName, { fkIndex, currentFk });
|
|
311
|
+
if (fkIndex) {
|
|
312
|
+
fkIndexes.set(fkIndex, { fk: currentFk, baseName });
|
|
313
|
+
}
|
|
295
314
|
}
|
|
296
315
|
else {
|
|
297
316
|
fksOnColumnProps.set(columnName, currentFk);
|
|
298
|
-
|
|
317
|
+
if (fkIndex) {
|
|
318
|
+
fkIndexes.set(fkIndex, { fk: currentFk, baseName: columnName });
|
|
319
|
+
}
|
|
299
320
|
}
|
|
300
321
|
continue;
|
|
301
322
|
}
|
|
@@ -307,12 +328,17 @@ class DatabaseTable {
|
|
|
307
328
|
const columnName = nullableColumnsInFk.at(0) ?? currentFk.columnNames[0];
|
|
308
329
|
if (scalarPropertiesForRelations === 'always') {
|
|
309
330
|
const baseName = this.getSafeBaseNameForFkProp(namingStrategy, currentFk, fks, columnName);
|
|
310
|
-
|
|
311
|
-
|
|
331
|
+
standaloneFksBasedOnColumnNames.set(baseName, currentFk);
|
|
332
|
+
fksOnStandaloneProps.set(baseName, { fkIndex, currentFk });
|
|
333
|
+
if (fkIndex) {
|
|
334
|
+
fkIndexes.set(fkIndex, { fk: currentFk, baseName });
|
|
335
|
+
}
|
|
312
336
|
}
|
|
313
337
|
else {
|
|
314
338
|
fksOnColumnProps.set(columnName, currentFk);
|
|
315
|
-
|
|
339
|
+
if (fkIndex) {
|
|
340
|
+
fkIndexes.set(fkIndex, { fk: currentFk, baseName: columnName });
|
|
341
|
+
}
|
|
316
342
|
}
|
|
317
343
|
continue;
|
|
318
344
|
}
|
|
@@ -320,14 +346,19 @@ class DatabaseTable {
|
|
|
320
346
|
// name a standalone prop after the column, but treat the column prop itself as not having FK.
|
|
321
347
|
const columnName = nullableColumnsInFk[0];
|
|
322
348
|
const baseName = this.getSafeBaseNameForFkProp(namingStrategy, currentFk, fks, columnName);
|
|
323
|
-
|
|
324
|
-
|
|
349
|
+
standaloneFksBasedOnColumnNames.set(baseName, currentFk);
|
|
350
|
+
fksOnStandaloneProps.set(baseName, { fkIndex, currentFk });
|
|
351
|
+
if (fkIndex) {
|
|
352
|
+
fkIndexes.set(fkIndex, { fk: currentFk, baseName });
|
|
353
|
+
}
|
|
325
354
|
continue;
|
|
326
355
|
}
|
|
327
356
|
// FK is not unambiguously mappable to a column. Pick another name for a standalone FK prop.
|
|
328
357
|
const baseName = this.getSafeBaseNameForFkProp(namingStrategy, currentFk, fks);
|
|
329
|
-
fksOnStandaloneProps.set(baseName,
|
|
330
|
-
|
|
358
|
+
fksOnStandaloneProps.set(baseName, { fkIndex, currentFk });
|
|
359
|
+
if (fkIndex) {
|
|
360
|
+
fkIndexes.set(fkIndex, { fk: currentFk, baseName });
|
|
361
|
+
}
|
|
331
362
|
}
|
|
332
363
|
const columnsInFks = Object.keys(columnFks);
|
|
333
364
|
const skippingHandlers = {
|
|
@@ -350,6 +381,41 @@ class DatabaseTable {
|
|
|
350
381
|
},
|
|
351
382
|
};
|
|
352
383
|
const skippedColumnNames = this.getColumns().filter(skippingHandlers[scalarPropertiesForRelations]).map(column => column.name);
|
|
384
|
+
// Check standalone FKs named after columns for potential conflicts among themselves.
|
|
385
|
+
// This typically happens when two standalone FKs named after a column resolve to the same prop name
|
|
386
|
+
// because the respective columns include the referenced table in the name.
|
|
387
|
+
// Depending on naming strategy and actual names, it may also originate from other scenarios.
|
|
388
|
+
// We do our best to de-duplicate them here.
|
|
389
|
+
const safePropNames = new Set();
|
|
390
|
+
const unsafePropNames = new Map();
|
|
391
|
+
for (const [unsafeBaseName, currentFk] of standaloneFksBasedOnColumnNames) {
|
|
392
|
+
const propName = this.getPropertyName(namingStrategy, unsafeBaseName, currentFk);
|
|
393
|
+
if (safePropNames.has(propName)) {
|
|
394
|
+
if (!unsafePropNames.has(propName)) {
|
|
395
|
+
unsafePropNames.set(propName, []);
|
|
396
|
+
}
|
|
397
|
+
unsafePropNames.get(propName).push({ unsafeBaseName, currentFk });
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
safePropNames.add(propName);
|
|
401
|
+
}
|
|
402
|
+
for (const [unsafePropName, affectedBaseNames] of unsafePropNames) {
|
|
403
|
+
safePropNames.delete(unsafePropName);
|
|
404
|
+
for (const { unsafeBaseName, currentFk } of affectedBaseNames) {
|
|
405
|
+
const newBaseName = this.getSafeBaseNameForFkProp(namingStrategy, currentFk, fks);
|
|
406
|
+
fksOnStandaloneProps.delete(unsafeBaseName);
|
|
407
|
+
let fkIndex;
|
|
408
|
+
for (const [indexDef, fkIndexDesc] of fkIndexes) {
|
|
409
|
+
if (fkIndexDesc.fk !== currentFk) {
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
fkIndexDesc.baseName = newBaseName;
|
|
413
|
+
fkIndex = indexDef;
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
fksOnStandaloneProps.set(newBaseName, { fkIndex, currentFk });
|
|
417
|
+
}
|
|
418
|
+
}
|
|
353
419
|
return { fksOnColumnProps, fksOnStandaloneProps, columnFks, fkIndexes, nullableForeignKeys, skippedColumnNames };
|
|
354
420
|
}
|
|
355
421
|
findFkIndex(currentFk) {
|
|
@@ -369,7 +435,7 @@ class DatabaseTable {
|
|
|
369
435
|
}
|
|
370
436
|
return a.keyName.localeCompare(b.keyName);
|
|
371
437
|
});
|
|
372
|
-
return possibleIndexes
|
|
438
|
+
return possibleIndexes.at(0);
|
|
373
439
|
}
|
|
374
440
|
getIndexProperties(index, columnFks, fksOnColumnProps, fksOnStandaloneProps, namingStrategy) {
|
|
375
441
|
const propBaseNames = new Set();
|
|
@@ -381,9 +447,13 @@ class DatabaseTable {
|
|
|
381
447
|
for (let i = 0; i < l; ++i) {
|
|
382
448
|
const columnName = columnNames[i];
|
|
383
449
|
// The column is not involved with FKs.
|
|
384
|
-
// It has a prop named after it.
|
|
385
|
-
// Add it and move on.
|
|
386
450
|
if (!(columnName in columnFks)) {
|
|
451
|
+
// If there is no such column, the "name" is actually an expression.
|
|
452
|
+
if (!this.hasColumn(columnName)) {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
// It has a prop named after it.
|
|
456
|
+
// Add it and move on.
|
|
387
457
|
propBaseNames.add(columnName);
|
|
388
458
|
continue;
|
|
389
459
|
}
|
|
@@ -398,7 +468,7 @@ class DatabaseTable {
|
|
|
398
468
|
// and all of its columns are a subset of this index,
|
|
399
469
|
// include that FK, and consider mapping of this column to a prop a success.
|
|
400
470
|
let propAdded = false;
|
|
401
|
-
for (const [propName,
|
|
471
|
+
for (const [propName, { currentFk: fk }] of fksOnStandaloneProps) {
|
|
402
472
|
if (!columnFks[columnName].includes(fk)) {
|
|
403
473
|
continue;
|
|
404
474
|
}
|
|
@@ -473,7 +543,7 @@ class DatabaseTable {
|
|
|
473
543
|
hasPrimaryKey() {
|
|
474
544
|
return !!this.getPrimaryKey();
|
|
475
545
|
}
|
|
476
|
-
getForeignKeyDeclaration(fk, namingStrategy, schemaHelper, fkIndex, nullable, propNameBase) {
|
|
546
|
+
getForeignKeyDeclaration(fk, namingStrategy, schemaHelper, fkIndex, nullable, propNameBase, fksOnColumnProps) {
|
|
477
547
|
const prop = this.getPropertyName(namingStrategy, propNameBase, fk);
|
|
478
548
|
const kind = (fkIndex?.unique && !fkIndex.primary) ? this.getReferenceKind(fk, fkIndex) : this.getReferenceKind(fk);
|
|
479
549
|
const runtimeType = this.getPropertyTypeForForeignKey(namingStrategy, fk);
|
|
@@ -499,6 +569,7 @@ class DatabaseTable {
|
|
|
499
569
|
columnOptions.length = column.length;
|
|
500
570
|
columnOptions.precision = column.precision;
|
|
501
571
|
columnOptions.scale = column.scale;
|
|
572
|
+
columnOptions.extra = column.extra;
|
|
502
573
|
columnOptions.comment = column.comment;
|
|
503
574
|
columnOptions.enum = !!column.enumItems?.length;
|
|
504
575
|
columnOptions.items = column.enumItems;
|
|
@@ -556,6 +627,7 @@ class DatabaseTable {
|
|
|
556
627
|
length: column.length,
|
|
557
628
|
precision: column.precision,
|
|
558
629
|
scale: column.scale,
|
|
630
|
+
extra: column.extra,
|
|
559
631
|
comment: column.comment,
|
|
560
632
|
index: index ? index.keyName : undefined,
|
|
561
633
|
unique: unique ? unique.keyName : undefined,
|