@mikro-orm/mongodb 7.0.0-dev.22 → 7.0.0-dev.220
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.
- package/MongoConnection.d.ts +18 -14
- package/MongoConnection.js +118 -81
- package/MongoDriver.d.ts +21 -12
- package/MongoDriver.js +84 -25
- package/MongoEntityManager.d.ts +10 -2
- package/MongoEntityManager.js +17 -3
- package/MongoExceptionConverter.d.ts +1 -1
- package/MongoExceptionConverter.js +2 -3
- package/MongoMikroORM.d.ts +10 -7
- package/MongoMikroORM.js +12 -8
- package/MongoPlatform.d.ts +2 -4
- package/MongoPlatform.js +4 -10
- package/MongoSchemaGenerator.d.ts +6 -4
- package/MongoSchemaGenerator.js +46 -24
- package/README.md +3 -2
- package/index.d.ts +1 -1
- package/package.json +6 -6
- package/tsconfig.build.tsbuildinfo +1 -0
package/MongoDriver.js
CHANGED
|
@@ -3,6 +3,7 @@ import { DatabaseDriver, EntityManagerType, ReferenceKind, Utils, } from '@mikro
|
|
|
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,24 @@ 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
|
+
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);
|
|
@@ -70,8 +89,19 @@ export class MongoDriver extends DatabaseDriver {
|
|
|
70
89
|
/* v8 ignore next */
|
|
71
90
|
return super.findVirtual(entityName, where, options);
|
|
72
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 */
|
|
101
|
+
return super.findVirtual(entityName, where, options);
|
|
102
|
+
}
|
|
73
103
|
async count(entityName, where, options = {}, ctx) {
|
|
74
|
-
/* v8 ignore next
|
|
104
|
+
/* v8 ignore next */
|
|
75
105
|
if (this.metadata.find(entityName)?.virtual) {
|
|
76
106
|
return this.countVirtual(entityName, where, options);
|
|
77
107
|
}
|
|
@@ -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(
|
|
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
|
-
|
|
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 =>
|
|
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,10 +195,19 @@ 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
|
}
|
|
163
|
-
renameFields(entityName, data, dotPaths = false, object) {
|
|
204
|
+
renameFields(entityName, data, dotPaths = false, object, root = true) {
|
|
205
|
+
if (data == null && root) {
|
|
206
|
+
return {};
|
|
207
|
+
}
|
|
208
|
+
if (typeof data !== 'object' || data === null) {
|
|
209
|
+
return data;
|
|
210
|
+
}
|
|
164
211
|
// copy to new variable to prevent changing the T type or doing as unknown casts
|
|
165
212
|
const copiedData = Object.assign({}, data); // copy first
|
|
166
213
|
const meta = this.metadata.find(entityName);
|
|
@@ -176,7 +223,7 @@ export class MongoDriver extends DatabaseDriver {
|
|
|
176
223
|
for (let i = 0; i < copiedData.$and.length; i++) {
|
|
177
224
|
const and = copiedData.$and[i];
|
|
178
225
|
if ('$fulltext' in and) {
|
|
179
|
-
/* v8 ignore next
|
|
226
|
+
/* v8 ignore next */
|
|
180
227
|
if ('$fulltext' in copiedData) {
|
|
181
228
|
throw new Error('Cannot merge multiple $fulltext conditions to top level of the query object.');
|
|
182
229
|
}
|
|
@@ -196,13 +243,12 @@ export class MongoDriver extends DatabaseDriver {
|
|
|
196
243
|
throw new Error('Full text search is only supported on the top level of the query object.');
|
|
197
244
|
}
|
|
198
245
|
Utils.keys(copiedData).forEach(k => {
|
|
199
|
-
if (Utils.
|
|
200
|
-
/* v8 ignore next 5 */
|
|
246
|
+
if (Utils.isOperator(k)) {
|
|
201
247
|
if (Array.isArray(copiedData[k])) {
|
|
202
|
-
copiedData[k] = copiedData[k].map(v => this.renameFields(entityName, v));
|
|
248
|
+
copiedData[k] = copiedData[k].map(v => this.renameFields(entityName, v, dotPaths, object, false));
|
|
203
249
|
}
|
|
204
250
|
else {
|
|
205
|
-
copiedData[k] = this.renameFields(entityName, copiedData[k]);
|
|
251
|
+
copiedData[k] = this.renameFields(entityName, copiedData[k], dotPaths, object, false);
|
|
206
252
|
}
|
|
207
253
|
return;
|
|
208
254
|
}
|
|
@@ -210,23 +256,23 @@ export class MongoDriver extends DatabaseDriver {
|
|
|
210
256
|
const prop = meta.properties[k];
|
|
211
257
|
let isObjectId = false;
|
|
212
258
|
if (prop.kind === ReferenceKind.SCALAR) {
|
|
213
|
-
isObjectId = prop.type
|
|
259
|
+
isObjectId = prop.type === 'ObjectId';
|
|
214
260
|
}
|
|
215
261
|
else if (prop.kind === ReferenceKind.EMBEDDED) {
|
|
216
262
|
if (copiedData[prop.name] == null) {
|
|
217
263
|
return;
|
|
218
264
|
}
|
|
219
265
|
if (prop.array && Array.isArray(copiedData[prop.name])) {
|
|
220
|
-
copiedData[prop.name] = copiedData[prop.name].map((item) => this.renameFields(prop.
|
|
266
|
+
copiedData[prop.name] = copiedData[prop.name].map((item) => this.renameFields(prop.targetMeta.class, item, dotPaths, true, false));
|
|
221
267
|
}
|
|
222
268
|
else {
|
|
223
|
-
copiedData[prop.name] = this.renameFields(prop.
|
|
269
|
+
copiedData[prop.name] = this.renameFields(prop.targetMeta.class, copiedData[prop.name], dotPaths, prop.object || object, false);
|
|
224
270
|
}
|
|
225
271
|
}
|
|
226
272
|
else {
|
|
227
|
-
const meta2 = this.metadata.find(prop.
|
|
273
|
+
const meta2 = this.metadata.find(prop.targetMeta.class);
|
|
228
274
|
const pk = meta2.properties[meta2.primaryKeys[0]];
|
|
229
|
-
isObjectId = pk.type
|
|
275
|
+
isObjectId = pk.type === 'ObjectId';
|
|
230
276
|
}
|
|
231
277
|
if (isObjectId) {
|
|
232
278
|
copiedData[k] = this.convertObjectIds(copiedData[k]);
|
|
@@ -245,7 +291,7 @@ export class MongoDriver extends DatabaseDriver {
|
|
|
245
291
|
if (data instanceof ObjectId) {
|
|
246
292
|
return data;
|
|
247
293
|
}
|
|
248
|
-
if (
|
|
294
|
+
if (typeof data === 'string' && data.match(/^[0-9a-f]{24}$/i)) {
|
|
249
295
|
return new ObjectId(data);
|
|
250
296
|
}
|
|
251
297
|
if (Array.isArray(data)) {
|
|
@@ -260,21 +306,18 @@ export class MongoDriver extends DatabaseDriver {
|
|
|
260
306
|
}
|
|
261
307
|
buildFilterById(entityName, id) {
|
|
262
308
|
const meta = this.metadata.find(entityName);
|
|
263
|
-
if (meta.properties[meta.primaryKeys[0]].type
|
|
309
|
+
if (meta.properties[meta.primaryKeys[0]].type === 'ObjectId') {
|
|
264
310
|
return { _id: new ObjectId(id) };
|
|
265
311
|
}
|
|
266
312
|
return { _id: id };
|
|
267
313
|
}
|
|
268
314
|
buildFields(entityName, populate, fields, exclude) {
|
|
269
|
-
const meta = this.metadata.
|
|
270
|
-
|
|
271
|
-
return fields;
|
|
272
|
-
}
|
|
273
|
-
const lazyProps = meta.props.filter(prop => prop.lazy && !populate.some(p => p.field === prop.name || p.all));
|
|
315
|
+
const meta = this.metadata.get(entityName);
|
|
316
|
+
const lazyProps = meta.props.filter(prop => prop.lazy && !populate.some(p => this.isPopulated(meta, prop, p)));
|
|
274
317
|
const ret = [];
|
|
275
318
|
if (fields) {
|
|
276
319
|
for (let field of fields) {
|
|
277
|
-
/* v8 ignore next
|
|
320
|
+
/* v8 ignore next */
|
|
278
321
|
if (Utils.isPlainObject(field)) {
|
|
279
322
|
continue;
|
|
280
323
|
}
|
|
@@ -282,7 +325,7 @@ export class MongoDriver extends DatabaseDriver {
|
|
|
282
325
|
field = field.toString().substring(0, field.toString().indexOf('.'));
|
|
283
326
|
}
|
|
284
327
|
let prop = meta.properties[field];
|
|
285
|
-
/* v8 ignore
|
|
328
|
+
/* v8 ignore next */
|
|
286
329
|
if (prop) {
|
|
287
330
|
if (!prop.fieldNames) {
|
|
288
331
|
continue;
|
|
@@ -297,7 +340,6 @@ export class MongoDriver extends DatabaseDriver {
|
|
|
297
340
|
else {
|
|
298
341
|
ret.push(field);
|
|
299
342
|
}
|
|
300
|
-
/* v8 ignore stop */
|
|
301
343
|
}
|
|
302
344
|
ret.unshift(...meta.primaryKeys.filter(pk => !fields.includes(pk)));
|
|
303
345
|
}
|
|
@@ -307,4 +349,21 @@ export class MongoDriver extends DatabaseDriver {
|
|
|
307
349
|
}
|
|
308
350
|
return ret.length > 0 ? ret : undefined;
|
|
309
351
|
}
|
|
352
|
+
handleVersionProperty(entityName, data, update = false) {
|
|
353
|
+
const meta = this.metadata.find(entityName);
|
|
354
|
+
if (!meta?.versionProperty) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
const versionProperty = meta.properties[meta.versionProperty];
|
|
358
|
+
if (versionProperty.runtimeType === 'Date') {
|
|
359
|
+
data[versionProperty.name] ??= new Date();
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
data[versionProperty.name] ??= update ? { $inc: 1 } : 1;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
/** @inheritDoc */
|
|
366
|
+
getORMClass() {
|
|
367
|
+
return MongoMikroORM;
|
|
368
|
+
}
|
|
310
369
|
}
|
package/MongoEntityManager.d.ts
CHANGED
|
@@ -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 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';
|
|
@@ -9,7 +9,15 @@ export declare class MongoEntityManager<Driver extends MongoDriver = MongoDriver
|
|
|
9
9
|
/**
|
|
10
10
|
* Shortcut to driver's aggregate method. Available in MongoDriver only.
|
|
11
11
|
*/
|
|
12
|
-
aggregate(entityName: EntityName
|
|
12
|
+
aggregate(entityName: EntityName, 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, 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
|
package/MongoEntityManager.js
CHANGED
|
@@ -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
|
*/
|
|
@@ -7,8 +7,22 @@ export class MongoEntityManager extends EntityManager {
|
|
|
7
7
|
* Shortcut to driver's aggregate method. Available in MongoDriver only.
|
|
8
8
|
*/
|
|
9
9
|
async aggregate(entityName, pipeline) {
|
|
10
|
-
entityName
|
|
11
|
-
|
|
10
|
+
return this.getDriver().aggregate(entityName, pipeline, this.getTransactionContext());
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Shortcut to driver's aggregate method. Returns a stream. Available in MongoDriver only.
|
|
14
|
+
*/
|
|
15
|
+
async *streamAggregate(entityName, pipeline) {
|
|
16
|
+
yield* this.getDriver().streamAggregate(entityName, pipeline, this.getTransactionContext());
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* @inheritDoc
|
|
20
|
+
*/
|
|
21
|
+
async *stream(entityName, options = {}) {
|
|
22
|
+
if (!Utils.isEmpty(options.populate)) {
|
|
23
|
+
throw new Error('Populate option is not supported when streaming results in MongoDB');
|
|
24
|
+
}
|
|
25
|
+
yield* super.stream(entityName, options);
|
|
12
26
|
}
|
|
13
27
|
getCollection(entityName) {
|
|
14
28
|
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
|
-
* @
|
|
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
|
-
* @
|
|
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 */
|
package/MongoMikroORM.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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>>>;
|
package/MongoMikroORM.js
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
import { defineConfig, MikroORM, } from '@mikro-orm/core';
|
|
2
2
|
import { MongoDriver } from './MongoDriver.js';
|
|
3
|
+
export function defineMongoConfig(options) {
|
|
4
|
+
return defineConfig({ driver: MongoDriver, ...options });
|
|
5
|
+
}
|
|
3
6
|
/**
|
|
4
7
|
* @inheritDoc
|
|
5
8
|
*/
|
|
6
9
|
export class MongoMikroORM extends MikroORM {
|
|
7
|
-
static DRIVER = MongoDriver;
|
|
8
10
|
/**
|
|
9
11
|
* @inheritDoc
|
|
10
12
|
*/
|
|
11
13
|
static async init(options) {
|
|
12
|
-
return super.init(options);
|
|
14
|
+
return super.init(defineMongoConfig(options));
|
|
13
15
|
}
|
|
14
16
|
/**
|
|
15
17
|
* @inheritDoc
|
|
16
18
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
constructor(options) {
|
|
20
|
+
super(defineMongoConfig(options));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Gets the Migrator.
|
|
24
|
+
*/
|
|
25
|
+
get migrator() {
|
|
26
|
+
return this.driver.getPlatform().getExtension('Migrator', '@mikro-orm/migrator', '@mikro-orm/migrations-mongodb', this.em);
|
|
19
27
|
}
|
|
20
|
-
}
|
|
21
|
-
/* v8 ignore next 3 */
|
|
22
|
-
export function defineMongoConfig(options) {
|
|
23
|
-
return defineConfig({ driver: MongoDriver, ...options });
|
|
24
28
|
}
|
package/MongoPlatform.d.ts
CHANGED
|
@@ -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 {
|
|
@@ -16,12 +16,10 @@ export declare class MongoPlatform extends Platform {
|
|
|
16
16
|
getSchemaGenerator(driver: IDatabaseDriver, em?: EntityManager): MongoSchemaGenerator;
|
|
17
17
|
normalizePrimaryKey<T extends number | string = number | string>(data: Primary<T> | IPrimaryKey | ObjectId): T;
|
|
18
18
|
denormalizePrimaryKey(data: number | string): IPrimaryKey;
|
|
19
|
-
getSerializedPrimaryKeyField(field: string): string;
|
|
20
|
-
usesDifferentSerializedPrimaryKey(): boolean;
|
|
21
19
|
usesImplicitTransactions(): boolean;
|
|
22
20
|
convertsJsonAutomatically(): boolean;
|
|
23
21
|
convertJsonToDatabaseValue(value: unknown): unknown;
|
|
24
|
-
convertJsonToJSValue(value: unknown,
|
|
22
|
+
convertJsonToJSValue(value: unknown, context?: TransformContext): unknown;
|
|
25
23
|
marshallArray(values: string[]): string;
|
|
26
24
|
cloneEmbeddable<T>(data: T): T;
|
|
27
25
|
shouldHaveColumn<T>(prop: EntityProperty<T>, populate: PopulateOptions<T>[], exclude?: string[]): boolean;
|
package/MongoPlatform.js
CHANGED
|
@@ -32,24 +32,18 @@ export class MongoPlatform extends Platform {
|
|
|
32
32
|
/* v8 ignore next */
|
|
33
33
|
return super.getExtension(extensionName, extensionKey, moduleName, em);
|
|
34
34
|
}
|
|
35
|
-
/* v8 ignore next
|
|
35
|
+
/* v8 ignore next: kept for type inference only */
|
|
36
36
|
getSchemaGenerator(driver, em) {
|
|
37
37
|
return new MongoSchemaGenerator(em ?? driver);
|
|
38
38
|
}
|
|
39
39
|
normalizePrimaryKey(data) {
|
|
40
|
-
if (Utils.
|
|
40
|
+
if (Utils.isObject(data) && data.constructor?.name === 'ObjectId') {
|
|
41
41
|
return data.toHexString();
|
|
42
42
|
}
|
|
43
43
|
return data;
|
|
44
44
|
}
|
|
45
45
|
denormalizePrimaryKey(data) {
|
|
46
|
-
return new ObjectId(data);
|
|
47
|
-
}
|
|
48
|
-
getSerializedPrimaryKeyField(field) {
|
|
49
|
-
return 'id';
|
|
50
|
-
}
|
|
51
|
-
usesDifferentSerializedPrimaryKey() {
|
|
52
|
-
return true;
|
|
46
|
+
return new ObjectId('' + data);
|
|
53
47
|
}
|
|
54
48
|
usesImplicitTransactions() {
|
|
55
49
|
return false;
|
|
@@ -60,7 +54,7 @@ export class MongoPlatform extends Platform {
|
|
|
60
54
|
convertJsonToDatabaseValue(value) {
|
|
61
55
|
return Utils.copy(value);
|
|
62
56
|
}
|
|
63
|
-
convertJsonToJSValue(value,
|
|
57
|
+
convertJsonToJSValue(value, context) {
|
|
64
58
|
return value;
|
|
65
59
|
}
|
|
66
60
|
marshallArray(values) {
|
|
@@ -2,13 +2,13 @@ import { AbstractSchemaGenerator, type CreateSchemaOptions, type MikroORM } from
|
|
|
2
2
|
import type { MongoDriver } from './MongoDriver.js';
|
|
3
3
|
export declare class MongoSchemaGenerator extends AbstractSchemaGenerator<MongoDriver> {
|
|
4
4
|
static register(orm: MikroORM): void;
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
create(options?: MongoCreateSchemaOptions): Promise<void>;
|
|
6
|
+
drop(options?: {
|
|
7
7
|
dropMigrationsTable?: boolean;
|
|
8
8
|
}): Promise<void>;
|
|
9
|
-
|
|
9
|
+
update(options?: MongoCreateSchemaOptions): Promise<void>;
|
|
10
10
|
ensureDatabase(): Promise<boolean>;
|
|
11
|
-
|
|
11
|
+
refresh(options?: MongoCreateSchemaOptions): Promise<void>;
|
|
12
12
|
dropIndexes(options?: {
|
|
13
13
|
skipIndexes?: {
|
|
14
14
|
collection: string;
|
|
@@ -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
|
}
|
package/MongoSchemaGenerator.js
CHANGED
|
@@ -1,30 +1,29 @@
|
|
|
1
|
-
import { AbstractSchemaGenerator, Utils, } from '@mikro-orm/core';
|
|
1
|
+
import { AbstractSchemaGenerator, Utils, inspect, } from '@mikro-orm/core';
|
|
2
2
|
export class MongoSchemaGenerator extends AbstractSchemaGenerator {
|
|
3
3
|
static register(orm) {
|
|
4
4
|
orm.config.registerExtension('@mikro-orm/schema-generator', () => new MongoSchemaGenerator(orm.em));
|
|
5
5
|
}
|
|
6
|
-
async
|
|
6
|
+
async create(options = {}) {
|
|
7
7
|
await this.connection.ensureConnection();
|
|
8
8
|
options.ensureIndexes ??= true;
|
|
9
9
|
const existing = await this.connection.listCollections();
|
|
10
10
|
const metadata = this.getOrderedMetadata();
|
|
11
|
-
/* v8 ignore
|
|
11
|
+
/* v8 ignore next */
|
|
12
12
|
const promises = metadata
|
|
13
13
|
.filter(meta => !existing.includes(meta.collection))
|
|
14
|
-
.map(meta => this.connection.createCollection(meta.
|
|
14
|
+
.map(meta => this.connection.createCollection(meta.class).catch(err => {
|
|
15
15
|
const existsErrorMessage = `Collection ${this.config.get('dbName')}.${meta.collection} already exists.`;
|
|
16
16
|
// ignore errors about the collection already existing
|
|
17
17
|
if (!(err.name === 'MongoServerError' && err.message.includes(existsErrorMessage))) {
|
|
18
18
|
throw err;
|
|
19
19
|
}
|
|
20
20
|
}));
|
|
21
|
-
/* v8 ignore stop */
|
|
22
21
|
if (options.ensureIndexes) {
|
|
23
22
|
await this.ensureIndexes({ ensureCollections: false });
|
|
24
23
|
}
|
|
25
24
|
await Promise.all(promises);
|
|
26
25
|
}
|
|
27
|
-
async
|
|
26
|
+
async drop(options = {}) {
|
|
28
27
|
await this.connection.ensureConnection();
|
|
29
28
|
const existing = await this.connection.listCollections();
|
|
30
29
|
const metadata = this.getOrderedMetadata();
|
|
@@ -33,19 +32,19 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
|
|
|
33
32
|
}
|
|
34
33
|
const promises = metadata
|
|
35
34
|
.filter(meta => existing.includes(meta.collection))
|
|
36
|
-
.map(meta => this.connection.dropCollection(meta.
|
|
35
|
+
.map(meta => this.connection.dropCollection(meta.class));
|
|
37
36
|
await Promise.all(promises);
|
|
38
37
|
}
|
|
39
|
-
async
|
|
40
|
-
await this.
|
|
38
|
+
async update(options = {}) {
|
|
39
|
+
await this.create(options);
|
|
41
40
|
}
|
|
42
41
|
async ensureDatabase() {
|
|
43
42
|
return false;
|
|
44
43
|
}
|
|
45
|
-
async
|
|
44
|
+
async refresh(options = {}) {
|
|
46
45
|
await this.ensureDatabase();
|
|
47
|
-
await this.
|
|
48
|
-
await this.
|
|
46
|
+
await this.drop();
|
|
47
|
+
await this.create(options);
|
|
49
48
|
}
|
|
50
49
|
async dropIndexes(options) {
|
|
51
50
|
await this.connection.ensureConnection();
|
|
@@ -59,9 +58,9 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
|
|
|
59
58
|
const indexes = await db.collection(collection.name).listIndexes().toArray();
|
|
60
59
|
for (const index of indexes) {
|
|
61
60
|
const isIdIndex = index.key._id === 1 && Utils.getObjectKeysSize(index.key) === 1;
|
|
62
|
-
/* v8 ignore next
|
|
61
|
+
/* v8 ignore next */
|
|
63
62
|
if (!isIdIndex && !options?.skipIndexes?.find(idx => idx.collection === collection.name && idx.indexName === index.name)) {
|
|
64
|
-
promises.push(db.collection(collection.name)
|
|
63
|
+
promises.push(this.executeQuery(db.collection(collection.name), 'dropIndex', index.name));
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
66
|
}
|
|
@@ -72,7 +71,7 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
|
|
|
72
71
|
options.ensureCollections ??= true;
|
|
73
72
|
options.retryLimit ??= 3;
|
|
74
73
|
if (options.ensureCollections) {
|
|
75
|
-
await this.
|
|
74
|
+
await this.create({ ensureIndexes: false });
|
|
76
75
|
}
|
|
77
76
|
const promises = [];
|
|
78
77
|
for (const meta of this.getOrderedMetadata()) {
|
|
@@ -113,12 +112,22 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
|
|
|
113
112
|
});
|
|
114
113
|
}
|
|
115
114
|
}
|
|
115
|
+
mapIndexProperties(index, meta) {
|
|
116
|
+
return Utils.flatten(Utils.asArray(index.properties).map(propName => {
|
|
117
|
+
const rootPropName = propName.split('.')[0];
|
|
118
|
+
const prop = meta.properties[rootPropName];
|
|
119
|
+
if (propName.includes('.')) {
|
|
120
|
+
return [prop.fieldNames[0] + propName.substring(propName.indexOf('.'))];
|
|
121
|
+
}
|
|
122
|
+
return prop?.fieldNames ?? propName;
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
116
125
|
createIndexes(meta) {
|
|
117
126
|
const res = [];
|
|
118
127
|
meta.indexes.forEach(index => {
|
|
119
128
|
let fieldOrSpec;
|
|
120
|
-
const properties =
|
|
121
|
-
const collection = this.connection.getCollection(meta.
|
|
129
|
+
const properties = this.mapIndexProperties(index, meta);
|
|
130
|
+
const collection = this.connection.getCollection(meta.class);
|
|
122
131
|
if (Array.isArray(index.options) && index.options.length === 2 && properties.length === 0) {
|
|
123
132
|
res.push([collection.collectionName, collection.createIndex(index.options[0], index.options[1])]);
|
|
124
133
|
return;
|
|
@@ -138,7 +147,7 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
|
|
|
138
147
|
else {
|
|
139
148
|
fieldOrSpec = properties.reduce((o, i) => { o[i] = 1; return o; }, {});
|
|
140
149
|
}
|
|
141
|
-
res.push([collection.collectionName, collection
|
|
150
|
+
res.push([collection.collectionName, this.executeQuery(collection, 'createIndex', fieldOrSpec, {
|
|
142
151
|
name: index.name,
|
|
143
152
|
unique: false,
|
|
144
153
|
...index.options,
|
|
@@ -146,13 +155,26 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
|
|
|
146
155
|
});
|
|
147
156
|
return res;
|
|
148
157
|
}
|
|
158
|
+
async executeQuery(collection, method, ...args) {
|
|
159
|
+
const now = Date.now();
|
|
160
|
+
return collection[method](...args).then((res) => {
|
|
161
|
+
Utils.dropUndefinedProperties(args);
|
|
162
|
+
const query = `db.getCollection('${collection.collectionName}').${method}(${args.map(arg => inspect(arg)).join(', ')});`;
|
|
163
|
+
this.config.getLogger().logQuery({
|
|
164
|
+
level: 'info',
|
|
165
|
+
query,
|
|
166
|
+
took: Date.now() - now,
|
|
167
|
+
});
|
|
168
|
+
return res;
|
|
169
|
+
});
|
|
170
|
+
}
|
|
149
171
|
createUniqueIndexes(meta) {
|
|
150
172
|
const res = [];
|
|
151
173
|
meta.uniques.forEach(index => {
|
|
152
|
-
const properties =
|
|
174
|
+
const properties = this.mapIndexProperties(index, meta);
|
|
153
175
|
const fieldOrSpec = properties.reduce((o, i) => { o[i] = 1; return o; }, {});
|
|
154
|
-
const collection = this.connection.getCollection(meta.
|
|
155
|
-
res.push([collection.collectionName, collection
|
|
176
|
+
const collection = this.connection.getCollection(meta.class);
|
|
177
|
+
res.push([collection.collectionName, this.executeQuery(collection, 'createIndex', fieldOrSpec, {
|
|
156
178
|
name: index.name,
|
|
157
179
|
unique: true,
|
|
158
180
|
...index.options,
|
|
@@ -164,12 +186,12 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
|
|
|
164
186
|
if (!prop[type] || !meta.collection) {
|
|
165
187
|
return [];
|
|
166
188
|
}
|
|
167
|
-
const collection = this.connection.getCollection(meta.
|
|
189
|
+
const collection = this.connection.getCollection(meta.class);
|
|
168
190
|
const fieldOrSpec = prop.embeddedPath
|
|
169
191
|
? prop.embeddedPath.join('.')
|
|
170
192
|
: prop.fieldNames.reduce((o, i) => { o[i] = 1; return o; }, {});
|
|
171
|
-
return [[collection.collectionName, collection
|
|
172
|
-
name:
|
|
193
|
+
return [[collection.collectionName, this.executeQuery(collection, 'createIndex', fieldOrSpec, {
|
|
194
|
+
name: typeof prop[type] === 'string' ? prop[type] : undefined,
|
|
173
195
|
unique: type === 'unique',
|
|
174
196
|
sparse: prop.nullable === true,
|
|
175
197
|
})]];
|