@mikro-orm/sql 7.0.0-dev.113 → 7.0.0-dev.115

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.
@@ -15,23 +15,23 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
15
15
  getPlatform(): Platform;
16
16
  createEntityManager(useContext?: boolean): this[typeof EntityManagerType];
17
17
  private createQueryBuilderFromOptions;
18
- find<T extends object, P extends string = never, F extends string = PopulatePath.ALL, E extends string = never>(entityName: string, where: ObjectQuery<T>, options?: FindOptions<T, P, F, E>): Promise<EntityData<T>[]>;
19
- findOne<T extends object, P extends string = never, F extends string = PopulatePath.ALL, E extends string = never>(entityName: string, where: ObjectQuery<T>, options?: FindOneOptions<T, P, F, E>): Promise<EntityData<T> | null>;
18
+ find<T extends object, P extends string = never, F extends string = PopulatePath.ALL, E extends string = never>(entityName: EntityName<T>, where: ObjectQuery<T>, options?: FindOptions<T, P, F, E>): Promise<EntityData<T>[]>;
19
+ findOne<T extends object, P extends string = never, F extends string = PopulatePath.ALL, E extends string = never>(entityName: EntityName<T>, where: ObjectQuery<T>, options?: FindOneOptions<T, P, F, E>): Promise<EntityData<T> | null>;
20
20
  protected hasToManyJoins<T extends object>(hint: PopulateOptions<T>, meta: EntityMetadata<T>): boolean;
21
- findVirtual<T extends object>(entityName: string, where: ObjectQuery<T>, options: FindOptions<T, any, any, any>): Promise<EntityData<T>[]>;
22
- countVirtual<T extends object>(entityName: string, where: ObjectQuery<T>, options: CountOptions<T, any>): Promise<number>;
23
- protected findFromVirtual<T extends object>(entityName: string, where: ObjectQuery<T>, options: FindOptions<T, any> | CountOptions<T, any>, type: QueryType): Promise<EntityData<T>[] | number>;
21
+ findVirtual<T extends object>(entityName: EntityName<T>, where: ObjectQuery<T>, options: FindOptions<T, any, any, any>): Promise<EntityData<T>[]>;
22
+ countVirtual<T extends object>(entityName: EntityName<T>, where: ObjectQuery<T>, options: CountOptions<T, any>): Promise<number>;
23
+ protected findFromVirtual<T extends object>(entityName: EntityName<T>, where: ObjectQuery<T>, options: FindOptions<T, any> | CountOptions<T, any>, type: QueryType): Promise<EntityData<T>[] | number>;
24
24
  protected streamFromVirtual<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options: StreamOptions<T, any>): AsyncIterableIterator<EntityData<T>>;
25
25
  protected wrapVirtualExpressionInSubquery<T extends object>(meta: EntityMetadata<T>, expression: string, where: FilterQuery<T>, options: FindOptions<T, any>, type: QueryType): Promise<T[] | number>;
26
26
  protected wrapVirtualExpressionInSubqueryStream<T extends object>(meta: EntityMetadata<T>, expression: string, where: FilterQuery<T>, options: FindOptions<T, any, any, any>, type: QueryType.SELECT): AsyncIterableIterator<T>;
27
27
  mapResult<T extends object>(result: EntityData<T>, meta: EntityMetadata<T>, populate?: PopulateOptions<T>[], qb?: QueryBuilder<T, any, any, any>, map?: Dictionary): EntityData<T> | null;
28
28
  private mapJoinedProps;
