• 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

91.93
/src/entity-manager/EntityManager.ts
1
import { DataSource } from "../data-source/DataSource"
26✔
2
import { FindManyOptions } from "../find-options/FindManyOptions"
26✔
3
import { EntityTarget } from "../common/EntityTarget"
26✔
4
import { ObjectType } from "../common/ObjectType"
26✔
5
import { EntityNotFoundError } from "../error/EntityNotFoundError"
26✔
6
import { QueryRunnerProviderAlreadyReleasedError } from "../error/QueryRunnerProviderAlreadyReleasedError"
26✔
7
import { FindOneOptions } from "../find-options/FindOneOptions"
26✔
8
import { DeepPartial } from "../common/DeepPartial"
26✔
9
import { RemoveOptions } from "../repository/RemoveOptions"
26✔
10
import { SaveOptions } from "../repository/SaveOptions"
26✔
11
import { NoNeedToReleaseEntityManagerError } from "../error/NoNeedToReleaseEntityManagerError"
26✔
12
import { MongoRepository } from "../repository/MongoRepository"
26✔
13
import { TreeRepository } from "../repository/TreeRepository"
26✔
14
import { Repository } from "../repository/Repository"
26✔
15
import { FindOptionsUtils } from "../find-options/FindOptionsUtils"
26✔
16
import { PlainObjectToNewEntityTransformer } from "../query-builder/transformer/PlainObjectToNewEntityTransformer"
26✔
17
import { PlainObjectToDatabaseEntityTransformer } from "../query-builder/transformer/PlainObjectToDatabaseEntityTransformer"
26✔
18
import {
26✔
19
    CustomRepositoryCannotInheritRepositoryError,
26✔
20
    CustomRepositoryNotFoundError,
26✔
21
    TreeRepositoryNotSupportedError,
26✔
22
    TypeORMError,
26✔
23
} from "../error"
26✔
24
import { AbstractRepository } from "../repository/AbstractRepository"
26✔
25
import { QueryRunner } from "../query-runner/QueryRunner"
26✔
26
import { SelectQueryBuilder } from "../query-builder/SelectQueryBuilder"
26✔
27
import { QueryDeepPartialEntity } from "../query-builder/QueryPartialEntity"
26✔
28
import { EntityPersistExecutor } from "../persistence/EntityPersistExecutor"
26✔
29
import { ObjectId } from "../driver/mongodb/typings"
26✔
30
import { InsertResult } from "../query-builder/result/InsertResult"
26✔
31
import { UpdateResult } from "../query-builder/result/UpdateResult"
26✔
32
import { DeleteResult } from "../query-builder/result/DeleteResult"
26✔
33
import { FindOptionsWhere } from "../find-options/FindOptionsWhere"
26✔
34
import { IsolationLevel } from "../driver/types/IsolationLevel"
26✔
35
import { ObjectUtils } from "../util/ObjectUtils"
26✔
36
import { getMetadataArgsStorage } from "../globals"
26✔
37
import { UpsertOptions } from "../repository/UpsertOptions"
26✔
38
import { InstanceChecker } from "../util/InstanceChecker"
26✔
39
import { ObjectLiteral } from "../common/ObjectLiteral"
26✔
40
import { PickKeysByType } from "../common/PickKeysByType"
26✔
41
import { buildSqlTag } from "../util/SqlTagUtils"
26✔
42
import { OrmUtils } from "../util/OrmUtils"
26✔
43

26✔
44
/**
26✔
45
 * Entity manager supposed to work with any entity, automatically find its repository and call its methods,
26✔
46
 * whatever entity type are you passing.
26✔
47
 */
