@mikro-orm/core 7.1.0-dev.30 → 7.1.0-dev.32

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.
@@ -10,7 +10,7 @@ import type { CountByOptions, CountOptions, DeleteOptions, FilterOptions, FindAl
10
10
  import type { AnyString, ArrayElement, AutoPath, ConnectionType, Dictionary, EntityClass, EntityData, EntityDictionary, EntityDTO, EntityKey, EntityMetadata, EntityName, FilterDef, FilterQuery, FromEntityType, GetRepository, IHydrator, IsSubset, Loaded, MergeLoaded, MergeSelected, ObjectQuery, PopulateOptions, Primary, Ref, RequiredEntityData, UnboxArray, IndexFilterQuery, WithUsingOptions } from './typings.js';
11
11
  import { FlushMode, LockMode, PopulatePath, type TransactionOptions } from './enums.js';
12
12
  import type { MetadataStorage } from './metadata/MetadataStorage.js';
13
- import type { Transaction } from './connections/Connection.js';
13
+ import type { AbortQueryOptions, InflightQueryAbortStrategy, Transaction } from './connections/Connection.js';
14
14
  import { EventManager } from './events/EventManager.js';
15
15
  import type { EntityComparator } from './utils/EntityComparator.js';
16
16
  /**
@@ -33,6 +33,10 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
33
33
  /** The context name of this EntityManager, derived from the ORM configuration. */
34
34
  readonly name: string;
35
35
  protected loggerContext?: Dictionary;
36
+ /** @internal */
37
+ protected signal?: AbortSignal;
38
+ /** @internal */
39
+ protected inflightQueryAbortStrategy?: InflightQueryAbortStrategy;
36
40
  /**
37
41
  * @internal
38
42
  */
@@ -532,6 +536,13 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
532
536
  * Gets the transaction context (driver dependent object used to make sure queries are executed on same connection).
533
537
  */
534
538
  getTransactionContext<T extends Transaction = Transaction>(): T | undefined;
539
+ /**
540
+ * Returns the cancellation defaults configured on this EntityManager (via `em.fork({ signal })`
541
+ * or inherited from a transactional fork). Returns `undefined` when no signal is set.
542
+ *
543
+ * @internal — exposed for subclass drivers and `UnitOfWork`; not part of the public API.
544
+ */
545
+ protected getAbortOptions(): AbortQueryOptions | undefined;
535
546
  /**
536
547
  * Sets the transaction context.
537
548
  */
@@ -566,7 +577,7 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
566
577
  * some additional lazy properties, if so, we reload and merge the data from database
567
578
  */
568
579
  protected shouldRefresh<T extends object, P extends string = never, F extends string = never, E extends string = never>(meta: EntityMetadata<T>, entity: T, options: FindOneOptions<T, P, F, E>): boolean;
569
- protected prepareOptions(options: FindOptions<any, any, any, any> | FindOneOptions<any, any, any, any> | CountOptions<any, any> | CountByOptions<any>): void;
580
+ protected prepareOptions(options: (FindOptions<any, any, any, any> | FindOneOptions<any, any, any, any> | CountOptions<any, any> | CountByOptions<any>) & AbortQueryOptions): void;
570
581
  /**
571
582
  * @internal
572
583
  */
@@ -661,4 +672,11 @@ export interface ForkOptions {
661
672
  schema?: string;
662
673
  /** default logger context, can be overridden via {@apilink FindOptions} */
663
674
  loggerContext?: Dictionary;
675
+ /**
676
+ * Default `AbortSignal` applied to every operation on this fork (queries and UoW flushes).
677
+ * Per-call options.signal still takes precedence.
678
+ */
679
+ signal?: AbortSignal;
680
+ /** Default cancellation strategy paired with {@link signal}. */
681
+ inflightQueryAbortStrategy?: InflightQueryAbortStrategy;
664
682
  }
package/EntityManager.js CHANGED
@@ -49,6 +49,10 @@ export class EntityManager {
49
49
  #disableTransactions;
50
50
  #flushMode;
51
51
  #schema;
52
+ /** @internal */
53
+ signal;
54
+ /** @internal */
55
+ inflightQueryAbortStrategy;
52
56
  #useContext;
53
57
  /**
54
58
  * @internal
@@ -1161,6 +1165,7 @@ export class EntityManager {
1161
1165
  */
1162
1166
  async lock(entity, lockMode, options = {}) {
1163
1167
  options = Utils.isPlainObject(options) ? options : { lockVersion: options };
1168
+ this.getContext(false).prepareOptions(options);
1164
1169
  await this.getUnitOfWork().lock(entity, { lockMode, ...options });
1165
1170
  }
1166
1171
  /**
@@ -1616,6 +1621,8 @@ export class EntityManager {
1616
1621
  fork.#filterParams = Utils.copy(em.#filterParams);
1617
1622
  fork.loggerContext = Utils.merge({}, em.loggerContext, options.loggerContext);
1618
1623
  fork.#schema = options.schema ?? em.#schema;
1624
+ fork.signal = options.signal ?? em.signal;
1625
+ fork.inflightQueryAbortStrategy = options.inflightQueryAbortStrategy ?? em.inflightQueryAbortStrategy;
1619
1626
  if (!options.clear) {
1620
1627
  for (const entity of em.#unitOfWork.getIdentityMap()) {
1621
1628
  fork.#unitOfWork.register(entity);
@@ -1691,6 +1698,22 @@ export class EntityManager {
1691
1698
  getTransactionContext() {
1692
1699
  return this.getContext(false).#transactionContext;
1693
1700
  }
1701
+ /**
1702
+ * Returns the cancellation defaults configured on this EntityManager (via `em.fork({ signal })`
1703
+ * or inherited from a transactional fork). Returns `undefined` when no signal is set.
1704
+ *
1705
+ * @internal — exposed for subclass drivers and `UnitOfWork`; not part of the public API.
1706
+ */
1707
+ getAbortOptions() {
1708
+ const em = this.getContext(false);
1709
+ if (em.signal == null && em.inflightQueryAbortStrategy == null) {
1710
+ return undefined;
1711
+ }
1712
+ return {
1713
+ signal: em.signal,
1714
+ inflightQueryAbortStrategy: em.inflightQueryAbortStrategy,
1715
+ };
1716
+ }
1694
1717
  /**
1695
1718
  * Sets the transaction context.
1696
1719
  */
@@ -1976,6 +1999,8 @@ export class EntityManager {
1976
1999
  throw new ValidationError(`Cannot combine 'fields' and 'exclude' option.`);
1977
2000
  }
1978
2001
  options.schema ??= this.#schema;
2002
+ options.signal ??= this.signal;
2003
+ options.inflightQueryAbortStrategy ??= this.inflightQueryAbortStrategy;
1979
2004
  options.logging = options.loggerContext = Utils.merge({ id: this.id }, this.loggerContext, options.loggerContext, options.logging);
1980
2005
  }
1981
2006
  /**
@@ -1984,7 +2009,15 @@ export class EntityManager {
1984
2009
  cacheKey(entityName, options, method, where) {
1985
2010
  const { ...opts } = options;
1986
2011
  // ignore some irrelevant options, e.g. logger context can contain dynamic data for the same query
1987
- for (const k of ['ctx', 'strategy', 'flushMode', 'logging', 'loggerContext']) {
2012
+ for (const k of [
2013
+ 'ctx',
2014
+ 'strategy',
2015
+ 'flushMode',
2016
+ 'logging',
2017
+ 'loggerContext',
2018
+ 'signal',
2019
+ 'inflightQueryAbortStrategy',
2020
+ ]) {
1988
2021
  delete opts[k];
1989
2022
  }
1990
2023
  return [Utils.className(entityName), method, opts, where];
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  <a href="https://mikro-orm.io"><img src="https://raw.githubusercontent.com/mikro-orm/mikro-orm/master/docs/static/img/logo-readme.svg?sanitize=true" alt="MikroORM" /></a>
3
3
  </h1>
4
4
 
5
- TypeScript ORM for Node.js based on Data Mapper, [Unit of Work](https://mikro-orm.io/docs/unit-of-work/) and [Identity Map](https://mikro-orm.io/docs/identity-map/) patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL, SQLite (including libSQL), MSSQL and Oracle databases.
5
+ TypeScript ORM for Node.js based on Data Mapper, [Unit of Work](https://mikro-orm.io/docs/unit-of-work/) and [Identity Map](https://mikro-orm.io/docs/identity-map/) patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL (including CockroachDB and PGlite), SQLite (including libSQL), MSSQL and Oracle databases.
6
6
 
7
7
  > Heavily inspired by [Doctrine](https://www.doctrine-project.org/) and [Hibernate](https://hibernate.org/).
8
8
 
@@ -19,6 +19,7 @@ Install a driver package for your database:
19
19
 
20
20
  ```sh
21
21
  npm install @mikro-orm/postgresql # PostgreSQL
22
+ npm install @mikro-orm/pglite # PGlite (embedded PostgreSQL in WASM)
22
23
  npm install @mikro-orm/mysql # MySQL
23
24
  npm install @mikro-orm/mariadb # MariaDB
24
25
  npm install @mikro-orm/sqlite # SQLite
@@ -104,3 +104,32 @@ export interface ConnectionConfig {
104
104
  }
105
105
  /** Opaque transaction context type, wrapping the driver-specific transaction object. */
106
106
  export type Transaction<T = any> = T & {};
107
+ /**
108
+ * Strategy applied when an `AbortSignal` fires while a query is in flight.
109
+ *
110
+ * - `'ignore query'` — stop awaiting; the query keeps running on the server until it settles
111
+ * (the connection returns to the pool only when the database replies).
112
+ * - `'cancel query'` — ask the database to cancel the running query (e.g. `pg_cancel_backend`,
113
+ * `KILL QUERY`). Falls back to `'ignore query'` if the dialect cannot cancel.
114
+ * Most engines do not cancel writes; partial commits are possible.
115
+ * - `'kill session'` — terminate the database session/process the query runs in
116
+ * (`pg_terminate_backend` etc.). Falls back to `'cancel query'` if not supported.
117
+ *
118
+ * Default: `'ignore query'`.
119
+ *
120
+ * **Streaming queries (`em.stream()` / `qb.stream()`):** the strategy is silently treated as
121
+ * `'ignore query'` because the underlying driver only accepts a plain `AbortSignal` for
122
+ * streamed reads — there is no server-side cancel for an open cursor. The MongoDB driver also
123
+ * has no notion of strategies; only the signal is honored there.
124
+ */
125
+ export type InflightQueryAbortStrategy = 'ignore query' | 'cancel query' | 'kill session';
126
+ /** Per-query cancellation controls forwarded to the underlying driver. */
127
+ export interface AbortQueryOptions {
128
+ /** AbortSignal that cancels the query when fired. */
129
+ signal?: AbortSignal;
130
+ /**
131
+ * Strategy used when the signal fires while the query is in flight. See
132
+ * {@apilink InflightQueryAbortStrategy} for caveats around streams and MongoDB.
133
+ */
134
+ inflightQueryAbortStrategy?: InflightQueryAbortStrategy;
135
+ }
@@ -1,5 +1,5 @@
1
1
  import type { ConnectionType, Constructor, EntityData, EntityMetadata, EntityProperty, FilterQuery, Primary, Dictionary, IPrimaryKey, PopulateOptions, EntityDictionary, AutoPath, ObjectQuery, FilterObject, Populate, EntityName, PopulateHintOptions, Prefixes, IndexName } from '../typings.js';
2
- import type { Connection, QueryResult, Transaction } from '../connections/Connection.js';
2
+ import type { AbortQueryOptions, Connection, QueryResult, Transaction } from '../connections/Connection.js';
3
3
  import type { FlushMode, LockMode, QueryOrderMap, QueryFlag, LoadStrategy, PopulateHint, PopulatePath } from '../enums.js';
4
4
  import type { Platform } from '../platforms/Platform.js';
5
5
  import type { MetadataStorage } from '../metadata/MetadataStorage.js';
@@ -144,7 +144,7 @@ export interface LoadHint<Entity, Hint extends string = never, Fields extends st
144
144
  exclude?: readonly AutoPath<Entity, Excludes>[];
145
145
  }