29
- count<T extends object>(entityName: string, where: any, options?: CountOptions<T>): Promise<number>;
30
- nativeInsert<T extends object>(entityName: string, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
31
- nativeInsertMany<T extends object>(entityName: string, data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>, transform?: (sql: string) => string): Promise<QueryResult<T>>;
32
- nativeUpdate<T extends object>(entityName: string, where: FilterQuery<T>, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T> & UpsertOptions<T>): Promise<QueryResult<T>>;
33
- nativeUpdateMany<T extends object>(entityName: string, where: FilterQuery<T>[], data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T> & UpsertManyOptions<T>): Promise<QueryResult<T>>;
34
- nativeDelete<T extends object>(entityName: string, where: FilterQuery<T> | string | any, options?: DeleteOptions<T>): Promise<QueryResult<T>>;
29
+ count<T extends object>(entityName: EntityName<T>, where: any, options?: CountOptions<T>): Promise<number>;
30
+ nativeInsert<T extends object>(entityName: EntityName<T>, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
31
+ nativeInsertMany<T extends object>(entityName: EntityName<T>, data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>, transform?: (sql: string) => string): Promise<QueryResult<T>>;
32
+ nativeUpdate<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T> & UpsertOptions<T>): Promise<QueryResult<T>>;
33
+ nativeUpdateMany<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>[], data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T> & UpsertManyOptions<T>): Promise<QueryResult<T>>;
34
+ nativeDelete<T extends object>(entityName: EntityName<T>, where: FilterQuery<T> | string | any, options?: DeleteOptions<T>): Promise<QueryResult<T>>;
35
35
  /**
36
36
  * Fast comparison for collection snapshots that are represented by PK arrays.
37
37
  * Compares scalars via `===` and fallbacks to Utils.equals()` for more complex types like Buffer.
@@ -69,8 +69,8 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
69
69
  ctx?: Transaction;
70
70
  connectionType?: ConnectionType;
71
71
  }): ConnectionType;
72
- protected extractManyToMany<T>(entityName: string, data: EntityDictionary<T>): EntityData<T>;
73
- protected processManyToMany<T extends object>(meta: EntityMetadata<T> | undefined, pks: Primary<T>[], collections: EntityData<T>, clear: boolean, options?: DriverMethodOptions): Promise<void>;
72
+ protected extractManyToMany<T>(meta: EntityMetadata<T>, data: EntityDictionary<T>): EntityData<T>;
73
+ protected processManyToMany<T extends object>(meta: EntityMetadata<T>, pks: Primary<T>[], collections: EntityData<T>, clear: boolean, options?: DriverMethodOptions): Promise<void>;
74
74
  lockPessimistic<T extends object>(entity: T, options: LockOptions): Promise<void>;
75
75
  protected buildPopulateWhere<T extends object>(meta: EntityMetadata<T>, joinedProps: PopulateOptions<T>[], options: Pick<FindOptions<any>, 'populateWhere'>): ObjectQuery<T>;
76
76
  protected buildOrderBy<T extends object>(qb: QueryBuilder<T, any, any, any>, meta: EntityMetadata<T>, populate: PopulateOptions<T>[], options: Pick<FindOptions<any>, 'strategy' | 'orderBy' | 'populateOrderBy'>): QueryOrderMap<T>[];
@@ -25,7 +25,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
25
25
  const connectionType = this.resolveConnectionType({ ctx: options.ctx, connectionType: options.connectionType });
26
26
  const populate = this.autoJoinOneToOneOwner(meta, options.populate, options.fields);
27
27
  const joinedProps = this.joinedProps(meta, populate, options);
28
- const qb = this.createQueryBuilder(meta.className, options.ctx, connectionType, false, options.logging, undefined, options.em);
28
+ const qb = this.createQueryBuilder(meta.class, options.ctx, connectionType, false, options.logging, undefined, options.em);
29
29
  const fields = this.buildFields(meta, populate, joinedProps, qb, qb.alias, options);
30
30
  const orderBy = this.buildOrderBy(qb, meta, populate, options);
31
31
  const populateWhere = this.buildPopulateWhere(meta, joinedProps, options);
@@ -66,8 +66,8 @@ export class AbstractSqlDriver extends DatabaseDriver {
66
66
  }
67
67
  async find(entityName, where, options = {}) {
68
68
  options = { populate: [], orderBy: [], ...options };
69
- const meta = this.metadata.find(entityName);
70
- if (meta?.virtual) {
69
+ const meta = this.metadata.get(entityName);
70
+ if (meta.virtual) {
71
71
  return this.findVirtual(entityName, where, options);
72
72
  }
73
73
  const qb = await this.createQueryBuilderFromOptions(meta, where, options);
@@ -167,7 +167,12 @@ export class AbstractSqlDriver extends DatabaseDriver {
167
167
  async wrapVirtualExpressionInSubquery(meta, expression, where, options, type) {
168
168
  const qb = await this.createQueryBuilderFromOptions(meta, where, options);
169
169
  qb.setFlag(QueryFlag.DISABLE_PAGINATE);
170
- const isCursorPagination = [options.first, options.last, options.before, options.after].some(v => v != null);
170
+ const isCursorPagination = [
171
+ options.first,
172
+ options.last,
173
+ options.before,
174
+ options.after,
175
+ ].some(v => v != null);
171
176
  const native = qb.getNativeQuery(false);
172
177
  if (type === QueryType.COUNT) {
173
178
  native
@@ -221,7 +226,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
221
226
  return;
222
227
  }
223
228
  const pivotRefJoin = prop.kind === ReferenceKind.MANY_TO_MANY && ref;
224
- const meta2 = this.metadata.find(prop.type);
229
+ const meta2 = prop.targetMeta;
225
230
  let path = parentJoinPath ? `${parentJoinPath}.${prop.name}` : `${meta.name}.${prop.name}`;
226
231
  if (!parentJoinPath) {
227
232
  path = '[populate]' + path;
@@ -317,10 +322,10 @@ export class AbstractSqlDriver extends DatabaseDriver {
317
322
  if (prop.kind === ReferenceKind.EMBEDDED && (prop.object || meta.embeddable)) {
318
323
  const item = parseJsonSafe(relationPojo[prop.name]);
319
324
  if (Array.isArray(item)) {
320
- relationPojo[prop.name] = item.map(row => row == null ? row : this.comparator.mapResult(prop.type, row));
325
+ relationPojo[prop.name] = item.map(row => row == null ? row : this.comparator.mapResult(prop.targetMeta, row));
321
326
  }
322
327
  else {
323
- relationPojo[prop.name] = item == null ? item : this.comparator.mapResult(prop.type, item);
328
+ relationPojo[prop.name] = item == null ? item : this.comparator.mapResult(prop.targetMeta, item);
324
329
  }
325
330
  }
326
331
  }
@@ -377,19 +382,18 @@ export class AbstractSqlDriver extends DatabaseDriver {
377
382
  }
378
383
  async nativeInsert(entityName, data, options = {}) {
379
384
  options.convertCustomTypes ??= true;
380
- const meta = this.metadata.find(entityName);
381
- const collections = this.extractManyToMany(entityName, data);
382
- const pks = meta?.primaryKeys ?? [this.config.getNamingStrategy().referenceColumnName()];
385
+ const meta = this.metadata.get(entityName);
386
+ const collections = this.extractManyToMany(meta, data);
383
387
  const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes, options.loggerContext).withSchema(this.getSchemaName(meta, options));
384
388
  const res = await this.rethrow(qb.insert(data).execute('run', false));
385
389
  res.row = res.row || {};
386
390
  let pk;
387
- if (pks.length > 1) { // owner has composite pk
388
- pk = Utils.getPrimaryKeyCond(data, pks);
391
+ if (meta.primaryKeys.length > 1) { // owner has composite pk
392
+ pk = Utils.getPrimaryKeyCond(data, meta.primaryKeys);
389
393
  }
390
394
  else {
391
395
  /* v8 ignore next */