26✔
48
export class EntityManager {
26✔
49
    readonly "@instanceof" = Symbol.for("EntityManager")
26✔
50

26✔
51
    // -------------------------------------------------------------------------
26✔
52
    // Public Properties
26✔
53
    // -------------------------------------------------------------------------
26✔
54

26✔
55
    /**
26✔
56
     * Connection used by this entity manager.
26✔
57
     */
26✔
58
    readonly connection: DataSource
26✔
59

26✔
60
    /**
26✔
61
     * Custom query runner to be used for operations in this entity manager.
26✔
62
     * Used only in non-global entity manager.
26✔
63
     */
26✔
64
    readonly queryRunner?: QueryRunner
26✔
65

26✔
66
    // -------------------------------------------------------------------------
26✔
67
    // Protected Properties
26✔
68
    // -------------------------------------------------------------------------
26✔
69

26✔
70
    /**
26✔
71
     * Once created and then reused by repositories.
26✔
72
     * Created as a future replacement for the #repositories to provide a bit more perf optimization.
26✔
73
     */
26✔
74
    protected repositories = new Map<EntityTarget<any>, Repository<any>>()
26✔
75

26✔
76
    /**
26✔
77
     * Once created and then reused by repositories.
26✔
78
     */
26✔
79
    protected treeRepositories: TreeRepository<any>[] = []
26✔
80

26✔
81
    /**
26✔
82
     * Plain to object transformer used in create and merge operations.
26✔
83
     */
26✔
84
    protected plainObjectToEntityTransformer =
26✔
85
        new PlainObjectToNewEntityTransformer()
26✔
86

26✔
87
    // -------------------------------------------------------------------------
26✔
88
    // Constructor
26✔
89
    // -------------------------------------------------------------------------
26✔
90

26✔
91
    constructor(connection: DataSource, queryRunner?: QueryRunner) {
26✔
92
        this.connection = connection
352,481✔
93
        if (queryRunner) {
352,481✔
94
            this.queryRunner = queryRunner
337,124✔
95
            // dynamic: this.queryRunner = manager;
337,124✔
96
            ObjectUtils.assign(this.queryRunner, { manager: this })
337,124✔
97
        }
337,124✔
98
    }
352,481✔
99

26✔
100
    // -------------------------------------------------------------------------
26✔
101
    // Public Methods
26✔
102
    // -------------------------------------------------------------------------
26✔
103

26✔
104
    /**
26✔
105
     * Wraps given function execution (and all operations made there) in a transaction.
26✔
106
     * All database operations must be executed using provided entity manager.
26✔
107
     */
26✔
108
    async transaction<T>(
26✔
109
        runInTransaction: (entityManager: EntityManager) => Promise<T>,
26✔
110
    ): Promise<T>
26✔
111

26✔
112
    /**
26✔
113
     * Wraps given function execution (and all operations made there) in a transaction.
26✔
114
     * All database operations must be executed using provided entity manager.
26✔
115
     */
26✔
116
    async transaction<T>(
26✔
117
        isolationLevel: IsolationLevel,
26✔
118
        runInTransaction: (entityManager: EntityManager) => Promise<T>,
26✔
119
    ): Promise<T>
26✔
120

26✔
121
    /**
26✔
122
     * Wraps given function execution (and all operations made there) in a transaction.
26✔
123
     * All database operations must be executed using provided entity manager.
26✔
124
     */
26✔
125
    async transaction<T>(
26✔
126
        isolationOrRunInTransaction:
1,031✔
127
            | IsolationLevel
1,031✔
128
            | ((entityManager: EntityManager) => Promise<T>),
1,031✔
129
        runInTransactionParam?: (entityManager: EntityManager) => Promise<T>,
1,031✔
130
    ): Promise<T> {
1,031✔
131
        const isolation =
1,031✔
132
            typeof isolationOrRunInTransaction === "string"
1,031✔
133
                ? isolationOrRunInTransaction
1,031✔
134
                : undefined
1,031✔
135
        const runInTransaction =
1,031✔
136
            typeof isolationOrRunInTransaction === "function"
1,031✔
137
                ? isolationOrRunInTransaction
1,031✔
138
                : runInTransactionParam
1,031✔
139

1,031✔
140
        if (!runInTransaction) {
1,031!
141
            throw new TypeORMError(
×
142
                `Transaction method requires callback in second parameter if isolation level is supplied.`,
×
143
            )
×
144
        }
×
145

1,031✔
146
        if (this.queryRunner && this.queryRunner.isReleased)
1,031✔
147
            throw new QueryRunnerProviderAlreadyReleasedError()
1,031!
148

1,031✔
149
        // if query runner is already defined in this class, it means this entity manager was already created for a single connection
1,031✔
150
        // if its not defined we create a new query runner - single connection where we'll execute all our operations
1,031✔
151
        const queryRunner =
1,031✔
152
            this.queryRunner || this.connection.createQueryRunner()
1,031✔
153

1,031✔
154
        try {
1,031✔
155
            await queryRunner.startTransaction(isolation)
1,031✔
156
            const result = await runInTransaction(queryRunner.manager)
1,025✔
157
            await queryRunner.commitTransaction()
724✔
158
            return result
722✔
159
        } catch (err) {
1,031✔
160
            try {
309✔
161
                // we throw original error even if rollback thrown an error
309✔
162
                await queryRunner.rollbackTransaction()
309✔
163
            } catch (rollbackError) {}
309!
164
            throw err
309✔
165
        } finally {
1,031!
166
            if (!this.queryRunner)
1,031✔
167
                // if we used a new query runner provider then release it
1,031✔
168
                await queryRunner.release()
1,031✔
169
        }
1,031✔
170
    }
1,031✔
171

26✔
172
    /**
26✔
173
     * Executes raw SQL query and returns raw database results.
26✔
174
     *
26✔
175
     * @see [Official docs](https://typeorm.io/docs/Working%20with%20Entity%20Manager/entity-manager-api/) for examples.
26✔
176
     */
26✔
177
    async query<T = any>(query: string, parameters?: any[]): Promise<T> {
26✔
178
        return this.connection.query(query, parameters, this.queryRunner)
230✔
179
    }
230✔
180

26✔
181
    /**
26✔
182
     * Tagged template function that executes raw SQL query and returns raw database results.
26✔
183
     * Template expressions are automatically transformed into database parameters.
26✔
184
     * Raw query execution is supported only by relational databases (MongoDB is not supported).
26✔
185
     * Note: Don't call this as a regular function, it is meant to be used with backticks to tag a template literal.
26✔
186
     * Example: entityManager.sql`SELECT * FROM table_name WHERE id = ${id}`
26✔
187
     */
26✔
188
    async sql<T = any>(
26✔
189
        strings: TemplateStringsArray,
24✔
190
        ...values: unknown[]
24✔
191
    ): Promise<T> {
24✔
192
        const { query, parameters } = buildSqlTag({
24✔
193
            driver: this.connection.driver,
24✔
194
            strings: strings,
24✔
195
            expressions: values,
24✔
196
        })
24✔
197

24✔
198
        return await this.query(query, parameters)
24✔
199
    }
24✔
200

26✔
201
    /**
26✔
202
     * Creates a new query builder that can be used to build a SQL query.
26✔
203
     */
26✔
204
    createQueryBuilder<Entity extends ObjectLiteral>(
26✔
205
        entityClass: EntityTarget<Entity>,
26✔
206
        alias: string,
26✔
207
        queryRunner?: QueryRunner,
26✔
208
    ): SelectQueryBuilder<Entity>
26✔
209

26✔
210
    /**
26✔
211
     * Creates a new query builder that can be used to build a SQL query.
26✔
212
     */
26✔
213
    createQueryBuilder(queryRunner?: QueryRunner): SelectQueryBuilder<any>
26✔
214

26✔
215
    /**
26✔
216
     * Creates a new query builder that can be used to build a SQL query.
26✔
217
     */
26✔
218
    createQueryBuilder<Entity extends ObjectLiteral>(
26✔
219
        entityClass?: EntityTarget<Entity> | QueryRunner,
757,607✔
220
        alias?: string,
757,607✔
221
        queryRunner?: QueryRunner,
757,607✔
222
    ): SelectQueryBuilder<Entity> {
757,607✔
223
        if (alias) {
757,607✔
224
            return this.connection.createQueryBuilder(
483,905✔
225
                entityClass as EntityTarget<Entity>,
483,905✔
226
                alias,
483,905✔
227
                queryRunner || this.queryRunner,
483,905✔
228
            )
483,905✔
229
        } else {
757,607✔
230
            return this.connection.createQueryBuilder(
273,702✔
231
                (entityClass as QueryRunner | undefined) ||
273,702✔
232
                    queryRunner ||
273,702✔
233
                    this.queryRunner,
273,702✔
234
            )
273,702✔
235
        }
273,702✔
236
    }
757,607✔
237

26✔
238
    /**
26✔
239
     * Checks if entity has an id.
26✔
240
     */
26✔
241
    hasId(entity: any): boolean
26✔
242

26✔
243
    /**
26✔
244
     * Checks if entity of given schema name has an id.
26✔
245
     */
26✔
246
    hasId(target: Function | string, entity: any): boolean
26✔
247

26✔
248
    /**
26✔
249
     * Checks if entity has an id by its Function type or schema name.
26✔
250
     */
26✔
251
    hasId(targetOrEntity: any | Function | string, maybeEntity?: any): boolean {
26✔
252
        const target =
366✔
253
            arguments.length === 2 ? targetOrEntity : targetOrEntity.constructor
366!
254
        const entity = arguments.length === 2 ? maybeEntity : targetOrEntity
366!
255
        const metadata = this.connection.getMetadata(target)
366✔
256
        return metadata.hasId(entity)
366✔
257
    }
366✔
258

26✔
259
    /**
26✔
260
     * Gets entity mixed id.
26✔
261
     */
26✔
262
    getId(entity: any): any
26✔
263

26✔
264
    /**
26✔
265
     * Gets entity mixed id.
26✔
266
     */
26✔
267
    getId(target: EntityTarget<any>, entity: any): any
26✔
268

26✔
269
    /**
26✔
270
     * Gets entity mixed id.
26✔
271
     */
26✔
272
    getId(targetOrEntity: any | EntityTarget<any>, maybeEntity?: any): any {
26✔
273
        const target =
84✔
274
            arguments.length === 2 ? targetOrEntity : targetOrEntity.constructor
84!
275
        const entity = arguments.length === 2 ? maybeEntity : targetOrEntity
84!
276
        const metadata = this.connection.getMetadata(target)
84✔
277
        return metadata.getEntityIdMixedMap(entity)
84✔
278
    }
84✔
279

26✔
280
    /**
26✔
281
     * Creates a new entity instance and copies all entity properties from this object into a new entity.
26✔
282
     * Note that it copies only properties that present in entity schema.
26✔
283
     */
26✔
284
    create<Entity, EntityLike extends DeepPartial<Entity>>(
26✔
285
        entityClass: EntityTarget<Entity>,
26✔
286
        plainObject?: EntityLike,
26✔
287
    ): Entity
26✔
288

26✔
289
    /**
26✔
290
     * Creates a new entities and copies all entity properties from given objects into their new entities.
26✔
291
     * Note that it copies only properties that present in entity schema.
26✔
292
     */
26✔
293
    create<Entity, EntityLike extends DeepPartial<Entity>>(
26✔
294
        entityClass: EntityTarget<Entity>,
26✔
295
        plainObjects?: EntityLike[],
26✔
296
    ): Entity[]
26✔
297

26✔
298
    /**
26✔
299
     * Creates a new entity instance or instances.
26✔
300
     * Can copy properties from the given object into new entities.
26✔
301
     */
26✔
302
    create<Entity, EntityLike extends DeepPartial<Entity>>(
26✔
303
        entityClass: EntityTarget<Entity>,
4,381✔
304
        plainObjectOrObjects?: EntityLike | EntityLike[],
4,381✔
305
    ): Entity | Entity[] {
4,381✔
306
        const metadata = this.connection.getMetadata(entityClass)
4,381✔
307

4,381✔
308
        if (!plainObjectOrObjects) return metadata.create(this.queryRunner)
4,381✔
309

1,934✔
310
        if (Array.isArray(plainObjectOrObjects))
1,934✔
311
            return (plainObjectOrObjects as EntityLike[]).map(
4,381!
312
                (plainEntityLike) => this.create(entityClass, plainEntityLike),
56✔
313
            )
56✔
314

1,878✔
315
        const mergeIntoEntity = metadata.create(this.queryRunner)
1,878✔
316
        this.plainObjectToEntityTransformer.transform(
1,878✔
317
            mergeIntoEntity,
1,878✔
318
            plainObjectOrObjects,
1,878✔
319
            metadata,
1,878✔
320
            true,
1,878✔
321
        )
1,878✔
322
        return mergeIntoEntity
1,878✔
323
    }
1,878✔
324

26✔
325
    /**
26✔
326
     * Merges two entities into one new entity.
26✔
327
     */
26✔
328
    merge<Entity extends ObjectLiteral>(
26✔
329
        entityClass: EntityTarget<Entity>,
1,342,191✔
330
        mergeIntoEntity: Entity,
1,342,191✔
331
        ...entityLikes: DeepPartial<Entity>[]
1,342,191✔
332
    ): Entity {
1,342,191✔
333
        // todo: throw exception if entity manager is released
1,342,191✔
334
        const metadata = this.connection.getMetadata(entityClass)
1,342,191✔
335
        entityLikes.forEach((object) =>
1,342,191✔
336
            this.plainObjectToEntityTransformer.transform(
1,342,309✔
337
                mergeIntoEntity,
1,342,309✔
338
                object,
1,342,309✔
339
                metadata,
1,342,309✔
340
            ),
1,342,191✔
341
        )
1,342,191✔
342
        return mergeIntoEntity
1,342,191✔
343
    }
1,342,191✔
344

26✔
345
    /**
26✔
346
     * Creates a new entity from the given plain javascript object. If entity already exist in the database, then
26✔
347
     * it loads it (and everything related to it), replaces all values with the new ones from the given object
26✔
348
     * and returns this new entity. This new entity is actually a loaded from the db entity with all properties
26✔
349
     * replaced from the new object.
26✔
350
     */
26✔
351
    async preload<Entity extends ObjectLiteral>(
26✔
352
        entityClass: EntityTarget<Entity>,
90✔
353
        entityLike: DeepPartial<Entity>,
90✔
354
    ): Promise<Entity | undefined> {
90✔
355
        const metadata = this.connection.getMetadata(entityClass)
90✔
356
        const plainObjectToDatabaseEntityTransformer =
90✔
357
            new PlainObjectToDatabaseEntityTransformer(this.connection.manager)
90✔
358
        const transformedEntity =
90✔
359
            await plainObjectToDatabaseEntityTransformer.transform(
90✔
360
                entityLike,
90✔
361
                metadata,
90✔
362
            )
90✔
363
        if (transformedEntity)
90✔
364
            return this.merge(
90✔
365
                entityClass as any,
90✔
366
                transformedEntity as Entity,
90✔
367
                entityLike,
90✔
368
            )
90✔
369

×
370
        return undefined
×
371
    }
×
372

26✔
373
    /**
26✔
374
     * Saves all given entities in the database.
26✔
375
     * If entities do not exist in the database then inserts, otherwise updates.
26✔
376
     */
26✔
377
    save<Entity>(entities: Entity[], options?: SaveOptions): Promise<Entity[]>
26✔
378

26✔
379
    /**
26✔
380
     * Saves all given entities in the database.
26✔
381
     * If entities do not exist in the database then inserts, otherwise updates.
26✔
382
     */
26✔
383
    save<Entity>(entity: Entity, options?: SaveOptions): Promise<Entity>
26✔
384

26✔
385
    /**
26✔
386
     * Saves all given entities in the database.
26✔
387
     * If entities do not exist in the database then inserts, otherwise updates.
26✔
388
     */
26✔
389
    save<Entity, T extends DeepPartial<Entity>>(
26✔
390
        targetOrEntity: EntityTarget<Entity>,
26✔
391
        entities: T[],
26✔
392
        options: SaveOptions & { reload: false },
26✔
393
    ): Promise<T[]>
26✔
394

26✔
395
    /**
26✔
396
     * Saves all given entities in the database.
26✔
397
     * If entities do not exist in the database then inserts, otherwise updates.
26✔
398
     */
26✔
399
    save<Entity, T extends DeepPartial<Entity>>(
26✔
400
        targetOrEntity: EntityTarget<Entity>,
26✔
401
        entities: T[],
26✔
402
        options?: SaveOptions,
26✔
403
    ): Promise<(T & Entity)[]>
26✔
404

26✔
405
    /**
26✔
406
     * Saves a given entity in the database.
26✔
407
     * If entity does not exist in the database then inserts, otherwise updates.
26✔
408
     */
26✔
409
    save<Entity, T extends DeepPartial<Entity>>(
26✔
410
        targetOrEntity: EntityTarget<Entity>,
26✔
411
        entity: T,
26✔
412
        options: SaveOptions & { reload: false },
26✔
413
    ): Promise<T>
26✔
414

26✔
415
    /**
26✔
416
     * Saves a given entity in the database.
26✔
417
     * If entity does not exist in the database then inserts, otherwise updates.
26✔
418
     */
26✔
419
    save<Entity, T extends DeepPartial<Entity>>(
26✔
420
        targetOrEntity: EntityTarget<Entity>,
26✔
421
        entity: T,
26✔
422
        options?: SaveOptions,
26✔
423
    ): Promise<T & Entity>
26✔
424

26✔
425
    /**
26✔
426
     * Saves a given entity in the database.
26✔
427
     */
26✔
428
    save<Entity extends ObjectLiteral, T extends DeepPartial<Entity>>(
26✔
429
        targetOrEntity: (T | T[]) | EntityTarget<Entity>,
180,324✔
430
        maybeEntityOrOptions?: T | T[],
180,324✔
431
        maybeOptions?: SaveOptions,
180,324✔
432
    ): Promise<T | T[]> {
180,324✔
433
        // normalize mixed parameters
180,324✔
434
        let target =
180,324✔
435
            arguments.length > 1 &&
180,324✔
436
            (typeof targetOrEntity === "function" ||
95,189!
437
                InstanceChecker.isEntitySchema(targetOrEntity) ||
95,189!
438
                typeof targetOrEntity === "string")
95,189✔
439
                ? (targetOrEntity as Function | string)
180,324✔
440
                : undefined
180,324✔
441
        const entity: T | T[] = target
180,324✔
442
            ? (maybeEntityOrOptions as T | T[])
180,324✔
443
            : (targetOrEntity as T | T[])
180,324✔
444
        const options = target
180,324✔
445
            ? maybeOptions
180,324✔
446
            : (maybeEntityOrOptions as SaveOptions)
180,324✔
447

180,324✔
448
        if (InstanceChecker.isEntitySchema(target)) target = target.options.name
180,324!
449

180,324✔
450
        // if user passed empty array of entities then we don't need to do anything
180,324✔
451
        if (Array.isArray(entity) && entity.length === 0)
180,324✔
452
            return Promise.resolve(entity)
180,324✔
453

180,294✔
454
        // execute save operation
180,294✔
455
        return new EntityPersistExecutor(
180,294✔
456
            this.connection,
180,294✔
457
            this.queryRunner,
180,294✔
458
            "save",
180,294✔
459
            target,
180,294✔
460
            entity,
180,294✔
461
            options,
180,294✔
462
        )
180,294✔
463
            .execute()
180,294✔
464
            .then(() => entity)
180,294✔
465
    }
180,294✔
466

26✔
467
    /**
26✔
468
     * Removes a given entity from the database.
26✔
469
     */
26✔
470
    remove<Entity>(entity: Entity, options?: RemoveOptions): Promise<Entity>
26✔
471

26✔
472
    /**
26✔
473
     * Removes a given entity from the database.
26✔
474
     */
26✔
475
    remove<Entity>(
26✔
476
        targetOrEntity: EntityTarget<Entity>,
26✔
477
        entity: Entity,
26✔
478
        options?: RemoveOptions,
26✔
479
    ): Promise<Entity>
26✔
480

26✔
481
    /**
26✔
482
     * Removes a given entity from the database.
26✔
483
     */
26✔
484
    remove<Entity>(entity: Entity[], options?: RemoveOptions): Promise<Entity>
26✔
485

26✔
486
    /**
26✔
487
     * Removes a given entity from the database.
26✔
488
     */
26✔
489
    remove<Entity>(
26✔
490
        targetOrEntity: EntityTarget<Entity>,
26✔
491
        entity: Entity[],
26✔
492
        options?: RemoveOptions,
26✔
493
    ): Promise<Entity[]>
26✔
494

26✔
495
    /**
26✔
496
     * Removes a given entity from the database.
26✔
497
     */
26✔
498
    remove<Entity extends ObjectLiteral>(
26✔
499
        targetOrEntity: (Entity | Entity[]) | EntityTarget<Entity>,
1,434✔
500
        maybeEntityOrOptions?: Entity | Entity[],
1,434✔
501
        maybeOptions?: RemoveOptions,
1,434✔
502
    ): Promise<Entity | Entity[]> {
1,434✔
503
        // normalize mixed parameters
1,434✔
504
        const target =
1,434✔
505
            arguments.length > 1 &&
1,434✔
506
            (typeof targetOrEntity === "function" ||
918!
507
                InstanceChecker.isEntitySchema(targetOrEntity) ||
918!
508
                typeof targetOrEntity === "string")
918✔
509
                ? (targetOrEntity as Function | string)
1,434✔
510
                : undefined
1,434!
511
        const entity: Entity | Entity[] = target
1,434✔
512
            ? (maybeEntityOrOptions as Entity | Entity[])
1,434✔
513
            : (targetOrEntity as Entity | Entity[])
1,434!
514
        const options = target
1,434✔
515
            ? maybeOptions
1,434✔
516
            : (maybeEntityOrOptions as SaveOptions)
1,434!
517

1,434✔
518
        // if user passed empty array of entities then we don't need to do anything
1,434✔
519
        if (Array.isArray(entity) && entity.length === 0)
1,434!
520
            return Promise.resolve(entity)
1,434!
521

1,434✔
522
        // execute save operation
1,434✔
523
        return new EntityPersistExecutor(
1,434✔
524
            this.connection,
1,434✔
525
            this.queryRunner,
1,434✔
526
            "remove",
1,434✔
527
            target,
1,434✔
528
            entity,
1,434✔
529
            options,
1,434✔
530
        )
1,434✔
531
            .execute()
1,434✔
532
            .then(() => entity)
1,434✔
533
    }
1,434✔
534

26✔
535
    /**
26✔
536
     * Records the delete date of all given entities.
26✔
537
     */
26✔
538
    softRemove<Entity>(
26✔
539
        entities: Entity[],
26✔
540
        options?: SaveOptions,
26✔
541
    ): Promise<Entity[]>
26✔
542

26✔
543
    /**
26✔
544
     * Records the delete date of a given entity.
26✔
545
     */
26✔
546
    softRemove<Entity>(entity: Entity, options?: SaveOptions): Promise<Entity>
26✔
547

26✔
548
    /**
26✔
549
     * Records the delete date of all given entities.
26✔
550
     */
26✔
551
    softRemove<Entity, T extends DeepPartial<Entity>>(
26✔
552
        targetOrEntity: EntityTarget<Entity>,
26✔
553
        entities: T[],
26✔
554
        options?: SaveOptions,
26✔
555
    ): Promise<T[]>
26✔
556

26✔
557
    /**
26✔
558
     * Records the delete date of a given entity.
26✔
559
     */
26✔
560
    softRemove<Entity, T extends DeepPartial<Entity>>(
26✔
561
        targetOrEntity: EntityTarget<Entity>,
26✔
562
        entity: T,
26✔
563
        options?: SaveOptions,
26✔
564
    ): Promise<T>
26✔
565

26✔
566
    /**
26✔
567
     * Records the delete date of one or many given entities.
26✔
568
     */
26✔
569
    softRemove<Entity extends ObjectLiteral, T extends DeepPartial<Entity>>(
26✔
570
        targetOrEntity: (T | T[]) | EntityTarget<Entity>,
454✔
571
        maybeEntityOrOptions?: T | T[],
454✔
572
        maybeOptions?: SaveOptions,
454✔
573
    ): Promise<T | T[]> {
454✔
574
        // normalize mixed parameters
454✔
575
        let target =
454✔
576
            arguments.length > 1 &&
454✔
577
            (typeof targetOrEntity === "function" ||
174!
578
                InstanceChecker.isEntitySchema(targetOrEntity) ||
174!
579
                typeof targetOrEntity === "string")
174✔
580
                ? (targetOrEntity as Function | string)
454✔
581
                : undefined
454!
582
        const entity: T | T[] = target
454✔
583
            ? (maybeEntityOrOptions as T | T[])
454✔
584
            : (targetOrEntity as T | T[])
454!
585
        const options = target
454✔
586
            ? maybeOptions
454✔
587
            : (maybeEntityOrOptions as SaveOptions)
454!
588

454✔
589
        if (InstanceChecker.isEntitySchema(target)) target = target.options.name
454!
590

454✔
591
        // if user passed empty array of entities then we don't need to do anything
454✔
592
        if (Array.isArray(entity) && entity.length === 0)
454!
593
            return Promise.resolve(entity)
454!
594

454✔
595
        // execute soft-remove operation
454✔
596
        return new EntityPersistExecutor(
454✔
597
            this.connection,
454✔
598
            this.queryRunner,
454✔
599
            "soft-remove",
454✔
600
            target,
454✔
601
            entity,
454✔
602
            options,
454✔
603
        )
454✔
604
            .execute()
454✔
605
            .then(() => entity)
454✔
606
    }
454✔
607

26✔
608
    /**
26✔
609
     * Recovers all given entities.
26✔
610
     */
26✔
611
    recover<Entity>(
26✔
612
        entities: Entity[],
26✔
613
        options?: SaveOptions,
26✔
614
    ): Promise<Entity[]>
26✔
615

26✔
616
    /**
26✔
617
     * Recovers a given entity.
26✔
618
     */
26✔
619
    recover<Entity>(entity: Entity, options?: SaveOptions): Promise<Entity>
26✔
620

26✔
621
    /**
26✔
622
     * Recovers all given entities.
26✔
623
     */
26✔
624
    recover<Entity, T extends DeepPartial<Entity>>(
26✔
625
        targetOrEntity: EntityTarget<Entity>,
26✔
626
        entities: T[],
26✔
627
        options?: SaveOptions,
26✔
628
    ): Promise<T[]>
26✔
629

26✔
630
    /**
26✔
631
     * Recovers a given entity.
26✔
632
     */
26✔
633
    recover<Entity, T extends DeepPartial<Entity>>(
26✔
634
        targetOrEntity: EntityTarget<Entity>,
26✔
635
        entity: T,
26✔
636
        options?: SaveOptions,
26✔
637
    ): Promise<T>
26✔
638

26✔
639
    /**
26✔
640
     * Recovers one or many given entities.
26✔
641
     */
26✔
642
    recover<Entity extends ObjectLiteral, T extends DeepPartial<Entity>>(
26✔
643
        targetOrEntity: (T | T[]) | EntityTarget<Entity>,
168✔
644
        maybeEntityOrOptions?: T | T[],
168✔
645
        maybeOptions?: SaveOptions,
168✔
646
    ): Promise<T | T[]> {
168✔
647
        // normalize mixed parameters
168✔
648
        let target =
168✔
649
            arguments.length > 1 &&
168✔
650
            (typeof targetOrEntity === "function" ||
140✔
651
                InstanceChecker.isEntitySchema(targetOrEntity) ||
140✔
652
                typeof targetOrEntity === "string")
140✔
653
                ? (targetOrEntity as Function | string)
168✔
654
                : undefined
168✔
655
        const entity: T | T[] = target
168✔
656
            ? (maybeEntityOrOptions as T | T[])
168✔
657
            : (targetOrEntity as T | T[])
168✔
658
        const options = target
168✔
659
            ? maybeOptions
168✔
660
            : (maybeEntityOrOptions as SaveOptions)
168✔
661

168✔
662
        if (InstanceChecker.isEntitySchema(target)) target = target.options.name
168!
663

168✔
664
        // if user passed empty array of entities then we don't need to do anything
168✔
665
        if (Array.isArray(entity) && entity.length === 0)
168!
666
            return Promise.resolve(entity)
168!
667

168✔
668
        // execute recover operation
168✔
669
        return new EntityPersistExecutor(
168✔
670
            this.connection,
168✔
671
            this.queryRunner,
168✔
672
            "recover",
168✔
673
            target,
168✔
674
            entity,
168✔
675
            options,
168✔
676
        )
168✔
677
            .execute()
168✔
678
            .then(() => entity)
168✔
679
    }
168✔
680

26✔
681
    /**
26✔
682
     * Inserts a given entity into the database.
26✔
683
     * Unlike save method executes a primitive operation without cascades, relations and other operations included.
26✔
684
     * Executes fast and efficient INSERT query.
26✔
685
     * Does not check if entity exist in the database, so query will fail if duplicate entity is being inserted.
26✔
686
     * You can execute bulk inserts using this method.
26✔
687
     */
26✔
688
    async insert<Entity extends ObjectLiteral>(
26✔
689
        target: EntityTarget<Entity>,
371✔
690
        entity:
371✔
691
            | QueryDeepPartialEntity<Entity>
371✔
692
            | QueryDeepPartialEntity<Entity>[],
371✔
693
    ): Promise<InsertResult> {
371✔
694
        return this.createQueryBuilder()
371✔
695
            .insert()
371✔
696
            .into(target)
371✔
697
            .values(entity)
371✔
698
            .execute()
371✔
699
    }
371✔
700

26✔
701
    async upsert<Entity extends ObjectLiteral>(
26✔
702
        target: EntityTarget<Entity>,
578✔
703
        entityOrEntities:
578✔
704
            | QueryDeepPartialEntity<Entity>
578✔
705
            | QueryDeepPartialEntity<Entity>[],
578✔
706
        conflictPathsOrOptions: string[] | UpsertOptions<Entity>,
578✔
707
    ): Promise<InsertResult> {
578✔
708
        const metadata = this.connection.getMetadata(target)
578✔
709

578✔
710
        let options: UpsertOptions<Entity>
578✔
711

578✔
712
        if (Array.isArray(conflictPathsOrOptions)) {
578✔
713
            options = {
532✔
714
                conflictPaths: conflictPathsOrOptions,
532✔
715
            }
532✔
716
        } else {
578!
717
            options = conflictPathsOrOptions
46✔
718
        }
46✔
719

578✔
720
        let entities: QueryDeepPartialEntity<Entity>[]
578✔
721

578✔
722
        if (!Array.isArray(entityOrEntities)) {
578✔
723
            entities = [entityOrEntities]
449✔
724
        } else {
578✔
725
            entities = entityOrEntities
129✔
726
        }
129✔
727

578✔
728
        const conflictColumns = metadata.mapPropertyPathsToColumns(
578✔
729
            Array.isArray(options.conflictPaths)
578✔
730
                ? options.conflictPaths
578✔
731
                : Object.keys(options.conflictPaths),
578!
732
        )
578✔
733

578✔
734
        const overwriteColumns = metadata.columns.filter(
578✔
735
            (col) =>
578✔
736
                !conflictColumns.includes(col) &&
2,590✔
737
                entities.some(
2,008✔
738
                    (entity) =>
2,008✔
739
                        typeof col.getEntityValue(entity) !== "undefined",
2,008✔
740
                ),
578✔
741
        )
578✔
742

578✔
743
        return this.createQueryBuilder()
578✔
744
            .insert()
578✔
745
            .into(target)
578✔
746
            .values(entities)
578✔
747
            .orUpdate(
578✔
748
                [...conflictColumns, ...overwriteColumns].map(
578✔
749
                    (col) => col.databaseName,
578✔
750
                ),
578✔
751
                conflictColumns.map((col) => col.databaseName),
578✔
752
                {
578✔
753
                    skipUpdateIfNoValuesChanged:
578✔
754
                        options.skipUpdateIfNoValuesChanged,
578✔
755
                    indexPredicate: options.indexPredicate,
578✔
756
                    upsertType:
578✔
757
                        options.upsertType ||
578✔
758
                        this.connection.driver.supportedUpsertTypes[0],
578✔
759
                },
578✔
760
            )
578✔
761
            .execute()
578✔
762
    }
578✔
763

26✔
764
    /**
26✔
765
     * Updates entity partially. Entity can be found by a given condition(s).
26✔
766
     * Unlike save method executes a primitive operation without cascades, relations and other operations included.
26✔
767
     * Executes fast and efficient UPDATE query.
26✔
768
     * Does not check if entity exist in the database.
26✔
769
     * Condition(s) cannot be empty.
26✔
770
     */
26✔
771
    update<Entity extends ObjectLiteral>(
26✔
772
        target: EntityTarget<Entity>,
545✔
773
        criteria:
545✔
774
            | string
545✔
775
            | string[]
545✔
776
            | number
545✔
777
            | number[]
545✔
778
            | Date
545✔
779
            | Date[]
545✔
780
            | ObjectId
545✔
781
            | ObjectId[]
545✔
782
            | any,
545✔
783
        partialEntity: QueryDeepPartialEntity<Entity>,
545✔
784
    ): Promise<UpdateResult> {
545✔
785
        // if user passed empty criteria or empty list of criterias, then throw an error
545✔
786
        if (OrmUtils.isCriteriaNullOrEmpty(criteria)) {
545✔
787
            return Promise.reject(
112✔
788
                new TypeORMError(
112✔
789
                    `Empty criteria(s) are not allowed for the update method.`,
112✔
790
                ),
112✔
791
            )
112✔
792
        }
112✔
793

433✔
794
        if (OrmUtils.isPrimitiveCriteria(criteria)) {
545✔
795
            return this.createQueryBuilder()
172✔
796
                .update(target)
172✔
797
                .set(partialEntity)
172✔
798
                .whereInIds(criteria)
172✔
799
                .execute()
172✔
800
        } else {
545✔
801
            return this.createQueryBuilder()
261✔
802
                .update(target)
261✔
803
                .set(partialEntity)
261✔
804
                .where(criteria)
261✔
805
                .execute()
261✔
806
        }
261✔
807
    }
545✔
808

26✔
809
    /**
26✔
810
     * Updates all entities of target type, setting fields from supplied partial entity.
26✔
811
     * This is a primitive operation without cascades, relations or other operations included.
26✔
812
     * Executes fast and efficient UPDATE query without WHERE clause.
26✔
813
     *
26✔
814
     * WARNING! This method updates ALL rows in the target table.
26✔
815
     */
26✔
816
    updateAll<Entity extends ObjectLiteral>(
26✔
817
        target: EntityTarget<Entity>,
28✔
818
        partialEntity: QueryDeepPartialEntity<Entity>,
28✔
819
    ): Promise<UpdateResult> {
28✔
820
        return this.createQueryBuilder()
28✔
821
            .update(target)
28✔
822
            .set(partialEntity)
28✔
823
            .execute()
28✔
824
    }
28✔
825

26✔
826
    /**
26✔
827
     * Deletes entities by a given condition(s).
26✔
828
     * Unlike save method executes a primitive operation without cascades, relations and other operations included.
26✔
829
     * Executes fast and efficient DELETE query.
26✔
830
     * Does not check if entity exist in the database.
26✔
831
     * Condition(s) cannot be empty.
26✔
832
     */
26✔
833
    delete<Entity extends ObjectLiteral>(
26✔
834
        targetOrEntity: EntityTarget<Entity>,
438✔
835
        criteria:
438✔
836
            | string
438✔
837
            | string[]
438✔
838
            | number
438✔
839
            | number[]
438✔
840
            | Date
438✔
841
            | Date[]
438✔
842
            | ObjectId
438✔
843
            | ObjectId[]
438✔
844
            | any,
438✔
845
    ): Promise<DeleteResult> {
438✔
846
        // if user passed empty criteria or empty list of criterias, then throw an error
438✔
847
        if (OrmUtils.isCriteriaNullOrEmpty(criteria)) {
438✔
848
            return Promise.reject(
112✔
849
                new TypeORMError(
112✔
850
                    `Empty criteria(s) are not allowed for the delete method.`,
112✔
851
                ),
112✔
852
            )
112✔
853
        }
112✔
854

326✔
855
        if (OrmUtils.isPrimitiveCriteria(criteria)) {
438✔
856
            return this.createQueryBuilder()
158✔
857
                .delete()
158✔
858
                .from(targetOrEntity)
158✔
859
                .whereInIds(criteria)
158✔
860
                .execute()
158✔
861
        } else {
338✔
862
            return this.createQueryBuilder()
168✔
863
                .delete()
168✔
864
                .from(targetOrEntity)
168✔
865
                .where(criteria)
168✔
866
                .execute()
168✔
867
        }
168✔
868
    }
438✔
869

26✔
870
    /**
26✔
871
     * Deletes all entities of target type.
26✔
872
     * This is a primitive operation without cascades, relations or other operations included.
26✔
873
     * Executes fast and efficient DELETE query without WHERE clause.
26✔
874
     *
26✔
875
     * WARNING! This method deletes ALL rows in the target table.
26✔
876
     */
26✔
877
    deleteAll<Entity extends ObjectLiteral>(
26✔
878
        targetOrEntity: EntityTarget<Entity>,
28✔
879
    ): Promise<DeleteResult> {
28✔
880
        return this.createQueryBuilder().delete().from(targetOrEntity).execute()
28✔
881
    }
28✔
882

26✔
883
    /**
26✔
884
     * Records the delete date of entities by a given condition(s).
26✔
885
     * Unlike save method executes a primitive operation without cascades, relations and other operations included.
26✔
886
     * Executes fast and efficient UPDATE query.
26✔
887
     * Does not check if entity exist in the database.
26✔
888
     * Condition(s) cannot be empty.
26✔
889
     */
26✔
890
    softDelete<Entity extends ObjectLiteral>(
26✔
891
        targetOrEntity: EntityTarget<Entity>,
140✔
892
        criteria:
140✔
893
            | string
140✔
894
            | string[]
140✔
895
            | number
140✔
896
            | number[]
140✔
897
            | Date
140✔
898
            | Date[]
140✔
899
            | ObjectId
140✔
900
            | ObjectId[]
140✔
901
            | any,
140✔
902
    ): Promise<UpdateResult> {
140✔
903
        // if user passed empty criteria or empty list of criterias, then throw an error
140✔
904
        if (OrmUtils.isCriteriaNullOrEmpty(criteria)) {
140!
905
            return Promise.reject(
×
906
                new TypeORMError(
×
907
                    `Empty criteria(s) are not allowed for the softDelete method.`,
×
908
                ),
×
909
            )
×
910
        }
×
911

140✔
912
        if (OrmUtils.isPrimitiveCriteria(criteria)) {
140!
913
            return this.createQueryBuilder()
×
914
                .softDelete()
×
915
                .from(targetOrEntity)
×
916
                .whereInIds(criteria)
×
917
                .execute()
×
918
        } else {
140✔
919
            return this.createQueryBuilder()
140✔
920
                .softDelete()
140✔
921
                .from(targetOrEntity)
140✔
922
                .where(criteria)
140✔
923
                .execute()
140✔
924
        }
140✔
925
    }
140✔
926

26✔
927
    /**
26✔
928
     * Restores entities by a given condition(s).
26✔
929
     * Unlike save method executes a primitive operation without cascades, relations and other operations included.
26✔
930
     * Executes fast and efficient UPDATE query.
26✔
931
     * Does not check if entity exist in the database.
26✔
932
     * Condition(s) cannot be empty.
26✔
933
     */
26✔
934
    restore<Entity extends ObjectLiteral>(
26✔
935
        targetOrEntity: EntityTarget<Entity>,
56✔
936
        criteria:
56✔
937
            | string
56✔
938
            | string[]
56✔
939
            | number
56✔
940
            | number[]
56✔
941
            | Date
56✔
942
            | Date[]
56✔
943
            | ObjectId
56✔
944
            | ObjectId[]
56✔
945
            | any,
56✔
946
    ): Promise<UpdateResult> {
56✔
947
        // if user passed empty criteria or empty list of criterias, then throw an error
56✔
948
        if (OrmUtils.isCriteriaNullOrEmpty(criteria)) {
56!
949
            return Promise.reject(
×
950
                new TypeORMError(
×
951
                    `Empty criteria(s) are not allowed for the restore method.`,
×
952
                ),
×
953
            )
×
954
        }
×
955

56✔
956
        if (OrmUtils.isPrimitiveCriteria(criteria)) {
56!
957
            return this.createQueryBuilder()
×
958
                .restore()
×
959
                .from(targetOrEntity)
×
960
                .whereInIds(criteria)
×
961
                .execute()
×
962
        } else {
56✔
963
            return this.createQueryBuilder()
56✔
964
                .restore()
56✔
965
                .from(targetOrEntity)
56✔
966
                .where(criteria)
56✔
967
                .execute()
56✔
968
        }
56✔
969
    }
56✔
970

26✔
971
    /**
26✔
972
     * Checks whether any entity exists with the given options.
26✔
973
     */
26✔
974
    exists<Entity extends ObjectLiteral>(
26✔
975
        entityClass: EntityTarget<Entity>,
196✔
976
        options?: FindManyOptions<Entity>,
196✔
977
    ): Promise<boolean> {
196✔
978
        const metadata = this.connection.getMetadata(entityClass)
196✔
979
        return this.createQueryBuilder(
196✔
980
            entityClass,
196✔
981
            FindOptionsUtils.extractFindManyOptionsAlias(options) ||
196✔
982
                metadata.name,
196✔
983
        )
196✔
984
            .setFindOptions(options || {})
196✔
985
            .getExists()
196✔
986
    }
196✔
987

26✔
988
    /**
26✔
989
     * Checks whether any entity exists with the given conditions.
26✔
990
     */
26✔
991
    async existsBy<Entity extends ObjectLiteral>(
26✔
992
        entityClass: EntityTarget<Entity>,
×
993
        where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[],
×
994
    ): Promise<boolean> {
×
995
        const metadata = this.connection.getMetadata(entityClass)
×
996
        return this.createQueryBuilder(entityClass, metadata.name)
×
997
            .setFindOptions({ where })
×
998
            .getExists()
×
999
    }
×
1000

26✔
1001
    /**
26✔
1002
     * Counts entities that match given options.
26✔
1003
     * Useful for pagination.
26✔
1004
     */
26✔
1005
    count<Entity extends ObjectLiteral>(
26✔
1006
        entityClass: EntityTarget<Entity>,
424✔
1007
        options?: FindManyOptions<Entity>,
424✔
1008
    ): Promise<number> {
424✔
1009
        const metadata = this.connection.getMetadata(entityClass)
424✔
1010
        return this.createQueryBuilder(
424✔
1011
            entityClass,
424✔
1012
            FindOptionsUtils.extractFindManyOptionsAlias(options) ||
424✔
1013
                metadata.name,
424✔
1014
        )
424✔
1015
            .setFindOptions(options || {})
424✔
1016
            .getCount()
424✔
1017
    }
424✔
1018

26✔
1019
    /**
26✔
1020
     * Counts entities that match given conditions.
26✔
1021
     * Useful for pagination.
26✔
1022
     */
26✔
1023
    countBy<Entity extends ObjectLiteral>(
26✔
1024
        entityClass: EntityTarget<Entity>,
56✔
1025
        where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[],
56✔
1026
    ): Promise<number> {
56✔
1027
        const metadata = this.connection.getMetadata(entityClass)
56✔
1028
        return this.createQueryBuilder(entityClass, metadata.name)
56✔
1029
            .setFindOptions({ where })
56✔
1030
            .getCount()
56✔
1031
    }
56✔
1032

26✔
1033
    /**
26✔
1034
     * Return the SUM of a column
26✔
1035
     */
26✔
1036
    sum<Entity extends ObjectLiteral>(
26✔
1037
        entityClass: EntityTarget<Entity>,
60✔
1038
        columnName: PickKeysByType<Entity, number>,
60✔
1039
        where?: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[],
60✔
1040
    ): Promise<number | null> {
60✔
1041
        return this.callAggregateFun(entityClass, "SUM", columnName, where)
60✔
1042
    }
60✔
1043

26✔
1044
    /**
26✔
1045
     * Return the AVG of a column
26✔
1046
     */
26✔
1047
    average<Entity extends ObjectLiteral>(
26✔
1048
        entityClass: EntityTarget<Entity>,
60✔
1049
        columnName: PickKeysByType<Entity, number>,
60✔
1050
        where?: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[],
60✔
1051
    ): Promise<number | null> {
60✔
1052
        return this.callAggregateFun(entityClass, "AVG", columnName, where)
60✔
1053
    }
60✔
1054

26✔
1055
    /**
26✔
1056
     * Return the MIN of a column
26✔
1057
     */
26✔
1058
    minimum<Entity extends ObjectLiteral>(
26✔
1059
        entityClass: EntityTarget<Entity>,
60✔
1060
        columnName: PickKeysByType<Entity, number>,
60✔
1061
        where?: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[],
60✔
1062
    ): Promise<number | null> {
60✔
1063
        return this.callAggregateFun(entityClass, "MIN", columnName, where)
60✔
1064
    }
60✔
1065

26✔
1066
    /**
26✔
1067
     * Return the MAX of a column
26✔
1068
     */
26✔
1069
    maximum<Entity extends ObjectLiteral>(
26✔
1070
        entityClass: EntityTarget<Entity>,
60✔
1071
        columnName: PickKeysByType<Entity, number>,
60✔
1072
        where?: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[],
60✔
1073
    ): Promise<number | null> {
60✔
1074
        return this.callAggregateFun(entityClass, "MAX", columnName, where)
60✔
1075
    }
60✔
1076

26✔
1077
    private async callAggregateFun<Entity extends ObjectLiteral>(
26✔
1078
        entityClass: EntityTarget<Entity>,
240✔
1079
        fnName: "SUM" | "AVG" | "MIN" | "MAX",
240✔
1080
        columnName: PickKeysByType<Entity, number>,
240✔
1081
        where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[] = {},
240✔
1082
    ): Promise<number | null> {
240✔
1083
        const metadata = this.connection.getMetadata(entityClass)
240✔
1084
        const column = metadata.columns.find(
240✔
1085
            (item) => item.propertyPath === columnName,
240✔
1086
        )
240✔
1087
        if (!column) {
240!
1088
            throw new TypeORMError(
×
1089
                `Column "${columnName}" was not found in table "${metadata.name}"`,
×
1090
            )
×
1091
        }
×
1092

240✔
1093
        const result = await this.createQueryBuilder(entityClass, metadata.name)
240✔
1094
            .setFindOptions({ where })
240✔
1095
            .select(
240✔
1096
                `${fnName}(${this.connection.driver.escape(
240✔
1097
                    column.databaseName,
240✔
1098
                )})`,
240✔
1099
                fnName,
240✔
1100
            )
240✔
1101
            .getRawOne()
240✔
1102
        return result[fnName] === null ? null : parseFloat(result[fnName])
240✔
1103
    }
240✔
1104

26✔
1105
    /**
26✔
1106
     * Finds entities that match given find options.
26✔
1107
     */
26✔
1108
    async find<Entity extends ObjectLiteral>(
26✔
1109
        entityClass: EntityTarget<Entity>,
4,974✔
1110
        options?: FindManyOptions<Entity>,
4,974✔
1111
    ): Promise<Entity[]> {
4,974✔
1112
        const metadata = this.connection.getMetadata(entityClass)
4,974✔
1113
        return this.createQueryBuilder<Entity>(
4,974✔
1114
            entityClass as any,
4,974✔
1115
            FindOptionsUtils.extractFindManyOptionsAlias(options) ||
4,974✔
1116
                metadata.name,
4,974✔
1117
        )
4,974✔
1118
            .setFindOptions(options || {})
4,974✔
1119
            .getMany()
4,974✔
1120
    }
4,974✔
1121

26✔
1122
    /**
26✔
1123
     * Finds entities that match given find options.
26✔
1124
     */
26✔
1125
    async findBy<Entity extends ObjectLiteral>(
26✔
1126
        entityClass: EntityTarget<Entity>,
1,244✔
1127
        where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[],
1,244✔
1128
    ): Promise<Entity[]> {
1,244✔
1129
        const metadata = this.connection.getMetadata(entityClass)
1,244✔
1130
        return this.createQueryBuilder<Entity>(
1,244✔
1131
            entityClass as any,
1,244✔
1132
            metadata.name,
1,244✔
1133
        )
1,244✔
1134
            .setFindOptions({ where: where })
1,244✔
1135
            .getMany()
1,244✔
1136
    }
1,244✔
1137

26✔
1138
    /**
26✔
1139
     * Finds entities that match given find options.
26✔
1140
     * Also counts all entities that match given conditions,
26✔
1141
     * but ignores pagination settings (from and take options).
26✔
1142
     */
26✔
1143
    findAndCount<Entity extends ObjectLiteral>(
26✔
1144
        entityClass: EntityTarget<Entity>,
340✔
1145
        options?: FindManyOptions<Entity>,
340✔
1146
    ): Promise<[Entity[], number]> {
340✔
1147
        const metadata = this.connection.getMetadata(entityClass)
340✔
1148
        return this.createQueryBuilder<Entity>(
340✔
1149
            entityClass as any,
340✔
1150
            FindOptionsUtils.extractFindManyOptionsAlias(options) ||
340✔
1151
                metadata.name,
340✔
1152
        )
340✔
1153
            .setFindOptions(options || {})
340✔
1154
            .getManyAndCount()
340✔
1155
    }
340✔
1156

26✔
1157
    /**
26✔
1158
     * Finds entities that match given WHERE conditions.
26✔
1159
     * Also counts all entities that match given conditions,
26✔
1160
     * but ignores pagination settings (from and take options).
26✔
1161
     */
26✔
1162
    findAndCountBy<Entity extends ObjectLiteral>(
26✔
1163
        entityClass: EntityTarget<Entity>,
×
1164
        where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[],
×
1165
    ): Promise<[Entity[], number]> {
×
1166
        const metadata = this.connection.getMetadata(entityClass)
×
1167
        return this.createQueryBuilder<Entity>(
×
1168
            entityClass as any,
×
1169
            metadata.name,
×
1170
        )
×
1171
            .setFindOptions({ where })
×
1172
            .getManyAndCount()
×
1173
    }
×
1174

26✔
1175
    /**
26✔
1176
     * Finds entities with ids.
26✔
1177
     * Optionally find options or conditions can be applied.
26✔
1178
     *
26✔
1179
     * @deprecated use `findBy` method instead in conjunction with `In` operator, for example:
26✔
1180
     *
26✔
1181
     * .findBy({
26✔
1182
     *     id: In([1, 2, 3])
26✔
1183
     * })
26✔
1184
     */
26✔
1185
    async findByIds<Entity extends ObjectLiteral>(
26✔
1186
        entityClass: EntityTarget<Entity>,
232✔
1187
        ids: any[],
232✔
1188
    ): Promise<Entity[]> {
232✔
1189
        // if no ids passed, no need to execute a query - just return an empty array of values
232✔
1190
        if (!ids.length) return Promise.resolve([])
232✔
1191

204✔
1192
        const metadata = this.connection.getMetadata(entityClass)
204✔
1193
        return this.createQueryBuilder<Entity>(
204✔
1194
            entityClass as any,
204✔
1195
            metadata.name,
204✔
1196
        )
204✔
1197
            .andWhereInIds(ids)
204✔
1198
            .getMany()
204✔
1199
    }
204✔
1200

26✔
1201
    /**
26✔
1202
     * Finds first entity by a given find options.
26✔
1203
     * If entity was not found in the database - returns null.
26✔
1204
     */
26✔
1205
    async findOne<Entity extends ObjectLiteral>(
26✔
1206
        entityClass: EntityTarget<Entity>,
10,246✔
1207
        options: FindOneOptions<Entity>,
10,246✔
1208
    ): Promise<Entity | null> {
10,246✔
1209
        const metadata = this.connection.getMetadata(entityClass)
10,246✔
1210

10,246✔
1211
        // prepare alias for built query
10,246✔
1212
        let alias: string = metadata.name
10,246✔
1213
        if (options && options.join) {
10,246✔
1214
            alias = options.join.alias
509✔
1215
        }
509✔
1216

10,246✔
1217
        if (!options.where) {
10,246✔
1218
            throw new Error(
28✔
1219
                `You must provide selection conditions in order to find a single row.`,
28✔
1220
            )
28✔
1221
        }
28✔
1222

10,218✔
1223
        // create query builder and apply find options
10,218✔
1224
        return this.createQueryBuilder<Entity>(entityClass, alias)
10,218✔
1225
            .setFindOptions({
10,218✔
1226
                ...options,
10,218✔
1227
                take: 1,
10,218✔
1228
            })
10,218✔
1229
            .getOne()
10,218✔
1230
    }
10,218✔
1231

26✔
1232
    /**
26✔
1233
     * Finds first entity that matches given where condition.
26✔
1234
     * If entity was not found in the database - returns null.
26✔
1235
     */
26✔
1236
    async findOneBy<Entity extends ObjectLiteral>(
26✔
1237
        entityClass: EntityTarget<Entity>,
6,151✔
1238
        where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[],
6,151✔
1239
    ): Promise<Entity | null> {
6,151✔
1240
        const metadata = this.connection.getMetadata(entityClass)
6,151✔
1241

6,151✔
1242
        // create query builder and apply find options
6,151✔
1243
        return this.createQueryBuilder<Entity>(entityClass, metadata.name)
6,151✔
1244
            .setFindOptions({
6,151✔
1245
                where,
6,151✔
1246
                take: 1,
6,151✔
1247
            })
6,151✔
1248
            .getOne()
6,151✔
1249
    }
6,151✔
1250

26✔
1251
    /**
26✔
1252
     * Finds first entity that matches given id.
26✔
1253
     * If entity was not found in the database - returns null.
26✔
1254
     *
26✔
1255
     * @deprecated use `findOneBy` method instead in conjunction with `In` operator, for example:
26✔
1256
     *
26✔
1257
     * .findOneBy({
26✔
1258
     *     id: 1 // where "id" is your primary column name
26✔
1259
     * })
26✔
1260
     */
26✔
1261
    async findOneById<Entity extends ObjectLiteral>(
26✔
1262
        entityClass: EntityTarget<Entity>,
116✔
1263
        id: number | string | Date | ObjectId,
116✔
1264
    ): Promise<Entity | null> {
116✔
1265
        const metadata = this.connection.getMetadata(entityClass)
116✔
1266

116✔
1267
        // create query builder and apply find options
116✔
1268
        return this.createQueryBuilder<Entity>(entityClass, metadata.name)
116✔
1269
            .setFindOptions({
116✔
1270
                take: 1,
116✔
1271
            })
116✔
1272
            .whereInIds(metadata.ensureEntityIdMap(id))
116✔
1273
            .getOne()
116✔
1274
    }
116✔
1275

26✔
1276
    /**
26✔
1277
     * Finds first entity by a given find options.
26✔
1278
     * If entity was not found in the database - rejects with error.
26✔
1279
     */
26✔
1280
    async findOneOrFail<Entity extends ObjectLiteral>(
26✔
1281
        entityClass: EntityTarget<Entity>,
496✔
1282
        options: FindOneOptions<Entity>,
496✔
1283
    ): Promise<Entity> {
496✔
1284
        return this.findOne<Entity>(entityClass as any, options).then(
496✔
1285
            (value) => {
496✔
1286
                if (value === null) {
496✔
1287
                    return Promise.reject(
56✔
1288
                        new EntityNotFoundError(entityClass, options),
56✔
1289
                    )
56✔
1290
                }
56✔
1291
                return Promise.resolve(value)
440✔
1292
            },
496✔
1293
        )
496✔
1294
    }
496✔
1295

26✔
1296
    /**
26✔
1297
     * Finds first entity that matches given where condition.
26✔
1298
     * If entity was not found in the database - rejects with error.
26✔
1299
     */
26✔
1300
    async findOneByOrFail<Entity extends ObjectLiteral>(
26✔
1301
        entityClass: EntityTarget<Entity>,
1,185✔
1302
        where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[],
1,185✔
1303
    ): Promise<Entity> {
1,185✔
1304
        return this.findOneBy<Entity>(entityClass as any, where).then(
1,185✔
1305
            (value) => {
1,185✔
1306
                if (value === null) {
1,185!
1307
                    return Promise.reject(
28✔
1308
                        new EntityNotFoundError(entityClass, where),
28✔
1309
                    )
28✔
1310
                }
28✔
1311
                return Promise.resolve(value)
1,157✔
1312
            },
1,185✔
1313
        )
1,185✔
1314
    }
1,185✔
1315

26✔
1316
    /**
26✔
1317
     * Clears all the data from the given table (truncates/drops it).
26✔
1318
     *
26✔
1319
     * Note: this method uses TRUNCATE and may not work as you expect in transactions on some platforms.
26✔
1320
     * @see https://stackoverflow.com/a/5972738/925151
26✔
1321
     */
26✔
1322
    async clear<Entity>(entityClass: EntityTarget<Entity>): Promise<void> {
26✔
1323
        const metadata = this.connection.getMetadata(entityClass)
76✔
1324
        const queryRunner =
76✔
1325
            this.queryRunner || this.connection.createQueryRunner()
76✔
1326
        try {
76✔
1327
            return await queryRunner.clearTable(metadata.tablePath) // await is needed here because we are using finally
76✔
1328
        } finally {
76✔
1329
            if (!this.queryRunner) await queryRunner.release()
76✔
1330
        }
76✔
1331
    }
76✔
1332

26✔
1333
    /**
26✔
1334
     * Increments some column by provided value of the entities matched given conditions.
26✔
1335
     */
26✔
1336
    async increment<Entity extends ObjectLiteral>(
26✔
1337
        entityClass: EntityTarget<Entity>,
252✔
1338
        conditions: any,
252✔
1339
        propertyPath: string,
252✔
1340
        value: number | string,
252✔
1341
    ): Promise<UpdateResult> {
252✔
1342
        const metadata = this.connection.getMetadata(entityClass)
252✔
1343
        const column = metadata.findColumnWithPropertyPath(propertyPath)
252✔
1344
        if (!column)
252✔
1345
            throw new TypeORMError(
252✔
1346
                `Column ${propertyPath} was not found in ${metadata.targetName} entity.`,
28✔
1347
            )
28✔
1348

224✔
1349
        if (isNaN(Number(value)))
224✔
1350
            throw new TypeORMError(`Value "${value}" is not a number.`)
252✔
1351

196✔
1352
        // convert possible embedded path "social.likes" into object { social: { like: () => value } }
196✔
1353
        const values: QueryDeepPartialEntity<Entity> = propertyPath
196✔
1354
            .split(".")
196✔
1355
            .reduceRight(
196✔
1356
                (value, key) => ({ [key]: value } as any),
196✔
1357
                () =>
196✔
1358
                    this.connection.driver.escape(column.databaseName) +
196✔
1359
                    " + " +
196✔
1360
                    value,
196✔
1361
            )
196✔
1362

196✔
1363
        return this.createQueryBuilder<Entity>(entityClass as any, "entity")
196✔
1364
            .update(entityClass)
196✔
1365
            .set(values)
196✔
1366
            .where(conditions)
196✔
1367
            .execute()
196✔
1368
    }
196✔
1369

26✔
1370
    /**
26✔
1371
     * Decrements some column by provided value of the entities matched given conditions.
26✔
1372
     */
26✔
1373
    async decrement<Entity extends ObjectLiteral>(
26✔
1374
        entityClass: EntityTarget<Entity>,
248✔
1375
        conditions: any,
248✔
1376
        propertyPath: string,
248✔
1377
        value: number | string,
248✔
1378
    ): Promise<UpdateResult> {
248✔
1379
        const metadata = this.connection.getMetadata(entityClass)
248✔
1380
        const column = metadata.findColumnWithPropertyPath(propertyPath)
248✔
1381
        if (!column)
248✔
1382
            throw new TypeORMError(
248✔
1383
                `Column ${propertyPath} was not found in ${metadata.targetName} entity.`,
28✔
1384
            )
28✔
1385

220✔
1386
        if (isNaN(Number(value)))
220✔
1387
            throw new TypeORMError(`Value "${value}" is not a number.`)
248✔
1388

192✔
1389
        // convert possible embedded path "social.likes" into object { social: { like: () => value } }
192✔
1390
        const values: QueryDeepPartialEntity<Entity> = propertyPath
192✔
1391
            .split(".")
192✔
1392
            .reduceRight(
192✔
1393
                (value, key) => ({ [key]: value } as any),
192✔
1394
                () =>
192✔
1395
                    this.connection.driver.escape(column.databaseName) +
192✔
1396
                    " - " +
192✔
1397
                    value,
192✔
1398
            )
192✔
1399

192✔
1400
        return this.createQueryBuilder<Entity>(entityClass as any, "entity")
192✔
1401
            .update(entityClass)
192✔
1402
            .set(values)
192✔
1403
            .where(conditions)
192✔
1404
            .execute()
192✔
1405
    }
192✔
1406

26✔
1407
    /**
26✔
1408
     * Gets repository for the given entity class or name.
26✔
1409
     * If single database connection mode is used, then repository is obtained from the
26✔
1410
     * repository aggregator, where each repository is individually created for this entity manager.
26✔
1411
     * When single database connection is not used, repository is being obtained from the connection.
26✔
1412
     */
26✔
1413
    getRepository<Entity extends ObjectLiteral>(
26✔
1414
        target: EntityTarget<Entity>,
425,694✔
1415
    ): Repository<Entity> {
425,694✔
1416
        // find already created repository instance and return it if found
425,694✔
1417
        const repoFromMap = this.repositories.get(target)
425,694✔
1418
        if (repoFromMap) return repoFromMap
425,694✔
1419

126,710✔
1420
        // if repository was not found then create it, store its instance and return it
126,710✔
1421
        if (this.connection.driver.options.type === "mongodb") {
425,612!
1422
            const newRepository = new MongoRepository(
94✔
1423
                target,
94✔
1424
                this,
94✔
1425
                this.queryRunner,
94✔
1426
            )
94✔
1427
            this.repositories.set(target, newRepository)
94✔
1428
            return newRepository
94✔
1429
        } else {
425,694!
1430
            const newRepository = new Repository<any>(
126,616✔
1431
                target,
126,616✔
1432
                this,
126,616✔
1433
                this.queryRunner,
126,616✔
1434
            )
126,616✔
1435
            this.repositories.set(target, newRepository)
126,616✔
1436
            return newRepository
126,616✔
1437
        }
126,616✔
1438
    }
425,694✔
1439

26✔
1440
    /**
26✔
1441
     * Gets tree repository for the given entity class or name.
26✔
1442
     * If single database connection mode is used, then repository is obtained from the
26✔
1443
     * repository aggregator, where each repository is individually created for this entity manager.
26✔
1444
     * When single database connection is not used, repository is being obtained from the connection.
26✔
1445
     */
26✔
1446
    getTreeRepository<Entity extends ObjectLiteral>(
26✔
1447
        target: EntityTarget<Entity>,
2,927✔
1448
    ): TreeRepository<Entity> {
2,927✔
1449
        // tree tables aren't supported by some drivers (mongodb)
2,927✔
1450
        if (this.connection.driver.treeSupport === false)
2,927✔
1451
            throw new TreeRepositoryNotSupportedError(this.connection.driver)
2,927!
1452

2,927✔
1453
        // find already created repository instance and return it if found
2,927✔
1454
        const repository = this.treeRepositories.find(
2,927✔
1455
            (repository) => repository.target === target,
2,927✔
1456
        )
2,927✔
1457
        if (repository) return repository
2,927✔
1458

671✔
1459
        // check if repository is real tree repository
671✔
1460
        const newRepository = new TreeRepository(target, this, this.queryRunner)
671✔
1461
        this.treeRepositories.push(newRepository)
671✔
1462
        return newRepository
671✔
1463
    }
671✔
1464

26✔
1465
    /**
26✔
1466
     * Gets mongodb repository for the given entity class.
26✔
1467
     */
26✔
1468
    getMongoRepository<Entity extends ObjectLiteral>(
26✔
1469
        target: EntityTarget<Entity>,
6✔
1470
    ): MongoRepository<Entity> {
6✔
1471
        return this.connection.getMongoRepository<Entity>(target)
6✔
1472
    }
6✔
1473

26✔
1474
    /**
26✔
1475
     * Creates a new repository instance out of a given Repository and
26✔
1476
     * sets current EntityManager instance to it. Used to work with custom repositories
26✔
1477
     * in transactions.
26✔
1478
     */
26✔
1479
    withRepository<Entity extends ObjectLiteral, R extends Repository<any>>(
26✔
1480
        repository: R & Repository<Entity>,
36✔
1481
    ): R {
36✔
1482
        const repositoryConstructor =
36✔
1483
            repository.constructor as typeof Repository
36✔
1484
        const { target, manager, queryRunner, ...otherRepositoryProperties } =
36✔
1485
            repository
36✔
1486
        return Object.assign(
36✔
1487
            new repositoryConstructor(repository.target, this) as R,
36✔
1488
            {
36✔
1489
                ...otherRepositoryProperties,
36✔
1490
            },
36✔
1491
        )
36✔
1492
    }
36✔
1493

26✔
1494
    /**
26✔
1495
     * Gets custom entity repository marked with @EntityRepository decorator.
26✔
1496
     *
26✔
1497
     * @deprecated use Repository.extend to create custom repositories
26✔
1498
     */
26✔
1499
    getCustomRepository<T>(customRepository: ObjectType<T>): T {
26✔
1500
        const entityRepositoryMetadataArgs =
36✔
1501
            getMetadataArgsStorage().entityRepositories.find((repository) => {
36✔
1502
                return (
48✔
1503
                    repository.target ===
48✔
1504
                    (typeof customRepository === "function"
48✔
1505
                        ? customRepository
48✔
1506
                        : (customRepository as any).constructor)
48!
1507
                )
48✔
1508
            })
36✔
1509
        if (!entityRepositoryMetadataArgs)
36✔
1510
            throw new CustomRepositoryNotFoundError(customRepository)
36!
1511

36✔
1512
        const entityMetadata = entityRepositoryMetadataArgs.entity
36✔
1513
            ? this.connection.getMetadata(entityRepositoryMetadataArgs.entity)
36!
1514
            : undefined
36✔
1515
        const entityRepositoryInstance =
36✔
1516
            new (entityRepositoryMetadataArgs.target as any)(
36✔
1517
                this,
36✔
1518
                entityMetadata,
36✔
1519
            )
36✔
1520

36✔
1521
        // NOTE: dynamic access to protected properties. We need this to prevent unwanted properties in those classes to be exposed,
36✔
1522
        // however we need these properties for internal work of the class
36✔
1523
        if (entityRepositoryInstance instanceof AbstractRepository) {
36✔
1524
            if (!(entityRepositoryInstance as any)["manager"])
36✔
1525
                (entityRepositoryInstance as any)["manager"] = this
36✔
1526
        } else {
36!
1527
            if (!entityMetadata)
×
1528
                throw new CustomRepositoryCannotInheritRepositoryError(
×
1529
                    customRepository,
×
1530
                )
×
1531
            ;(entityRepositoryInstance as any)["manager"] = this
×
1532
            ;(entityRepositoryInstance as any)["metadata"] = entityMetadata
×
1533
        }
×
1534

36✔
1535
        return entityRepositoryInstance
36✔
1536
    }
36✔
1537

26✔
1538
    /**
26✔
1539
     * Releases all resources used by entity manager.
26✔
1540
     * This is used when entity manager is created with a single query runner,
26✔
1541
     * and this single query runner needs to be released after job with entity manager is done.
26✔
1542
     */
26✔
1543
    async release(): Promise<void> {
26✔
1544
        if (!this.queryRunner) throw new NoNeedToReleaseEntityManagerError()
×
1545

×
1546
        return this.queryRunner.release()
×
1547
    }
×
1548
}
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