@mikro-orm/mongodb 7.0.0-dev.4 → 7.0.0-dev.41

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.
@@ -24,12 +24,15 @@ export declare class MongoConnection extends Connection {
24
24
  getDb(): Db;
25
25
  execute(query: string): Promise<any>;
26
26
  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>[]>;
27
+ 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>;
28
+ private _find;
27
29
  insertOne<T extends object>(collection: string, data: Partial<T>, ctx?: Transaction<ClientSession>): Promise<QueryResult<T>>;
28
30
  insertMany<T extends object>(collection: string, data: Partial<T>[], ctx?: Transaction<ClientSession>): Promise<QueryResult<T>>;
29
31
  updateMany<T extends object>(collection: string, where: FilterQuery<T>, data: Partial<T>, ctx?: Transaction<ClientSession>, upsert?: boolean, upsertOptions?: UpsertOptions<T>): Promise<QueryResult<T>>;
30
32
  bulkUpdateMany<T extends object>(collection: string, where: FilterQuery<T>[], data: Partial<T>[], ctx?: Transaction<ClientSession>, upsert?: boolean, upsertOptions?: UpsertManyOptions<T>): Promise<QueryResult<T>>;
31
33
  deleteMany<T extends object>(collection: string, where: FilterQuery<T>, ctx?: Transaction<ClientSession>): Promise<QueryResult<T>>;
32
34
  aggregate<T extends object = any>(collection: string, pipeline: any[], ctx?: Transaction<ClientSession>, loggerContext?: LoggingOptions): Promise<T[]>;
35
+ streamAggregate<T extends object>(collection: string, pipeline: any[], ctx?: Transaction<ClientSession>, loggerContext?: LoggingOptions, stream?: boolean): AsyncIterableIterator<T>;
33
36
  countDocuments<T extends object>(collection: string, where: FilterQuery<T>, ctx?: Transaction<ClientSession>): Promise<number>;
34
37
  transactional<T>(cb: (trx: Transaction<ClientSession>) => Promise<T>, options?: {
35
38
  isolationLevel?: IsolationLevel;
@@ -109,6 +109,18 @@ export class MongoConnection extends Connection {
109
109
  throw new Error(`${this.constructor.name} does not support generic execute method`);
110
110
  }
111
111
  async find(collection, where, orderBy, limit, offset, fields, ctx, loggerContext) {
112
+ const { cursor, query } = await this._find(collection, where, orderBy, limit, offset, fields, ctx, loggerContext);
113
+ const now = Date.now();
114
+ const res = await cursor.toArray();
115
+ this.logQuery(`${query}.toArray();`, { took: Date.now() - now, results: res.length, ...loggerContext });
116
+ return res;
117
+ }
118
+ async *stream(collection, where, orderBy, limit, offset, fields, ctx, loggerContext) {
119
+ const { cursor, query } = await this._find(collection, where, orderBy, limit, offset, fields, ctx, loggerContext);
120
+ this.logQuery(`${query}.toArray();`, loggerContext);
121
+ yield* cursor;
122
+ }
123
+ async _find(collection, where, orderBy, limit, offset, fields, ctx, loggerContext) {
112
124
  await this.ensureConnection();
113
125
  collection = this.getCollectionName(collection);
114
126
  const options = ctx ? { session: ctx } : {};
@@ -128,7 +140,6 @@ export class MongoConnection extends Connection {
128
140
  });
129
141
  if (orderByTuples.length > 0) {
130
142
  query += `.sort(${this.logObject(orderByTuples)})`;
131
- // @ts-expect-error ??
132
143
  resultSet.sort(orderByTuples);
133
144
  }
134
145
  }
@@ -140,10 +151,7 @@ export class MongoConnection extends Connection {
140
151
  query += `.skip(${offset})`;
141
152
  resultSet.skip(offset);
142
153
  }
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;
154
+ return { cursor: resultSet, query };
147
155
  }
148
156
  async insertOne(collection, data, ctx) {
149
157
  return this.runQuery('insertOne', collection, data, undefined, ctx);
@@ -171,6 +179,16 @@ export class MongoConnection extends Connection {
171
179
  this.logQuery(query, { took: Date.now() - now, results: res.length, ...loggerContext });
172
180
  return res;
173
181
  }
182
+ async *streamAggregate(collection, pipeline, ctx, loggerContext, stream = false) {
183
+ await this.ensureConnection();
184
+ collection = this.getCollectionName(collection);
185
+ /* v8 ignore next */
186
+ const options = ctx ? { session: ctx } : {};
187
+ const query = `db.getCollection('${collection}').aggregate(${this.logObject(pipeline)}, ${this.logObject(options)})};`;
188
+ const cursor = this.getCollection(collection).aggregate(pipeline, options);
189
+ this.logQuery(query, { ...loggerContext });
190
+ yield* cursor;
191
+ }
174
192
  async countDocuments(collection, where, ctx) {
175
193
  return this.runQuery('countDocuments', collection, undefined, where, ctx);
176
194
  }
@@ -292,12 +310,19 @@ export class MongoConnection extends Connection {
292
310
  createUpdatePayload(row, upsertOptions) {
293
311
  const doc = { $set: row };
294
312
  const $unset = {};
295
- Utils.keys(row)
296
- .filter(k => typeof row[k] === 'undefined')
297
- .forEach(k => {
298
- $unset[k] = '';
299
- delete row[k];
300
- });
313
+ const $inc = {};
314
+ for (const k of Utils.keys(row)) {
315
+ const item = row[k];
316
+ if (typeof item === 'undefined') {
317
+ $unset[k] = '';
318
+ delete row[k];
319
+ continue;
320
+ }
321
+ if (Utils.isPlainObject(item) && '$inc' in item) {
322
+ $inc[k] = item.$inc;
323
+ delete row[k];
324
+ }
325
+ }
301
326
  if (upsertOptions) {
302
327
  if (upsertOptions.onConflictAction === 'ignore') {
303
328
  doc.$setOnInsert = doc.$set;
@@ -323,9 +348,12 @@ export class MongoConnection extends Connection {
323
348
  }
324
349
  if (Utils.hasObjectKeys($unset)) {
325
350
  doc.$unset = $unset;
326
- if (!Utils.hasObjectKeys(doc.$set)) {
327
- delete doc.$set;
328
- }
351
+ }
352
+ if (Utils.hasObjectKeys($inc)) {
353
+ doc.$inc = $inc;
354
+ }
355
+ if (!Utils.hasObjectKeys(doc.$set)) {
356
+ delete doc.$set;
329
357
  }
330
358
  return doc;
331
359
  }
package/MongoDriver.d.ts CHANGED
@@ -1,5 +1,5 @@
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 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';
@@ -9,9 +9,13 @@ export declare class MongoDriver extends DatabaseDriver<MongoConnection> {
9
9
  protected readonly platform: MongoPlatform;
10
10
  constructor(config: Configuration);
11
11
  createEntityManager(useContext?: boolean): this[typeof EntityManagerType];
12
+ stream<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options: StreamOptions<T, any, any, any> & {
13
+ rawResults?: boolean;
14
+ }): AsyncIterableIterator<T>;
12
15
  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
16
  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
17
  findVirtual<T extends object>(entityName: string, where: FilterQuery<T>, options: FindOptions<T, any, any, any>): Promise<EntityData<T>[]>;
18
+ streamVirtual<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options: FindOptions<T, any, any, any>): AsyncIterableIterator<EntityData<T>>;
15
19
  count<T extends object>(entityName: string, where: FilterQuery<T>, options?: CountOptions<T>, ctx?: Transaction<ClientSession>): Promise<number>;
16
20
  nativeInsert<T extends object>(entityName: string, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
17
21
  nativeInsertMany<T extends object>(entityName: string, data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>): Promise<QueryResult<T>>;
@@ -21,9 +25,11 @@ export declare class MongoDriver extends DatabaseDriver<MongoConnection> {
21
25
  ctx?: Transaction<ClientSession>;
22
26
  }): Promise<QueryResult<T>>;
23
27
  aggregate(entityName: string, pipeline: any[], ctx?: Transaction<ClientSession>): Promise<any[]>;
28
+ streamAggregate<T extends object>(entityName: string, pipeline: any[], ctx?: Transaction<ClientSession>): AsyncIterableIterator<T>;
24
29
  getPlatform(): MongoPlatform;
25
30
  private renameFields;
26
31
  private convertObjectIds;
27
32
  private buildFilterById;
28
33
  protected buildFields<T extends object, P extends string = never>(entityName: string, populate: PopulateOptions<T>[], fields?: readonly EntityField<T, P>[], exclude?: string[]): string[] | undefined;
34
+ private handleVersionProperty;
29
35
  }
package/MongoDriver.js CHANGED
@@ -14,6 +14,25 @@ export class MongoDriver extends DatabaseDriver {
14
14
  const EntityManagerClass = this.config.get('entityManager', MongoEntityManager);
15
15
  return new EntityManagerClass(this.config, this, this.metadata, useContext);
16
16
  }
17
+ async *stream(entityName, where, options) {
18
+ if (this.metadata.find(entityName)?.virtual) {
19
+ yield* this.streamVirtual(entityName, where, options);
20
+ return;
21
+ }
22
+ entityName = Utils.className(entityName);
23
+ const fields = this.buildFields(entityName, options.populate || [], options.fields, options.exclude);
24
+ where = this.renameFields(entityName, where, true);
25
+ const orderBy = Utils.asArray(options.orderBy).map(orderBy => this.renameFields(entityName, orderBy, true));
26
+ const res = this.getConnection('read').stream(entityName, where, orderBy, options.limit, options.offset, fields, options.ctx);
27
+ for await (const item of res) {
28
+ if (options.rawResults) {
29
+ yield item;
30
+ }
31
+ else {
32
+ yield this.mapResult(item, this.metadata.find(entityName));
33
+ }
34
+ }
35
+ }
17
36
  async find(entityName, where, options = {}) {
18
37
  if (this.metadata.find(entityName)?.virtual) {
19
38
  return this.findVirtual(entityName, where, options);
@@ -67,7 +86,18 @@ export class MongoDriver extends DatabaseDriver {
67
86
  const em = this.createEntityManager();
68
87
  return meta.expression(em, where, options);
69
88
  }
70
- /* v8 ignore next */
89
+ /* v8 ignore next 2 */
90
+ return super.findVirtual(entityName, where, options);
91
+ }
92
+ async *streamVirtual(entityName, where, options) {
93
+ const meta = this.metadata.find(entityName);
94
+ if (meta.expression instanceof Function) {
95
+ const em = this.createEntityManager();
96
+ const stream = await meta.expression(em, where, options, true);
97
+ yield* stream;
98
+ return;
99
+ }
100
+ /* v8 ignore next 2 */
71
101
  return super.findVirtual(entityName, where, options);
72
102
  }
73
103
  async count(entityName, where, options = {}, ctx) {
@@ -79,11 +109,15 @@ export class MongoDriver extends DatabaseDriver {
79
109
  return this.rethrow(this.getConnection('read').countDocuments(entityName, where, ctx));
80
110
  }
81
111
  async nativeInsert(entityName, data, options = {}) {
112
+ this.handleVersionProperty(entityName, data);
82
113
  data = this.renameFields(entityName, data);
83
114
  return this.rethrow(this.getConnection('write').insertOne(entityName, data, options.ctx));
84
115
  }
85
116
  async nativeInsertMany(entityName, data, options = {}) {
86
- data = data.map(d => this.renameFields(entityName, d));
117
+ data = data.map(item => {
118
+ this.handleVersionProperty(entityName, item);
119
+ return this.renameFields(entityName, item);
120
+ });
87
121
  const meta = this.metadata.find(entityName);
88
122
  /* v8 ignore next */
89
123
  const pk = meta?.getPrimaryProps()[0].fieldNames[0] ?? '_id';
@@ -95,8 +129,9 @@ export class MongoDriver extends DatabaseDriver {
95
129
  if (Utils.isPrimaryKey(where)) {
96
130
  where = this.buildFilterById(entityName, where);
97
131
  }
98
- where = this.renameFields(entityName, where, true);
132
+ this.handleVersionProperty(entityName, data, true);
99
133
  data = this.renameFields(entityName, data);
134
+ where = this.renameFields(entityName, where, true);
100
135
  options = { ...options };
101
136
  const meta = this.metadata.find(entityName);
102
137
  /* v8 ignore next */
@@ -119,7 +154,10 @@ export class MongoDriver extends DatabaseDriver {
119
154
  }
120
155
  return row;
121
156
  });
122
- data = data.map(row => this.renameFields(entityName, row));
157
+ data = data.map(row => {
158
+ this.handleVersionProperty(entityName, row, true);
159
+ return this.renameFields(entityName, row);
160
+ });
123
161
  options = { ...options };
124
162
  const meta = this.metadata.find(entityName);
125
163
  /* v8 ignore next */
@@ -157,6 +195,9 @@ export class MongoDriver extends DatabaseDriver {
157
195
  async aggregate(entityName, pipeline, ctx) {
158
196
  return this.rethrow(this.getConnection('read').aggregate(entityName, pipeline, ctx));
159
197
  }
198
+ async *streamAggregate(entityName, pipeline, ctx) {
199
+ yield* this.getConnection('read').streamAggregate(entityName, pipeline, ctx);
200
+ }
160
201
  getPlatform() {
161
202
  return this.platform;
162
203
  }
@@ -307,4 +348,17 @@ 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
+ }
310
364
  }
@@ -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,19 +1,19 @@
1
- import { MikroORM, type Options, type IDatabaseDriver, type EntityManager, type EntityManagerType } from '@mikro-orm/core';
1
+ import { type AnyEntity, type EntityClass, type EntityClassGroup, type EntitySchema, MikroORM, type Options, type IDatabaseDriver, type EntityManager, type EntityManagerType } from '@mikro-orm/core';
2
2
  import { MongoDriver } from './MongoDriver.js';
3
3
  import type { MongoEntityManager } from './MongoEntityManager.js';
4
4
  /**
5
5
  * @inheritDoc
6
6
  */
7
- export declare class MongoMikroORM<EM extends EntityManager = MongoEntityManager> extends MikroORM<MongoDriver, EM> {
7
+ export declare class MongoMikroORM<EM extends EntityManager = MongoEntityManager> extends MikroORM<MongoDriver, EM, any> {
8
8
  private static DRIVER;
9
9
  /**
10
10
  * @inheritDoc
11
11
  */
12
- static init<D extends IDatabaseDriver = MongoDriver, EM extends EntityManager = D[typeof EntityManagerType] & EntityManager>(options?: Options<D, EM>): Promise<MikroORM<D, EM>>;
12
+ static init<D extends IDatabaseDriver = MongoDriver, EM extends EntityManager = D[typeof EntityManagerType] & EntityManager, Entities extends (string | EntityClass<AnyEntity> | EntityClassGroup<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntityClassGroup<AnyEntity> | EntitySchema)[]>(options?: Options<D, EM, Entities>): Promise<MikroORM<D, EM, Entities>>;
13
13
  /**
14
14
  * @inheritDoc
15
15
  */
16
- static initSync<D extends IDatabaseDriver = MongoDriver, EM extends EntityManager = D[typeof EntityManagerType] & EntityManager>(options: Options<D, EM>): MikroORM<D, EM>;
16
+ static initSync<D extends IDatabaseDriver = MongoDriver, EM extends EntityManager = D[typeof EntityManagerType] & EntityManager, Entities extends (string | EntityClass<AnyEntity> | EntityClassGroup<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntityClassGroup<AnyEntity> | EntitySchema)[]>(options: Options<D, EM, Entities>): MikroORM<D, EM, Entities>;
17
17
  }
18
18
  export type MongoOptions = Options<MongoDriver>;
19
- export declare function defineMongoConfig(options: MongoOptions): Options<MongoDriver, MongoEntityManager<MongoDriver> & EntityManager<IDatabaseDriver<import("@mikro-orm/core").Connection>>>;
19
+ export declare function defineMongoConfig(options: MongoOptions): Options<MongoDriver, MongoEntityManager<MongoDriver> & EntityManager<IDatabaseDriver<import("@mikro-orm/core").Connection>>, (string | EntityClass<Partial<any>> | EntityClassGroup<Partial<any>> | EntitySchema<any, never>)[]>;
@@ -1,5 +1,5 @@
1
1
  import { ObjectId } from 'mongodb';
2
- import { Platform, type IPrimaryKey, type Primary, type NamingStrategy, type Constructor, type EntityRepository, type EntityProperty, type PopulateOptions, type EntityMetadata, type IDatabaseDriver, type EntityManager, type Configuration, type MikroORM } from '@mikro-orm/core';
2
+ import { Platform, type IPrimaryKey, type Primary, type NamingStrategy, type Constructor, type EntityRepository, type EntityProperty, type PopulateOptions, type EntityMetadata, type IDatabaseDriver, type EntityManager, type Configuration, type MikroORM, type TransformContext } from '@mikro-orm/core';
3
3
  import { MongoExceptionConverter } from './MongoExceptionConverter.js';
4
4
  import { MongoSchemaGenerator } from './MongoSchemaGenerator.js';
5
5
  export declare class MongoPlatform extends Platform {
@@ -21,7 +21,7 @@ export declare class MongoPlatform extends Platform {
21
21
  usesImplicitTransactions(): boolean;
22
22
  convertsJsonAutomatically(): boolean;
23
23
  convertJsonToDatabaseValue(value: unknown): unknown;
24
- convertJsonToJSValue(value: unknown, prop: EntityProperty): unknown;
24
+ convertJsonToJSValue(value: unknown, context?: TransformContext): unknown;
25
25
  marshallArray(values: string[]): string;
26
26
  cloneEmbeddable<T>(data: T): T;
27
27
  shouldHaveColumn<T>(prop: EntityProperty<T>, populate: PopulateOptions<T>[], exclude?: string[]): boolean;
package/MongoPlatform.js CHANGED
@@ -60,7 +60,7 @@ export class MongoPlatform extends Platform {
60
60
  convertJsonToDatabaseValue(value) {
61
61
  return Utils.copy(value);
62
62
  }
63
- convertJsonToJSValue(value, prop) {
63
+ convertJsonToJSValue(value, context) {
64
64
  return value;
65
65
  }
66
66
  marshallArray(values) {
@@ -17,7 +17,9 @@ export declare class MongoSchemaGenerator extends AbstractSchemaGenerator<MongoD
17
17
  collectionsWithFailedIndexes?: string[];
18
18
  }): Promise<void>;
19
19
  ensureIndexes(options?: EnsureIndexesOptions): Promise<void>;
20
+ private mapIndexProperties;
20
21
  private createIndexes;
22
+ private executeQuery;
21
23
  private createUniqueIndexes;
22
24
  private createPropertyIndexes;
23
25
  }
@@ -1,13 +1,14 @@
1
+ import { inspect } from 'node:util';
1
2
  import { AbstractSchemaGenerator, Utils, } from '@mikro-orm/core';
2
3
  export class MongoSchemaGenerator extends AbstractSchemaGenerator {
3
4
  static register(orm) {
4
5
  orm.config.registerExtension('@mikro-orm/schema-generator', () => new MongoSchemaGenerator(orm.em));
5
6
  }
6
7
  async createSchema(options = {}) {
8
+ await this.connection.ensureConnection();
7
9
  options.ensureIndexes ??= true;
8
10
  const existing = await this.connection.listCollections();
9
11
  const metadata = this.getOrderedMetadata();
10
- metadata.push({ collection: this.config.get('migrations').tableName });
11
12
  /* v8 ignore start */
12
13
  const promises = metadata
13
14
  .filter(meta => !existing.includes(meta.collection))
@@ -25,9 +26,8 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
25
26
  await Promise.all(promises);
26
27
  }
27
28
  async dropSchema(options = {}) {
28
- const db = this.connection.getDb();
29
- const collections = await db.listCollections().toArray();
30
- const existing = collections.map(c => c.name);
29
+ await this.connection.ensureConnection();
30
+ const existing = await this.connection.listCollections();
31
31
  const metadata = this.getOrderedMetadata();
32
32
  if (options.dropMigrationsTable) {
33
33
  metadata.push({ collection: this.config.get('migrations').tableName });
@@ -49,6 +49,7 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
49
49
  await this.createSchema(options);
50
50
  }
51
51
  async dropIndexes(options) {
52
+ await this.connection.ensureConnection();
52
53
  const db = this.connection.getDb();
53
54
  const collections = await db.listCollections().toArray();
54
55
  const promises = [];
@@ -61,13 +62,14 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
61
62
  const isIdIndex = index.key._id === 1 && Utils.getObjectKeysSize(index.key) === 1;
62
63
  /* v8 ignore next 3 */
63
64
  if (!isIdIndex && !options?.skipIndexes?.find(idx => idx.collection === collection.name && idx.indexName === index.name)) {
64
- promises.push(db.collection(collection.name).dropIndex(index.name));
65
+ promises.push(this.executeQuery(db.collection(collection.name), 'dropIndex', index.name));
65
66
  }
66
67
  }
67
68
  }
68
69
  await Promise.all(promises);
69
70
  }
70
71
  async ensureIndexes(options = {}) {
72
+ await this.connection.ensureConnection();
71
73
  options.ensureCollections ??= true;
72
74
  options.retryLimit ??= 3;
73
75
  if (options.ensureCollections) {
@@ -112,11 +114,21 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
112
114
  });
113
115
  }
114
116
  }
117
+ mapIndexProperties(index, meta) {
118
+ return Utils.flatten(Utils.asArray(index.properties).map(propName => {
119
+ const rootPropName = propName.substring(0, propName.indexOf('.'));
120
+ const prop = meta.properties[rootPropName];
121
+ if (propName.includes('.')) {
122
+ return [prop.fieldNames[0] + propName.substring(propName.indexOf('.'))];
123
+ }
124
+ return prop?.fieldNames ?? propName;
125
+ }));
126
+ }
115
127
  createIndexes(meta) {
116
128
  const res = [];
117
129
  meta.indexes.forEach(index => {
118
130
  let fieldOrSpec;
119
- const properties = Utils.flatten(Utils.asArray(index.properties).map(prop => meta.properties[prop].fieldNames));
131
+ const properties = this.mapIndexProperties(index, meta);
120
132
  const collection = this.connection.getCollection(meta.className);
121
133
  if (Array.isArray(index.options) && index.options.length === 2 && properties.length === 0) {
122
134
  res.push([collection.collectionName, collection.createIndex(index.options[0], index.options[1])]);
@@ -137,7 +149,7 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
137
149
  else {
138
150
  fieldOrSpec = properties.reduce((o, i) => { o[i] = 1; return o; }, {});
139
151
  }
140
- res.push([collection.collectionName, collection.createIndex(fieldOrSpec, {
152
+ res.push([collection.collectionName, this.executeQuery(collection, 'createIndex', fieldOrSpec, {
141
153
  name: index.name,
142
154
  unique: false,
143
155
  ...index.options,
@@ -145,13 +157,26 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
145
157
  });
146
158
  return res;
147
159
  }
160
+ async executeQuery(collection, method, ...args) {
161
+ const now = Date.now();
162
+ return collection[method](...args).then((res) => {
163
+ Utils.dropUndefinedProperties(args);
164
+ const query = `db.getCollection('${collection.collectionName}').${method}(${args.map(arg => inspect(arg)).join(', ')});`;
165
+ this.config.getLogger().logQuery({
166
+ level: 'info',
167
+ query,
168
+ took: Date.now() - now,
169
+ });
170
+ return res;
171
+ });
172
+ }
148
173
  createUniqueIndexes(meta) {
149
174
  const res = [];
150
175
  meta.uniques.forEach(index => {
151
- const properties = Utils.flatten(Utils.asArray(index.properties).map(prop => meta.properties[prop].fieldNames));
176
+ const properties = this.mapIndexProperties(index, meta);
152
177
  const fieldOrSpec = properties.reduce((o, i) => { o[i] = 1; return o; }, {});
153
178
  const collection = this.connection.getCollection(meta.className);
154
- res.push([collection.collectionName, collection.createIndex(fieldOrSpec, {
179
+ res.push([collection.collectionName, this.executeQuery(collection, 'createIndex', fieldOrSpec, {
155
180
  name: index.name,
156
181
  unique: true,
157
182
  ...index.options,
@@ -167,7 +192,7 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
167
192
  const fieldOrSpec = prop.embeddedPath
168
193
  ? prop.embeddedPath.join('.')
169
194
  : prop.fieldNames.reduce((o, i) => { o[i] = 1; return o; }, {});
170
- return [[collection.collectionName, collection.createIndex(fieldOrSpec, {
195
+ return [[collection.collectionName, this.executeQuery(collection, 'createIndex', fieldOrSpec, {
171
196
  name: (Utils.isString(prop[type]) ? prop[type] : undefined),
172
197
  unique: type === 'unique',
173
198
  sparse: prop.nullable === true,
package/README.md CHANGED
@@ -11,7 +11,6 @@ TypeScript ORM for Node.js based on Data Mapper, [Unit of Work](https://mikro-or
11
11
  [![Chat on discord](https://img.shields.io/discord/1214904142443839538?label=discord&color=blue)](https://discord.gg/w8bjxFHS7X)
12
12
  [![Downloads](https://img.shields.io/npm/dm/@mikro-orm/core.svg)](https://www.npmjs.com/package/@mikro-orm/core)
13
13
  [![Coverage Status](https://img.shields.io/coveralls/mikro-orm/mikro-orm.svg)](https://coveralls.io/r/mikro-orm/mikro-orm?branch=master)
14
- [![Maintainability](https://api.codeclimate.com/v1/badges/27999651d3adc47cfa40/maintainability)](https://codeclimate.com/github/mikro-orm/mikro-orm/maintainability)
15
14
  [![Build Status](https://github.com/mikro-orm/mikro-orm/workflows/tests/badge.svg?branch=master)](https://github.com/mikro-orm/mikro-orm/actions?workflow=tests)
16
15
 
17
16
  ## 🤔 Unit of What?
@@ -141,7 +140,7 @@ There is also auto-generated [CHANGELOG.md](CHANGELOG.md) file based on commit m
141
140
  - [Composite and Foreign Keys as Primary Key](https://mikro-orm.io/docs/composite-keys)
142
141
  - [Filters](https://mikro-orm.io/docs/filters)
143
142
  - [Using `QueryBuilder`](https://mikro-orm.io/docs/query-builder)
144
- - [Preloading Deeply Nested Structures via populate](https://mikro-orm.io/docs/nested-populate)
143
+ - [Populating relations](https://mikro-orm.io/docs/populating-relations)
145
144
  - [Property Validation](https://mikro-orm.io/docs/property-validation)
146
145
  - [Lifecycle Hooks](https://mikro-orm.io/docs/events#hooks)
147
146
  - [Vanilla JS Support](https://mikro-orm.io/docs/usage-with-js)
@@ -382,6 +381,8 @@ See also the list of contributors who [participated](https://github.com/mikro-or
382
381
 
383
382
  Please ⭐️ this repository if this project helped you!
384
383
 
384
+ > If you'd like to support my open-source work, consider sponsoring me directly at [github.com/sponsors/b4nan](https://github.com/sponsors/b4nan).
385
+
385
386
  ## 📝 License
386
387
 
387
388
  Copyright © 2018 [Martin Adámek](https://github.com/b4nan).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mikro-orm/mongodb",
3
3
  "type": "module",
4
- "version": "7.0.0-dev.4",
4
+ "version": "7.0.0-dev.41",
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",
@@ -50,12 +50,12 @@
50
50
  "access": "public"
51
51
  },
52
52
  "dependencies": {
53
- "mongodb": "6.13.1"
53
+ "mongodb": "6.20.0"
54
54
  },
55
55
  "devDependencies": {
56
- "@mikro-orm/core": "^6.4.7"
56
+ "@mikro-orm/core": "^6.6.0"
57
57
  },
58
58
  "peerDependencies": {
59
- "@mikro-orm/core": "7.0.0-dev.4"
59
+ "@mikro-orm/core": "7.0.0-dev.41"
60
60
  }
61
61
  }