@mikro-orm/sql 7.1.9-dev.22 → 7.1.9-dev.24
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/AbstractSqlDriver.js +52 -12
- package/package.json +2 -2
package/AbstractSqlDriver.js
CHANGED
|
@@ -1316,7 +1316,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1316
1316
|
}
|
|
1317
1317
|
}
|
|
1318
1318
|
}
|
|
1319
|
-
return this.buildPivotResultMap(owners, res, pivotProp2.name, pivotProp1.name);
|
|
1319
|
+
return this.buildPivotResultMap(owners, res, pivotProp2.name, pivotProp1.name, ownerMeta);
|
|
1320
1320
|
}
|
|
1321
1321
|
/**
|
|
1322
1322
|
* Load from a polymorphic M:N pivot table.
|
|
@@ -1337,10 +1337,15 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1337
1337
|
async loadPolymorphicPivotOwnerSide(prop, owners, where, orderBy, ctx, options, pivotJoin, inverseProp) {
|
|
1338
1338
|
const pivotMeta = this.metadata.get(prop.pivotEntity);
|
|
1339
1339
|
const targetMeta = prop.targetMeta;
|
|
1340
|
-
//
|
|
1340
|
+
// `prop.discriminator` spans all owner FK columns but carries no target metadata, so a composite
|
|
1341
|
+
// owner PK neither expands to a tuple condition nor gets mapped back; the virtual M:1 relation
|
|
1342
|
+
// to this discriminator's owner describes the same columns as an actual relation
|
|
1343
|
+
const ownerMeta = this.metadata.get(pivotMeta.polymorphicDiscriminatorMap[prop.discriminatorValue]);
|
|
1344
|
+
const ownerProp = pivotMeta.properties[`${prop.discriminator}_${ownerMeta.tableName}`];
|
|
1345
|
+
// Build condition: discriminator = 'post' AND {owner} IN (...)
|
|
1341
1346
|
const cond = {
|
|
1342
1347
|
[prop.discriminatorColumn]: prop.discriminatorValue,
|
|
1343
|
-
[
|
|
1348
|
+
[ownerProp.name]: { $in: owners.length === 1 && owners[0].length === 1 ? owners.map(o => o[0]) : owners },
|
|
1344
1349
|
};
|
|
1345
1350
|
if (!Utils.isEmpty(where)) {
|
|
1346
1351
|
cond[inverseProp.name] = { ...where };
|
|
@@ -1351,9 +1356,12 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1351
1356
|
const childExclude = !Utils.isEmpty(options?.exclude)
|
|
1352
1357
|
? options.exclude.map(f => `${inverseProp.name}.${f}`)
|
|
1353
1358
|
: [];
|
|
1359
|
+
// the owner relation is virtual, so the FK columns have to be selected via the per-column pivot
|
|
1360
|
+
// props a composite owner PK gets; a single column owner PK is covered by the flat prop itself
|
|
1361
|
+
const ownerFields = ownerMeta.compositePK ? prop.joinColumns : [prop.discriminator];
|
|
1354
1362
|
const fields = pivotJoin
|
|
1355
|
-
? [inverseProp.name,
|
|
1356
|
-
: [inverseProp.name,
|
|
1363
|
+
? [inverseProp.name, ...ownerFields, prop.discriminatorColumn]
|
|
1364
|
+
: [inverseProp.name, ...ownerFields, prop.discriminatorColumn, ...childFields];
|
|
1357
1365
|
const res = await this.find(pivotMeta.class, cond, {
|
|
1358
1366
|
ctx,
|
|
1359
1367
|
...options,
|
|
@@ -1374,7 +1382,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1374
1382
|
_populateWhere: 'infer',
|
|
1375
1383
|
populateFilter: this.wrapPopulateFilter(options, inverseProp.name),
|
|
1376
1384
|
});
|
|
1377
|
-
return this.buildPivotResultMap(owners, res,
|
|
1385
|
+
return this.buildPivotResultMap(owners, res, ownerProp.name, inverseProp.name, ownerMeta);
|
|
1378
1386
|
}
|
|
1379
1387
|
/**
|
|
1380
1388
|
* Load from inverse side of polymorphic M:N (e.g., Tag -> Posts)
|
|
@@ -1423,7 +1431,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1423
1431
|
_populateWhere: 'infer',
|
|
1424
1432
|
populateFilter: this.wrapPopulateFilter(options, ownerRelationName),
|
|
1425
1433
|
});
|
|
1426
|
-
return this.buildPivotResultMap(owners, res, tagProp.name, ownerRelationName);
|
|
1434
|
+
return this.buildPivotResultMap(owners, res, tagProp.name, ownerRelationName, tagProp.targetMeta);
|
|
1427
1435
|
}
|
|
1428
1436
|
/**
|
|
1429
1437
|
* Load a union-target polymorphic M:N pivot (e.g. Post.attachments -> Image | Video).
|
|
@@ -1519,19 +1527,23 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1519
1527
|
}
|
|
1520
1528
|
}
|
|
1521
1529
|
const result = orphanedRows.size > 0 ? pivotRows.filter(r => !orphanedRows.has(r)) : pivotRows;
|
|
1522
|
-
return this.buildPivotResultMap(owners, result, ownerProp.name, prop.discriminator);
|
|
1530
|
+
return this.buildPivotResultMap(owners, result, ownerProp.name, prop.discriminator, ownerMeta);
|
|
1523
1531
|
}
|
|
1524
1532
|
/**
|
|
1525
1533
|
* Build a map from owner PKs to their related entities from pivot table results.
|
|
1526
1534
|
*/
|
|
1527
|
-
buildPivotResultMap(owners, results, keyProp, valueProp) {
|
|
1535
|
+
buildPivotResultMap(owners, results, keyProp, valueProp, ownerMeta) {
|
|
1528
1536
|
const map = {};
|
|
1529
1537
|
for (const owner of owners) {
|
|
1530
1538
|
const key = Utils.getPrimaryKeyHash(owner);
|
|
1531
1539
|
map[key] = [];
|
|
1532
1540
|
}
|
|
1533
1541
|
for (const item of results) {
|
|
1534
|
-
const
|
|
1542
|
+
const fk = item[keyProp];
|
|
1543
|
+
// the owner PKs are always flat, while the pivot FK follows the owner PK structure,
|
|
1544
|
+
// so a PK built from a relation to another composite PK entity needs flattening too
|
|
1545
|
+
const pks = ownerMeta && fk != null ? Utils.getOrderedPrimaryKeys(fk, ownerMeta) : Utils.asArray(fk);
|
|
1546
|
+
const key = Utils.getPrimaryKeyHash(pks);
|
|
1535
1547
|
const entity = item[valueProp];
|
|
1536
1548
|
if (map[key]) {
|
|
1537
1549
|
map[key].push(entity);
|
|
@@ -1657,8 +1669,23 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1657
1669
|
const [propName, ref] = hint.field.split(':', 2);
|
|
1658
1670
|
return { propName, ref, children: hint.children };
|
|
1659
1671
|
});
|
|
1672
|
+
// with `fixedOrder` the pivot PK is the order column, which is not guaranteed to be unique when the
|
|
1673
|
+
// pivot table is managed externally, so we disambiguate the rows by their FKs on top of the PK
|
|
1674
|
+
const pivotRelations = meta.pivotTable && !meta.compositePK
|
|
1675
|
+
? meta.relations.filter(p => p.kind === ReferenceKind.MANY_TO_ONE && p.persist !== false)
|
|
1676
|
+
: [];
|
|
1660
1677
|
for (const item of rawResults) {
|
|
1661
|
-
|
|
1678
|
+
let pk = Utils.getCompositeKeyHash(item, meta);
|
|
1679
|
+
if (pivotRelations.length > 0) {
|
|
1680
|
+
pk = Utils.getPrimaryKeyHash([
|
|
1681
|
+
pk,
|
|
1682
|
+
...pivotRelations.flatMap(p => {
|
|
1683
|
+
const value = item[p.name];
|
|
1684
|
+
// composite FKs are mapped to an array of values, which `extractPK` does not accept
|
|
1685
|
+
return (Array.isArray(value) ? value : Utils.extractPK(value, p.targetMeta));
|
|
1686
|
+
}),
|
|
1687
|
+
]);
|
|
1688
|
+
}
|
|
1662
1689
|
if (map[pk]) {
|
|
1663
1690
|
for (const { propName } of hints) {
|
|
1664
1691
|
if (!item[propName]) {
|
|
@@ -2087,7 +2114,20 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
2087
2114
|
const ret = {};
|
|
2088
2115
|
for (const prop of meta.relations) {
|
|
2089
2116
|
if (prop.kind === ReferenceKind.MANY_TO_MANY && data[prop.name]) {
|
|
2090
|
-
|
|
2117
|
+
// union targets are validated to have a single PK column, so a pivot row is always keyed
|
|
2118
|
+
// by exactly `[discriminator, pk]` - anything else cannot address a target table
|
|
2119
|
+
const discriminators = QueryHelper.isUnionTargetPolymorphic(prop)
|
|
2120
|
+
? Object.keys(prop.discriminatorMap)
|
|
2121
|
+
: undefined;
|
|
2122
|
+
ret[prop.name] = data[prop.name].map((item) => {
|
|
2123
|
+
const values = Utils.asArray(item);
|
|
2124
|
+
if (discriminators && !(values.length === 2 && discriminators.includes('' + values[0]))) {
|
|
2125
|
+
throw new Error(`Cannot resolve the discriminator value of ${meta.className}.${prop.name} from '${values.join(', ')}', ` +
|
|
2126
|
+
`as the same primary key can exist in any of the target tables. ` +
|
|
2127
|
+
`Pass the target as a [discriminator, ...primaryKey] tuple, e.g. ${JSON.stringify([discriminators[0], ...values])}.`);
|
|
2128
|
+
}
|
|
2129
|
+
return values;
|
|
2130
|
+
});
|
|
2091
2131
|
delete data[prop.name];
|
|
2092
2132
|
}
|
|
2093
2133
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/sql",
|
|
3
|
-
"version": "7.1.9-dev.
|
|
3
|
+
"version": "7.1.9-dev.24",
|
|
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
|
"keywords": [
|
|
6
6
|
"data-mapper",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@mikro-orm/core": "^7.1.8"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@mikro-orm/core": "7.1.9-dev.
|
|
56
|
+
"@mikro-orm/core": "7.1.9-dev.24"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">= 22.17.0"
|