@mikro-orm/knex 6.0.0-dev.111 → 6.0.0-dev.113

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.
@@ -29,7 +29,7 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
29
29
  nativeUpdateMany<T extends object>(entityName: string, where: FilterQuery<T>[], data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T> & UpsertManyOptions<T>): Promise<QueryResult<T>>;
30
30
  nativeDelete<T extends object>(entityName: string, where: FilterQuery<T> | string | any, options?: DeleteOptions<T>): Promise<QueryResult<T>>;
31
31
  syncCollection<T extends object, O extends object>(coll: Collection<T, O>, options?: DriverMethodOptions): Promise<void>;
32
- loadFromPivotTable<T extends object, O extends object>(prop: EntityProperty, owners: Primary<O>[][], where?: FilterQuery<any>, orderBy?: OrderDefinition<T>, ctx?: Transaction, options?: FindOptions<T, any, any>): Promise<Dictionary<T[]>>;
32
+ loadFromPivotTable<T extends object, O extends object>(prop: EntityProperty, owners: Primary<O>[][], where?: FilterQuery<any>, orderBy?: OrderDefinition<T>, ctx?: Transaction, options?: FindOptions<T, any, any>, pivotJoin?: boolean): Promise<Dictionary<T[]>>;
33
33
  private getPivotOrderBy;
34
34
  execute<T extends QueryResult | EntityData<AnyEntity> | EntityData<AnyEntity>[] = EntityData<AnyEntity>[]>(queryOrKnex: string | Knex.QueryBuilder | Knex.Raw, params?: any[], method?: 'all' | 'get' | 'run', ctx?: Transaction): Promise<T>;
