@mikro-orm/sql 7.1.9-dev.22 → 7.1.9-dev.23

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.
@@ -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.
@@ -1423,7 +1423,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
1423
1423
  _populateWhere: 'infer',
1424
1424
  populateFilter: this.wrapPopulateFilter(options, ownerRelationName),
1425
1425
  });
1426
- return this.buildPivotResultMap(owners, res, tagProp.name, ownerRelationName);
1426
+ return this.buildPivotResultMap(owners, res, tagProp.name, ownerRelationName, tagProp.targetMeta);
1427
1427
  }
1428
1428
  /**
1429
1429
  * Load a union-target polymorphic M:N pivot (e.g. Post.attachments -> Image | Video).
@@ -1519,19 +1519,23 @@ export class AbstractSqlDriver extends DatabaseDriver {
1519
1519
  }
1520
1520
  }
1521
1521
  const result = orphanedRows.size > 0 ? pivotRows.filter(r => !orphanedRows.has(r)) : pivotRows;
1522
- return this.buildPivotResultMap(owners, result, ownerProp.name, prop.discriminator);
1522
+ return this.buildPivotResultMap(owners, result, ownerProp.name, prop.discriminator, ownerMeta);
1523
1523
  }
1524
1524
  /**
1525
1525
  * Build a map from owner PKs to their related entities from pivot table results.
1526
1526
  */
1527
- buildPivotResultMap(owners, results, keyProp, valueProp) {
1527
+ buildPivotResultMap(owners, results, keyProp, valueProp, ownerMeta) {
1528
1528
  const map = {};
1529
1529
  for (const owner of owners) {
1530
1530
  const key = Utils.getPrimaryKeyHash(owner);
1531
1531
  map[key] = [];
1532
1532
  }
1533
1533
  for (const item of results) {
1534
- const key = Utils.getPrimaryKeyHash(Utils.asArray(item[keyProp]));
1534
+ const fk = item[keyProp];
1535
+ // the owner PKs are always flat, while the pivot FK follows the owner PK structure,
1536
+ // so a PK built from a relation to another composite PK entity needs flattening too
1537
+ const pks = ownerMeta && fk != null ? Utils.getOrderedPrimaryKeys(fk, ownerMeta) : Utils.asArray(fk);
1538
+ const key = Utils.getPrimaryKeyHash(pks);
1535
1539
  const entity = item[valueProp];
1536
1540
  if (map[key]) {
1537
1541
  map[key].push(entity);
@@ -1657,8 +1661,19 @@ export class AbstractSqlDriver extends DatabaseDriver {
1657
1661
  const [propName, ref] = hint.field.split(':', 2);
1658
1662
  return { propName, ref, children: hint.children };
1659
1663
  });
1664
+ // with `fixedOrder` the pivot PK is the order column, which is not guaranteed to be unique when the
1665
+ // pivot table is managed externally, so we disambiguate the rows by their FKs on top of the PK
1666
+ const pivotRelations = meta.pivotTable && !meta.compositePK
1667
+ ? meta.relations.filter(p => p.kind === ReferenceKind.MANY_TO_ONE && p.persist !== false)
1668
+ : [];
1660
1669
  for (const item of rawResults) {
1661
- const pk = Utils.getCompositeKeyHash(item, meta);
1670
+ let pk = Utils.getCompositeKeyHash(item, meta);
1671
+ if (pivotRelations.length > 0) {
1672
+ pk = Utils.getPrimaryKeyHash([
1673
+ pk,
1674
+ ...pivotRelations.map(p => Utils.extractPK(item[p.name], p.targetMeta)),
1675
+ ]);
1676
+ }
1662
1677
  if (map[pk]) {
1663
1678
  for (const { propName } of hints) {
1664
1679
  if (!item[propName]) {
@@ -2087,7 +2102,20 @@ export class AbstractSqlDriver extends DatabaseDriver {
2087
2102
  const ret = {};
2088
2103
  for (const prop of meta.relations) {
2089
2104
  if (prop.kind === ReferenceKind.MANY_TO_MANY && data[prop.name]) {
2090
- ret[prop.name] = data[prop.name].map((item) => Utils.asArray(item));
2105
+ // union targets are validated to have a single PK column, so a pivot row is always keyed
2106
+ // by exactly `[discriminator, pk]` - anything else cannot address a target table
2107
+ const discriminators = QueryHelper.isUnionTargetPolymorphic(prop)
2108
+ ? Object.keys(prop.discriminatorMap)
2109
+ : undefined;
2110
+ ret[prop.name] = data[prop.name].map((item) => {
2111
+ const values = Utils.asArray(item);
2112
+ if (discriminators && !(values.length === 2 && discriminators.includes('' + values[0]))) {
2113
+ throw new Error(`Cannot resolve the discriminator value of ${meta.className}.${prop.name} from '${values.join(', ')}', ` +
2114
+ `as the same primary key can exist in any of the target tables. ` +
2115
+ `Pass the target as a [discriminator, ...primaryKey] tuple, e.g. ${JSON.stringify([discriminators[0], ...values])}.`);
2116
+ }
2117
+ return values;
2118
+ });
2091
2119
  delete data[prop.name];
2092
2120
  }
2093
2121
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/sql",
3
- "version": "7.1.9-dev.22",
3
+ "version": "7.1.9-dev.23",
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.22"
56
+ "@mikro-orm/core": "7.1.9-dev.23"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">= 22.17.0"