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

typeorm / typeorm / 14796576772

02 May 2025 01:52PM UTC coverage: 45.367% (-30.9%) from 76.309%
14796576772

Pull #11434

github

web-flow
Merge ec4ce2d00 into fadad1a74
Pull Request #11434: feat: release PR releases using pkg.pr.new

5216 of 12761 branches covered (40.87%)

Branch coverage included in aggregate %.

11439 of 23951 relevant lines covered (47.76%)

15712.55 hits per line

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

33.33
/src/repository/BaseEntity.ts
1
import { Repository } from "./Repository"
2
import { FindOptionsWhere } from "../find-options/FindOptionsWhere"
3
import { DeepPartial } from "../common/DeepPartial"
4
import { SaveOptions } from "./SaveOptions"
5
import { FindOneOptions } from "../find-options/FindOneOptions"
6
import { RemoveOptions } from "./RemoveOptions"
7
import { FindManyOptions } from "../find-options/FindManyOptions"
8
import { DataSource } from "../data-source"
9
import { SelectQueryBuilder } from "../query-builder/SelectQueryBuilder"
10
import { InsertResult } from "../query-builder/result/InsertResult"
11
import { UpdateResult } from "../query-builder/result/UpdateResult"
12
import { DeleteResult } from "../query-builder/result/DeleteResult"
13
import { ObjectId } from "../driver/mongodb/typings"
14
import { ObjectUtils } from "../util/ObjectUtils"
4✔
15
import { QueryDeepPartialEntity } from "../query-builder/QueryPartialEntity"
16
import { UpsertOptions } from "./UpsertOptions"
17
import { EntityTarget } from "../common/EntityTarget"
18
import { PickKeysByType } from "../common/PickKeysByType"
19

20
/**
21
 * Base abstract entity for all entities, used in ActiveRecord patterns.
22
 */