392
- res.insertId = data[pks[0]] ?? res.insertId ?? res.row[pks[0]];
396
+ res.insertId = data[meta.primaryKeys[0]] ?? res.insertId ?? res.row[meta.primaryKeys[0]];
393
397
  pk = [res.insertId];
394
398
  }
395
399
  await this.processManyToMany(meta, pk, collections, false, options);
@@ -398,23 +402,22 @@ export class AbstractSqlDriver extends DatabaseDriver {
398
402
  async nativeInsertMany(entityName, data, options = {}, transform) {
399
403
  options.processCollections ??= true;
400
404
  options.convertCustomTypes ??= true;
401
- const meta = this.metadata.find(entityName)?.root;
402
- const collections = options.processCollections ? data.map(d => this.extractManyToMany(entityName, d)) : [];
403
- const pks = this.getPrimaryKeyFields(entityName);
405
+ const meta = this.metadata.get(entityName).root;
406
+ const collections = options.processCollections ? data.map(d => this.extractManyToMany(meta, d)) : [];
407
+ const pks = this.getPrimaryKeyFields(meta);
404
408
  const set = new Set();
405
409
  data.forEach(row => Utils.keys(row).forEach(k => set.add(k)));
406
- const props = [...set].map(name => meta?.properties[name] ?? { name, fieldNames: [name] });
410
+ const props = [...set].map(name => meta.properties[name] ?? { name, fieldNames: [name] });
407
411
  let fields = Utils.flatten(props.map(prop => prop.fieldNames));
408
412
  const duplicates = Utils.findDuplicates(fields);
409
413
  const params = [];
410
414
  if (duplicates.length) {
411
415
  fields = Utils.unique(fields);
412
416
  }
413
- /* v8 ignore next */
414
- const tableName = meta ? this.getTableName(meta, options) : this.platform.quoteIdentifier(entityName);
417
+ const tableName = this.getTableName(meta, options);
415
418
  let sql = `insert into ${tableName} `;
416
419
  sql += fields.length > 0 ? '(' + fields.map(k => this.platform.quoteIdentifier(k)).join(', ') + ')' : `(${this.platform.quoteIdentifier(pks[0])})`;
417
- if (meta && this.platform.usesOutputStatement()) {
420
+ if (this.platform.usesOutputStatement()) {
418
421
  const returningProps = meta.props
419
422
  .filter(prop => prop.persist !== false && prop.defaultRaw || prop.autoincrement || prop.generated)
420
423
  .filter(prop => !(prop.name in data[0]) || isRaw(data[0][prop.name]));
@@ -531,13 +534,13 @@ export class AbstractSqlDriver extends DatabaseDriver {
531
534
  }
532
535
  async nativeUpdate(entityName, where, data, options = {}) {
533
536
  options.convertCustomTypes ??= true;
534
- const meta = this.metadata.find(entityName);
535
- const pks = this.getPrimaryKeyFields(entityName);
536
- const collections = this.extractManyToMany(entityName, data);
537
+ const meta = this.metadata.get(entityName);
538
+ const pks = this.getPrimaryKeyFields(meta);
539
+ const collections = this.extractManyToMany(meta, data);
537
540
  let res = { affectedRows: 0, insertId: 0, row: {} };
538
541
  if (Utils.isPrimaryKey(where) && pks.length === 1) {
539
542
  /* v8 ignore next */
540
- where = { [meta?.primaryKeys[0] ?? pks[0]]: where };
543
+ where = { [meta.primaryKeys[0] ?? pks[0]]: where };
541
544
  }
542
545
  if (Utils.hasObjectKeys(data)) {
543
546
  const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes, options.loggerContext)
@@ -561,7 +564,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
561
564
  qb.update(data).where(where);
562
565
  // reload generated columns and version fields
563
566
  const returning = [];
564
- meta?.props
567
+ meta.props
565
568
  .filter(prop => (prop.generated && !prop.primary) || prop.version)
566
569
  .forEach(prop => returning.push(prop.name));
567
570
  qb.returning(returning);
@@ -593,7 +596,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
593
596
  }
594
597
  return this.rethrow(qb.execute('run', false));
595
598
  }
596
- const collections = options.processCollections ? data.map(d => this.extractManyToMany(entityName, d)) : [];
599
+ const collections = options.processCollections ? data.map(d => this.extractManyToMany(meta, d)) : [];
597
600
  const keys = new Set();
598
601
  const fields = new Set();
599
602
  const returning = new Set();
@@ -606,7 +609,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
606
609
  }
607
610
  }
608
611
  // reload generated columns and version fields
609
- meta?.props
612
+ meta.props
610
613
  .filter(prop => prop.generated || prop.version || prop.primary)
611
614
  .forEach(prop => returning.add(prop.name));
612
615
  const pkCond = Utils.flatten(meta.primaryKeys.map(pk => meta.properties[pk].fieldNames)).map(pk => `${this.platform.quoteIdentifier(pk)} = ?`).join(' and ');
@@ -699,8 +702,8 @@ export class AbstractSqlDriver extends DatabaseDriver {
699
702
  return res;
700
703
  }
701
704
  async nativeDelete(entityName, where, options = {}) {
702
- const meta = this.metadata.find(entityName);
703
- const pks = this.getPrimaryKeyFields(entityName);
705
+ const meta = this.metadata.get(entityName);
706
+ const pks = this.getPrimaryKeyFields(meta);
704
707
  if (Utils.isPrimaryKey(where) && pks.length === 1) {
705
708
  where = { [pks[0]]: where };
706
709
  }
@@ -753,7 +756,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
753
756
  }
754
757
  if (coll.property.kind === ReferenceKind.ONE_TO_MANY) {
755
758
  const cols = coll.property.referencedColumnNames;
756
- const qb = this.createQueryBuilder(coll.property.type, options?.ctx, 'write')
759
+ const qb = this.createQueryBuilder(coll.property.targetMeta.class, options?.ctx, 'write')
757
760
  .withSchema(this.getSchemaName(meta, options));
758
761
  if (coll.getSnapshot() === undefined) {
759
762
  if (coll.property.orphanRemoval) {
@@ -774,7 +777,6 @@ export class AbstractSqlDriver extends DatabaseDriver {
774
777
  await this.rethrow(query.execute());
775
778
  continue;
776
779
  }
777
- /* v8 ignore next */
778
780
  const pivotMeta = this.metadata.find(coll.property.pivotEntity);
779
781
  let schema = pivotMeta.schema;
780
782
  if (schema === '*') {
@@ -802,10 +804,10 @@ export class AbstractSqlDriver extends DatabaseDriver {
802
804
  if (owners.length === 0) {
803
805
  return {};
804
806
  }
805
- const pivotMeta = this.metadata.find(prop.pivotEntity);
807
+ const pivotMeta = this.metadata.get(prop.pivotEntity);
806
808
  const pivotProp1 = pivotMeta.relations[prop.owner ? 1 : 0];
807
809
  const pivotProp2 = pivotMeta.relations[prop.owner ? 0 : 1];
808
- const ownerMeta = this.metadata.find(pivotProp2.type);
810
+ const ownerMeta = pivotProp2.targetMeta;
809
811
  const cond = {
810
812
  [pivotProp2.name]: { $in: ownerMeta.compositePK ? owners : owners.map(o => o[0]) },
811
813
  };
@@ -820,7 +822,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
820
822
  const fields = pivotJoin
821
823
  ? [pivotProp1.name, pivotProp2.name]
822
824
  : [pivotProp1.name, pivotProp2.name, ...childFields];
823
- const res = await this.find(pivotMeta.className, where, {
825
+ const res = await this.find(pivotMeta.class, where, {
824
826
  ctx,
825
827
  ...options,
826
828
  fields,
@@ -830,7 +832,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
830
832
  populateWhere: undefined,
831
833
  // @ts-ignore
832
834
  _populateWhere: 'infer',
833
- populateFilter: !Utils.isEmpty(options?.populateFilter) ? { [pivotProp2.name]: options?.populateFilter } : undefined,
835
+ populateFilter: !Utils.isEmpty(options?.populateFilter) || RawQueryFragment.hasObjectFragments(options?.populateFilter) ? { [pivotProp2.name]: options?.populateFilter } : undefined,
834
836
  });
835
837
  const map = {};
836
838
  for (const owner of owners) {
@@ -844,7 +846,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
844
846
  return map;
845
847
  }
846
848
  getPivotOrderBy(prop, pivotProp, orderBy, parentOrderBy) {
847
- if (!Utils.isEmpty(orderBy)) {
849
+ if (!Utils.isEmpty(orderBy) || RawQueryFragment.hasObjectFragments(orderBy)) {
848
850
  return Utils.asArray(orderBy).map(o => ({ [pivotProp.name]: o }));
849
851
  }
850
852
  if (prop.kind === ReferenceKind.MANY_TO_MANY && Utils.asArray(parentOrderBy).some(o => o[prop.name])) {
@@ -852,7 +854,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
852
854
  .filter(o => o[prop.name])
853
855
  .map(o => ({ [pivotProp.name]: o[prop.name] }));
854
856
  }
855
- if (!Utils.isEmpty(prop.orderBy)) {
857
+ if (!Utils.isEmpty(prop.orderBy) || RawQueryFragment.hasObjectFragments(prop.orderBy)) {
856
858
  return Utils.asArray(prop.orderBy).map(o => ({ [pivotProp.name]: o }));
857
859
  }
858
860
  if (prop.fixedOrder) {
@@ -865,8 +867,8 @@ export class AbstractSqlDriver extends DatabaseDriver {
865
867
  }
866
868
  async *stream(entityName, where, options) {
867
869
  options = { populate: [], orderBy: [], ...options };
868
- const meta = this.metadata.find(entityName);
869
- if (meta?.virtual) {
870
+ const meta = this.metadata.get(entityName);
871
+ if (meta.virtual) {
870
872
  yield* this.streamFromVirtual(entityName, where, options);
871
873
  return;
872
874
  }
@@ -1003,7 +1005,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
1003
1005
  if (ref && !hint.filter && (prop.kind === ReferenceKind.MANY_TO_ONE || (prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner))) {
1004
1006
  continue;
1005
1007
  }
1006
- const meta2 = this.metadata.find(prop.type);
1008
+ const meta2 = prop.targetMeta;
1007
1009
  const pivotRefJoin = prop.kind === ReferenceKind.MANY_TO_MANY && ref;
1008
1010
  const tableAlias = qb.getNextAlias(prop.name);
1009
1011
  const field = `${options.parentTableAlias}.${prop.name}`;
@@ -1114,26 +1116,20 @@ export class AbstractSqlDriver extends DatabaseDriver {
1114
1116
  }
1115
1117
  return 'write';
1116
1118
  }
1117
- extractManyToMany(entityName, data) {
1118
- if (!this.metadata.has(entityName)) {
1119
- return {};
1120
- }
1119
+ extractManyToMany(meta, data) {
1121
1120
  const ret = {};
1122
- this.metadata.find(entityName).relations.forEach(prop => {
1121
+ for (const prop of meta.relations) {
1123
1122
  if (prop.kind === ReferenceKind.MANY_TO_MANY && data[prop.name]) {
1124
1123
  ret[prop.name] = data[prop.name].map((item) => Utils.asArray(item));
1125
1124
  delete data[prop.name];
1126
1125
  }
1127
- });
1126
+ }
1128
1127
  return ret;
1129
1128
  }
1130
1129
  async processManyToMany(meta, pks, collections, clear, options) {
1131
- if (!meta) {
1132
- return;
1133
- }
1134
1130
  for (const prop of meta.relations) {
1135
1131
  if (collections[prop.name]) {
1136
- const pivotMeta = this.metadata.find(prop.pivotEntity);
1132
+ const pivotMeta = this.metadata.get(prop.pivotEntity);
1137
1133
  const persister = new PivotCollectionPersister(pivotMeta, this, options?.ctx, options?.schema, options?.loggerContext);
1138
1134
  persister.enqueueUpdate(prop, collections[prop.name], clear, pks);
1139
1135
  await this.rethrow(persister.execute());
@@ -1142,7 +1138,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
1142
1138
  }
1143
1139
  async lockPessimistic(entity, options) {
1144
1140
  const meta = helper(entity).__meta;
1145
- const qb = this.createQueryBuilder(entity.constructor.name, options.ctx, undefined, undefined, options.logging).withSchema(options.schema ?? meta.schema);
1141
+ const qb = this.createQueryBuilder(meta.class, options.ctx, undefined, undefined, options.logging).withSchema(options.schema ?? meta.schema);
1146
1142
  const cond = Utils.getPrimaryKeyCond(entity, meta.primaryKeys);
1147
1143
  qb.select(raw('1')).where(cond).setLockMode(options.lockMode, options.lockTableAliases);
1148
1144
  await this.rethrow(qb.execute());
@@ -1152,21 +1148,21 @@ export class AbstractSqlDriver extends DatabaseDriver {
1152
1148
  for (const hint of joinedProps) {
1153
1149
  const [propName] = hint.field.split(':', 2);
1154
1150
  const prop = meta.properties[propName];
1155
- if (!Utils.isEmpty(prop.where)) {
1151
+ if (!Utils.isEmpty(prop.where) || RawQueryFragment.hasObjectFragments(prop.where)) {
1156
1152
  where[prop.name] = Utils.copy(prop.where);
1157
1153
  }
1158
1154
  if (hint.children) {
1159
1155
  const inner = this.buildPopulateWhere(prop.targetMeta, hint.children, {});
1160
- if (!Utils.isEmpty(inner)) {
1156
+ if (!Utils.isEmpty(inner) || RawQueryFragment.hasObjectFragments(inner)) {
1161
1157
  where[prop.name] ??= {};
1162
1158
  Object.assign(where[prop.name], inner);
1163
1159
  }
1164
1160
  }
1165
1161
  }
1166
- if (Utils.isEmpty(options.populateWhere)) {
1162
+ if (Utils.isEmpty(options.populateWhere) && !RawQueryFragment.hasObjectFragments(options.populateWhere)) {
1167
1163
  return where;
1168
1164
  }
1169
- if (Utils.isEmpty(where)) {
1165
+ if (Utils.isEmpty(where) && !RawQueryFragment.hasObjectFragments(where)) {
1170
1166
  return options.populateWhere;
1171
1167
  }
1172
1168
  /* v8 ignore next */
@@ -1178,31 +1174,31 @@ export class AbstractSqlDriver extends DatabaseDriver {
1178
1174
  // as `options.populateWhere` will be always recomputed to respect filters
1179
1175
  const populateWhereAll = options._populateWhere !== 'infer' && !Utils.isEmpty(options._populateWhere);
1180
1176
  const path = (populateWhereAll ? '[populate]' : '') + meta.className;
1177
+ const optionsOrderBy = Utils.asArray(options.orderBy);
1181
1178
  const populateOrderBy = this.buildPopulateOrderBy(qb, meta, Utils.asArray(options.populateOrderBy ?? options.orderBy), path, !!options.populateOrderBy);
1182
1179
  const joinedPropsOrderBy = this.buildJoinedPropsOrderBy(qb, meta, joinedProps, options, path);
1183
- return [...Utils.asArray(options.orderBy), ...populateOrderBy, ...joinedPropsOrderBy];
1180
+ return [...optionsOrderBy, ...populateOrderBy, ...joinedPropsOrderBy];
1184
1181
  }
1185
1182
  buildPopulateOrderBy(qb, meta, populateOrderBy, parentPath, explicit, parentAlias = qb.alias) {
1186
1183
  const orderBy = [];
1187
1184
  for (let i = 0; i < populateOrderBy.length; i++) {
1188
1185
  const orderHint = populateOrderBy[i];
1189
- for (const propName of Utils.keys(orderHint)) {
1190
- const raw = RawQueryFragment.getKnownFragment(propName, explicit);
1191
- if (raw) {
1192
- const sql = raw.sql.replace(new RegExp(ALIAS_REPLACEMENT_RE, 'g'), parentAlias);
1193
- const raw2 = new RawQueryFragment(sql, raw.params);
1194
- orderBy.push({ [raw2]: orderHint[propName] });
1186
+ for (const field of Utils.getObjectQueryKeys(orderHint)) {
1187
+ const childOrder = orderHint[field];
1188
+ if (RawQueryFragment.isKnownFragmentSymbol(field)) {
1189
+ const { sql, params } = RawQueryFragment.getKnownFragment(field);
1190
+ const key = raw(sql.replace(new RegExp(ALIAS_REPLACEMENT_RE, 'g'), parentAlias), params);
1191
+ orderBy.push({ [key]: childOrder });
1195
1192
  continue;
1196
1193
  }
1197
- const prop = meta.properties[propName];
1194
+ const prop = meta.properties[field];
1198
1195
  if (!prop) {
1199
- throw new Error(`Trying to order by not existing property ${meta.className}.${propName}`);
1196
+ throw new Error(`Trying to order by not existing property ${meta.className}.${field}`);
1200
1197
  }
1201
1198
  let path = parentPath;
1202
- const meta2 = this.metadata.find(prop.type);
1203
- const childOrder = orderHint[prop.name];
1199
+ const meta2 = prop.targetMeta;
1204
1200
  if (prop.kind !== ReferenceKind.SCALAR && (![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) || !prop.owner || Utils.isPlainObject(childOrder))) {
1205
- path += `.${propName}`;
1201
+ path += `.${field}`;
1206
1202
  }
1207
1203
  if (prop.kind === ReferenceKind.MANY_TO_MANY && typeof childOrder !== 'object') {
1208
1204
  path += '[pivot]';
@@ -1228,9 +1224,9 @@ export class AbstractSqlDriver extends DatabaseDriver {
1228
1224
  }
1229
1225
  continue;
1230
1226
  }
1231
- const order = typeof childOrder === 'object' ? childOrder[propName] : childOrder;
1227
+ const order = typeof childOrder === 'object' ? childOrder[field] : childOrder;
1232
1228
  if (order) {
1233
- orderBy.push({ [`${propAlias}.${propName}`]: order });
1229
+ orderBy.push({ [`${propAlias}.${field}`]: order });
1234
1230
  }
1235
1231
  }
1236
1232
  }
@@ -1249,22 +1245,23 @@ export class AbstractSqlDriver extends DatabaseDriver {
1249
1245
  }
1250
1246
  const join = qb.getJoinForPath(path, { matchPopulateJoins: true });
1251
1247
  const propAlias = qb.getAliasForJoinPath(join ?? path, { matchPopulateJoins: true });
1252
- const meta2 = this.metadata.find(prop.type);
1248
+ const meta2 = prop.targetMeta;
1253
1249
  if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.fixedOrder && join) {
1254
1250
  const alias = ref ? propAlias : join.ownerAlias;
1255
1251
  orderBy.push({ [`${alias}.${prop.fixedOrderColumn}`]: QueryOrder.ASC });
1256
1252
  }
1257
1253
  if (propOrderBy) {
1258
1254
  for (const item of Utils.asArray(propOrderBy)) {
1259
- for (const field of Utils.keys(item)) {
1260
- const rawField = RawQueryFragment.getKnownFragment(field, false);
1261
- if (rawField) {
1262
- const sql = propAlias ? rawField.sql.replace(new RegExp(ALIAS_REPLACEMENT_RE, 'g'), propAlias) : rawField.sql;
1263
- const raw2 = raw(sql, rawField.params);
1264
- orderBy.push({ [raw2.toString()]: item[field] });
1255
+ for (const field of Utils.getObjectQueryKeys(item)) {
1256
+ const order = item[field];
1257
+ if (RawQueryFragment.isKnownFragmentSymbol(field)) {
1258
+ const { sql, params } = RawQueryFragment.getKnownFragment(field);
1259
+ const sql2 = propAlias ? sql.replace(new RegExp(ALIAS_REPLACEMENT_RE, 'g'), propAlias) : sql;
1260
+ const key = raw(sql2, params);
1261
+ orderBy.push({ [key]: order });
1265
1262
  continue;
1266
1263
  }
1267
- orderBy.push({ [`${propAlias}.${field}`]: item[field] });
1264
+ orderBy.push({ [`${propAlias}.${field}`]: order });
1268
1265
  }
1269
1266
  }
1270
1267
  }
@@ -1332,7 +1329,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
1332
1329
  const prop = QueryHelper.findProperty(rootPropName, {
1333
1330
  metadata: this.metadata,
1334
1331
  platform: this.platform,
1335
- entityName: meta.className,
1332
+ entityName: meta.class,
1336
1333
  where: {},
1337
1334
  aliasMap: qb.getAliasMap(),
1338
1335
  });
@@ -120,7 +120,7 @@ export class PivotCollectionPersister {
120
120
  for (const item of chunk) {
121
121
  cond.$or.push(item.getCondition());
122
122
  }
123
- await this.driver.nativeDelete(this.meta.className, cond, {
123
+ await this.driver.nativeDelete(this.meta.class, cond, {
124
124
  ctx: this.ctx,
125
125
  schema: this.schema,
126
126
  loggerContext: this.loggerContext,
@@ -131,7 +131,7 @@ export class PivotCollectionPersister {
131
131
  const filtered = this.collectStatements(this.inserts);
132
132
  for (let i = 0; i < filtered.length; i += this.batchSize) {
133
133
  const chunk = filtered.slice(i, i + this.batchSize);
134
- await this.driver.nativeInsertMany(this.meta.className, chunk, {
134
+ await this.driver.nativeInsertMany(this.meta.class, chunk, {
135
135
  ctx: this.ctx,
136
136
  schema: this.schema,
137
137
  convertCustomTypes: false,
@@ -144,7 +144,7 @@ export class PivotCollectionPersister {
144
144
  const filtered = this.collectStatements(this.upserts);
145
145
  for (let i = 0; i < filtered.length; i += this.batchSize) {
146
146
  const chunk = filtered.slice(i, i + this.batchSize);
147
- await this.driver.nativeUpdateMany(this.meta.className, [], chunk, {
147
+ await this.driver.nativeUpdateMany(this.meta.class, [], chunk, {
148
148
  ctx: this.ctx,
149
149
  schema: this.schema,
150
150
  convertCustomTypes: false,
@@ -27,7 +27,7 @@ export declare class SqlEntityManager<Driver extends AbstractSqlDriver = Abstrac
27
27
  getKysely<TDB = undefined, TOptions extends GetKyselyOptions = GetKyselyOptions>(options?: TOptions): Kysely<TDB extends undefined ? InferKyselyDB<EntitiesFromManager<this>, TOptions> : TDB>;
28
28
  execute<T extends QueryResult | EntityData<AnyEntity> | EntityData<AnyEntity>[] = EntityData<AnyEntity>[]>(query: string | NativeQueryBuilder | RawQueryFragment, params?: any[], method?: 'all' | 'get' | 'run', loggerContext?: LoggingOptions): Promise<T>;
29
29
  getRepository<T extends object, U extends EntityRepository<T> = SqlEntityRepository<T>>(entityName: EntityName<T>): GetRepository<T, U>;
30
- protected applyDiscriminatorCondition<Entity extends object>(entityName: string, where: FilterQuery<Entity>): FilterQuery<Entity>;
30
+ protected applyDiscriminatorCondition<Entity extends object>(entityName: EntityName<Entity>, where: FilterQuery<Entity>): FilterQuery<Entity>;
31
31
  }
32
32
  type EntitiesFromManager<TEntityManager extends EntityManager<any>> = NonNullable<TEntityManager['~entities']> extends any[] ? (Extract<NonNullable<TEntityManager['~entities']>[number], EntitySchemaWithMeta>) : never;
33
33
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/sql",
3
- "version": "7.0.0-dev.113",
3
+ "version": "7.0.0-dev.115",
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
  "type": "module",
6
6
  "exports": {
@@ -56,6 +56,6 @@
56
56
  "@mikro-orm/core": "^6.6.2"
57
57
  },
58
58
  "peerDependencies": {
59
- "@mikro-orm/core": "7.0.0-dev.113"
59
+ "@mikro-orm/core": "7.0.0-dev.115"
60
60
  }
61
61
  }
@@ -706,7 +706,7 @@ export class MikroTransformer extends OperationNodeTransformer {
706
706
  * Find entity metadata by table name or entity name
707
707
  */
708
708
  findEntityMetadata(name) {
709
- const byEntity = this.metadata.find(name);
709
+ const byEntity = this.metadata.getByClassName(name, false);
710
710
  if (byEntity) {
711
711
  return byEntity;
712
712
  }
@@ -1,4 +1,4 @@
1
- import { type EntityKey, type EntityProperty, type MetadataStorage } from '@mikro-orm/core';
1
+ import { type EntityKey, type EntityProperty, type MetadataStorage, type RawQueryFragmentSymbol, type EntityName } from '@mikro-orm/core';
2
2
  import type { ICriteriaNode, ICriteriaNodeProcessOptions, IQueryBuilder } from '../typings.js';
3
3
  /**
4
4
  * Helper for working with deeply nested where/orderBy/having criteria. Uses composite pattern to build tree from the payload.
@@ -7,14 +7,14 @@ import type { ICriteriaNode, ICriteriaNodeProcessOptions, IQueryBuilder } from '
7
7
  */
8
8
  export declare class CriteriaNode<T extends object> implements ICriteriaNode<T> {
9
9
  protected readonly metadata: MetadataStorage;
10
- readonly entityName: string;
10
+ readonly entityName: EntityName<T>;
11
11
  readonly parent?: ICriteriaNode<T> | undefined;
12
- readonly key?: EntityKey<T> | undefined;
12
+ readonly key?: (EntityKey<T> | RawQueryFragmentSymbol) | undefined;
13
13
  readonly strict: boolean;
14
14
  payload: any;
15
15
  prop?: EntityProperty<T>;
16
16
  index?: number;
17
- constructor(metadata: MetadataStorage, entityName: string, parent?: ICriteriaNode<T> | undefined, key?: EntityKey<T> | undefined, validate?: boolean, strict?: boolean);
17
+ constructor(metadata: MetadataStorage, entityName: EntityName<T>, parent?: ICriteriaNode<T> | undefined, key?: (EntityKey<T> | RawQueryFragmentSymbol) | undefined, validate?: boolean, strict?: boolean);
18
18
  process(qb: IQueryBuilder<T>, options?: ICriteriaNodeProcessOptions): any;
19
19
  unwrap(): any;
20
20
  shouldInline(payload: any): boolean;
@@ -20,7 +20,7 @@ export class CriteriaNode {
20
20
  this.key = key;
21
21
  this.strict = strict;
22
22
  const meta = parent && metadata.find(parent.entityName);
23
- if (meta && key) {
23
+ if (meta && key && !RawQueryFragment.isKnownFragmentSymbol(key)) {
24
24
  const pks = Utils.splitPrimaryKeys(key);
25
25
  if (pks.length > 1) {
26
26
  return;
@@ -29,8 +29,8 @@ export class CriteriaNode {
29
29
  this.prop = meta.props.find(prop => prop.name === k || (prop.fieldNames?.length === 1 && prop.fieldNames[0] === k && prop.persist !== false));
30
30
  const isProp = this.prop || meta.props.find(prop => (prop.fieldNames || []).includes(k));
31
31
  // do not validate if the key is prefixed or type casted (e.g. `k::text`)
32
- if (validate && !isProp && !k.includes('.') && !k.includes('::') && !Utils.isOperator(k) && !RawQueryFragment.isKnownFragment(k)) {
33
- throw new Error(`Trying to query by not existing property ${entityName}.${k}`);
32
+ if (validate && !isProp && !k.includes('.') && !k.includes('::') && !Utils.isOperator(k)) {
33
+ throw new Error(`Trying to query by not existing property ${Utils.className(entityName)}.${k}`);
34
34
  }
35
35
  }
36
36
  }
@@ -50,11 +50,9 @@ export class CriteriaNode {
50
50
  shouldRename(payload) {
51
51
  const type = this.prop ? this.prop.kind : null;
52
52
  const composite = this.prop?.joinColumns ? this.prop.joinColumns.length > 1 : false;
53
- const customExpression = RawQueryFragment.isKnownFragment(this.key);
54
- const scalar = payload === null || Utils.isPrimaryKey(payload) || payload instanceof RegExp || payload instanceof Date || customExpression;
55
- const plainObject = Utils.isPlainObject(payload);
56
- const keys = plainObject ? Object.keys(payload) : [];
57
- const operator = plainObject && keys.every(k => Utils.isOperator(k, false));
53
+ const rawField = RawQueryFragment.isKnownFragmentSymbol(this.key);
54
+ const scalar = payload === null || Utils.isPrimaryKey(payload) || payload instanceof RegExp || payload instanceof Date || rawField;
55
+ const operator = Utils.isPlainObject(payload) && Utils.getObjectQueryKeys(payload).every(k => Utils.isOperator(k, false));
58
56
  if (composite) {
59
57
  return true;
60
58
  }
@@ -81,10 +79,10 @@ export class CriteriaNode {
81
79
  getPath(addIndex = false) {
82
80
  // use index on parent only if we are processing to-many relation
83
81
  const addParentIndex = this.prop && [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(this.prop.kind);
84
- const parentPath = this.parent?.getPath(addParentIndex) ?? this.entityName;
82
+ const parentPath = this.parent?.getPath(addParentIndex) ?? Utils.className(this.entityName);
85
83
  const index = addIndex && this.index != null ? `[${this.index}]` : '';
86
84
  // ignore group operators to allow easier mapping (e.g. for orderBy)
87
- const key = this.key && !['$and', '$or', '$not'].includes(this.key) ? '.' + this.key : '';
85
+ const key = this.key && !RawQueryFragment.isKnownFragmentSymbol(this.key) && !['$and', '$or', '$not'].includes(this.key) ? '.' + this.key : '';
88
86
  const ret = parentPath + index + key;
89
87
  if (this.isPivotJoin()) {
90
88
  // distinguish pivot table join from target entity join
@@ -96,9 +94,9 @@ export class CriteriaNode {
96
94
  if (!this.key || !this.prop) {
97
95
  return false;
98
96
  }
99
- const customExpression = RawQueryFragment.isKnownFragment(this.key);
100
- const scalar = this.payload === null || Utils.isPrimaryKey(this.payload) || this.payload instanceof RegExp || this.payload instanceof Date || customExpression;
101
- const operator = Utils.isObject(this.payload) && Object.keys(this.payload).every(k => Utils.isOperator(k, false));
97
+ const rawField = RawQueryFragment.isKnownFragmentSymbol(this.key);
98
+ const scalar = this.payload === null || Utils.isPrimaryKey(this.payload) || this.payload instanceof RegExp || this.payload instanceof Date || rawField;
99
+ const operator = Utils.isObject(this.payload) && Utils.getObjectQueryKeys(this.payload).every(k => Utils.isOperator(k, false));
102
100
  return this.prop.kind === ReferenceKind.MANY_TO_MANY && (scalar || operator);
103
101
  }
104
102
  getPivotPath(path) {
@@ -111,6 +109,7 @@ export class CriteriaNode {
111
109
  return this.strict;
112
110
  }
113
111
  /** @ignore */
112
+ /* v8 ignore next */
114
113
  [Symbol.for('nodejs.util.inspect.custom')]() {
115
114
  const o = {};
116
115
  ['entityName', 'key', 'index', 'payload']