@mikro-orm/core 7.0.0-dev.291 → 7.0.0-dev.293

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.
@@ -121,6 +121,7 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
121
121
  }): T;
122
122
  setFlushMode(flushMode?: FlushMode | `${FlushMode}`): void;
123
123
  protected processWhere<Entity extends object, Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(entityName: EntityName<Entity>, where: FilterQuery<Entity>, options: FindOptions<Entity, Hint, Fields, Excludes> | FindOneOptions<Entity, Hint, Fields, Excludes>, type: 'read' | 'update' | 'delete'): Promise<FilterQuery<Entity>>;
124
+ protected processUnionWhere<Entity extends object, Hint extends string = never>(entityName: EntityName<Entity>, options: FindOptions<Entity, Hint, any, any> | CountOptions<Entity, Hint> | UpdateOptions<Entity> | DeleteOptions<Entity>, type: 'read' | 'update' | 'delete'): Promise<void>;
124
125
  protected applyDiscriminatorCondition<Entity extends object>(entityName: EntityName<Entity>, where: FilterQuery<Entity>): FilterQuery<Entity>;
125
126
  protected createPopulateWhere<Entity extends object>(cond: ObjectQuery<Entity>, options: FindOptions<Entity, any, any, any> | FindOneOptions<Entity, any, any, any> | CountOptions<Entity, any>): ObjectQuery<Entity>;
126
127
  protected getJoinedFilters<Entity extends object>(meta: EntityMetadata<Entity>, options: FindOptions<Entity, any, any, any> | FindOneOptions<Entity, any, any, any>): Promise<ObjectQuery<Entity> | undefined>;