35
35
  /**
@@ -61,5 +61,5 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
61
61
  protected buildJoinedPropsOrderBy<T extends object>(entityName: string, qb: QueryBuilder<T>, meta: EntityMetadata<T>, populate: PopulateOptions<T>[], parentPath?: string): QueryOrderMap<T>[];
62
62
  protected normalizeFields<T extends object>(fields: Field<T>[], prefix?: string): string[];
63
63
  protected processField<T extends object>(meta: EntityMetadata<T>, prop: EntityProperty<T> | undefined, field: string, ret: Field<T>[], populate: PopulateOptions<T>[], joinedProps: PopulateOptions<T>[], qb: QueryBuilder<T>): void;
64
- protected buildFields<T extends object>(meta: EntityMetadata<T>, populate: PopulateOptions<T>[], joinedProps: PopulateOptions<T>[], qb: QueryBuilder<T>, fields?: Field<T>[]): Field<T>[];
64
+ protected buildFields<T extends object>(meta: EntityMetadata<T>, populate: PopulateOptions<T>[], joinedProps: PopulateOptions<T>[], qb: QueryBuilder<T>, alias: string, fields?: Field<T>[]): Field<T>[];
65
65
  }
@@ -30,7 +30,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
30
30
  const populate = this.autoJoinOneToOneOwner(meta, options.populate, options.fields);
31
31
  const joinedProps = this.joinedProps(meta, populate);
32
32
  const qb = this.createQueryBuilder(entityName, options.ctx, options.connectionType, false, options.logging);
33
- const fields = this.buildFields(meta, populate, joinedProps, qb, options.fields);
33
+ const fields = this.buildFields(meta, populate, joinedProps, qb, qb.alias, options.fields);
34
34
  const joinedPropsOrderBy = this.buildJoinedPropsOrderBy(entityName, qb, meta, joinedProps);
35
35
  const orderBy = [...core_1.Utils.asArray(options.orderBy), ...joinedPropsOrderBy];
36
36
  if (core_1.Utils.isPrimaryKey(where, meta.compositePK)) {
@@ -575,18 +575,18 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
575
575
  }
576
576
  return this.rethrow(this.updateCollectionDiff(meta, coll.property, pks, deleteDiff, insertDiff, options));
577
577
  }
578
- async loadFromPivotTable(prop, owners, where = {}, orderBy, ctx, options) {
579
- const pivotProp2 = this.getPivotInverseProperty(prop);
580
- const prop2 = prop.targetMeta.properties[prop.mappedBy ?? prop.inversedBy];
581
- const ownerMeta = this.metadata.find(pivotProp2.type);
578
+ async loadFromPivotTable(prop, owners, where = {}, orderBy, ctx, options, pivotJoin) {
582
579
  const pivotMeta = this.metadata.find(prop.pivotEntity);
580
+ const pivotProp1 = pivotMeta.relations[prop.owner ? 1 : 0];
581
+ const pivotProp2 = pivotMeta.relations[prop.owner ? 0 : 1];
582
+ const ownerMeta = this.metadata.find(pivotProp2.type);
583
583
  options = { ...options };
584
- const qb = this.createQueryBuilder(prop.type, ctx, options.connectionType)
585
- .withSchema(this.getSchemaName(prop.targetMeta, options))
584
+ const qb = this.createQueryBuilder(prop.pivotEntity, ctx, options.connectionType)
585
+ .withSchema(this.getSchemaName(pivotMeta, options))
586
586
  .indexHint(options.indexHint)
587
587
  .comment(options.comments)
588
588
  .hintComment(options.hintComments);
589
- const pivotAlias = qb.getNextAlias(pivotMeta.tableName);
589
+ const pivotAlias = qb.alias;
590
590
  const pivotKey = pivotProp2.joinColumns.map(column => `${pivotAlias}.${column}`).join(core_1.Utils.PK_SEPARATOR);
591
591
  const cond = {
592
592
  [pivotKey]: { $in: ownerMeta.compositePK ? owners : owners.map(o => o[0]) },
@@ -598,9 +598,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
598
598
  else {
599
599
  where = { ...where, ...cond };
600
600
  }
601
- orderBy = this.getPivotOrderBy(prop, pivotAlias, orderBy);
601
+ orderBy = this.getPivotOrderBy(prop, pivotProp1, pivotAlias, orderBy);
602
602
  const populate = this.autoJoinOneToOneOwner(prop.targetMeta, []);
603
- const fields = this.buildFields(prop.targetMeta, (options.populate ?? []), [], qb, options.fields);
603
+ const fields = [];
604
604
  const k1 = !prop.owner ? 'joinColumns' : 'inverseJoinColumns';
605
605
  const k2 = prop.owner ? 'joinColumns' : 'inverseJoinColumns';
606
606
  const cols = [
@@ -608,25 +608,36 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
608
608
  ...prop[k2].map(col => `${pivotAlias}.${col} as fk__${col}`),
609
609
  ];
610
610
  fields.push(...cols);
611
+ if (!pivotJoin) {
612
+ const targetAlias = qb.getNextAlias(prop.targetMeta.tableName);
613
+ const targetSchema = this.getSchemaName(prop.targetMeta, options) ?? this.platform.getDefaultSchemaName();
614
+ qb.innerJoin(pivotProp1.name, targetAlias, {}, targetSchema);
615
+ const targetFields = this.buildFields(prop.targetMeta, (options.populate ?? []), [], qb, targetAlias, options.fields);
616
+ for (const field of targetFields) {
617
+ const f = field.toString();
618
+ fields.unshift(f.includes('.') ? field : `${targetAlias}.${f}`);
619
+ }
620
+ // we need to handle 1:1 owner auto-joins explicitly, as the QB type is the pivot table, not the target
621
+ populate.forEach(hint => {
622
+ const alias = qb.getNextAlias(prop.targetMeta.tableName);
623
+ qb.leftJoin(`${targetAlias}.${hint.field}`, alias);
624
+ // eslint-disable-next-line dot-notation
625
+ Object.values(qb['_joins']).forEach(join => {
626
+ if (join.alias === alias && join.prop.name === hint.field) {
627
+ fields.push(...qb.helper.mapJoinColumns(qb.type, join));
628
+ }
629
+ });
630
+ });
631
+ }
611
632
  qb.select(fields)
612
- .join(prop2.name, pivotAlias, {}, 'pivotJoin', undefined, options.schema)
613
- .populate(populate)
614
- .where(where)
633
+ .where({ [pivotProp1.name]: where })
615
634
  .orderBy(orderBy)
616
635
  .setLockMode(options.lockMode, options.lockTableAliases);
617
636
  if (owners.length === 1 && (options.offset != null || options.limit != null)) {
618
637
  qb.limit(options.limit, options.offset);
619
638
  }
620
- const schema = this.config.get('schema');
621
- if (prop.targetMeta.schema !== '*' && pivotMeta.schema === '*' && options.schema) {
622
- // eslint-disable-next-line dot-notation
623
- qb['finalize']();
624
- // eslint-disable-next-line dot-notation
625
- Object.values(qb['_joins']).forEach(join => {
626
- join.schema = schema;
627
- });
628
- }
629
- const items = owners.length ? await this.rethrow(qb.execute('all')) : [];
639
+ const res = owners.length ? await this.rethrow(qb.execute('all', false)) : [];
640
+ const items = res.map((row) => super.mapResult(row, prop.targetMeta));
630
641
  const map = {};
631
642
  const pkProps = ownerMeta.getPrimaryProps();
632
643
  owners.forEach(owner => {
@@ -643,16 +654,19 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
643
654
  }));
644
655
  map[key].push(item);
645
656
  prop.joinColumns.forEach(col => delete item[`fk__${col}`]);
646
- prop.inverseJoinColumns.forEach(col => delete item[`fk__${col}`]);
657
+ prop.inverseJoinColumns.forEach((col, idx) => {
658
+ core_1.Utils.renameKey(item, `fk__${col}`, prop.targetMeta.primaryKeys[idx]);
659
+ });
647
660
  });
648
661
  return map;
649
662
  }
650
- getPivotOrderBy(prop, pivotAlias, orderBy) {
663
+ getPivotOrderBy(prop, pivotProp, pivotAlias, orderBy) {
664
+ // FIXME this is ignoring the rest of the array items
651
665
  if (!core_1.Utils.isEmpty(orderBy)) {
652
- return orderBy;
666
+ return [{ [pivotProp.name]: core_1.Utils.asArray(orderBy)[0] }];
653
667
  }
654
668
  if (!core_1.Utils.isEmpty(prop.orderBy)) {
655
- return core_1.Utils.asArray(prop.orderBy);
669
+ return [{ [pivotProp.name]: core_1.Utils.asArray(prop.orderBy)[0] }];
656
670
  }
657
671
  if (prop.fixedOrder) {
658
672
  return [{ [`${pivotAlias}.${prop.fixedOrderColumn}`]: core_1.QueryOrder.ASC }];
@@ -728,7 +742,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
728
742
  .filter(prop => shouldHaveColumn(prop, populate, explicitFields))
729
743
  .forEach(prop => fields.push(...this.mapPropToFieldNames(qb, prop, parentTableAlias)));
730
744
  joinedProps.forEach(relation => {
731
- const prop = meta.properties[relation.field];
745
+ const [propName] = relation.field.split(':', 2);
746
+ const prop = meta.properties[propName];
732
747
  const meta2 = this.metadata.find(prop.type);
733
748
  const tableAlias = qb.getNextAlias(prop.name);
734
749
  const field = parentTableAlias ? `${parentTableAlias}.${prop.name}` : prop.name;
@@ -858,7 +873,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
858
873
  const orderBy = [];
859
874
  const joinedProps = this.joinedProps(meta, populate);
860
875
  joinedProps.forEach(relation => {
861
- const prop = meta.properties[relation.field];
876
+ const [propName] = relation.field.split(':', 2);
877
+ const prop = meta.properties[propName];
862
878
  const propOrderBy = prop.orderBy;
863
879
  const path = `${parentPath ? parentPath : entityName}.${relation.field}`;
864
880
  const propAlias = qb.getAliasForJoinPath(path);
@@ -909,7 +925,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
909
925
  }
910
926
  ret.push(prop.name);
911
927
  }
912
- buildFields(meta, populate, joinedProps, qb, fields) {
928
+ buildFields(meta, populate, joinedProps, qb, alias, fields) {
913
929
  const lazyProps = meta.props.filter(prop => prop.lazy && !populate.some(p => p.field === prop.name || p.all));
914
930
  const hasLazyFormulas = meta.props.some(p => p.lazy && p.formula);
915
931
  const requiresSQLConversion = meta.props.some(p => p.customType?.convertToJSValueSQL);
@@ -951,9 +967,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
951
967
  meta.props
952
968
  .filter(prop => prop.formula && !lazyProps.includes(prop))
953
969
  .forEach(prop => {
954
- const alias = this.connection.getKnex().ref(qb.alias).toString();
970
+ const a = this.connection.getKnex().ref(alias).toString();
955
971
  const aliased = this.connection.getKnex().ref(prop.fieldNames[0]).toString();
956
- ret.push((0, core_1.raw)(`${prop.formula(alias)} as ${aliased}`));
972
+ ret.push((0, core_1.raw)(`${prop.formula(a)} as ${aliased}`));
957
973
  });
958
974
  meta.props
959
975
  .filter(prop => prop.hasConvertToDatabaseValueSQL || prop.hasConvertToJSValueSQL)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/knex",
3
- "version": "6.0.0-dev.111",
3
+ "version": "6.0.0-dev.113",
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",
@@ -63,9 +63,9 @@
63
63
  "sqlstring": "2.3.3"
64
64
  },
65
65
  "devDependencies": {
66
- "@mikro-orm/core": "^5.8.5"
66
+ "@mikro-orm/core": "^5.8.6"
67
67
  },
68
68
  "peerDependencies": {
69
- "@mikro-orm/core": "6.0.0-dev.111"
69
+ "@mikro-orm/core": "6.0.0-dev.113"
70
70
  }
71
71
  }
@@ -274,6 +274,7 @@ class QueryBuilder {
274
274
  aliasMap: this.getAliasMap(),
275
275
  aliased: !this.type || [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
276
276
  convertCustomTypes: false,
277
+ type: 'orderBy',
277
278
  });
278
279
  this._orderBy.push(CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, processed).process(this));
279
280
  });
@@ -26,7 +26,7 @@ export declare class QueryBuilderHelper {
26
26
  private processJoinClause;
27
27
  private wrapQueryGroup;
28
28
  mapJoinColumns(type: QueryType, join: JoinOptions): (string | Knex.Raw)[];
29
- isOneToOneInverse(field: string): boolean;
29
+ isOneToOneInverse(field: string, meta?: EntityMetadata): boolean;
30
30
  getTableName(entityName: string): string;
31
31
  /**
32
32
  * Checks whether the RE can be rewritten to simple LIKE query
@@ -157,6 +157,8 @@ class QueryBuilderHelper {
157
157
  const prop2 = prop.owner ? pivotMeta.relations[1] : pivotMeta.relations[0];
158
158
  ret[`${pivotAlias}.${prop2.name}#${alias}`] = this.joinManyToOneReference(prop2, pivotAlias, alias, type, cond, schema);
159
159
  ret[`${pivotAlias}.${prop2.name}#${alias}`].path = path;
160
+ const tmp = prop2.referencedTableName.split('.');
161
+ ret[`${pivotAlias}.${prop2.name}#${alias}`].schema ??= tmp.length > 1 ? tmp[0] : undefined;
160
162
  return ret;
161
163
  }
162
164
  processJoins(qb, joins, schema) {
@@ -177,7 +179,7 @@ class QueryBuilderHelper {
177
179
  conditions.push(`${left} = ${this.knex.ref(right)}`);
178
180
  return;
179
181
  }
180
- const left = join.prop.kind === core_1.ReferenceKind.SCALAR && join.prop.persist === false ? primaryKey : `${join.ownerAlias}.${primaryKey}`;
182
+ const left = `${join.ownerAlias}.${primaryKey}`;
181
183
  conditions.push(`${this.knex.ref(left)} = ${this.knex.ref(right)}`);
182
184
  });
183
185
  }
@@ -282,8 +284,8 @@ class QueryBuilderHelper {
282
284
  ...join.inverseJoinColumns.map(col => this.mapper(`${join.alias}.${col}`, type, undefined, `fk__${col}`)),
283
285
  ];
284
286
  }
285
- isOneToOneInverse(field) {
286
- const meta = this.metadata.find(this.entityName);
287
+ isOneToOneInverse(field, meta) {
288
+ meta ??= this.metadata.find(this.entityName);
287
289
  const prop = meta.properties[field];
288
290
  return prop && prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner;
289
291
  }
@@ -474,7 +476,12 @@ class QueryBuilderHelper {
474
476
  if (core_1.Utils.isRawSql(colPart)) {
475
477
  colPart = this.platform.formatQuery(colPart.sql, colPart.params);
476
478
  }
477
- ret.push(`${colPart} ${order.toLowerCase()}`);
479
+ if (Array.isArray(order)) {
480
+ order.forEach(part => ret.push(this.getQueryOrderFromObject(type, part, populate)));
481
+ }
482
+ else {
483
+ ret.push(`${colPart} ${order.toLowerCase()}`);
484
+ }
478
485
  });
479
486
  });
480
487
  return ret.join(', ');