@mikro-orm/mongodb 7.0.0-dev.11 → 7.0.0-dev.110
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 +10 -6
- package/MongoConnection.js +81 -50
- package/MongoDriver.d.ts +10 -1
- package/MongoDriver.js +74 -16
- package/MongoEntityManager.d.ts +9 -1
- package/MongoEntityManager.js +18 -2
- 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 +41 -19
- package/README.md +3 -2
- package/index.d.ts +1 -1
- package/package.json +5 -5
package/MongoConnection.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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
|
-
|
|
5
|
-
protected db: Db;
|
|
4
|
+
#private;
|
|
6
5
|
constructor(config: Configuration, options?: ConnectionOptions, type?: ConnectionType);
|
|
7
|
-
connect(
|
|
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;
|
package/MongoConnection.js
CHANGED
|
@@ -1,49 +1,54 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { inspect } from '
|
|
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 =
|
|
27
|
+
driverOptions = driverOptions();
|
|
22
28
|
}
|
|
23
29
|
if (driverOptions instanceof MongoClient) {
|
|
24
30
|
this.logger.log('info', 'Reusing MongoClient provided via `driverOptions`');
|
|
25
|
-
this
|
|
31
|
+
this.#client = driverOptions;
|
|
26
32
|
}
|
|
27
33
|
else {
|
|
28
|
-
this
|
|
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
|
|
32
|
-
this
|
|
33
|
-
void onCreateConnection?.(this
|
|
36
|
+
/* v8 ignore next */
|
|
37
|
+
this.#client.on('connectionCreated', () => {
|
|
38
|
+
void onCreateConnection?.(this.#client);
|
|
34
39
|
});
|
|
35
40
|
}
|
|
36
|
-
this
|
|
37
|
-
this.connected = true;
|
|
41
|
+
this.#db = this.#client.db(this.config.get('dbName'));
|
|
38
42
|
}
|
|
39
43
|
async close(force) {
|
|
40
|
-
await this
|
|
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
|
|
46
|
-
return this.connected = !!res
|
|
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
|
|
55
|
-
return res
|
|
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
|
-
|
|
69
|
+
if (!this.#client) {
|
|
70
|
+
this.createClient();
|
|
71
|
+
}
|
|
72
|
+
return this.#client;
|
|
65
73
|
}
|
|
66
74
|
getCollection(name) {
|
|
67
|
-
return this.
|
|
75
|
+
return this.getDb().collection(this.getCollectionName(name));
|
|
68
76
|
}
|
|
69
77
|
async createCollection(name) {
|
|
70
|
-
return this.
|
|
78
|
+
return this.getDb().createCollection(this.getCollectionName(name));
|
|
71
79
|
}
|
|
72
80
|
async listCollections() {
|
|
73
|
-
const collections = await this.
|
|
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.
|
|
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
|
-
|
|
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(),
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
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
|
-
|
|
327
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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 =>
|
|
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
|
|
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 (
|
|
200
|
-
/* v8 ignore next
|
|
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
|
|
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
|
|
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 (
|
|
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
|
|
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 =>
|
|
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
|
|
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
|
|
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
|
}
|
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 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
|
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
|
*/
|
|
@@ -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
|
-
* @
|
|
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,14 +1,14 @@
|
|
|
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
14
|
.map(meta => this.connection.createCollection(meta.collection).catch(err => {
|
|
@@ -18,13 +18,12 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
|
|
|
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();
|
|
@@ -36,16 +35,16 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
|
|
|
36
35
|
.map(meta => this.connection.dropCollection(meta.collection));
|
|
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,11 +112,21 @@ 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 =
|
|
129
|
+
const properties = this.mapIndexProperties(index, meta);
|
|
121
130
|
const collection = this.connection.getCollection(meta.className);
|
|
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])]);
|
|
@@ -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
176
|
const collection = this.connection.getCollection(meta.className);
|
|
155
|
-
res.push([collection.collectionName, collection
|
|
177
|
+
res.push([collection.collectionName, this.executeQuery(collection, 'createIndex', fieldOrSpec, {
|
|
156
178
|
name: index.name,
|
|
157
179
|
unique: true,
|
|
158
180
|
...index.options,
|
|
@@ -168,8 +190,8 @@ export class MongoSchemaGenerator extends AbstractSchemaGenerator {
|
|
|
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
|
})]];
|
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
|
[](https://discord.gg/w8bjxFHS7X)
|
|
12
12
|
[](https://www.npmjs.com/package/@mikro-orm/core)
|
|
13
13
|
[](https://coveralls.io/r/mikro-orm/mikro-orm?branch=master)
|
|
14
|
-
[](https://codeclimate.com/github/mikro-orm/mikro-orm/maintainability)
|
|
15
14
|
[](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
|
-
- [
|
|
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/index.d.ts
CHANGED
|
@@ -8,4 +8,4 @@ export * from './MongoEntityRepository.js';
|
|
|
8
8
|
export * from './MongoSchemaGenerator.js';
|
|
9
9
|
export { MongoEntityManager as EntityManager } from './MongoEntityManager.js';
|
|
10
10
|
export { MongoEntityRepository as EntityRepository } from './MongoEntityRepository.js';
|
|
11
|
-
export { MongoMikroORM as MikroORM, MongoOptions as Options, defineMongoConfig as defineConfig, } from './MongoMikroORM.js';
|
|
11
|
+
export { MongoMikroORM as MikroORM, type MongoOptions as Options, defineMongoConfig as defineConfig, } from './MongoMikroORM.js';
|
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
|
+
"version": "7.0.0-dev.110",
|
|
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",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"homepage": "https://mikro-orm.io",
|
|
40
40
|
"engines": {
|
|
41
|
-
"node": ">= 22.
|
|
41
|
+
"node": ">= 22.17.0"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "yarn clean && yarn compile && yarn copy",
|
|
@@ -50,12 +50,12 @@
|
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"mongodb": "
|
|
53
|
+
"mongodb": "7.0.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@mikro-orm/core": "^6.
|
|
56
|
+
"@mikro-orm/core": "^6.6.2"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@mikro-orm/core": "7.0.0-dev.
|
|
59
|
+
"@mikro-orm/core": "7.0.0-dev.110"
|
|
60
60
|
}
|
|
61
61
|
}
|