146
146
  /** Options for `em.find()` queries, including population, ordering, pagination, and locking. */
147
- export interface FindOptions<Entity, Hint extends string = never, Fields extends string = never, Excludes extends string = never> extends LoadHint<Entity, Hint, Fields, Excludes> {
147
+ export interface FindOptions<Entity, Hint extends string = never, Fields extends string = never, Excludes extends string = never> extends LoadHint<Entity, Hint, Fields, Excludes>, AbortQueryOptions {
148
148
  /**
149
149
  * Where condition for populated relations. This will have no effect on the root entity.
150
150
  * With `select-in` strategy, this is applied only to the populate queries.
@@ -274,7 +274,7 @@ export interface FindOneOrFailOptions<T extends object, P extends string = never
274
274
  strict?: boolean;
275
275
  }
276
276
  /** Options for native insert and update operations. */
277
- export interface NativeInsertUpdateOptions<T> {
277
+ export interface NativeInsertUpdateOptions<T> extends AbortQueryOptions {
278
278
  convertCustomTypes?: boolean;
279
279
  ctx?: Transaction;
280
280
  schema?: string;
@@ -308,7 +308,7 @@ export interface UpsertManyOptions<Entity, Fields extends string = never> extend
308
308
  batchSize?: number;
309
309
  }
310
310
  /** Options for `em.count()` queries. */
311
- export interface CountOptions<T extends object, P extends string = never> {
311
+ export interface CountOptions<T extends object, P extends string = never> extends AbortQueryOptions {
312
312
  filters?: FilterOptions;
313
313
  schema?: string;
314
314
  groupBy?: string | readonly string[];
@@ -350,7 +350,7 @@ export interface CountByOptions<T extends object> {
350
350
  logging?: LoggingOptions;
351
351
  }
352
352
  /** Options for `em.qb().update()` operations. */
353
- export interface UpdateOptions<T> {
353
+ export interface UpdateOptions<T> extends AbortQueryOptions {
354
354
  filters?: FilterOptions;
355
355
  schema?: string;
356
356
  ctx?: Transaction;
@@ -389,7 +389,7 @@ export interface LockOptions extends DriverMethodOptions {
389
389
  logging?: LoggingOptions;
390
390
  }
391
391
  /** Base options shared by all driver methods (transaction context, schema, logging). */
392
- export interface DriverMethodOptions {
392
+ export interface DriverMethodOptions extends AbortQueryOptions {
393
393
  ctx?: Transaction;
394
394
  schema?: string;
395
395
  loggerContext?: LogContext;
@@ -1,6 +1,7 @@
1
1
  import type { AnyEntity, AutoPath, ConnectionType, EntityName, EntityProperty, FilterQuery, PopulateHintOptions, PopulateOptions } from '../typings.js';
2
2
  import type { EntityManager } from '../EntityManager.js';
3
3
  import { LoadStrategy, type LockMode, type PopulateHint, PopulatePath, type QueryOrderMap } from '../enums.js';
4
+ import type { InflightQueryAbortStrategy } from '../connections/Connection.js';
4
5
  import type { FilterOptions } from '../drivers/IDatabaseDriver.js';
5
6
  import type { LoggingOptions } from '../logging/Logger.js';
6
7
  /** Options for controlling how relations are loaded by the EntityLoader. */
@@ -39,6 +40,10 @@ export interface EntityLoaderOptions<Entity, Fields extends string = never, Excl
39
40
  logging?: LoggingOptions;
40
41
  /** Per-relation populate overrides (limit, offset, orderBy). */
41
42
  populateHints?: Record<string, PopulateHintOptions>;
43
+ /** AbortSignal forwarded to populated relation queries. */
44
+ signal?: AbortSignal;
45
+ /** Cancellation strategy paired with {@link signal}. */
46
+ inflightQueryAbortStrategy?: InflightQueryAbortStrategy;
42
47
  }
43
48
  /** Responsible for batch-loading entity relations using either select-in or joined loading strategies. */
44
49
  export declare class EntityLoader {
@@ -393,6 +393,8 @@ export class EntityLoader {
393
393
  fields,
394
394
  schema,
395
395
  connectionType,
396
+ signal: options.signal,
397
+ inflightQueryAbortStrategy: options.inflightQueryAbortStrategy,
396
398
  // @ts-ignore not a public option, will be propagated to the populate call
397
399
  refresh: refresh && !children.every(item => options.visited.has(item)),
398
400
  // @ts-ignore not a public option, will be propagated to the populate call
package/enums.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { EntityKey, ExpandProperty } from './typings.js';
2
- import type { Transaction } from './connections/Connection.js';
2
+ import type { InflightQueryAbortStrategy, Transaction } from './connections/Connection.js';
3
3
  import type { LogContext } from './logging/Logger.js';
4
4
  /** Controls when the `EntityManager` flushes pending changes to the database. */
5
5
  export declare enum FlushMode {
@@ -307,6 +307,13 @@ export interface TransactionOptions {
307
307
  flushMode?: FlushMode | `${FlushMode}`;
308
308
  ignoreNestedTransactions?: boolean;
309
309
  loggerContext?: LogContext;
310
+ /**
311
+ * `AbortSignal` cancelling every query within the transaction (including the implicit flush).
312
+ * Cancelling mid-transaction triggers a rollback once the in-flight query settles.
313
+ */
314
+ signal?: AbortSignal;
315
+ /** Cancellation strategy paired with {@link signal}. */
316
+ inflightQueryAbortStrategy?: InflightQueryAbortStrategy;
310
317
  }
311
318
  export declare abstract class PlainObject {
312
319
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
- "version": "7.1.0-dev.30",
3
+ "version": "7.1.0-dev.32",
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",
@@ -36,6 +36,13 @@ export class UnitOfWork {
36
36
  #flushQueue = [];
37
37
  #working = false;
38
38
  #em;
39
+ /**
40
+ * UoW lives in `@mikro-orm/core` alongside `EntityManager` and reaches `getAbortOptions`
41
+ * (TS-protected) via cast — TS has no `friend` keyword, so this is the documented escape hatch.
42
+ */
43
+ get #abortOptions() {
44
+ return this.#em.getAbortOptions();
45
+ }
39
46
  constructor(em) {
40
47
  this.#em = em;
41
48
  this.#metadata = this.#em.getMetadata();
@@ -1002,7 +1009,7 @@ export class UnitOfWork {
1002
1009
  this.findExtraUpdates(changeSet, props);
1003
1010
  await this.runHooks(EventType.beforeCreate, changeSet, true);
1004
1011
  }
1005
- await this.#changeSetPersister.executeInserts(changeSets, { ctx });
1012
+ await this.#changeSetPersister.executeInserts(changeSets, { ctx, ...this.#abortOptions });
1006
1013
  for (const changeSet of changeSets) {
1007
1014
  // For TPT entities, use the full entity snapshot instead of the partial changeset payload,
1008
1015
  // since each table's changeset only contains its own properties. Without this, the snapshot
@@ -1071,7 +1078,7 @@ export class UnitOfWork {
1071
1078
  for (const changeSet of changeSets) {
1072
1079
  await this.runHooks(EventType.beforeUpdate, changeSet, true);
1073
1080
  }
1074
- await this.#changeSetPersister.executeUpdates(changeSets, batched, { ctx });
1081
+ await this.#changeSetPersister.executeUpdates(changeSets, batched, { ctx, ...this.#abortOptions });
1075
1082
  for (const changeSet of changeSets) {
1076
1083
  const wrapped = helper(changeSet.entity);
1077
1084
  wrapped.__originalEntityData = this.#comparator.prepareEntity(changeSet.entity);
@@ -1094,7 +1101,7 @@ export class UnitOfWork {
1094
1101
  for (const changeSet of changeSets) {
1095
1102
  await this.runHooks(EventType.beforeDelete, changeSet, true);
1096
1103
  }
1097
- await this.#changeSetPersister.executeDeletes(changeSets, { ctx });
1104
+ await this.#changeSetPersister.executeDeletes(changeSets, { ctx, ...this.#abortOptions });
1098
1105
  for (const changeSet of changeSets) {
1099
1106
  this.unsetIdentity(changeSet.entity);
1100
1107
  await this.runHooks(EventType.afterDelete, changeSet);
@@ -1132,6 +1139,7 @@ export class UnitOfWork {
1132
1139
  ctx,
1133
1140
  schema: this.#em.schema,
1134
1141
  loggerContext,
1142
+ ...this.#abortOptions,
1135
1143
  });
1136
1144
  for (const coll of this.#collectionUpdates) {
1137
1145
  coll.takeSnapshot();
@@ -136,6 +136,8 @@ export class TransactionManager {
136
136
  cloneEventManager: true,
137
137
  disableTransactions: options.ignoreNestedTransactions,
138
138
  loggerContext: options.loggerContext,
139
+ signal: options.signal,
140
+ inflightQueryAbortStrategy: options.inflightQueryAbortStrategy,
139
141
  });
140
142
  }
141
143
  /**
package/utils/Utils.js CHANGED
@@ -141,7 +141,7 @@ export function parseJsonSafe(value) {
141
141
  /** Collection of general-purpose utility methods used throughout the ORM. */
142
142
  export class Utils {
143
143
  static PK_SEPARATOR = '~~~';
144
- static #ORM_VERSION = '7.1.0-dev.30';
144
+ static #ORM_VERSION = '7.1.0-dev.32';
145
145
  /**
146
146
  * Checks if the argument is instance of `Object`. Returns false for arrays.
147
147
  */