@mikro-orm/mongodb 7.0.0-dev.11 → 7.0.0-dev.111

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.
@@ -1,10 +1,12 @@
1
- import { MongoClient, type ClientSession, type Collection, type Db, type MongoClientOptions, type TransactionOptions } from 'mongodb';
2
- import { Connection, type AnyEntity, type Configuration, type ConnectionOptions, type ConnectionType, type EntityData, type EntityName, type FilterQuery, type IsolationLevel, type QueryOrderMap, type QueryResult, type Transaction, type TransactionEventBroadcaster, type UpsertOptions, type UpsertManyOptions, type LoggingOptions } from '@mikro-orm/core';
1
+ import { type ClientSession, type Collection, type Db, MongoClient, type MongoClientOptions, type TransactionOptions } from 'mongodb';
2
+ import { type AnyEntity, type Configuration, Connection, type ConnectionOptions, type ConnectionType, type EntityData, type EntityName, type FilterQuery, type IsolationLevel, type LoggingOptions, type QueryOrderMap, type QueryResult, type Transaction, type TransactionEventBroadcaster, type UpsertManyOptions, type UpsertOptions } from '@mikro-orm/core';
3
3
  export declare class MongoConnection extends Connection {
4
- protected client: MongoClient;
5
- protected db: Db;
4
+ #private;
6
5
  constructor(config: Configuration, options?: ConnectionOptions, type?: ConnectionType);
7
- connect(): Promise<void>;
6
+ connect(options?: {
7
+ skipOnConnect?: boolean;
8
+ }): Promise<void>;
9
+ createClient(): void;
8
10
  close(force?: boolean): Promise<void>;
9
11
  isConnected(): Promise<boolean>;
10
12
  checkConnection(): Promise<{
@@ -20,16 +22,18 @@ export declare class MongoConnection extends Connection {
20
22
  listCollections(): Promise<string[]>;
21
23
  dropCollection(name: EntityName<AnyEntity>): Promise<boolean>;
22
24
  mapOptions(overrides: MongoClientOptions): MongoClientOptions;
23
- getClientUrl(): string;
24
25
  getDb(): Db;
25
26
  execute(query: string): Promise<any>;
26
27
  find<T extends object>(collection: string, where: FilterQuery<T>, orderBy?: QueryOrderMap<T> | QueryOrderMap<T>[], limit?: number, offset?: number, fields?: string[], ctx?: Transaction<ClientSession>, loggerContext?: LoggingOptions): Promise<EntityData<T>[]>;
28
+ stream<T extends object>(collection: string, where: FilterQuery<T>, orderBy?: QueryOrderMap<T> | QueryOrderMap<T>[], limit?: number, offset?: number, fields?: string[], ctx?: Transaction<ClientSession>, loggerContext?: LoggingOptions): AsyncIterableIterator<T>;
29
+ private _find;
27
30
  insertOne<T extends object>(collection: string, data: Partial<T>, ctx?: Transaction<ClientSession>): Promise<QueryResult<T>>;
28
31
  insertMany<T extends object>(collection: string, data: Partial<T>[], ctx?: Transaction<ClientSession>): Promise<QueryResult<T>>;
29
32
  updateMany<T extends object>(collection: string, where: FilterQuery<T>, data: Partial<T>, ctx?: Transaction<ClientSession>, upsert?: boolean, upsertOptions?: UpsertOptions<T>): Promise<QueryResult<T>>;
30
33
  bulkUpdateMany<T extends object>(collection: string, where: FilterQuery<T>[], data: Partial<T>[], ctx?: Transaction<ClientSession>, upsert?: boolean, upsertOptions?: UpsertManyOptions<T>): Promise<QueryResult<T>>;
31
34
  deleteMany<T extends object>(collection: string, where: FilterQuery<T>, ctx?: Transaction<ClientSession>): Promise<QueryResult<T>>;
32
35
  aggregate<T extends object = any>(collection: string, pipeline: any[], ctx?: Transaction<ClientSession>, loggerContext?: LoggingOptions): Promise<T[]>;
36
+ streamAggregate<T extends object>(collection: string, pipeline: any[], ctx?: Transaction<ClientSession>, loggerContext?: LoggingOptions, stream?: boolean): AsyncIterableIterator<T>;
33
37
  countDocuments<T extends object>(collection: string, where: FilterQuery<T>, ctx?: Transaction<ClientSession>): Promise<number>;
34
38
  transactional<T>(cb: (trx: Transaction<ClientSession>) => Promise<T>, options?: {
35
39
  isolationLevel?: IsolationLevel;
@@ -1,49 +1,54 @@
1
- import { ObjectId, MongoClient, } from 'mongodb';
2
- import { inspect } from 'node:util';
3
- import { Connection, EventType, QueryOrder, Utils, ValidationError, } from '@mikro-orm/core';
1
+ import { MongoClient, ObjectId, } from 'mongodb';
2
+ import { Connection, EventType, QueryOrder, Utils, ValidationError, inspect, } from '@mikro-orm/core';
4
3
  export class MongoConnection extends Connection {
5
- client;
6
- db;
4
+ #client;
5
+ #db;
7
6
  constructor(config, options, type = 'write') {
8
7
  super(config, options, type);
9
8
  // @ts-ignore
10
- ObjectId.prototype[inspect.custom] = function () {
9
+ ObjectId.prototype[Symbol.for('nodejs.util.inspect.custom')] = function () {
11
10
  return `ObjectId('${this.toHexString()}')`;
12
11
  };
13
12
  // @ts-ignore
14
- Date.prototype[inspect.custom] = function () {
13
+ Date.prototype[Symbol.for('nodejs.util.inspect.custom')] = function () {
15
14
  return `ISODate('${this.toISOString()}')`;
16
15
  };
17
16
  }
18
- async connect() {
17
+ async connect(options) {
18
+ this.getClient();
19
+ this.connected = true;
20
+ if (options?.skipOnConnect !== true) {
21
+ await this.onConnect();
22
+ }
23
+ }
24
+ createClient() {
19
25
  let driverOptions = this.options.driverOptions ?? this.config.get('driverOptions');
20
26
  if (typeof driverOptions === 'function') {
21
- driverOptions = await driverOptions();
27
+ driverOptions = driverOptions();
22
28
  }
23
29
  if (driverOptions instanceof MongoClient) {
24
30
  this.logger.log('info', 'Reusing MongoClient provided via `driverOptions`');
25
- this.client = driverOptions;
31
+ this.#client = driverOptions;
26
32
  }
27
33
  else {
28
- this.client = new MongoClient(this.config.getClientUrl(), this.mapOptions(driverOptions));
29
- await this.client.connect();
34
+ this.#client = new MongoClient(this.config.get('clientUrl'), this.mapOptions(driverOptions));
30
35
  const onCreateConnection = this.options.onCreateConnection ?? this.config.get('onCreateConnection');
31
- /* v8 ignore next 3 */
32
- this.client.on('connectionCreated', () => {
33
- void onCreateConnection?.(this.client);
36
+ /* v8 ignore next */
37
+ this.#client.on('connectionCreated', () => {
38
+ void onCreateConnection?.(this.#client);
34
39
  });
35
40
  }
36
- this.db = this.client.db(this.config.get('dbName'));
37
- this.connected = true;
41
+ this.#db = this.#client.db(this.config.get('dbName'));
38
42
  }
39
43
  async close(force) {
40
- await this.client?.close(!!force);
44
+ await this.#client?.close(force);
41
45
  this.connected = false;
46
+ this.#client = undefined;
42
47
  }
43
48
  async isConnected() {
44
49
  try {
45
- const res = await this.db?.command({ ping: 1 });
46
- return this.connected = !!res.ok;
50
+ const res = await this.#db?.command({ ping: 1 });
51
+ return this.connected = !!res?.ok;
47
52
  }
48
53
  catch (error) {
49
54
  return this.connected = false;
@@ -51,8 +56,8 @@ export class MongoConnection extends Connection {
51
56
  }
52
57
  async checkConnection() {
53
58
  try {
54
- const res = await this.db?.command({ ping: 1 });
55
- return res.ok
59
+ const res = await this.#db?.command({ ping: 1 });
60
+ return res?.ok
56
61
  ? { ok: true }
57
62
  : { ok: false, reason: 'Ping reply does not feature "ok" property, or it evaluates to "false"' };
58
63
  }
@@ -61,20 +66,23 @@ export class MongoConnection extends Connection {
61
66
  }
62
67
  }
63
68
  getClient() {
64
- return this.client;
69
+ if (!this.#client) {
70
+ this.createClient();
71
+ }
72
+ return this.#client;
65
73
  }
66
74
  getCollection(name) {
67
- return this.db.collection(this.getCollectionName(name));
75
+ return this.getDb().collection(this.getCollectionName(name));
68
76
  }
69
77
  async createCollection(name) {
70
- return this.db.createCollection(this.getCollectionName(name));
78
+ return this.getDb().createCollection(this.getCollectionName(name));
71
79
  }
72
80
  async listCollections() {
73
- const collections = await this.db.listCollections({}, { nameOnly: true }).toArray();
81
+ const collections = await this.getDb().listCollections({}, { nameOnly: true }).toArray();
74
82
  return collections.map(c => c.name);
75
83
  }
76
84
  async dropCollection(name) {
77
- return this.db.dropCollection(this.getCollectionName(name));
85
+ return this.getDb().dropCollection(this.getCollectionName(name));
78
86
  }
79
87
  mapOptions(overrides) {
80
88
  const ret = {};
@@ -96,19 +104,26 @@ export class MongoConnection extends Connection {
96
104
  };
97
105
  return Utils.mergeConfig(ret, overrides);
98
106
  }
99
- getClientUrl() {
100
- const options = this.mapOptions(this.options.driverOptions ?? {});
101
- const clientUrl = this.config.getClientUrl(true);
102
- const match = clientUrl.match(/^(\w+):\/\/((.*@.+)|.+)$/);
103
- return match ? `${match[1]}://${options.auth ? options.auth.username + ':*****@' : ''}${match[2]}` : clientUrl;
104
- }
105
107
  getDb() {
106
- return this.db;
108
+ this.#db ??= this.getClient().db(this.config.get('dbName'));
109
+ return this.#db;
107
110
  }
108
111
  async execute(query) {
109
112
  throw new Error(`${this.constructor.name} does not support generic execute method`);
110
113
  }
111
114
  async find(collection, where, orderBy, limit, offset, fields, ctx, loggerContext) {
115
+ const { cursor, query } = await this._find(collection, where, orderBy, limit, offset, fields, ctx, loggerContext);
116
+ const now = Date.now();
117
+ const res = await cursor.toArray();
118
+ this.logQuery(`${query}.toArray();`, { took: Date.now() - now, results: res.length, ...loggerContext });
119
+ return res;
120
+ }
121
+ async *stream(collection, where, orderBy, limit, offset, fields, ctx, loggerContext) {
122
+ const { cursor, query } = await this._find(collection, where, orderBy, limit, offset, fields, ctx, loggerContext);
123
+ this.logQuery(`${query}.toArray();`, loggerContext);
124
+ yield* cursor;
125
+ }
126
+ async _find(collection, where, orderBy, limit, offset, fields, ctx, loggerContext) {
112
127
  await this.ensureConnection();
113
128
  collection = this.getCollectionName(collection);
114
129
  const options = ctx ? { session: ctx } : {};
@@ -123,12 +138,11 @@ export class MongoConnection extends Connection {
123
138
  orderBy.forEach(o => {
124
139
  Utils.keys(o).forEach(k => {
125
140
  const direction = o[k];
126
- orderByTuples.push([k.toString(), Utils.isString(direction) ? direction.toUpperCase() === QueryOrder.ASC ? 1 : -1 : direction]);
141
+ orderByTuples.push([k.toString(), typeof direction === 'string' ? direction.toUpperCase() === QueryOrder.ASC ? 1 : -1 : direction]);
127
142
  });
128
143
  });
129
144
  if (orderByTuples.length > 0) {
130
145
  query += `.sort(${this.logObject(orderByTuples)})`;
131
- // @ts-expect-error ??
132
146
  resultSet.sort(orderByTuples);
133
147
  }
134
148
  }
@@ -140,10 +154,7 @@ export class MongoConnection extends Connection {
140
154
  query += `.skip(${offset})`;
141
155
  resultSet.skip(offset);
142
156
  }
143
- const now = Date.now();
144
- const res = await resultSet.toArray();
145
- this.logQuery(`${query}.toArray();`, { took: Date.now() - now, results: res.length, ...loggerContext });
146
- return res;
157
+ return { cursor: resultSet, query };
147
158
  }
148
159
  async insertOne(collection, data, ctx) {
149
160
  return this.runQuery('insertOne', collection, data, undefined, ctx);
@@ -171,6 +182,16 @@ export class MongoConnection extends Connection {
171
182
  this.logQuery(query, { took: Date.now() - now, results: res.length, ...loggerContext });
172
183
  return res;
173
184
  }
185
+ async *streamAggregate(collection, pipeline, ctx, loggerContext, stream = false) {
186
+ await this.ensureConnection();
187
+ collection = this.getCollectionName(collection);
188
+ /* v8 ignore next */
189
+ const options = ctx ? { session: ctx } : {};
190
+ const query = `db.getCollection('${collection}').aggregate(${this.logObject(pipeline)}, ${this.logObject(options)})};`;
191
+ const cursor = this.getCollection(collection).aggregate(pipeline, options);
192
+ this.logQuery(query, { ...loggerContext });
193
+ yield* cursor;
194
+ }
174
195
  async countDocuments(collection, where, ctx) {
175
196
  return this.runQuery('countDocuments', collection, undefined, where, ctx);
176
197
  }
@@ -196,7 +217,7 @@ export class MongoConnection extends Connection {
196
217
  if (!ctx) {
197
218
  await eventBroadcaster?.dispatchEvent(EventType.beforeTransactionStart);
198
219
  }
199
- const session = ctx || this.client.startSession();
220
+ const session = ctx || this.getClient().startSession();
200
221
  session.startTransaction(txOptions);
201
222
  this.logQuery('db.begin();');
202
223
  await eventBroadcaster?.dispatchEvent(EventType.afterTransactionStart, session);
@@ -292,12 +313,19 @@ export class MongoConnection extends Connection {
292
313
  createUpdatePayload(row, upsertOptions) {
293
314
  const doc = { $set: row };
294
315
  const $unset = {};
295
- Utils.keys(row)
296
- .filter(k => typeof row[k] === 'undefined')
297
- .forEach(k => {
298
- $unset[k] = '';
299
- delete row[k];
300
- });
316
+ const $inc = {};
317
+ for (const k of Utils.keys(row)) {
318
+ const item = row[k];
319
+ if (typeof item === 'undefined') {
320
+ $unset[k] = '';
321
+ delete row[k];
322
+ continue;
323
+ }
324
+ if (Utils.isPlainObject(item) && '$inc' in item) {
325
+ $inc[k] = item.$inc;
326
+ delete row[k];
327
+ }
328
+ }
301
329
  if (upsertOptions) {
302
330
  if (upsertOptions.onConflictAction === 'ignore') {
303
331
  doc.$setOnInsert = doc.$set;
@@ -323,9 +351,12 @@ export class MongoConnection extends Connection {
323
351
  }
324
352
  if (Utils.hasObjectKeys($unset)) {
325
353
  doc.$unset = $unset;
326
- if (!Utils.hasObjectKeys(doc.$set)) {
327
- delete doc.$set;
328
- }
354
+ }
355
+ if (Utils.hasObjectKeys($inc)) {
356
+ doc.$inc = $inc;
357
+ }
358
+ if (!Utils.hasObjectKeys(doc.$set)) {
359
+ delete doc.$set;
329
360
  }
330
361
  return doc;
331
362
  }
package/MongoDriver.d.ts CHANGED
@@ -1,17 +1,22 @@
1
1
  import { type ClientSession } from 'mongodb';
2
- import { type Configuration, type CountOptions, DatabaseDriver, type EntityData, type EntityDictionary, type EntityField, EntityManagerType, type FilterQuery, type FindOneOptions, type FindOptions, type NativeInsertUpdateManyOptions, type NativeInsertUpdateOptions, type PopulateOptions, type PopulatePath, type QueryResult, type Transaction, type UpsertManyOptions, type UpsertOptions } from '@mikro-orm/core';
2
+ import { type Configuration, type Constructor, type CountOptions, DatabaseDriver, type EntityData, type EntityDictionary, type EntityField, EntityManagerType, type EntityName, type FilterQuery, type FindOneOptions, type FindOptions, type NativeInsertUpdateManyOptions, type NativeInsertUpdateOptions, type PopulateOptions, type PopulatePath, type QueryResult, type StreamOptions, type Transaction, type UpsertManyOptions, type UpsertOptions } from '@mikro-orm/core';
3
3
  import { MongoConnection } from './MongoConnection.js';
4
4
  import { MongoPlatform } from './MongoPlatform.js';
5
5
  import { MongoEntityManager } from './MongoEntityManager.js';
6
+ import { MongoMikroORM } from './MongoMikroORM.js';
6
7
  export declare class MongoDriver extends DatabaseDriver<MongoConnection> {
7
8
  [EntityManagerType]: MongoEntityManager<this>;
8
9
  protected readonly connection: MongoConnection;
9
10
  protected readonly platform: MongoPlatform;
10
11
  constructor(config: Configuration);
11
12
  createEntityManager(useContext?: boolean): this[typeof EntityManagerType];
13
+ stream<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options: StreamOptions<T, any, any, any> & {
14
+ rawResults?: boolean;
15
+ }): AsyncIterableIterator<T>;
12
16
  find<T extends object, P extends string = never, F extends string = '*', E extends string = never>(entityName: string, where: FilterQuery<T>, options?: FindOptions<T, P, F, E>): Promise<EntityData<T>[]>;
13
17
  findOne<T extends object, P extends string = never, F extends string = PopulatePath.ALL, E extends string = never>(entityName: string, where: FilterQuery<T>, options?: FindOneOptions<T, P, F, E>): Promise<EntityData<T> | null>;
14
18
  findVirtual<T extends object>(entityName: string, where: FilterQuery<T>, options: FindOptions<T, any, any, any>): Promise<EntityData<T>[]>;
19
+ streamVirtual<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options: FindOptions<T, any, any, any>): AsyncIterableIterator<EntityData<T>>;
15
20
  count<T extends object>(entityName: string, where: FilterQuery<T>, options?: CountOptions<T>, ctx?: Transaction<ClientSession>): Promise<number>;
16
21
  nativeInsert<T extends object>(entityName: string, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
17
22
  nativeInsertMany<T extends object>(entityName: string, data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>): Promise<QueryResult<T>>;
@@ -21,9 +26,13 @@ export declare class MongoDriver extends DatabaseDriver<MongoConnection> {
21
26
  ctx?: Transaction<ClientSession>;
22
27
  }): Promise<QueryResult<T>>;
23
28
  aggregate(entityName: string, pipeline: any[], ctx?: Transaction<ClientSession>): Promise<any[]>;
29
+ streamAggregate<T extends object>(entityName: string, pipeline: any[], ctx?: Transaction<ClientSession>): AsyncIterableIterator<T>;
24
30
  getPlatform(): MongoPlatform;
25
31
  private renameFields;
26
32
  private convertObjectIds;
27
33
  private buildFilterById;
28
34
  protected buildFields<T extends object, P extends string = never>(entityName: string, populate: PopulateOptions<T>[], fields?: readonly EntityField<T, P>[], exclude?: string[]): string[] | undefined;
35
+ private handleVersionProperty;
36
+ /** @inheritDoc */
37
+ getORMClass(): Constructor<MongoMikroORM>;
29
38
  }
package/MongoDriver.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { ObjectId } from 'mongodb';
2
- import { DatabaseDriver, EntityManagerType, ReferenceKind, Utils, } from '@mikro-orm/core';
2
+ import { DatabaseDriver, EntityManagerType, GroupOperator, ReferenceKind, Utils, } from '@mikro-orm/core';
3
3
  import { MongoConnection } from './MongoConnection.js';
4
4
  import { MongoPlatform } from './MongoPlatform.js';
5
5
  import { MongoEntityManager } from './MongoEntityManager.js';
6
+ import { MongoMikroORM } from './MongoMikroORM.js';
6
7
  export class MongoDriver extends DatabaseDriver {
7
8
  [EntityManagerType];
8
9
  connection = new MongoConnection(this.config);
@@ -14,6 +15,25 @@ export class MongoDriver extends DatabaseDriver {
14
15
  const EntityManagerClass = this.config.get('entityManager', MongoEntityManager);
15
16
  return new EntityManagerClass(this.config, this, this.metadata, useContext);
16
17
  }
18
+ async *stream(entityName, where, options) {
19
+ if (this.metadata.find(entityName)?.virtual) {
20
+ yield* this.streamVirtual(entityName, where, options);
21
+ return;
22
+ }
23
+ entityName = Utils.className(entityName);
24
+ const fields = this.buildFields(entityName, options.populate || [], options.fields, options.exclude);
25
+ where = this.renameFields(entityName, where, true);
26
+ const orderBy = Utils.asArray(options.orderBy).map(orderBy => this.renameFields(entityName, orderBy, true));
27
+ const res = this.getConnection('read').stream(entityName, where, orderBy, options.limit, options.offset, fields, options.ctx);
28
+ for await (const item of res) {
29
+ if (options.rawResults) {
30
+ yield item;
31
+ }
32
+ else {
33
+ yield this.mapResult(item, this.metadata.find(entityName));
34
+ }
35
+ }
36
+ }
17
37
  async find(entityName, where, options = {}) {
18
38
  if (this.metadata.find(entityName)?.virtual) {
19
39
  return this.findVirtual(entityName, where, options);
@@ -70,8 +90,19 @@ export class MongoDriver extends DatabaseDriver {
70
90
  /* v8 ignore next */
71
91
  return super.findVirtual(entityName, where, options);
72
92
  }
93
+ async *streamVirtual(entityName, where, options) {
94
+ const meta = this.metadata.find(entityName);
95
+ if (meta.expression instanceof Function) {
96
+ const em = this.createEntityManager();
97
+ const stream = await meta.expression(em, where, options, true);
98
+ yield* stream;
99
+ return;
100
+ }
101
+ /* v8 ignore next */
102
+ return super.findVirtual(entityName, where, options);
103
+ }
73
104
  async count(entityName, where, options = {}, ctx) {
74
- /* v8 ignore next 3 */
105
+ /* v8 ignore next */
75
106
  if (this.metadata.find(entityName)?.virtual) {
76
107
  return this.countVirtual(entityName, where, options);
77
108
  }
@@ -79,11 +110,15 @@ export class MongoDriver extends DatabaseDriver {
79
110
  return this.rethrow(this.getConnection('read').countDocuments(entityName, where, ctx));
80
111
  }
81
112
  async nativeInsert(entityName, data, options = {}) {
113
+ this.handleVersionProperty(entityName, data);
82
114
  data = this.renameFields(entityName, data);
83
115
  return this.rethrow(this.getConnection('write').insertOne(entityName, data, options.ctx));
84
116
  }
85
117
  async nativeInsertMany(entityName, data, options = {}) {
86
- data = data.map(d => this.renameFields(entityName, d));
118
+ data = data.map(item => {
119
+ this.handleVersionProperty(entityName, item);
120
+ return this.renameFields(entityName, item);
121
+ });
87
122
  const meta = this.metadata.find(entityName);
88
123
  /* v8 ignore next */
89
124
  const pk = meta?.getPrimaryProps()[0].fieldNames[0] ?? '_id';
@@ -95,8 +130,9 @@ export class MongoDriver extends DatabaseDriver {
95
130
  if (Utils.isPrimaryKey(where)) {
96
131
  where = this.buildFilterById(entityName, where);
97
132
  }
98
- where = this.renameFields(entityName, where, true);
133
+ this.handleVersionProperty(entityName, data, true);
99
134
  data = this.renameFields(entityName, data);
135
+ where = this.renameFields(entityName, where, true);
100
136
  options = { ...options };
101
137
  const meta = this.metadata.find(entityName);
102
138
  /* v8 ignore next */
@@ -119,7 +155,10 @@ export class MongoDriver extends DatabaseDriver {
119
155
  }
120
156
  return row;
121
157
  });
122
- data = data.map(row => this.renameFields(entityName, row));
158
+ data = data.map(row => {
159
+ this.handleVersionProperty(entityName, row, true);
160
+ return this.renameFields(entityName, row);
161
+ });
123
162
  options = { ...options };
124
163
  const meta = this.metadata.find(entityName);
125
164
  /* v8 ignore next */
@@ -157,6 +196,9 @@ export class MongoDriver extends DatabaseDriver {
157
196
  async aggregate(entityName, pipeline, ctx) {
158
197
  return this.rethrow(this.getConnection('read').aggregate(entityName, pipeline, ctx));
159
198
  }
199
+ async *streamAggregate(entityName, pipeline, ctx) {
200
+ yield* this.getConnection('read').streamAggregate(entityName, pipeline, ctx);
201
+ }
160
202
  getPlatform() {
161
203
  return this.platform;
162
204
  }
@@ -176,7 +218,7 @@ export class MongoDriver extends DatabaseDriver {
176
218
  for (let i = 0; i < copiedData.$and.length; i++) {
177
219
  const and = copiedData.$and[i];
178
220
  if ('$fulltext' in and) {
179
- /* v8 ignore next 3 */
221
+ /* v8 ignore next */
180
222
  if ('$fulltext' in copiedData) {
181
223
  throw new Error('Cannot merge multiple $fulltext conditions to top level of the query object.');
182
224
  }
@@ -196,8 +238,8 @@ export class MongoDriver extends DatabaseDriver {
196
238
  throw new Error('Full text search is only supported on the top level of the query object.');
197
239
  }
198
240
  Utils.keys(copiedData).forEach(k => {
199
- if (Utils.isGroupOperator(k)) {
200
- /* v8 ignore next 5 */
241
+ if (k in GroupOperator) {
242
+ /* v8 ignore next */
201
243
  if (Array.isArray(copiedData[k])) {
202
244
  copiedData[k] = copiedData[k].map(v => this.renameFields(entityName, v));
203
245
  }
@@ -210,7 +252,7 @@ export class MongoDriver extends DatabaseDriver {
210
252
  const prop = meta.properties[k];
211
253
  let isObjectId = false;
212
254
  if (prop.kind === ReferenceKind.SCALAR) {
213
- isObjectId = prop.type.toLowerCase() === 'objectid';
255
+ isObjectId = prop.type === 'ObjectId';
214
256
  }
215
257
  else if (prop.kind === ReferenceKind.EMBEDDED) {
216
258
  if (copiedData[prop.name] == null) {
@@ -226,7 +268,7 @@ export class MongoDriver extends DatabaseDriver {
226
268
  else {
227
269
  const meta2 = this.metadata.find(prop.type);
228
270
  const pk = meta2.properties[meta2.primaryKeys[0]];
229
- isObjectId = pk.type.toLowerCase() === 'objectid';
271
+ isObjectId = pk.type === 'ObjectId';
230
272
  }
231
273
  if (isObjectId) {
232
274
  copiedData[k] = this.convertObjectIds(copiedData[k]);
@@ -245,7 +287,7 @@ export class MongoDriver extends DatabaseDriver {
245
287
  if (data instanceof ObjectId) {
246
288
  return data;
247
289
  }
248
- if (Utils.isString(data) && data.match(/^[0-9a-f]{24}$/i)) {
290
+ if (typeof data === 'string' && data.match(/^[0-9a-f]{24}$/i)) {
249
291
  return new ObjectId(data);
250
292
  }
251
293
  if (Array.isArray(data)) {
@@ -260,7 +302,7 @@ export class MongoDriver extends DatabaseDriver {
260
302
  }
261
303
  buildFilterById(entityName, id) {
262
304
  const meta = this.metadata.find(entityName);
263
- if (meta.properties[meta.primaryKeys[0]].type.toLowerCase() === 'objectid') {
305
+ if (meta.properties[meta.primaryKeys[0]].type === 'ObjectId') {
264
306
  return { _id: new ObjectId(id) };
265
307
  }
266
308
  return { _id: id };
@@ -270,11 +312,11 @@ export class MongoDriver extends DatabaseDriver {
270
312
  if (!meta) {
271
313
  return fields;
272
314
  }
273
- const lazyProps = meta.props.filter(prop => prop.lazy && !populate.some(p => p.field === prop.name || p.all));
315
+ const lazyProps = meta.props.filter(prop => prop.lazy && !populate.some(p => this.isPopulated(meta, prop, p)));
274
316
  const ret = [];
275
317
  if (fields) {
276
318
  for (let field of fields) {
277
- /* v8 ignore next 3 */
319
+ /* v8 ignore next */
278
320
  if (Utils.isPlainObject(field)) {
279
321
  continue;
280
322
  }
@@ -282,7 +324,7 @@ export class MongoDriver extends DatabaseDriver {
282
324
  field = field.toString().substring(0, field.toString().indexOf('.'));
283
325
  }
284
326
  let prop = meta.properties[field];
285
- /* v8 ignore start */
327
+ /* v8 ignore next */
286
328
  if (prop) {
287
329
  if (!prop.fieldNames) {
288
330
  continue;
@@ -297,7 +339,6 @@ export class MongoDriver extends DatabaseDriver {
297
339
  else {
298
340
  ret.push(field);
299
341
  }
300
- /* v8 ignore stop */
301
342
  }
302
343
  ret.unshift(...meta.primaryKeys.filter(pk => !fields.includes(pk)));
303
344
  }
@@ -307,4 +348,21 @@ export class MongoDriver extends DatabaseDriver {
307
348
  }
308
349
  return ret.length > 0 ? ret : undefined;
309
350
  }
351
+ handleVersionProperty(entityName, data, update = false) {
352
+ const meta = this.metadata.find(entityName);
353
+ if (!meta?.versionProperty) {
354
+ return;
355
+ }
356
+ const versionProperty = meta.properties[meta.versionProperty];
357
+ if (versionProperty.runtimeType === 'Date') {
358
+ data[versionProperty.name] ??= new Date();
359
+ }
360
+ else {
361
+ data[versionProperty.name] ??= update ? { $inc: 1 } : 1;
362
+ }
363
+ }
364
+ /** @inheritDoc */
365
+ getORMClass() {
366
+ return MongoMikroORM;
367
+ }
310
368
  }
@@ -1,4 +1,4 @@
1
- import { EntityManager, type EntityName, type EntityRepository, type GetRepository, type TransactionOptions } from '@mikro-orm/core';
1
+ import { EntityManager, type EntityName, type EntityRepository, type GetRepository, type TransactionOptions, type StreamOptions, type NoInfer, type Loaded } from '@mikro-orm/core';
2
2
  import type { Collection, Document, TransactionOptions as MongoTransactionOptions } from 'mongodb';
3
3
  import type { MongoDriver } from './MongoDriver.js';
4
4
  import type { MongoEntityRepository } from './MongoEntityRepository.js';
@@ -10,6 +10,14 @@ export declare class MongoEntityManager<Driver extends MongoDriver = MongoDriver
10
10
  * Shortcut to driver's aggregate method. Available in MongoDriver only.
11
11
  */
12
12
  aggregate(entityName: EntityName<any>, pipeline: any[]): Promise<any[]>;
13
+ /**
14
+ * Shortcut to driver's aggregate method. Returns a stream. Available in MongoDriver only.
15
+ */
16
+ streamAggregate<T extends object>(entityName: EntityName<any>, pipeline: any[]): AsyncIterableIterator<T>;
17
+ /**
18
+ * @inheritDoc
19
+ */
20
+ stream<Entity extends object, Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(entityName: EntityName<Entity>, options?: StreamOptions<NoInfer<Entity>, Hint, Fields, Excludes>): AsyncIterableIterator<Loaded<Entity, Hint, Fields, Excludes>>;
13
21
  getCollection<T extends Document>(entityName: EntityName<T>): Collection<T>;
14
22
  /**
15
23
  * @inheritDoc
@@ -1,4 +1,4 @@
1
- import { EntityManager, Utils } from '@mikro-orm/core';
1
+ import { EntityManager, Utils, } from '@mikro-orm/core';
2
2
  /**
3
3
  * @inheritDoc
4
4
  */
@@ -8,7 +8,23 @@ export class MongoEntityManager extends EntityManager {
8
8
  */
9
9
  async aggregate(entityName, pipeline) {
10
10
  entityName = Utils.className(entityName);
11
- return this.getDriver().aggregate(entityName, pipeline);
11
+ return this.getDriver().aggregate(entityName, pipeline, this.getTransactionContext());
12
+ }
13
+ /**
14
+ * Shortcut to driver's aggregate method. Returns a stream. Available in MongoDriver only.
15
+ */
16
+ async *streamAggregate(entityName, pipeline) {
17
+ entityName = Utils.className(entityName);
18
+ yield* this.getDriver().streamAggregate(entityName, pipeline, this.getTransactionContext());
19
+ }
20
+ /**
21
+ * @inheritDoc
22
+ */
23
+ async *stream(entityName, options = {}) {
24
+ if (!Utils.isEmpty(options.populate)) {
25
+ throw new Error('Populate option is not supported when streaming results in MongoDB');
26
+ }
27
+ yield* super.stream(entityName, options);
12
28
  }
13
29
  getCollection(entityName) {
14
30
  return this.getConnection().getCollection(entityName);
@@ -1,7 +1,7 @@
1
1
  import { ExceptionConverter, type Dictionary, type DriverException } from '@mikro-orm/core';
2
2
  export declare class MongoExceptionConverter extends ExceptionConverter {
3
3
  /**
4
- * @link https://gist.github.com/rluvaton/a97a8da46ab6541a3e5702e83b9d357b
4
+ * @see https://gist.github.com/rluvaton/a97a8da46ab6541a3e5702e83b9d357b
5
5
  */
6
6
  convertException(exception: Error & Dictionary): DriverException;
7
7
  }
@@ -1,9 +1,9 @@
1
1
  import { UniqueConstraintViolationException, ExceptionConverter, TableExistsException } from '@mikro-orm/core';
2
- /* v8 ignore start */
3
2
  export class MongoExceptionConverter extends ExceptionConverter {
4
3
  /**
5
- * @link https://gist.github.com/rluvaton/a97a8da46ab6541a3e5702e83b9d357b
4
+ * @see https://gist.github.com/rluvaton/a97a8da46ab6541a3e5702e83b9d357b
6
5
  */
6
+ /* v8 ignore next */
7
7
  convertException(exception) {
8
8
  switch (exception.code) {
9
9
  case 48:
@@ -14,4 +14,3 @@ export class MongoExceptionConverter extends ExceptionConverter {
14
14
  return super.convertException(exception);
15
15
  }
16
16
  }
17
- /* v8 ignore stop */
@@ -1,19 +1,22 @@
1
- import { MikroORM, type Options, type IDatabaseDriver, type EntityManager, type EntityManagerType } from '@mikro-orm/core';
1
+ import { type AnyEntity, type EntityClass, type EntitySchema, MikroORM, type Options, type IDatabaseDriver, type EntityManager, type EntityManagerType, type IMigrator } from '@mikro-orm/core';
2
2
  import { MongoDriver } from './MongoDriver.js';
3
3
  import type { MongoEntityManager } from './MongoEntityManager.js';
4
+ export type MongoOptions<EM extends MongoEntityManager = MongoEntityManager, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> = Options<MongoDriver, EM, Entities>;
5
+ export declare function defineMongoConfig<EM extends MongoEntityManager = MongoEntityManager, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]>(options: MongoOptions<EM, Entities>): Options<MongoDriver, EM, Entities>;
4
6
  /**
5
7
  * @inheritDoc
6
8
  */
7
- export declare class MongoMikroORM<EM extends EntityManager = MongoEntityManager> extends MikroORM<MongoDriver, EM> {
8
- private static DRIVER;
9
+ export declare class MongoMikroORM<EM extends MongoEntityManager = MongoEntityManager, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> extends MikroORM<MongoDriver, EM, Entities> {
9
10
  /**
10
11
  * @inheritDoc
11
12
  */
12
- static init<D extends IDatabaseDriver = MongoDriver, EM extends EntityManager = D[typeof EntityManagerType] & EntityManager>(options?: Options<D, EM>): Promise<MikroORM<D, EM>>;
13
+ static init<D extends IDatabaseDriver = MongoDriver, EM extends EntityManager<D> = D[typeof EntityManagerType] & EntityManager<D>, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]>(options: Options<D, EM, Entities>): Promise<MikroORM<D, EM, Entities>>;
13
14
  /**
14
15
  * @inheritDoc
15
16
  */
16
- static initSync<D extends IDatabaseDriver = MongoDriver, EM extends EntityManager = D[typeof EntityManagerType] & EntityManager>(options: Options<D, EM>): MikroORM<D, EM>;
17
+ constructor(options: Options<MongoDriver, EM, Entities>);
18
+ /**
19
+ * Gets the Migrator.
20
+ */
21
+ get migrator(): IMigrator;
17
22
  }
18
- export type MongoOptions = Options<MongoDriver>;
19
- export declare function defineMongoConfig(options: MongoOptions): Options<MongoDriver, MongoEntityManager<MongoDriver> & EntityManager<IDatabaseDriver<import("@mikro-orm/core").Connection>>>;