• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

typeorm / typeorm / 19549987525

20 Nov 2025 08:11PM UTC coverage: 80.769% (+4.3%) from 76.433%
19549987525

push

github

web-flow
ci: run tests on commits to master and next (#11783)

Co-authored-by: Oleg "OSA413" Sokolov <OSA413@users.noreply.github.com>

26500 of 32174 branches covered (82.36%)

Branch coverage included in aggregate %.

91252 of 113615 relevant lines covered (80.32%)

88980.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.21
/src/entity-manager/MongoEntityManager.ts
1
import { EntityManager } from "./EntityManager"
26✔
2
import { EntityTarget } from "../common/EntityTarget"
26✔
3

26✔
4
import { ObjectLiteral } from "../common/ObjectLiteral"
26✔
5
import { MongoQueryRunner } from "../driver/mongodb/MongoQueryRunner"
26✔
6
import { MongoDriver } from "../driver/mongodb/MongoDriver"
26✔
7
import { DocumentToEntityTransformer } from "../query-builder/transformer/DocumentToEntityTransformer"
26✔
8
import { FindManyOptions } from "../find-options/FindManyOptions"
26✔
9
import { FindOptionsUtils } from "../find-options/FindOptionsUtils"
26✔
10
import { PlatformTools } from "../platform/PlatformTools"
26✔
11
import { QueryDeepPartialEntity } from "../query-builder/QueryPartialEntity"
26✔
12
import { InsertResult } from "../query-builder/result/InsertResult"
26✔
13
import { UpdateResult } from "../query-builder/result/UpdateResult"
26✔
14
import { DeleteResult } from "../query-builder/result/DeleteResult"
26✔
15
import { EntityMetadata } from "../metadata/EntityMetadata"
26✔
16

26✔
17
import {
26✔
18
    BulkWriteResult,
26✔
19
    AggregationCursor,
26✔
20
    Collection,
26✔
21
    FindCursor,
26✔
22
    Document,
26✔
23
    AggregateOptions,
26✔
24
    AnyBulkWriteOperation,
26✔
25
    BulkWriteOptions,
26✔
26
    Filter,
26✔
27
    CountOptions,
26✔
28
    IndexSpecification,
26✔
29
    CreateIndexesOptions,
26✔
30
    IndexDescription,
26✔
31
    DeleteResult as DeleteResultMongoDb,
26✔
32
    DeleteOptions,
26✔
33
    CommandOperationOptions,
26✔
34
    FindOneAndDeleteOptions,
26✔
35
    FindOneAndReplaceOptions,
26✔
36
    UpdateFilter,
26✔
37
    FindOneAndUpdateOptions,
26✔
38
    RenameOptions,
26✔
39
    ReplaceOptions,
26✔
40
    UpdateResult as UpdateResultMongoDb,
26✔
41
    CollStats,
26✔
42
    CollStatsOptions,
26✔
43
    ChangeStreamOptions,
26✔
44
    ChangeStream,
26✔
45
    UpdateOptions,
26✔
46
    ListIndexesOptions,
26✔
47
    ListIndexesCursor,
26✔
48
    OptionalId,
26✔
49
    InsertOneOptions,
26✔
50
    InsertOneResult,
26✔
51
    InsertManyResult,
26✔
52
    UnorderedBulkOperation,
26✔
53
    OrderedBulkOperation,
26✔
54
    IndexInformationOptions,
26✔
55
    ObjectId,
26✔
56
    FilterOperators,
26✔
57
    CountDocumentsOptions,
26✔
58
} from "../driver/mongodb/typings"
26✔
59
import { DataSource } from "../data-source/DataSource"
26✔
60
import { MongoFindManyOptions } from "../find-options/mongodb/MongoFindManyOptions"
26✔
61
import { MongoFindOneOptions } from "../find-options/mongodb/MongoFindOneOptions"
26✔
62
import {
26✔
63
    FindOptionsSelect,
26✔
64
    FindOptionsSelectByString,
26✔
65
} from "../find-options/FindOptionsSelect"
26✔
66
import { ObjectUtils } from "../util/ObjectUtils"
26✔
67
import { ColumnMetadata } from "../metadata/ColumnMetadata"
26✔
68

26✔
69
/**
26✔
70
 * Entity manager supposed to work with any entity, automatically find its repository and call its methods,
26✔
71
 * whatever entity type are you passing.
26✔
72
 *
26✔
73
 * This implementation is used for MongoDB driver which has some specifics in its EntityManager.
26✔
74
 */
26✔
75
export class MongoEntityManager extends EntityManager {
26✔
76
    readonly "@instanceof" = Symbol.for("MongoEntityManager")
26✔
77

26✔
78
    get mongoQueryRunner(): MongoQueryRunner {
26✔
79
        return (this.connection.driver as MongoDriver)
674✔
80
            .queryRunner as MongoQueryRunner
674✔
81
    }
674✔
82

26✔
83
    // -------------------------------------------------------------------------
26✔
84
    // Constructor
26✔
85
    // -------------------------------------------------------------------------
26✔
86

26✔
87
    constructor(connection: DataSource) {
26✔
88
        super(connection)
636✔
89
    }
636✔
90

26✔
91
    // -------------------------------------------------------------------------
26✔
92
    // Overridden Methods
26✔
93
    // -------------------------------------------------------------------------
26✔
94

26✔
95
    /**
26✔
96
     * Finds entities that match given find options.
26✔
97
     */
26✔
98
    /**
26✔
99
     * Finds entities that match given find options or conditions.
26✔
100
     */
26✔
101
    async find<Entity>(
26✔
102
        entityClassOrName: EntityTarget<Entity>,
62✔
103
        optionsOrConditions?:
62✔
104
            | FindManyOptions<Entity>
62✔
105
            | Partial<Entity>
62✔
106
            | FilterOperators<Entity>,
62✔
107
    ): Promise<Entity[]> {
62✔
108
        const query =
62✔
109
            this.convertFindManyOptionsOrConditionsToMongodbQuery(
62✔
110
                optionsOrConditions,
62✔
111
            )
62✔
112
        const cursor = this.createEntityCursor<Entity>(
62✔
113
            entityClassOrName,
62✔
114
            query as Filter<Entity>,
62✔
115
        )
62✔
116
        const deleteDateColumn =
62✔
117
            this.connection.getMetadata(entityClassOrName).deleteDateColumn
62✔
118
        if (FindOptionsUtils.isFindManyOptions(optionsOrConditions)) {
62✔
119
            if (optionsOrConditions.select)
28✔
120
                cursor.project(
28✔
121
                    this.convertFindOptionsSelectToProjectCriteria(
4✔
122
                        optionsOrConditions.select,
4✔
123
                    ),
4✔
124
                )
4✔
125
            if (optionsOrConditions.skip) cursor.skip(optionsOrConditions.skip)
28✔
126
            if (optionsOrConditions.take) cursor.limit(optionsOrConditions.take)
28✔
127
            if (optionsOrConditions.order)
28✔
128
                cursor.sort(
28✔
129
                    this.convertFindOptionsOrderToOrderCriteria(
18✔
130
                        optionsOrConditions.order,
18✔
131
                    ),
18✔
132
                )
18✔
133
            if (deleteDateColumn && !optionsOrConditions.withDeleted) {
28✔
134
                this.filterSoftDeleted(cursor, deleteDateColumn, query)
4✔
135
            }
4✔
136
        } else if (deleteDateColumn) {
62✔
137
            this.filterSoftDeleted(cursor, deleteDateColumn, query)
4✔
138
        }
4✔
139
        return cursor.toArray()
62✔
140
    }
62✔
141

26✔
142
    /**
26✔
143
     * Finds entities that match given find options or conditions.
26✔
144
     * Also counts all entities that match given conditions,
26✔
145
     * but ignores pagination settings (from and take options).
26✔
146
     */
26✔
147
    async findAndCount<Entity>(
26✔
148
        entityClassOrName: EntityTarget<Entity>,
20✔
149
        options?: MongoFindManyOptions<Entity>,
20✔
150
    ): Promise<[Entity[], number]> {
20✔
151
        return this.executeFindAndCount(entityClassOrName, options)
20✔
152
    }
20✔
153

26✔
154
    /**
26✔
155
     * Finds entities that match given where conditions.
26✔
156
     */
26✔
157
    async findAndCountBy<Entity>(
26✔
158
        entityClassOrName: EntityTarget<Entity>,
×
159
        where: any,
×
160
    ): Promise<[Entity[], number]> {
×
161
        return this.executeFindAndCount(entityClassOrName, where)
×
162
    }
×
163

26✔
164
    /**
26✔
165
     * Finds entities by ids.
26✔
166
     * Optionally find options can be applied.
26✔
167
     *
26✔
168
     * @deprecated use `findBy` method instead.
26✔
169
     */
26✔
170
    async findByIds<Entity>(
26✔
171
        entityClassOrName: EntityTarget<Entity>,
50✔
172
        ids: any[],
50✔
173
        optionsOrConditions?: FindManyOptions<Entity> | Partial<Entity>,
50✔
174
    ): Promise<Entity[]> {
50✔
175
        const metadata = this.connection.getMetadata(entityClassOrName)
50✔
176
        const query =
50✔
177
            this.convertFindManyOptionsOrConditionsToMongodbQuery(
50✔
178
                optionsOrConditions,
50✔
179
            ) || {}
50✔
180
        const objectIdInstance = PlatformTools.load("mongodb").ObjectId
50✔
181
        query["_id"] = {
50✔
182
            $in: ids.map((id) => {
50✔
183
                if (typeof id === "string") {
52✔
184
                    return new objectIdInstance(id)
2✔
185
                }
2✔
186

50✔
187
                if (typeof id === "object") {
52✔
188
                    if (id instanceof objectIdInstance) {
48✔
189
                        return id
8✔
190
                    }
8✔
191

40✔
192
                    const propertyName = metadata.objectIdColumn!.propertyName
40✔
193

40✔
194
                    if (id[propertyName] instanceof objectIdInstance) {
40✔
195
                        return id[propertyName]
40✔
196
                    }
40✔
197
                }
48✔
198
            }),
50✔
199
        }
50✔
200

50✔
201
        const cursor = this.createEntityCursor<Entity>(
50✔
202
            entityClassOrName,
50✔
203
            query as Filter<Entity>,
50✔
204
        )
50✔
205
        if (FindOptionsUtils.isFindManyOptions(optionsOrConditions)) {
50✔
206
            if (optionsOrConditions.select)
38✔
207
                cursor.project(
38!
208
                    this.convertFindOptionsSelectToProjectCriteria(
×
209
                        optionsOrConditions.select,
×
210
                    ),
×
211
                )
×
212
            if (optionsOrConditions.skip) cursor.skip(optionsOrConditions.skip)
38!
213
            if (optionsOrConditions.take) cursor.limit(optionsOrConditions.take)
38!
214
            if (optionsOrConditions.order)
38✔
215
                cursor.sort(
38!
216
                    this.convertFindOptionsOrderToOrderCriteria(
×
217
                        optionsOrConditions.order,
×
218
                    ),
×
219
                )
×
220
        }
38✔
221
        return cursor.toArray()
50✔
222
    }
50✔
223

26✔
224
    /**
26✔
225
     * Finds first entity that matches given conditions and/or find options.
26✔
226
     */
26✔
227
    async findOne<Entity>(
26✔
228
        entityClassOrName: EntityTarget<Entity>,
16✔
229
        options: MongoFindOneOptions<Entity>,
16✔
230
    ): Promise<Entity | null> {
16✔
231
        return this.executeFindOne(entityClassOrName, options)
16✔
232
    }
16✔
233

26✔
234
    /**
26✔
235
     * Finds first entity that matches given WHERE conditions.
26✔
236
     */
26✔
237
    async findOneBy<Entity>(
26✔
238
        entityClassOrName: EntityTarget<Entity>,
38✔
239
        where: any,
38✔
240
    ): Promise<Entity | null> {
38✔
241
        return this.executeFindOne(entityClassOrName, where)
38✔
242
    }
38✔
243

26✔
244
    /**
26✔
245
     * Finds entity that matches given id.
26✔
246
     *
26✔
247
     * @deprecated use `findOneBy` method instead in conjunction with `In` operator, for example:
26✔
248
     *
26✔
249
     * .findOneBy({
26✔
250
     *     id: 1 // where "id" is your primary column name
26✔
251
     * })
26✔
252
     */
26✔
253
    async findOneById<Entity>(
26✔
254
        entityClassOrName: EntityTarget<Entity>,
4✔
255
        id: string | number | Date | ObjectId,
4✔
256
    ): Promise<Entity | null> {
4✔
257
        return this.executeFindOne(entityClassOrName, id)
4✔
258
    }
4✔
259

26✔
260
    /**
26✔
261
     * Inserts a given entity into the database.
26✔
262
     * Unlike save method executes a primitive operation without cascades, relations and other operations included.
26✔
263
     * Executes fast and efficient INSERT query.
26✔
264
     * Does not check if entity exist in the database, so query will fail if duplicate entity is being inserted.
26✔
265
     * You can execute bulk inserts using this method.
26✔
266
     */
26✔
267
    async insert<Entity>(
26✔
268
        target: EntityTarget<Entity>,
200✔
269
        entity:
200✔
270
            | QueryDeepPartialEntity<Entity>
200✔
271
            | QueryDeepPartialEntity<Entity>[],
200✔
272
    ): Promise<InsertResult> {
200✔
273
        // todo: convert entity to its database name
200✔
274
        const result = new InsertResult()
200✔
275
        if (Array.isArray(entity)) {
200✔
276
            result.raw = await this.insertMany(target, entity)
192✔
277
            Object.keys(result.raw.insertedIds).forEach((key: any) => {
192✔
278
                const insertedId = result.raw.insertedIds[key]
504✔
279
                result.generatedMaps.push(
504✔
280
                    this.connection.driver.createGeneratedMap(
504✔
281
                        this.connection.getMetadata(target),
504✔
282
                        insertedId,
504✔
283
                    )!,
504✔
284
                )
504✔
285
                result.identifiers.push(
504✔
286
                    this.connection.driver.createGeneratedMap(
504✔
287
                        this.connection.getMetadata(target),
504✔
288
                        insertedId,
504✔
289
                    )!,
504✔
290
                )
504✔
291
            })
192✔
292
        } else {
200✔
293
            result.raw = await this.insertOne(target, entity)
8✔
294
            result.generatedMaps.push(
8✔
295
                this.connection.driver.createGeneratedMap(
8✔
296
                    this.connection.getMetadata(target),
8✔
297
                    result.raw.insertedId,
8✔
298
                )!,
8✔
299
            )
8✔
300
            result.identifiers.push(
8✔
301
                this.connection.driver.createGeneratedMap(
8✔
302
                    this.connection.getMetadata(target),
8✔
303
                    result.raw.insertedId,
8✔
304
                )!,
8✔
305
            )
8✔
306
        }
8✔
307

198✔
308
        return result
198✔
309
    }
198✔
310

26✔
311
    /**
26✔
312
     * Updates entity partially. Entity can be found by a given conditions.
26✔
313
     * Unlike save method executes a primitive operation without cascades, relations and other operations included.
26✔
314
     * Executes fast and efficient UPDATE query.
26✔
315
     * Does not check if entity exist in the database.
26✔
316
     */
26✔
317
    async update<Entity>(
26✔
318
        target: EntityTarget<Entity>,
32✔
319
        criteria:
32✔
320
            | string
32✔
321
            | string[]
32✔
322
            | number
32✔
323
            | number[]
32✔
324
            | Date
32✔
325
            | Date[]
32✔
326
            | ObjectId
32✔
327
            | ObjectId[]
32✔
328
            | ObjectLiteral,
32✔
329
        partialEntity: QueryDeepPartialEntity<Entity>,
32✔
330
    ): Promise<UpdateResult> {
32✔
331
        const result = new UpdateResult()
32✔
332

32✔
333
        if (Array.isArray(criteria)) {
32!
334
            const updateResults = await Promise.all(
×
335
                (criteria as any[]).map((criteriaItem) => {
×
336
                    return this.update(target, criteriaItem, partialEntity)
×
337
                }),
×
338
            )
×
339

×
340
            result.raw = updateResults.map((r) => r.raw)
×
341
            result.affected = updateResults
×
342
                .map((r) => r.affected || 0)
×
343
                .reduce((c, r) => c + r, 0)
×
344
            result.generatedMaps = updateResults.reduce(
×
345
                (c, r) => c.concat(r.generatedMaps),
×
346
                [] as ObjectLiteral[],
×
347
            )
×
348
        } else {
32✔
349
            const metadata = this.connection.getMetadata(target)
32✔
350
            const mongoResult = await this.updateMany(
32✔
351
                target,
32✔
352
                this.convertMixedCriteria(metadata, criteria),
32✔
353
                { $set: partialEntity },
32✔
354
            )
32✔
355

32✔
356
            result.raw = mongoResult
32✔
357
            result.affected = mongoResult.modifiedCount
32✔
358
        }
32✔
359

32✔
360
        return result
32✔
361
    }
32✔
362

26✔
363
    /**
26✔
364
     * Deletes entities by a given conditions.
26✔
365
     * Unlike save method executes a primitive operation without cascades, relations and other operations included.
26✔
366
     * Executes fast and efficient DELETE query.
26✔
367
     * Does not check if entity exist in the database.
26✔
368
     */
26✔
369
    async delete<Entity>(
26✔
370
        target: EntityTarget<Entity>,
24✔
371
        criteria:
24✔
372
            | string
24✔
373
            | string[]
24✔
374
            | number
24✔
375
            | number[]
24✔
376
            | Date
24✔
377
            | Date[]
24✔
378
            | ObjectId
24✔
379
            | ObjectId[]
24✔
380
            | ObjectLiteral[],
24✔
381
    ): Promise<DeleteResult> {
24✔
382
        const result = new DeleteResult()
24✔
383

24✔
384
        if (Array.isArray(criteria)) {
24✔
385
            const deleteResults = await Promise.all(
8✔
386
                (criteria as any[]).map((criteriaItem) => {
8✔
387
                    return this.delete(target, criteriaItem)
8✔
388
                }),
8✔
389
            )
8✔
390

8✔
391
            result.raw = deleteResults.map((r) => r.raw)
8✔
392
            result.affected = deleteResults
8✔
393
                .map((r) => r.affected || 0)
8!
394
                .reduce((c, r) => c + r, 0)
8✔
395
        } else {
24✔
396
            const mongoResult = await this.deleteMany(
16✔
397
                target,
16✔
398
                this.convertMixedCriteria(
16✔
399
                    this.connection.getMetadata(target),
16✔
400
                    criteria,
16✔
401
                ),
16✔
402
            )
16✔
403

16✔
404
            result.raw = mongoResult
16✔
405
            result.affected = mongoResult.deletedCount
16✔
406
        }
16✔
407

24✔
408
        return result
24✔
409
    }
24✔
410

26✔
411
    // -------------------------------------------------------------------------
26✔
412
    // Public Methods
26✔
413
    // -------------------------------------------------------------------------
26✔
414

26✔
415
    /**
26✔
416
     * Creates a cursor for a query that can be used to iterate over results from MongoDB.
26✔
417
     */
26✔
418
    createCursor<Entity, T = any>(
26✔
419
        entityClassOrName: EntityTarget<Entity>,
198✔
420
        query: ObjectLiteral = {},
198✔
421
    ): FindCursor<T> {
198✔
422
        const metadata = this.connection.getMetadata(entityClassOrName)
198✔
423
        return this.mongoQueryRunner.cursor(metadata.tableName, query)
198✔
424
    }
198✔
425

26✔
426
    /**
26✔
427
     * Creates a cursor for a query that can be used to iterate over results from MongoDB.
26✔
428
     * This returns modified version of cursor that transforms each result into Entity model.
26✔
429
     */
26✔
430
    createEntityCursor<Entity>(
26✔
431
        entityClassOrName: EntityTarget<Entity>,
192✔
432
        query: ObjectLiteral = {},
192✔
433
    ): FindCursor<Entity> {
192✔
434
        const metadata = this.connection.getMetadata(entityClassOrName)
192✔
435
        const cursor = this.createCursor(entityClassOrName, query)
192✔
436
        this.applyEntityTransformationToCursor(metadata, cursor)
192✔
437
        return cursor
192✔
438
    }
192✔
439

26✔
440
    /**
26✔
441
     * Execute an aggregation framework pipeline against the collection.
26✔
442
     */
26✔
443
    aggregate<Entity, R = any>(
26✔
444
        entityClassOrName: EntityTarget<Entity>,
4✔
445
        pipeline: Document[],
4✔
446
        options?: AggregateOptions,
4✔
447
    ): AggregationCursor<R> {
4✔
448
        const metadata = this.connection.getMetadata(entityClassOrName)
4✔
449
        return this.mongoQueryRunner.aggregate(
4✔
450
            metadata.tableName,
4✔
451
            pipeline,
4✔
452
            options,
4✔
453
        )
4✔
454
    }
4✔
455

26✔
456
    /**
26✔
457
     * Execute an aggregation framework pipeline against the collection.
26✔
458
     * This returns modified version of cursor that transforms each result into Entity model.
26✔
459
     */
26✔
460
    aggregateEntity<Entity>(
26✔
461
        entityClassOrName: EntityTarget<Entity>,
×
462
        pipeline: Document[],
×
463
        options?: AggregateOptions,
×
464
    ): AggregationCursor<Entity> {
×
465
        const metadata = this.connection.getMetadata(entityClassOrName)
×
466
        const cursor = this.mongoQueryRunner.aggregate(
×
467
            metadata.tableName,
×
468
            pipeline,
×
469
            options,
×
470
        )
×
471
        this.applyEntityTransformationToCursor(metadata, cursor)
×
472
        return cursor
×
473
    }
×
474

26✔
475
    /**
26✔
476
     * Perform a bulkWrite operation without a fluent API.
26✔
477
     */
26✔
478
    bulkWrite<Entity>(
26✔
479
        entityClassOrName: EntityTarget<Entity>,
×
480
        operations: AnyBulkWriteOperation<Document>[],
×
481
        options?: BulkWriteOptions,
×
482
    ): Promise<BulkWriteResult> {
×
483
        const metadata = this.connection.getMetadata(entityClassOrName)
×
484
        return this.mongoQueryRunner.bulkWrite(
×
485
            metadata.tableName,
×
486
            operations,
×
487
            options,
×
488
        )
×
489
    }
×
490

26✔
491
    /**
26✔
492
     * Count number of matching documents in the db to a query.
26✔
493
     */
26✔
494
    count<Entity>(
26✔
495
        entityClassOrName: EntityTarget<Entity>,
32✔
496
        query: Filter<Document> = {},
32✔
497
        options: CountOptions = {},
32✔
498
    ): Promise<number> {
32✔
499
        const metadata = this.connection.getMetadata(entityClassOrName)
32✔
500
        return this.mongoQueryRunner.count(metadata.tableName, query, options)
32✔
501
    }
32✔
502

26✔
503
    /**
26✔
504
     * Count number of matching documents in the db to a query.
26✔
505
     */
26✔
506
    countDocuments<Entity>(
26✔
507
        entityClassOrName: EntityTarget<Entity>,
×
508
        query: Filter<Document> = {},
×
509
        options: CountDocumentsOptions = {},
×
510
    ): Promise<number> {
×
511
        const metadata = this.connection.getMetadata(entityClassOrName)
×
512
        return this.mongoQueryRunner.countDocuments(
×
513
            metadata.tableName,
×
514
            query,
×
515
            options,
×
516
        )
×
517
    }
×
518

26✔
519
    /**
26✔
520
     * Count number of matching documents in the db to a query.
26✔
521
     */
26✔
522
    countBy<Entity>(
26✔
523
        entityClassOrName: EntityTarget<Entity>,
12✔
524
        query?: ObjectLiteral,
12✔
525
        options?: CountOptions,
12✔
526
    ): Promise<number> {
12✔
527
        return this.count(entityClassOrName, query, options)
12✔
528
    }
12✔
529

26✔
530
    /**
26✔
531
     * Creates an index on the db and collection.
26✔
532
     */
26✔
533
    createCollectionIndex<Entity>(
26✔
534
        entityClassOrName: EntityTarget<Entity>,
×
535
        fieldOrSpec: IndexSpecification,
×
536
        options?: CreateIndexesOptions,
×
537
    ): Promise<string> {
×
538
        const metadata = this.connection.getMetadata(entityClassOrName)
×
539
        return this.mongoQueryRunner.createCollectionIndex(
×
540
            metadata.tableName,
×
541
            fieldOrSpec,
×
542
            options,
×
543
        )
×
544
    }
×
545

26✔
546
    /**
26✔
547
     * Creates multiple indexes in the collection, this method is only supported for MongoDB 2.6 or higher.
26✔
548
     * Earlier version of MongoDB will throw a command not supported error.
26✔
549
     * Index specifications are defined at http://docs.mongodb.org/manual/reference/command/createIndexes/.
26✔
550
     */
26✔
551
    createCollectionIndexes<Entity>(
26✔
552
        entityClassOrName: EntityTarget<Entity>,
×
553
        indexSpecs: IndexDescription[],
×
554
    ): Promise<string[]> {
×
555
        const metadata = this.connection.getMetadata(entityClassOrName)
×
556
        return this.mongoQueryRunner.createCollectionIndexes(
×
557
            metadata.tableName,
×
558
            indexSpecs,
×
559
        )
×
560
    }
×
561

26✔
562
    /**
26✔
563
     * Delete multiple documents on MongoDB.
26✔
564
     */
26✔
565
    deleteMany<Entity>(
26✔
566
        entityClassOrName: EntityTarget<Entity>,
16✔
567
        query: Filter<Document>,
16✔
568
        options: DeleteOptions = {},
16✔
569
    ): Promise<DeleteResultMongoDb> {
16✔
570
        const metadata = this.connection.getMetadata(entityClassOrName)
16✔
571
        return this.mongoQueryRunner.deleteMany(
16✔
572
            metadata.tableName,
16✔
573
            query,
16✔
574
            options,
16✔
575
        )
16✔
576
    }
16✔
577

26✔
578
    /**
26✔
579
     * Delete a document on MongoDB.
26✔
580
     */
26✔
581
    deleteOne<Entity>(
26✔
582
        entityClassOrName: EntityTarget<Entity>,
×
583
        query: Filter<Document>,
×
584
        options: DeleteOptions = {},
×
585
    ): Promise<DeleteResultMongoDb> {
×
586
        const metadata = this.connection.getMetadata(entityClassOrName)
×
587
        return this.mongoQueryRunner.deleteOne(
×
588
            metadata.tableName,
×
589
            query,
×
590
            options,
×
591
        )
×
592
    }
×
593

26✔
594
    /**
26✔
595
     * The distinct command returns returns a list of distinct values for the given key across a collection.
26✔
596
     */
26✔
597
    distinct<Entity>(
26✔
598
        entityClassOrName: EntityTarget<Entity>,
×
599
        key: string,
×
600
        query: Filter<Document>,
×
601
        options?: CommandOperationOptions,
×
602
    ): Promise<any> {
×
603
        const metadata = this.connection.getMetadata(entityClassOrName)
×
604
        return this.mongoQueryRunner.distinct(
×
605
            metadata.tableName,
×
606
            key,
×
607
            query,
×
608
            options,
×
609
        )
×
610
    }
×
611

26✔
612
    /**
26✔
613
     * Drops an index from this collection.
26✔
614
     */
26✔
615
    dropCollectionIndex<Entity>(
26✔
616
        entityClassOrName: EntityTarget<Entity>,
×
617
        indexName: string,
×
618
        options?: CommandOperationOptions,
×
619
    ): Promise<any> {
×
620
        const metadata = this.connection.getMetadata(entityClassOrName)
×
621
        return this.mongoQueryRunner.dropCollectionIndex(
×
622
            metadata.tableName,
×
623
            indexName,
×
624
            options,
×
625
        )
×
626
    }
×
627

26✔
628
    /**
26✔
629
     * Drops all indexes from the collection.
26✔
630
     */
26✔
631
    dropCollectionIndexes<Entity>(
26✔
632
        entityClassOrName: EntityTarget<Entity>,
×
633
    ): Promise<any> {
×
634
        const metadata = this.connection.getMetadata(entityClassOrName)
×
635
        return this.mongoQueryRunner.dropCollectionIndexes(metadata.tableName)
×
636
    }
×
637

26✔
638
    /**
26✔
639
     * Find a document and delete it in one atomic operation, requires a write lock for the duration of the operation.
26✔
640
     */
26✔
641
    findOneAndDelete<Entity>(
26✔
642
        entityClassOrName: EntityTarget<Entity>,
×
643
        query: ObjectLiteral,
×
644
        options?: FindOneAndDeleteOptions,
×
645
    ): Promise<Document | null> {
×
646
        const metadata = this.connection.getMetadata(entityClassOrName)
×
647
        return this.mongoQueryRunner.findOneAndDelete(
×
648
            metadata.tableName,
×
649
            query,
×
650
            options,
×
651
        )
×
652
    }
×
653

26✔
654
    /**
26✔
655
     * Find a document and replace it in one atomic operation, requires a write lock for the duration of the operation.
26✔
656
     */
26✔
657
    findOneAndReplace<Entity>(
26✔
658
        entityClassOrName: EntityTarget<Entity>,
×
659
        query: Filter<Document>,
×
660
        replacement: Document,
×
661
        options?: FindOneAndReplaceOptions,
×
662
    ): Promise<Document | null> {
×
663
        const metadata = this.connection.getMetadata(entityClassOrName)
×
664
        return this.mongoQueryRunner.findOneAndReplace(
×
665
            metadata.tableName,
×
666
            query,
×
667
            replacement,
×
668
            options,
×
669
        )
×
670
    }
×
671

26✔
672
    /**
26✔
673
     * Find a document and update it in one atomic operation, requires a write lock for the duration of the operation.
26✔
674
     */
26✔
675
    findOneAndUpdate<Entity>(
26✔
676
        entityClassOrName: EntityTarget<Entity>,
×
677
        query: Filter<Document>,
×
678
        update: UpdateFilter<Document>,
×
679
        options?: FindOneAndUpdateOptions,
×
680
    ): Promise<Document | null> {
×
681
        const metadata = this.connection.getMetadata(entityClassOrName)
×
682
        return this.mongoQueryRunner.findOneAndUpdate(
×
683
            metadata.tableName,
×
684
            query,
×
685
            update,
×
686
            options,
×
687
        )
×
688
    }
×
689

26✔
690
    /**
26✔
691
     * Retrieve all the indexes on the collection.
26✔
692
     */
26✔
693
    collectionIndexes<Entity>(
26✔
694
        entityClassOrName: EntityTarget<Entity>,
×
695
    ): Promise<Document> {
×
696
        const metadata = this.connection.getMetadata(entityClassOrName)
×
697
        return this.mongoQueryRunner.collectionIndexes(metadata.tableName)
×
698
    }
×
699

26✔
700
    /**
26✔
701
     * Retrieve all the indexes on the collection.
26✔
702
     */
26✔
703
    collectionIndexExists<Entity>(
26✔
704
        entityClassOrName: EntityTarget<Entity>,
×
705
        indexes: string | string[],
×
706
    ): Promise<boolean> {
×
707
        const metadata = this.connection.getMetadata(entityClassOrName)
×
708
        return this.mongoQueryRunner.collectionIndexExists(
×
709
            metadata.tableName,
×
710
            indexes,
×
711
        )
×
712
    }
×
713

26✔
714
    /**
26✔
715
     * Retrieves this collections index info.
26✔
716
     */
26✔
717
    collectionIndexInformation<Entity>(
26✔
718
        entityClassOrName: EntityTarget<Entity>,
×
719
        options?: IndexInformationOptions,
×
720
    ): Promise<any> {
×
721
        const metadata = this.connection.getMetadata(entityClassOrName)
×
722
        return this.mongoQueryRunner.collectionIndexInformation(
×
723
            metadata.tableName,
×
724
            options,
×
725
        )
×
726
    }
×
727

26✔
728
    /**
26✔
729
     * Initiate an In order bulk write operation, operations will be serially executed in the order they are added, creating a new operation for each switch in types.
26✔
730
     */
26✔
731
    initializeOrderedBulkOp<Entity>(
26✔
732
        entityClassOrName: EntityTarget<Entity>,
×
733
        options?: BulkWriteOptions,
×
734
    ): OrderedBulkOperation {
×
735
        const metadata = this.connection.getMetadata(entityClassOrName)
×
736
        return this.mongoQueryRunner.initializeOrderedBulkOp(
×
737
            metadata.tableName,
×
738
            options,
×
739
        )
×
740
    }
×
741

26✔
742
    /**
26✔
743
     * Initiate a Out of order batch write operation. All operations will be buffered into insert/update/remove commands executed out of order.
26✔
744
     */
26✔
745
    initializeUnorderedBulkOp<Entity>(
26✔
746
        entityClassOrName: EntityTarget<Entity>,
×
747
        options?: BulkWriteOptions,
×
748
    ): UnorderedBulkOperation {
×
749
        const metadata = this.connection.getMetadata(entityClassOrName)
×
750
        return this.mongoQueryRunner.initializeUnorderedBulkOp(
×
751
            metadata.tableName,
×
752
            options,
×
753
        )
×
754
    }
×
755

26✔
756
    /**
26✔
757
     * Inserts an array of documents into MongoDB.
26✔
758
     */
26✔
759
    insertMany<Entity>(
26✔
760
        entityClassOrName: EntityTarget<Entity>,
192✔
761
        docs: OptionalId<Document>[],
192✔
762
        options?: BulkWriteOptions,
192✔
763
    ): Promise<InsertManyResult> {
192✔
764
        const metadata = this.connection.getMetadata(entityClassOrName)
192✔
765
        return this.mongoQueryRunner.insertMany(
192✔
766
            metadata.tableName,
192✔
767
            docs,
192✔
768
            options,
192✔
769
        )
192✔
770
    }
192✔
771

26✔
772
    /**
26✔
773
     * Inserts a single document into MongoDB.
26✔
774
     */
26✔
775
    insertOne<Entity>(
26✔
776
        entityClassOrName: EntityTarget<Entity>,
8✔
777
        doc: OptionalId<Document>,
8✔
778
        options?: InsertOneOptions,
8✔
779
    ): Promise<InsertOneResult> {
8✔
780
        const metadata = this.connection.getMetadata(entityClassOrName)
8✔
781
        return this.mongoQueryRunner.insertOne(metadata.tableName, doc, options)
8✔
782
    }
8✔
783

26✔
784
    /**
26✔
785
     * Returns if the collection is a capped collection.
26✔
786
     */
26✔
787
    isCapped<Entity>(entityClassOrName: EntityTarget<Entity>): Promise<any> {
26✔
788
        const metadata = this.connection.getMetadata(entityClassOrName)
×
789
        return this.mongoQueryRunner.isCapped(metadata.tableName)
×
790
    }
×
791

26✔
792
    /**
26✔
793
     * Get the list of all indexes information for the collection.
26✔
794
     */
26✔
795
    listCollectionIndexes<Entity>(
26✔
796
        entityClassOrName: EntityTarget<Entity>,
×
797
        options?: ListIndexesOptions,
×
798
    ): ListIndexesCursor {
×
799
        const metadata = this.connection.getMetadata(entityClassOrName)
×
800
        return this.mongoQueryRunner.listCollectionIndexes(
×
801
            metadata.tableName,
×
802
            options,
×
803
        )
×
804
    }
×
805

26✔
806
    /**
26✔
807
     * Reindex all indexes on the collection Warning: reIndex is a blocking operation (indexes are rebuilt in the foreground) and will be slow for large collections.
26✔
808
     */
26✔
809
    rename<Entity>(
26✔
810
        entityClassOrName: EntityTarget<Entity>,
×
811
        newName: string,
×
812
        options?: RenameOptions,
×
813
    ): Promise<Collection<Document>> {
×
814
        const metadata = this.connection.getMetadata(entityClassOrName)
×
815
        return this.mongoQueryRunner.rename(
×
816
            metadata.tableName,
×
817
            newName,
×
818
            options,
×
819
        )
×
820
    }
×
821

26✔
822
    /**
26✔
823
     * Replace a document on MongoDB.
26✔
824
     */
26✔
825
    replaceOne<Entity>(
26✔
826
        entityClassOrName: EntityTarget<Entity>,
×
827
        query: Filter<Document>,
×
828
        doc: Document,
×
829
        options?: ReplaceOptions,
×
830
    ): Promise<Document | UpdateResultMongoDb> {
×
831
        const metadata = this.connection.getMetadata(entityClassOrName)
×
832
        return this.mongoQueryRunner.replaceOne(
×
833
            metadata.tableName,
×
834
            query,
×
835
            doc,
×
836
            options,
×
837
        )
×
838
    }
×
839

26✔
840
    /**
26✔
841
     * Get all the collection statistics.
26✔
842
     */
26✔
843
    stats<Entity>(
26✔
844
        entityClassOrName: EntityTarget<Entity>,
×
845
        options?: CollStatsOptions,
×
846
    ): Promise<CollStats> {
×
847
        const metadata = this.connection.getMetadata(entityClassOrName)
×
848
        return this.mongoQueryRunner.stats(metadata.tableName, options)
×
849
    }
×
850

26✔
851
    watch<Entity>(
26✔
852
        entityClassOrName: EntityTarget<Entity>,
×
853
        pipeline?: Document[],
×
854
        options?: ChangeStreamOptions,
×
855
    ): ChangeStream {
×
856
        const metadata = this.connection.getMetadata(entityClassOrName)
×
857
        return this.mongoQueryRunner.watch(
×
858
            metadata.tableName,
×
859
            pipeline,
×
860
            options,
×
861
        )
×
862
    }
×
863

26✔
864
    /**
26✔
865
     * Update multiple documents on MongoDB.
26✔
866
     */
26✔
867
    updateMany<Entity>(
26✔
868
        entityClassOrName: EntityTarget<Entity>,
32✔
869
        query: Filter<Document>,
32✔
870
        update: UpdateFilter<Document>,
32✔
871
        options?: UpdateOptions,
32✔
872
    ): Promise<Document | UpdateResultMongoDb> {
32✔
873
        const metadata = this.connection.getMetadata(entityClassOrName)
32✔
874
        return this.mongoQueryRunner.updateMany(
32✔
875
            metadata.tableName,
32✔
876
            query,
32✔
877
            update,
32✔
878
            options,
32✔
879
        )
32✔
880
    }
32✔
881

26✔
882
    /**
26✔
883
     * Update a single document on MongoDB.
26✔
884
     */
26✔
885
    updateOne<Entity>(
26✔
886
        entityClassOrName: EntityTarget<Entity>,
×
887
        query: Filter<Document>,
×
888
        update: UpdateFilter<Document>,
×
889
        options?: UpdateOptions,
×
890
    ): Promise<Document | UpdateResultMongoDb> {
×
891
        const metadata = this.connection.getMetadata(entityClassOrName)
×
892
        return this.mongoQueryRunner.updateOne(
×
893
            metadata.tableName,
×
894
            query,
×
895
            update,
×
896
            options,
×
897
        )
×
898
    }
×
899

26✔
900
    // -------------------------------------------------------------------------
26✔
901
    // Protected Methods
26✔
902
    // -------------------------------------------------------------------------
26✔
903

26✔
904
    /**
26✔
905
     * Converts FindManyOptions to mongodb query.
26✔
906
     */
26✔
907
    protected convertFindManyOptionsOrConditionsToMongodbQuery<Entity>(
26✔
908
        optionsOrConditions:
132✔
909
            | MongoFindManyOptions<Entity>
132✔
910
            | Partial<Entity>
132✔
911
            | FilterOperators<Entity>
132✔
912
            | any[]
132✔
913
            | undefined,
132✔
914
    ): ObjectLiteral | undefined {
132✔
915
        if (!optionsOrConditions) return undefined
132✔
916

76✔
917
        if (FindOptionsUtils.isFindManyOptions<Entity>(optionsOrConditions))
76✔
918
            // If where condition is passed as a string which contains sql we have to ignore
76✔
919
            // as mongo is not a sql database
76✔
920
            return typeof optionsOrConditions.where === "string"
132✔
921
                ? {}
74!
922
                : optionsOrConditions.where
74✔
923

2✔
924
        return optionsOrConditions
2✔
925
    }
2✔
926

26✔
927
    /**
26✔
928
     * Converts FindOneOptions to mongodb query.
26✔
929
     */
26✔
930
    protected convertFindOneOptionsOrConditionsToMongodbQuery<Entity>(
26✔
931
        optionsOrConditions:
58✔
932
            | MongoFindOneOptions<Entity>
58✔
933
            | Partial<Entity>
58✔
934
            | undefined,
58✔
935
    ): ObjectLiteral | undefined {
58✔
936
        if (!optionsOrConditions) return undefined
58✔
937

54✔
938
        if (FindOptionsUtils.isFindOneOptions<Entity>(optionsOrConditions))
54✔
939
            // If where condition is passed as a string which contains sql we have to ignore
54✔
940
            // as mongo is not a sql database
54✔
941
            return typeof optionsOrConditions.where === "string"
58✔
942
                ? {}
18!
943
                : optionsOrConditions.where
18✔
944

36✔
945
        return optionsOrConditions
36✔
946
    }
36✔
947

26✔
948
    /**
26✔
949
     * Converts FindOptions into mongodb order by criteria.
26✔
950
     */
26✔
951
    protected convertFindOptionsOrderToOrderCriteria(order: ObjectLiteral) {
26✔
952
        return Object.keys(order).reduce((orderCriteria, key) => {
24✔
953
            switch (order[key]) {
24✔
954
                case "DESC":
24✔
955
                    orderCriteria[key] = -1
4✔
956
                    break
4✔
957
                case "ASC":
24✔
958
                    orderCriteria[key] = 1
8✔
959
                    break
8✔
960
                default:
24✔
961
                    orderCriteria[key] = order[key]
12✔
962
            }
24✔
963
            return orderCriteria
24✔
964
        }, {} as ObjectLiteral)
24✔
965
    }
24✔
966

26✔
967
    /**
26✔
968
     * Converts FindOptions into mongodb select by criteria.
26✔
969
     */
26✔
970
    protected convertFindOptionsSelectToProjectCriteria(
26✔
971
        selects: FindOptionsSelect<any> | FindOptionsSelectByString<any>,
8✔
972
    ) {
8✔
973
        if (Array.isArray(selects)) {
8!
974
            return selects.reduce((projectCriteria, key) => {
×
975
                projectCriteria[key] = 1
×
976
                return projectCriteria
×
977
            }, {} as any)
×
978
        } else {
8✔
979
            // todo: implement
8✔
980
            return {}
8✔
981
        }
8✔
982
    }
8✔
983

26✔
984
    /**
26✔
985
     * Ensures given id is an id for query.
26✔
986
     */
26✔
987
    protected convertMixedCriteria(
26✔
988
        metadata: EntityMetadata,
48✔
989
        idMap: any,
48✔
990
    ): ObjectLiteral {
48✔
991
        const objectIdInstance = PlatformTools.load("mongodb").ObjectId
48✔
992

48✔
993
        // check first if it's ObjectId compatible:
48✔
994
        // string, number, Buffer, ObjectId or ObjectId-like
48✔
995
        if (objectIdInstance.isValid(idMap)) {
48✔
996
            return {
4✔
997
                _id: new objectIdInstance(idMap),
4✔
998
            }
4✔
999
        }
4✔
1000

44✔
1001
        // if it's some other type of object build a query from the columns
44✔
1002
        // this check needs to be after the ObjectId check, because a valid ObjectId is also an Object instance
44✔
1003
        if (ObjectUtils.isObject(idMap)) {
44✔
1004
            return metadata.columns.reduce((query, column) => {
44✔
1005
                const columnValue = column.getEntityValue(idMap)
230✔
1006
                if (columnValue !== undefined)
230✔
1007
                    query[column.databasePath] = columnValue
230✔
1008
                return query
230✔
1009
            }, {} as any)
44✔
1010
        }
44✔
1011

×
1012
        // last resort: try to convert it to an ObjectId anyway
×
1013
        // most likely it will fail, but we want to be backwards compatible and keep the same thrown Errors.
×
1014
        // it can still pass with null/undefined
×
1015
        return {
×
1016
            _id: new objectIdInstance(idMap),
×
1017
        }
×
1018
    }
×
1019

26✔
1020
    /**
26✔
1021
     * Overrides cursor's toArray and next methods to convert results to entity automatically.
26✔
1022
     */
26✔
1023
    protected applyEntityTransformationToCursor<Entity extends ObjectLiteral>(
26✔
1024
        metadata: EntityMetadata,
192✔
1025
        cursor: FindCursor<Entity> | AggregationCursor<Entity>,
192✔
1026
    ) {
192✔
1027
        const queryRunner = this.mongoQueryRunner
192✔
1028

192✔
1029
        ;(cursor as any)["__to_array_func"] = cursor.toArray
192✔
1030
        cursor.toArray = () =>
192✔
1031
            ((cursor as any)["__to_array_func"] as CallableFunction)().then(
192✔
1032
                async (results: Entity[]) => {
192✔
1033
                    const transformer = new DocumentToEntityTransformer()
190✔
1034
                    const entities = transformer.transformAll(results, metadata)
190✔
1035
                    // broadcast "load" events
190✔
1036
                    await queryRunner.broadcaster.broadcast(
190✔
1037
                        "Load",
190✔
1038
                        metadata,
190✔
1039
                        entities,
190✔
1040
                    )
190✔
1041
                    return entities
190✔
1042
                },
192✔
1043
            )
192✔
1044
        ;(cursor as any)["__next_func"] = cursor.next
192✔
1045
        cursor.next = () =>
192✔
1046
            ((cursor as any)["__next_func"] as CallableFunction)().then(
192✔
1047
                async (result: Entity) => {
192✔
1048
                    if (!result) {
190✔
1049
                        return result
32✔
1050
                    }
32✔
1051
                    const transformer = new DocumentToEntityTransformer()
158✔
1052
                    const entity = transformer.transform(result, metadata)
158✔
1053
                    // broadcast "load" events
158✔
1054
                    await queryRunner.broadcaster.broadcast("Load", metadata, [
158✔
1055
                        entity,
158✔
1056
                    ])
158✔
1057
                    return entity
158✔
1058
                },
192✔
1059
            )
192✔
1060
    }
192✔
1061

26✔
1062
    protected filterSoftDeleted<Entity>(
26✔
1063
        cursor: FindCursor<Entity>,
20✔
1064
        deleteDateColumn: ColumnMetadata,
20✔
1065
        query?: ObjectLiteral,
20✔
1066
    ) {
20✔
1067
        const { $or, ...restQuery } = query ?? {}
20✔
1068
        cursor.filter({
20✔
1069
            $or: [
20✔
1070
                { [deleteDateColumn.propertyName]: { $eq: null } },
20✔
1071
                ...(Array.isArray($or) ? $or : []),
20✔
1072
            ],
20✔
1073
            ...restQuery,
20✔
1074
        })
20✔
1075
    }
20✔
1076

26✔
1077
    /**
26✔
1078
     * Finds first entity that matches given conditions and/or find options.
26✔
1079
     */
26✔
1080
    protected async executeFindOne<Entity>(
26✔
1081
        entityClassOrName: EntityTarget<Entity>,
58✔
1082
        optionsOrConditions?: any,
58✔
1083
        maybeOptions?: MongoFindOneOptions<Entity>,
58✔
1084
    ): Promise<Entity | null> {
58✔
1085
        const objectIdInstance = PlatformTools.load("mongodb").ObjectId
58✔
1086
        const id =
58✔
1087
            optionsOrConditions instanceof objectIdInstance ||
58✔
1088
            typeof optionsOrConditions === "string"
54✔
1089
                ? optionsOrConditions
58✔
1090
                : undefined
58✔
1091
        const findOneOptionsOrConditions = (
58✔
1092
            id ? maybeOptions : optionsOrConditions
58✔
1093
        ) as any
58✔
1094
        const query =
58✔
1095
            this.convertFindOneOptionsOrConditionsToMongodbQuery(
58✔
1096
                findOneOptionsOrConditions,
58✔
1097
            ) || {}
58✔
1098
        if (id) {
58✔
1099
            query["_id"] =
4✔
1100
                id instanceof objectIdInstance ? id : new objectIdInstance(id)
4!
1101
        }
4✔
1102
        const cursor = this.createEntityCursor<Entity>(entityClassOrName, query)
58✔
1103
        const deleteDateColumn =
58✔
1104
            this.connection.getMetadata(entityClassOrName).deleteDateColumn
58✔
1105
        if (FindOptionsUtils.isFindOneOptions(findOneOptionsOrConditions)) {
58✔
1106
            if (findOneOptionsOrConditions.select)
18✔
1107
                cursor.project(
18✔
1108
                    this.convertFindOptionsSelectToProjectCriteria(
2✔
1109
                        findOneOptionsOrConditions.select,
2✔
1110
                    ),
2✔
1111
                )
2✔
1112
            if (findOneOptionsOrConditions.order)
18✔
1113
                cursor.sort(
18✔
1114
                    this.convertFindOptionsOrderToOrderCriteria(
2✔
1115
                        findOneOptionsOrConditions.order,
2✔
1116
                    ),
2✔
1117
                )
2✔
1118
            if (deleteDateColumn && !findOneOptionsOrConditions.withDeleted) {
18✔
1119
                this.filterSoftDeleted(cursor, deleteDateColumn, query)
8✔
1120
            }
8✔
1121
        } else if (deleteDateColumn) {
58!
1122
            this.filterSoftDeleted(cursor, deleteDateColumn, query)
×
1123
        }
×
1124

58✔
1125
        // const result = await cursor.limit(1).next();
58✔
1126
        const result = await cursor.limit(1).toArray()
58✔
1127
        return result.length > 0 ? result[0] : null
58✔
1128
    }
58✔
1129

26✔
1130
    protected async executeFind<Entity>(
26✔
1131
        entityClassOrName: EntityTarget<Entity>,
×
1132
        optionsOrConditions?:
×
1133
            | MongoFindManyOptions<Entity>
×
1134
            | Partial<Entity>
×
1135
            | any[],
×
1136
    ): Promise<Entity[]> {
×
1137
        const query =
×
1138
            this.convertFindManyOptionsOrConditionsToMongodbQuery(
×
1139
                optionsOrConditions,
×
1140
            )
×
1141
        const cursor = this.createEntityCursor<Entity>(entityClassOrName, query)
×
1142
        const deleteDateColumn =
×
1143
            this.connection.getMetadata(entityClassOrName).deleteDateColumn
×
1144

×
1145
        if (FindOptionsUtils.isFindManyOptions(optionsOrConditions)) {
×
1146
            if (optionsOrConditions.select)
×
1147
                cursor.project(
×
1148
                    this.convertFindOptionsSelectToProjectCriteria(
×
1149
                        optionsOrConditions.select,
×
1150
                    ),
×
1151
                )
×
1152
            if (optionsOrConditions.skip) cursor.skip(optionsOrConditions.skip)
×
1153
            if (optionsOrConditions.take) cursor.limit(optionsOrConditions.take)
×
1154
            if (optionsOrConditions.order)
×
1155
                cursor.sort(
×
1156
                    this.convertFindOptionsOrderToOrderCriteria(
×
1157
                        optionsOrConditions.order,
×
1158
                    ),
×
1159
                )
×
1160
            if (deleteDateColumn && !optionsOrConditions.withDeleted) {
×
1161
                this.filterSoftDeleted(cursor, deleteDateColumn, query)
×
1162
            }
×
1163
        } else if (deleteDateColumn) {
×
1164
            this.filterSoftDeleted(cursor, deleteDateColumn, query)
×
1165
        }
×
1166
        return cursor.toArray()
×
1167
    }
×
1168

26✔
1169
    /**
26✔
1170
     * Finds entities that match given find options or conditions.
26✔
1171
     */
26✔
1172
    async executeFindAndCount<Entity>(
26✔
1173
        entityClassOrName: EntityTarget<Entity>,
20✔
1174
        optionsOrConditions?: MongoFindManyOptions<Entity> | Partial<Entity>,
20✔
1175
    ): Promise<[Entity[], number]> {
20✔
1176
        const query =
20✔
1177
            this.convertFindManyOptionsOrConditionsToMongodbQuery(
20✔
1178
                optionsOrConditions,
20✔
1179
            )
20✔
1180
        const cursor = this.createEntityCursor(entityClassOrName, query)
20✔
1181
        const deleteDateColumn =
20✔
1182
            this.connection.getMetadata(entityClassOrName).deleteDateColumn
20✔
1183

20✔
1184
        if (FindOptionsUtils.isFindManyOptions(optionsOrConditions)) {
20✔
1185
            if (optionsOrConditions.select)
8✔
1186
                cursor.project(
8✔
1187
                    this.convertFindOptionsSelectToProjectCriteria(
2✔
1188
                        optionsOrConditions.select,
2✔
1189
                    ),
2✔
1190
                )
2✔
1191
            if (optionsOrConditions.skip) cursor.skip(optionsOrConditions.skip)
8✔
1192
            if (optionsOrConditions.take) cursor.limit(optionsOrConditions.take)
8✔
1193
            if (optionsOrConditions.order)
8✔
1194
                cursor.sort(
8✔
1195
                    this.convertFindOptionsOrderToOrderCriteria(
4✔
1196
                        optionsOrConditions.order,
4✔
1197
                    ),
4✔
1198
                )
4✔
1199
            if (deleteDateColumn && !optionsOrConditions.withDeleted) {
8✔
1200
                this.filterSoftDeleted(cursor, deleteDateColumn, query)
2✔
1201
            }
2✔
1202
        } else if (deleteDateColumn) {
20✔
1203
            this.filterSoftDeleted(cursor, deleteDateColumn, query)
2✔
1204
        }
2✔
1205
        const [results, count] = await Promise.all<any>([
20✔
1206
            cursor.toArray(),
20✔
1207
            this.count(entityClassOrName, query),
20✔
1208
        ])
20✔
1209
        return [results, parseInt(count)]
20✔
1210
    }
20✔
1211
}
26✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc