@mikro-orm/sql 7.1.9-dev.21 → 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
  }
@@ -53,6 +53,7 @@ export declare class MySqlSchemaHelper extends SchemaHelper {
53
53
  getPreAlterTable(tableDiff: TableDifference, safe: boolean): string[];
54
54
  getRenameColumnSQL(tableName: string, oldColumnName: string, to: Column): string;
55
55
  getRenameIndexSQL(tableName: string, index: IndexDef, oldIndexName: string): string[];
56
+ protected hasInlineColumnComment(): boolean;
56
57
  getChangeColumnCommentSQL(tableName: string, to: Column, schemaName?: string): string;
57
58
  alterTableColumn(column: Column, table: DatabaseTable, changedProperties: Set<string>): string[];
58
59
  private getColumnDeclarationSQL;
@@ -540,6 +540,9 @@ export class MySqlSchemaHelper extends SchemaHelper {
540
540
  const keyName = this.quote(index.keyName);
541
541
  return [`alter table ${tableName} rename index ${oldIndexName} to ${keyName}`];
542
542
  }
543
+ hasInlineColumnComment() {
544
+ return true;
545
+ }
543
546
  getChangeColumnCommentSQL(tableName, to, schemaName) {
544
547
  tableName = this.quote(tableName);
545
548
  const columnName = this.quote(to.name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/sql",
3
- "version": "7.1.9-dev.21",
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.21"
56
+ "@mikro-orm/core": "7.1.9-dev.23"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">= 22.17.0"
@@ -143,6 +143,8 @@ export declare abstract class SchemaHelper {
143
143
  }[];
144
144
  }[], safe: boolean): string[];
145
145
  getChangeColumnCommentSQL(tableName: string, to: Column, schemaName?: string): string;
146
+ /** Whether the column comment is part of the column declaration, as opposed to a separate statement. */
147
+ protected hasInlineColumnComment(): boolean;
146
148
  getNamespaces(connection: AbstractSqlConnection, ctx?: Transaction): Promise<string[]>;
147
149
  protected mapIndexes(indexes: IndexDef[]): Promise<IndexDef[]>;
148
150
  mapForeignKeys(fks: any[], tableName: string, schemaName?: string): Dictionary;
@@ -446,7 +446,8 @@ export class SchemaHelper {
446
446
  this.append(ret, this.alterTableColumn(column, diff.fromTable, changedProperties));
447
447
  }
448
448
  for (const { column, changedProperties } of Object.values(diff.changedColumns).filter(diff => diff.changedProperties.has('comment'))) {
449
- if (['type', 'nullable', 'autoincrement', 'unsigned', 'default', 'enumItems', 'collation'].some(t => changedProperties.has(t))) {
449
+ if (this.hasInlineColumnComment() &&
450
+ ['type', 'nullable', 'autoincrement', 'unsigned', 'default', 'enumItems', 'collation'].some(t => changedProperties.has(t))) {
450
451
  continue; // will be handled via column update
451
452
  }
452
453
  ret.push(this.getChangeColumnCommentSQL(tableName, column, schemaName));
@@ -499,7 +500,13 @@ export class SchemaHelper {
499
500
  return `add ${this.createTableColumn(column, table)}`;
500
501
  })
501
502
  .join(', ');
502
- return [`alter table ${table.getQuotedName()} ${adds}`];
503
+ const ret = [`alter table ${table.getQuotedName()} ${adds}`];
504
+ if (!this.hasInlineColumnComment()) {
505
+ for (const column of columns.filter(column => column.comment)) {
506
+ ret.push(this.getChangeColumnCommentSQL(table.name, column, table.schema));
507
+ }
508
+ }
509
+ return ret;
503
510
  }
504
511
  getDropColumnsSQL(tableName, columns, schemaName) {
505
512
  const name = this.quote(this.getTableName(tableName, schemaName));
@@ -618,6 +625,10 @@ export class SchemaHelper {
618
625
  getChangeColumnCommentSQL(tableName, to, schemaName) {
619
626
  return '';
620
627
  }
628
+ /** Whether the column comment is part of the column declaration, as opposed to a separate statement. */
629
+ hasInlineColumnComment() {
630
+ return false;
631
+ }
621
632
  async getNamespaces(connection, ctx) {
622
633
  return [];
623
634
  }