package/EntityManager.js CHANGED
@@ -141,6 +141,7 @@ export class EntityManager {
141
141
  options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
142
142
  options.populateWhere = this.createPopulateWhere({ ...where }, options);
143
143
  options.populateFilter = await this.getJoinedFilters(meta, options);
144
+ await em.processUnionWhere(entityName, options, 'read');
144
145
  const results = await em.driver.find(entityName, where, { ctx: em.transactionContext, em, ...options });
145
146
  if (results.length === 0) {
146
147
  await em.storeCache(options.cache, cached, []);
@@ -298,6 +299,14 @@ export class EntityManager {
298
299
  where = this.applyDiscriminatorCondition(entityName, where);
299
300
  return where;
300
301
  }
302
+ async processUnionWhere(entityName, options, type) {
303
+ if (options.unionWhere?.length) {
304
+ if (!this.driver.getPlatform().supportsUnionWhere()) {
305
+ throw new Error(`unionWhere is only supported on SQL drivers`);
306
+ }
307
+ options.unionWhere = await Promise.all(options.unionWhere.map(branch => this.processWhere(entityName, branch, options, type)));
308
+ }
309
+ }
301
310
  // this method only handles the problem for mongo driver, SQL drivers have their implementation inside QueryBuilder
302
311
  applyDiscriminatorCondition(entityName, where) {
303
312
  const meta = this.metadata.find(entityName);
@@ -642,6 +651,7 @@ export class EntityManager {
642
651
  options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
643
652
  options.populateWhere = this.createPopulateWhere({ ...where }, options);
644
653
  options.populateFilter = await this.getJoinedFilters(meta, options);
654
+ await em.processUnionWhere(entityName, options, 'read');
645
655
  const data = await em.driver.findOne(entityName, where, {
646
656
  ctx: em.transactionContext,
647
657
  em,
@@ -1188,11 +1198,12 @@ export class EntityManager {
1188
1198
  async nativeUpdate(entityName, where, data, options = {}) {
1189
1199
  const em = this.getContext(false);
1190
1200
  em.prepareOptions(options);
1201
+ await em.processUnionWhere(entityName, options, 'update');
1191
1202
  data = QueryHelper.processObjectParams(data);
1192
1203
  where = await em.processWhere(entityName, where, { ...options, convertCustomTypes: false }, 'update');
1193
1204
  validateParams(data, 'update data');
1194
1205
  validateParams(where, 'update condition');
1195
- const res = await em.driver.nativeUpdate(entityName, where, data, { ctx: em.transactionContext, ...options });
1206
+ const res = await em.driver.nativeUpdate(entityName, where, data, { ctx: em.transactionContext, em, ...options });
1196
1207
  return res.affectedRows;
1197
1208
  }
1198
1209
  /**
@@ -1201,9 +1212,10 @@ export class EntityManager {
1201
1212
  async nativeDelete(entityName, where, options = {}) {
1202
1213
  const em = this.getContext(false);
1203
1214
  em.prepareOptions(options);
1215
+ await em.processUnionWhere(entityName, options, 'delete');
1204
1216
  where = await em.processWhere(entityName, where, options, 'delete');
1205
1217
  validateParams(where, 'delete condition');
1206
- const res = await em.driver.nativeDelete(entityName, where, { ctx: em.transactionContext, ...options });
1218
+ const res = await em.driver.nativeDelete(entityName, where, { ctx: em.transactionContext, em, ...options });
1207
1219
  return res.affectedRows;
1208
1220
  }
1209
1221
  /**
@@ -1322,6 +1334,7 @@ export class EntityManager {
1322
1334
  options.populateFilter = await this.getJoinedFilters(meta, options);
1323
1335
  validateParams(where);
1324
1336
  delete options.orderBy;
1337
+ await em.processUnionWhere(entityName, options, 'read');
1325
1338
  const cacheKey = em.cacheKey(entityName, options, 'em.count', where);
1326
1339
  const cached = await em.tryCache(entityName, options.cache, cacheKey);
1327
1340
  if (cached?.data !== undefined) {
@@ -110,6 +110,22 @@ export interface FindOptions<Entity, Hint extends string = never, Fields extends
110
110
  * when nesting the condition. This is used for implementation of joined filters.
111
111
  */
112
112
  populateFilter?: ObjectQuery<Entity>;
113
+ /**
114
+ * Index-friendly alternative to `$or` for conditions that span joined relations.
115
+ * Each array element becomes an independent branch combined via `UNION ALL` subquery:
116
+ * `WHERE pk IN (branch_1 UNION ALL branch_2 ... branch_N)`.
117
+ * The database plans each branch independently, enabling per-table index usage
118
+ * (e.g. GIN trigram indexes for fuzzy search across related entities).
119
+ * sql only
120
+ */
121
+ unionWhere?: ObjectQuery<Entity>[];
122
+ /**
123
+ * Strategy for combining `unionWhere` branches.
124
+ * - `'union-all'` (default) — skips deduplication, faster for most use cases.
125
+ * - `'union'` — deduplicates rows between branches; useful when branch overlap is very high.
126
+ * sql only
127
+ */
128
+ unionWhereStrategy?: 'union-all' | 'union';
113
129
  /** Used for ordering of the populate queries. If not specified, the value of `options.orderBy` is used. */
114
130
  populateOrderBy?: OrderDefinition<Entity>;
115
131
  /** Per-relation overrides for populate loading behavior. Keys are populate paths (same as used in `populate`). */
@@ -199,6 +215,13 @@ export interface NativeInsertUpdateOptions<T> {
199
215
  /** `nativeUpdate()` only option */
200
216
  upsert?: boolean;
201
217
  loggerContext?: LogContext;
218
+ /** sql only */
219
+ unionWhere?: ObjectQuery<T>[];
220
+ /** sql only */
221
+ unionWhereStrategy?: 'union-all' | 'union';
222
+ filters?: FilterOptions;
223
+ /** @internal */
224
+ em?: EntityManager;
202
225
  }
203
226
  export interface NativeInsertUpdateManyOptions<T> extends NativeInsertUpdateOptions<T> {
204
227
  processCollections?: boolean;
@@ -223,6 +246,10 @@ export interface CountOptions<T extends object, P extends string = never> {
223
246
  populate?: Populate<T, P>;
224
247
  populateWhere?: ObjectQuery<T> | PopulateHint | `${PopulateHint}`;
225
248
  populateFilter?: ObjectQuery<T>;
249
+ /** @see FindOptions.unionWhere */
250
+ unionWhere?: ObjectQuery<T>[];
251
+ /** @see FindOptions.unionWhereStrategy */
252
+ unionWhereStrategy?: 'union-all' | 'union';
226
253
  ctx?: Transaction;
227
254
  connectionType?: ConnectionType;
228
255
  flushMode?: FlushMode | `${FlushMode}`;
@@ -245,12 +272,28 @@ export interface UpdateOptions<T> {
245
272
  filters?: FilterOptions;
246
273
  schema?: string;
247
274
  ctx?: Transaction;
275
+ /** sql only */
276
+ unionWhere?: ObjectQuery<T>[];
277
+ /** sql only */
278
+ unionWhereStrategy?: 'union-all' | 'union';
248
279
  }
249
280
  export interface DeleteOptions<T> extends DriverMethodOptions {
250
281
  filters?: FilterOptions;
282
+ /** sql only */
283
+ unionWhere?: ObjectQuery<T>[];
284
+ /** sql only */
285
+ unionWhereStrategy?: 'union-all' | 'union';
286
+ /** @internal */
287
+ em?: EntityManager;
251
288
  }
252
289
  export interface NativeDeleteOptions<T> extends DriverMethodOptions {
253
290
  filters?: FilterOptions;
291
+ /** sql only */
292
+ unionWhere?: ObjectQuery<T>[];
293
+ /** sql only */
294
+ unionWhereStrategy?: 'union-all' | 'union';
295
+ /** @internal */
296
+ em?: EntityManager;
254
297
  }
255
298
  export interface LockOptions extends DriverMethodOptions {
256
299
  lockMode?: LockMode;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
3
  "type": "module",
4
- "version": "7.0.0-dev.291",
4
+ "version": "7.0.0-dev.293",
5
5
  "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.",
6
6
  "exports": {
7
7
  "./package.json": "./package.json",
@@ -140,6 +140,7 @@ export declare abstract class Platform {
140
140
  getDefaultMappedType(type: string): Type<unknown>;
141
141
  supportsMultipleCascadePaths(): boolean;
142
142
  supportsMultipleStatements(): boolean;
143
+ supportsUnionWhere(): boolean;
143
144
  getArrayDeclarationSQL(): string;
144
145
  marshallArray(values: string[]): string;
145
146
  unmarshallArray(value: string): string[];
@@ -235,6 +235,9 @@ export class Platform {
235
235
  supportsMultipleStatements() {
236
236
  return this.config.get('multipleStatements');
237
237
  }
238
+ supportsUnionWhere() {
239
+ return false;
240
+ }
238
241
  getArrayDeclarationSQL() {
239
242
  return 'text';
240
243
  }
package/utils/Utils.js CHANGED
@@ -123,7 +123,7 @@ export function parseJsonSafe(value) {
123
123
  }
124
124
  export class Utils {
125
125
  static PK_SEPARATOR = '~~~';
126
- static #ORM_VERSION = '7.0.0-dev.291';
126
+ static #ORM_VERSION = '7.0.0-dev.293';
127
127
  /**
128
128
  * Checks if the argument is instance of `Object`. Returns false for arrays.
129
129
  */