@mikro-orm/knex 6.3.5-dev.1 → 6.3.5-dev.11
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.11",
|
|
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.11",
|
|
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,17 +381,49 @@ 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) {
|
|
356
422
|
const fkColumnsLength = currentFk.columnNames.length;
|
|
357
423
|
const possibleIndexes = this.indexes.filter(index => {
|
|
358
|
-
return index.columnNames.length
|
|
424
|
+
return index.columnNames.length === fkColumnsLength && !currentFk.columnNames.some((columnName, i) => index.columnNames[i] !== columnName);
|
|
359
425
|
});
|
|
360
426
|
possibleIndexes.sort((a, b) => {
|
|
361
|
-
if (a.columnNames.length !== b.columnNames.length) {
|
|
362
|
-
return a.columnNames.length < b.columnNames.length ? -1 : 1;
|
|
363
|
-
}
|
|
364
427
|
if (a.primary !== b.primary) {
|
|
365
428
|
return a.primary ? -1 : 1;
|
|
366
429
|
}
|
|
@@ -369,7 +432,7 @@ class DatabaseTable {
|
|
|
369
432
|
}
|
|
370
433
|
return a.keyName.localeCompare(b.keyName);
|
|
371
434
|
});
|
|
372
|
-
return possibleIndexes
|
|
435
|
+
return possibleIndexes.at(0);
|
|
373
436
|
}
|
|
374
437
|
getIndexProperties(index, columnFks, fksOnColumnProps, fksOnStandaloneProps, namingStrategy) {
|
|
375
438
|
const propBaseNames = new Set();
|
|
@@ -381,9 +444,13 @@ class DatabaseTable {
|
|
|
381
444
|
for (let i = 0; i < l; ++i) {
|
|
382
445
|
const columnName = columnNames[i];
|
|
383
446
|
// The column is not involved with FKs.
|
|
384
|
-
// It has a prop named after it.
|
|
385
|
-
// Add it and move on.
|
|
386
447
|
if (!(columnName in columnFks)) {
|
|
448
|
+
// If there is no such column, the "name" is actually an expression.
|
|
449
|
+
if (!this.hasColumn(columnName)) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
// It has a prop named after it.
|
|
453
|
+
// Add it and move on.
|
|
387
454
|
propBaseNames.add(columnName);
|
|
388
455
|
continue;
|
|
389
456
|
}
|
|
@@ -398,7 +465,7 @@ class DatabaseTable {
|
|
|
398
465
|
// and all of its columns are a subset of this index,
|
|
399
466
|
// include that FK, and consider mapping of this column to a prop a success.
|
|
400
467
|
let propAdded = false;
|
|
401
|
-
for (const [propName,
|
|
468
|
+
for (const [propName, { currentFk: fk }] of fksOnStandaloneProps) {
|
|
402
469
|
if (!columnFks[columnName].includes(fk)) {
|
|
403
470
|
continue;
|
|
404
471
|
}
|
|
@@ -473,7 +540,7 @@ class DatabaseTable {
|
|
|
473
540
|
hasPrimaryKey() {
|
|
474
541
|
return !!this.getPrimaryKey();
|
|
475
542
|
}
|
|
476
|
-
getForeignKeyDeclaration(fk, namingStrategy, schemaHelper, fkIndex, nullable, propNameBase) {
|
|
543
|
+
getForeignKeyDeclaration(fk, namingStrategy, schemaHelper, fkIndex, nullable, propNameBase, fksOnColumnProps) {
|
|
477
544
|
const prop = this.getPropertyName(namingStrategy, propNameBase, fk);
|
|
478
545
|
const kind = (fkIndex?.unique && !fkIndex.primary) ? this.getReferenceKind(fk, fkIndex) : this.getReferenceKind(fk);
|
|
479
546
|
const runtimeType = this.getPropertyTypeForForeignKey(namingStrategy, fk);
|
|
@@ -499,6 +566,7 @@ class DatabaseTable {
|
|
|
499
566
|
columnOptions.length = column.length;
|
|
500
567
|
columnOptions.precision = column.precision;
|
|
501
568
|
columnOptions.scale = column.scale;
|
|
569
|
+
columnOptions.extra = column.extra;
|
|
502
570
|
columnOptions.comment = column.comment;
|
|
503
571
|
columnOptions.enum = !!column.enumItems?.length;
|
|
504
572
|
columnOptions.items = column.enumItems;
|
|
@@ -556,6 +624,7 @@ class DatabaseTable {
|
|
|
556
624
|
length: column.length,
|
|
557
625
|
precision: column.precision,
|
|
558
626
|
scale: column.scale,
|
|
627
|
+
extra: column.extra,
|
|
559
628
|
comment: column.comment,
|
|
560
629
|
index: index ? index.keyName : undefined,
|
|
561
630
|
unique: unique ? unique.keyName : undefined,
|