@mikro-orm/knex 6.6.7-dev.5 → 6.6.7-dev.6

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.
@@ -19,7 +19,12 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
19
19
  findVirtual<T extends object>(entityName: string, where: ObjectQuery<T>, options: FindOptions<T, any, any, any>): Promise<EntityData<T>[]>;
20
20
  countVirtual<T extends object>(entityName: string, where: ObjectQuery<T>, options: CountOptions<T, any>): Promise<number>;
21
21
  protected findFromVirtual<T extends object>(entityName: string, where: ObjectQuery<T>, options: FindOptions<T, any> | CountOptions<T, any>, type: QueryType): Promise<EntityData<T>[] | number>;
22
- protected wrapVirtualExpressionInSubquery<T extends object>(meta: EntityMetadata<T>, expression: string, where: FilterQuery<T>, options: FindOptions<T, any>, type: QueryType): Promise<T[] | number>;
22
+ protected wrapVirtualExpressionInSubquery<T extends object>(meta: EntityMetadata<T>, expression: string, where: FilterQuery<T>, options: FindOptions<T, any, any, any>, type: QueryType): Promise<T[] | number>;
23
+ /**
24
+ * Virtual entities have no PKs, so to-many populate joins can't be deduplicated.
25
+ * Force balanced strategy to load to-many relations via separate queries.
26
+ */
27
+ private forceBalancedStrategy;
23
28
  mapResult<T extends object>(result: EntityData<T>, meta: EntityMetadata<T>, populate?: PopulateOptions<T>[], qb?: QueryBuilder<T, any, any, any>, map?: Dictionary): EntityData<T> | null;
24
29
  private mapJoinedProps;
25
30
  count<T extends object>(entityName: string, where: any, options?: CountOptions<T>): Promise<number>;
@@ -140,6 +140,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
140
140
  .comment(options.comments)
141
141
  .hintComment(options.hintComments);
142
142
  qb.where(where);
143
+ options = this.forceBalancedStrategy(options);
143
144
  const { first, last, before, after } = options;
144
145
  const isCursorPagination = [first, last, before, after].some(v => v != null);
145
146
  if (type !== query_1.QueryType.COUNT) {
@@ -171,6 +172,24 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
171
172
  }
172
173
  return res.map(row => this.mapResult(row, meta));
173
174
  }
175
+ /**
176
+ * Virtual entities have no PKs, so to-many populate joins can't be deduplicated.
177
+ * Force balanced strategy to load to-many relations via separate queries.
178
+ */
179
+ forceBalancedStrategy(options) {
180
+ const clearStrategy = (hints) => {
181
+ return hints.map(hint => ({
182
+ ...hint,
183
+ strategy: undefined,
184
+ children: hint.children ? clearStrategy(hint.children) : undefined,
185
+ }));
186
+ };
187
+ const opts = { ...options, strategy: 'balanced' };
188
+ if (Array.isArray(opts.populate)) {
189
+ opts.populate = clearStrategy(opts.populate);
190
+ }
191
+ return opts;
192
+ }
174
193
  mapResult(result, meta, populate = [], qb, map = {}) {
175
194
  const ret = super.mapResult(result, meta);
176
195
  /* istanbul ignore if */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/knex",
3
- "version": "6.6.7-dev.5",
3
+ "version": "6.6.7-dev.6",
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",
@@ -66,7 +66,7 @@
66
66
  "@mikro-orm/core": "^6.6.6"
67
67
  },
68
68
  "peerDependencies": {
69
- "@mikro-orm/core": "6.6.7-dev.5",
69
+ "@mikro-orm/core": "6.6.7-dev.6",
70
70
  "better-sqlite3": "*",
71
71
  "libsql": "*",
72
72
  "mariadb": "*"
@@ -83,7 +83,7 @@ class ObjectCriteriaNode extends CriteriaNode_1.CriteriaNode {
83
83
  const operator = core_1.Utils.isOperator(field);
84
84
  const isRawField = core_1.RawQueryFragment.isKnownFragment(field);
85
85
  // we need to keep the prefixing for formulas otherwise we would lose aliasing context when nesting inside group operators
86
- const virtual = childNode.prop?.persist === false && !childNode.prop?.formula;
86
+ const virtual = childNode.prop?.persist === false && !childNode.prop?.formula && !!options?.type;
87
87
  // if key is missing, we are inside group operator and we need to prefix with alias
88
88
  const primaryKey = this.key && this.metadata.find(this.entityName).primaryKeys.includes(field);
89
89
  const isToOne = childNode.prop && [core_1.ReferenceKind.MANY_TO_ONE, core_1.ReferenceKind.ONE_TO_ONE].includes(childNode.prop.kind);
@@ -398,7 +398,7 @@ class QueryBuilder {
398
398
  if (core_1.Utils.isString(cond)) {
399
399
  cond = { [(0, core_1.raw)(`(${cond})`, params)]: [] };
400
400
  }
401
- cond = CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond).process(this);
401
+ cond = CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond).process(this, { type: 'having' });
402
402
  if (!this._having || !operator) {
403
403
  this._having = cond;
404
404
  }
@@ -1193,7 +1193,7 @@ class QueryBuilder {
1193
1193
  if (!this.flags.has(core_1.QueryFlag.DISABLE_PAGINATE) && this._groupBy.length === 0 && this.hasToManyJoins()) {
1194
1194
  this.flags.add(core_1.QueryFlag.PAGINATE);
1195
1195
  }
1196
- if (meta && this.flags.has(core_1.QueryFlag.PAGINATE) && (this._limit > 0 || this._offset > 0)) {
1196
+ if (meta && !meta.virtual && this.flags.has(core_1.QueryFlag.PAGINATE) && (this._limit > 0 || this._offset > 0)) {
1197
1197
  this.wrapPaginateSubQuery(meta);
1198
1198
  }
1199
1199
  if (meta && (this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(core_1.QueryFlag.DELETE_SUB_QUERY))) {
package/typings.d.ts CHANGED
@@ -172,7 +172,7 @@ export interface ICriteriaNodeProcessOptions {
172
172
  matchPopulateJoins?: boolean;
173
173
  ignoreBranching?: boolean;
174
174
  preferNoBranch?: boolean;
175
- type?: 'orderBy';
175
+ type?: 'orderBy' | 'having';
176
176
  filter?: boolean;
177
177
  }
178
178
  export interface ICriteriaNode<T extends object> {