23
export class BaseEntity {
4✔
24
    // -------------------------------------------------------------------------
25
    // Private Static Properties
26
    // -------------------------------------------------------------------------
27

28
    /**
29
     * DataSource used in all static methods of the BaseEntity.
30
     */
31
    private static dataSource: DataSource | null
32

33
    // -------------------------------------------------------------------------
34
    // Public Methods
35
    // -------------------------------------------------------------------------
36

37
    /**
38
     * Checks if entity has an id.
39
     * If entity composite compose ids, it will check them all.
40
     */
41
    hasId(): boolean {
42
        const baseEntity = this.constructor as typeof BaseEntity
×
43
        return baseEntity.getRepository().hasId(this)
×
44
    }
45

46
    /**
47
     * Saves current entity in the database.
48
     * If entity does not exist in the database then inserts, otherwise updates.
49
     */
50
    save(options?: SaveOptions): Promise<this> {
51
        const baseEntity = this.constructor as typeof BaseEntity
32✔
52
        return baseEntity.getRepository().save(this, options)
32✔
53
    }
54

55
    /**
56
     * Removes current entity from the database.
57
     */
58
    remove(options?: RemoveOptions): Promise<this> {
59
        const baseEntity = this.constructor as typeof BaseEntity
×
60
        return baseEntity.getRepository().remove(this, options) as Promise<this>
×
61
    }
62

63
    /**
64
     * Records the delete date of current entity.
65
     */
66
    softRemove(options?: SaveOptions): Promise<this> {
67
        const baseEntity = this.constructor as typeof BaseEntity
×
68
        return baseEntity.getRepository().softRemove(this, options)
×
69
    }
70

71
    /**
72
     * Recovers a given entity in the database.
73
     */
74
    recover(options?: SaveOptions): Promise<this> {
75
        const baseEntity = this.constructor as typeof BaseEntity
×
76
        return baseEntity.getRepository().recover(this, options)
×
77
    }
78

79
    /**
80
     * Reloads entity data from the database.
81
     */
82
    async reload(): Promise<void> {
83
        const baseEntity = this.constructor as typeof BaseEntity
16✔
84
        const id = baseEntity.getRepository().metadata.getEntityIdMap(this)
16✔
85
        if (!id) {
16!
86
            throw new Error(
×
87
                `Entity doesn't have id-s set, cannot reload entity`,
88
            )
89
        }
90
        const reloadedEntity: BaseEntity = await baseEntity
16✔
91
            .getRepository()
92
            .findOneByOrFail(id)
93

94
        ObjectUtils.assign(this, reloadedEntity)
16✔
95
    }
96

97
    // -------------------------------------------------------------------------
98
    // Public Static Methods
99
    // -------------------------------------------------------------------------
100

101
    /**
102
     * Sets DataSource to be used by entity.
103
     */
104
    static useDataSource(dataSource: DataSource | null) {
105
        this.dataSource = dataSource
193✔
106
    }
107

108
    /**
109
     * Gets current entity's Repository.
110
     */
111
    static getRepository<T extends BaseEntity>(
112
        this: { new (): T } & typeof BaseEntity,
113
    ): Repository<T> {
114
        const dataSource = (this as typeof BaseEntity).dataSource
120✔
115
        if (!dataSource)
120!
116
            throw new Error(`DataSource is not set for this entity.`)
×
117
        return dataSource.getRepository<T>(this)
120✔
118
    }
119

120
    /**
121
     * Returns object that is managed by this repository.
122
     * If this repository manages entity from schema,
123
     * then it returns a name of that schema instead.
124
     */
125
    static get target(): EntityTarget<any> {
126
        return this.getRepository().target
×
127
    }
128

129
    /**
130
     * Checks entity has an id.
131
     * If entity composite compose ids, it will check them all.
132
     */
133
    static hasId(entity: BaseEntity): boolean {
134
        return this.getRepository().hasId(entity)
×
135
    }
136

137
    /**
138
     * Gets entity mixed id.
139
     */
140
    static getId<T extends BaseEntity>(
141
        this: { new (): T } & typeof BaseEntity,
142
        entity: T,
143
    ): any {
144
        return this.getRepository<T>().getId(entity)
×
145
    }
146

147
    /**
148
     * Creates a new query builder that can be used to build a SQL query.
149
     */
150
    static createQueryBuilder<T extends BaseEntity>(
151
        this: { new (): T } & typeof BaseEntity,
152
        alias?: string,
153
    ): SelectQueryBuilder<T> {
154
        return this.getRepository<T>().createQueryBuilder(alias)
×
155
    }
156

157
    /**
158
     * Creates a new entity instance.
159
     */
160
    static create<T extends BaseEntity>(
161
        this: { new (): T } & typeof BaseEntity,
162
    ): T
163

164
    /**
165
     * Creates a new entities and copies all entity properties from given objects into their new entities.
166
     * Note that it copies only properties that present in entity schema.
167
     */
168
    static create<T extends BaseEntity>(
169
        this: { new (): T } & typeof BaseEntity,
170
        entityLikeArray: DeepPartial<T>[],
171
    ): T[]
172

173
    /**
174
     * Creates a new entity instance and copies all entity properties from this object into a new entity.
175
     * Note that it copies only properties that present in entity schema.
176
     */
177
    static create<T extends BaseEntity>(
178
        this: { new (): T } & typeof BaseEntity,
179
        entityLike: DeepPartial<T>,
180
    ): T
181

182
    /**
183
     * Creates a new entity instance and copies all entity properties from this object into a new entity.
184
     * Note that it copies only properties that present in entity schema.
185
     */
186
    static create<T extends BaseEntity>(
187
        this: { new (): T } & typeof BaseEntity,
188
        entityOrEntities?: any,
189
    ) {
190
        return this.getRepository<T>().create(entityOrEntities)
20✔
191
    }
192

193
    /**
194
     * Merges multiple entities (or entity-like objects) into a given entity.
195
     */
196
    static merge<T extends BaseEntity>(
197
        this: { new (): T } & typeof BaseEntity,
198
        mergeIntoEntity: T,
199
        ...entityLikes: DeepPartial<T>[]
200
    ): T {
201
        return this.getRepository<T>().merge(
×
202
            mergeIntoEntity,
203
            ...entityLikes,
204
        ) as T
205
    }
206

207
    /**
208
     * Creates a new entity from the given plain javascript object. If entity already exist in the database, then
209
     * it loads it (and everything related to it), replaces all values with the new ones from the given object
210
     * and returns this new entity. This new entity is actually a loaded from the db entity with all properties
211
     * replaced from the new object.
212
     *
213
     * Note that given entity-like object must have an entity id / primary key to find entity by.
214
     * Returns undefined if entity with given id was not found.
215
     */
216
    static preload<T extends BaseEntity>(
217
        this: { new (): T } & typeof BaseEntity,
218
        entityLike: DeepPartial<T>,
219
    ): Promise<T | undefined> {
220
        const thisRepository = this.getRepository<T>()
×
221
        return thisRepository.preload(entityLike)
×
222
    }
223

224
    /**
225
     * Saves all given entities in the database.
226
     * If entities do not exist in the database then inserts, otherwise updates.
227
     */
228
    static save<T extends BaseEntity>(
229
        this: { new (): T } & typeof BaseEntity,
230
        entities: DeepPartial<T>[],
231
        options?: SaveOptions,
232
    ): Promise<T[]>
233

234
    /**
235
     * Saves a given entity in the database.
236
     * If entity does not exist in the database then inserts, otherwise updates.
237
     */
238
    static save<T extends BaseEntity>(
239
        this: { new (): T } & typeof BaseEntity,
240
        entity: DeepPartial<T>,
241
        options?: SaveOptions,
242
    ): Promise<T>
243

244
    /**
245
     * Saves one or many given entities.
246
     */
247
    static save<T extends BaseEntity>(
248
        this: { new (): T } & typeof BaseEntity,
249
        entityOrEntities: DeepPartial<T> | DeepPartial<T>[],
250
        options?: SaveOptions,
251
    ) {
252
        return this.getRepository<T>().save(entityOrEntities as any, options)
2✔
253
    }
254

255
    /**
256
     * Removes a given entities from the database.
257
     */
258
    static remove<T extends BaseEntity>(
259
        this: { new (): T } & typeof BaseEntity,
260
        entities: T[],
261
        options?: RemoveOptions,
262
    ): Promise<T[]>
263

264
    /**
265
     * Removes a given entity from the database.
266
     */
267
    static remove<T extends BaseEntity>(
268
        this: { new (): T } & typeof BaseEntity,
269
        entity: T,
270
        options?: RemoveOptions,
271
    ): Promise<T>
272

273
    /**
274
     * Removes one or many given entities.
275
     */
276
    static remove<T extends BaseEntity>(
277
        this: { new (): T } & typeof BaseEntity,
278
        entityOrEntities: T | T[],
279
        options?: RemoveOptions,
280
    ) {
281
        return this.getRepository<T>().remove(entityOrEntities as any, options)
×
282
    }
283

284
    /**
285
     * Records the delete date of all given entities.
286
     */
287
    static softRemove<T extends BaseEntity>(
288
        this: { new (): T } & typeof BaseEntity,
289
        entities: T[],
290
        options?: SaveOptions,
291
    ): Promise<T[]>
292

293
    /**
294
     * Records the delete date of a given entity.
295
     */
296
    static softRemove<T extends BaseEntity>(
297
        this: { new (): T } & typeof BaseEntity,
298
        entity: T,
299
        options?: SaveOptions,
300
    ): Promise<T>
301

302
    /**
303
     * Records the delete date of one or many given entities.
304
     */
305
    static softRemove<T extends BaseEntity>(
306
        this: { new (): T } & typeof BaseEntity,
307
        entityOrEntities: T | T[],
308
        options?: SaveOptions,
309
    ) {
310
        return this.getRepository<T>().softRemove(
×
311
            entityOrEntities as any,
312
            options,
313
        )
314
    }
315

316
    /**
317
     * Inserts a given entity into the database.
318
     * Unlike save method executes a primitive operation without cascades, relations and other operations included.
319
     * Executes fast and efficient INSERT query.
320
     * Does not check if entity exist in the database, so query will fail if duplicate entity is being inserted.
321
     */
322
    static insert<T extends BaseEntity>(
323
        this: { new (): T } & typeof BaseEntity,
324
        entity: QueryDeepPartialEntity<T> | QueryDeepPartialEntity<T>[],
325
    ): Promise<InsertResult> {
326
        return this.getRepository<T>().insert(entity)
×
327
    }
328

329
    /**
330
     * Updates entity partially. Entity can be found by a given conditions.
331
     * Unlike save method executes a primitive operation without cascades, relations and other operations included.
332
     * Executes fast and efficient UPDATE query.
333
     * Does not check if entity exist in the database.
334
     */
335
    static update<T extends BaseEntity>(
336
        this: { new (): T } & typeof BaseEntity,
337
        criteria:
338
            | string
339
            | string[]
340
            | number
341
            | number[]
342
            | Date
343
            | Date[]
344
            | ObjectId
345
            | ObjectId[]
346
            | FindOptionsWhere<T>,
347
        partialEntity: QueryDeepPartialEntity<T>,
348
    ): Promise<UpdateResult> {
349
        return this.getRepository<T>().update(criteria, partialEntity)
×
350
    }
351

352
    /**
353
     * Inserts a given entity into the database, unless a unique constraint conflicts then updates the entity
354
     * Unlike save method executes a primitive operation without cascades, relations and other operations included.
355
     * Executes fast and efficient INSERT ... ON CONFLICT DO UPDATE/ON DUPLICATE KEY UPDATE query.
356
     */
357
    static upsert<T extends BaseEntity>(
358
        this: { new (): T } & typeof BaseEntity,
359
        entityOrEntities:
360
            | QueryDeepPartialEntity<T>
361
            | QueryDeepPartialEntity<T>[],
362
        conflictPathsOrOptions: string[] | UpsertOptions<T>,
363
    ): Promise<InsertResult> {
364
        return this.getRepository<T>().upsert(
6✔
365
            entityOrEntities,
366
            conflictPathsOrOptions,
367
        )
368
    }
369

370
    /**
371
     * Deletes entities by a given criteria.
372
     * Unlike remove method executes a primitive operation without cascades, relations and other operations included.
373
     * Executes fast and efficient DELETE query.
374
     * Does not check if entity exist in the database.
375
     */
376
    static delete<T extends BaseEntity>(
377
        this: { new (): T } & typeof BaseEntity,
378
        criteria:
379
            | string
380
            | string[]
381
            | number
382
            | number[]
383
            | Date
384
            | Date[]
385
            | ObjectId
386
            | ObjectId[]
387
            | FindOptionsWhere<T>,
388
    ): Promise<DeleteResult> {
389
        return this.getRepository<T>().delete(criteria)
×
390
    }
391

392
    /**
393
     * Checks whether any entity exists that matches the given options.
394
     */
395
    static exists<T extends BaseEntity>(
396
        this: { new (): T } & typeof BaseEntity,
397
        options?: FindManyOptions<T>,
398
    ): Promise<boolean> {
399
        return this.getRepository<T>().exists(options)
×
400
    }
401

402
    /**
403
     * Checks whether any entity exists that matches the given conditions.
404
     */
405
    static existsBy<T extends BaseEntity>(
406
        this: { new (): T } & typeof BaseEntity,
407
        where: FindOptionsWhere<T>,
408
    ): Promise<boolean> {
409
        return this.getRepository<T>().existsBy(where)
×
410
    }
411

412
    /**
413
     * Counts entities that match given options.
414
     */
415
    static count<T extends BaseEntity>(
416
        this: { new (): T } & typeof BaseEntity,
417
        options?: FindManyOptions<T>,
418
    ): Promise<number> {
419
        return this.getRepository<T>().count(options)
×
420
    }
421

422
    /**
423
     * Counts entities that match given WHERE conditions.
424
     */
425
    static countBy<T extends BaseEntity>(
426
        this: { new (): T } & typeof BaseEntity,
427
        where: FindOptionsWhere<T>,
428
    ): Promise<number> {
429
        return this.getRepository<T>().countBy(where)
×
430
    }
431

432
    /**
433
     * Return the SUM of a column
434
     */
435
    static sum<T extends BaseEntity>(
436
        this: { new (): T } & typeof BaseEntity,
437
        columnName: PickKeysByType<T, number>,
438
        where: FindOptionsWhere<T>,
439
    ): Promise<number | null> {
440
        return this.getRepository<T>().sum(columnName, where)
×
441
    }
442

443
    /**
444
     * Return the AVG of a column
445
     */
446
    static average<T extends BaseEntity>(
447
        this: { new (): T } & typeof BaseEntity,
448
        columnName: PickKeysByType<T, number>,
449
        where: FindOptionsWhere<T>,
450
    ): Promise<number | null> {
451
        return this.getRepository<T>().average(columnName, where)
×
452
    }
453

454
    /**
455
     * Return the MIN of a column
456
     */
457
    static minimum<T extends BaseEntity>(
458
        this: { new (): T } & typeof BaseEntity,
459
        columnName: PickKeysByType<T, number>,
460
        where: FindOptionsWhere<T>,
461
    ): Promise<number | null> {
462
        return this.getRepository<T>().minimum(columnName, where)
×
463
    }
464

465
    /**
466
     * Return the MAX of a column
467
     */
468
    static maximum<T extends BaseEntity>(
469
        this: { new (): T } & typeof BaseEntity,
470
        columnName: PickKeysByType<T, number>,
471
        where: FindOptionsWhere<T>,
472
    ): Promise<number | null> {
473
        return this.getRepository<T>().maximum(columnName, where)
×
474
    }
475

476
    /**
477
     * Finds entities that match given options.
478
     */
479
    static find<T extends BaseEntity>(
480
        this: { new (): T } & typeof BaseEntity,
481
        options?: FindManyOptions<T>,
482
    ): Promise<T[]> {
483
        return this.getRepository<T>().find(options)
×
484
    }
485

486
    /**
487
     * Finds entities that match given WHERE conditions.
488
     */
489
    static findBy<T extends BaseEntity>(
490
        this: { new (): T } & typeof BaseEntity,
491
        where: FindOptionsWhere<T>,
492
    ): Promise<T[]> {
493
        return this.getRepository<T>().findBy(where)
4✔
494
    }
495

496
    /**
497
     * Finds entities that match given find options.
498
     * Also counts all entities that match given conditions,
499
     * but ignores pagination settings (from and take options).
500
     */
501
    static findAndCount<T extends BaseEntity>(
502
        this: { new (): T } & typeof BaseEntity,
503
        options?: FindManyOptions<T>,
504
    ): Promise<[T[], number]> {
505
        return this.getRepository<T>().findAndCount(options)
×
506
    }
507

508
    /**
509
     * Finds entities that match given WHERE conditions.
510
     * Also counts all entities that match given conditions,
511
     * but ignores pagination settings (from and take options).
512
     */
513
    static findAndCountBy<T extends BaseEntity>(
514
        this: { new (): T } & typeof BaseEntity,
515
        where: FindOptionsWhere<T>,
516
    ): Promise<[T[], number]> {
517
        return this.getRepository<T>().findAndCountBy(where)
×
518
    }
519

520
    /**
521
     * Finds entities by ids.
522
     * Optionally find options can be applied.
523
     *
524
     * @deprecated use `findBy` method instead in conjunction with `In` operator, for example:
525
     *
526
     * .findBy({
527
     *     id: In([1, 2, 3])
528
     * })
529
     */
530
    static findByIds<T extends BaseEntity>(
531
        this: { new (): T } & typeof BaseEntity,
532
        ids: any[],
533
    ): Promise<T[]> {
534
        return this.getRepository<T>().findByIds(ids)
×
535
    }
536

537
    /**
538
     * Finds first entity that matches given conditions.
539
     */
540
    static findOne<T extends BaseEntity>(
541
        this: { new (): T } & typeof BaseEntity,
542
        options: FindOneOptions<T>,
543
    ): Promise<T | null> {
544
        return this.getRepository<T>().findOne(options)
4✔
545
    }
546

547
    /**
548
     * Finds first entity that matches given conditions.
549
     */
550
    static findOneBy<T extends BaseEntity>(
551
        this: { new (): T } & typeof BaseEntity,
552
        where: FindOptionsWhere<T>,
553
    ): Promise<T | null> {
554
        return this.getRepository<T>().findOneBy(where)
×
555
    }
556

557
    /**
558
     * Finds first entity that matches given options.
559
     *
560
     * @deprecated use `findOneBy` method instead in conjunction with `In` operator, for example:
561
     *
562
     * .findOneBy({
563
     *     id: 1 // where "id" is your primary column name
564
     * })
565
     */
566
    static findOneById<T extends BaseEntity>(
567
        this: { new (): T } & typeof BaseEntity,
568
        id: string | number | Date | ObjectId,
569
    ): Promise<T | null> {
570
        return this.getRepository<T>().findOneById(id)
×
571
    }
572

573
    /**
574
     * Finds first entity that matches given conditions.
575
     */
576
    static findOneOrFail<T extends BaseEntity>(
577
        this: { new (): T } & typeof BaseEntity,
578
        options: FindOneOptions<T>,
579
    ): Promise<T> {
580
        return this.getRepository<T>().findOneOrFail(options)
8✔
581
    }
582

583
    /**
584
     * Finds first entity that matches given conditions.
585
     */
586
    static findOneByOrFail<T extends BaseEntity>(
587
        this: { new (): T } & typeof BaseEntity,
588
        where: FindOptionsWhere<T>,
589
    ): Promise<T> {
590
        return this.getRepository<T>().findOneByOrFail(where)
12✔
591
    }
592

593
    /**
594
     * Executes a raw SQL query and returns a raw database results.
595
     * Raw query execution is supported only by relational databases (MongoDB is not supported).
596
     */
597
    static query<T extends BaseEntity>(
598
        this: { new (): T } & typeof BaseEntity,
599
        query: string,
600
        parameters?: any[],
601
    ): Promise<any> {
602
        return this.getRepository<T>().query(query, parameters)
×
603
    }
604

605
    /**
606
     * Clears all the data from the given table/collection (truncates/drops it).
607
     */
608
    static clear<T extends BaseEntity>(
609
        this: { new (): T } & typeof BaseEntity,
610
    ): Promise<void> {
611
        return this.getRepository<T>().clear()
×
612
    }
613
}
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

© 2025 Coveralls, Inc