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

typeorm / typeorm / 14093537090

26 Mar 2025 09:10PM UTC coverage: 72.108% (-0.3%) from 72.384%
14093537090

push

github

web-flow
build: improve test workflow (#11361)

8649 of 12641 branches covered (68.42%)

Branch coverage included in aggregate %.

5 of 5 new or added lines in 1 file covered. (100.0%)

19 existing lines in 12 files now uncovered.

17602 of 23764 relevant lines covered (74.07%)

161388.77 hits per line

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

82.82
/src/data-source/DataSource.ts
1
import { Driver } from "../driver/Driver"
2
import { registerQueryBuilders } from "../query-builder"
35✔
3
import { Repository } from "../repository/Repository"
4
import { EntitySubscriberInterface } from "../subscriber/EntitySubscriberInterface"
5
import { EntityTarget } from "../common/EntityTarget"
6
import { ObjectType } from "../common/ObjectType"
7
import { EntityManager } from "../entity-manager/EntityManager"
8
import { DefaultNamingStrategy } from "../naming-strategy/DefaultNamingStrategy"
35✔
9
import {
35✔
10
    CannotConnectAlreadyConnectedError,
11
    CannotExecuteNotConnectedError,
12
    EntityMetadataNotFoundError,
13
    QueryRunnerProviderAlreadyReleasedError,
14
    TypeORMError,
15
} from "../error"
16
import { TreeRepository } from "../repository/TreeRepository"
17
import { NamingStrategyInterface } from "../naming-strategy/NamingStrategyInterface"
18
import { EntityMetadata } from "../metadata/EntityMetadata"
19
import { Logger } from "../logger/Logger"
20
import { MigrationInterface } from "../migration/MigrationInterface"
21
import { MigrationExecutor } from "../migration/MigrationExecutor"
35✔
22
import { Migration } from "../migration/Migration"
23
import { MongoRepository } from "../repository/MongoRepository"
24
import { MongoEntityManager } from "../entity-manager/MongoEntityManager"
25
import { EntityMetadataValidator } from "../metadata-builder/EntityMetadataValidator"
35✔
26
import { DataSourceOptions } from "./DataSourceOptions"
27
import { EntityManagerFactory } from "../entity-manager/EntityManagerFactory"
35✔
28
import { DriverFactory } from "../driver/DriverFactory"
35✔
29
import { ConnectionMetadataBuilder } from "../connection/ConnectionMetadataBuilder"
35✔
30
import { QueryRunner } from "../query-runner/QueryRunner"
31
import { SelectQueryBuilder } from "../query-builder/SelectQueryBuilder"
35✔
32
import { LoggerFactory } from "../logger/LoggerFactory"
35✔
33
import { QueryResultCacheFactory } from "../cache/QueryResultCacheFactory"
35✔
34
import { QueryResultCache } from "../cache/QueryResultCache"
35
import { SqljsEntityManager } from "../entity-manager/SqljsEntityManager"
36
import { RelationLoader } from "../query-builder/RelationLoader"
35✔
37
import { ObjectUtils } from "../util/ObjectUtils"
35✔
38
import { IsolationLevel } from "../driver/types/IsolationLevel"
39
import { ReplicationMode } from "../driver/types/ReplicationMode"
40
import { RelationIdLoader } from "../query-builder/RelationIdLoader"
35✔
41
import { DriverUtils } from "../driver/DriverUtils"
35✔
42
import { InstanceChecker } from "../util/InstanceChecker"
35✔
43
import { ObjectLiteral } from "../common/ObjectLiteral"
44

45
registerQueryBuilders()
35✔
46

47
/**
48
 * DataSource is a pre-defined connection configuration to a specific database.
49
 * You can have multiple data sources connected (with multiple connections in it),
50
 * connected to multiple databases in your application.
51
 *
52
 * Before, it was called `Connection`, but now `Connection` is deprecated
53
 * because `Connection` isn't the best name for what it's actually is.
54
 */
55
export class DataSource {
35✔
56
    readonly "@instanceof" = Symbol.for("DataSource")
17,412✔
57

58
    // -------------------------------------------------------------------------
59
    // Public Readonly Properties
60
    // -------------------------------------------------------------------------
61

62
    /**
63
     * Connection name.
64
     *
65
     * @deprecated we don't need names anymore since we are going to drop all related methods relying on this property.
66
     */
67
    readonly name: string
68

69
    /**
70
     * Connection options.
71
     */
72
    readonly options: DataSourceOptions
73

74
    /**
75
     * Indicates if DataSource is initialized or not.
76
     */
77
    readonly isInitialized: boolean
78

79
    /**
80
     * Database driver used by this connection.
81
     */
82
    driver: Driver
83

84
    /**
85
     * EntityManager of this connection.
86
     */
87
    readonly manager: EntityManager
88

89
    /**
90
     * Naming strategy used in the connection.
91
     */
92
    namingStrategy: NamingStrategyInterface
93

94
    /**
95
     * Name for the metadata table
96
     */
97
    readonly metadataTableName: string
98

99
    /**
100
     * Logger used to log orm events.
101
     */
102
    logger: Logger
103

104
    /**
105
     * Migration instances that are registered for this connection.
106
     */
107
    readonly migrations: MigrationInterface[] = []
17,412✔
108

109
    /**
110
     * Entity subscriber instances that are registered for this connection.
111
     */
112
    readonly subscribers: EntitySubscriberInterface<any>[] = []
17,412✔
113

114
    /**
115
     * All entity metadatas that are registered for this connection.
116
     */
117
    readonly entityMetadatas: EntityMetadata[] = []
17,412✔
118

119
    /**
120
     * All entity metadatas that are registered for this connection.
121
     * This is a copy of #.entityMetadatas property -> used for more performant searches.
122
     */
123
    readonly entityMetadatasMap = new Map<EntityTarget<any>, EntityMetadata>()
17,412✔
124

125
    /**
126
     * Used to work with query result cache.
127
     */
128
    queryResultCache?: QueryResultCache
129

130
    /**
131
     * Used to load relations and work with lazy relations.
132
     */
133
    readonly relationLoader: RelationLoader
134

135
    readonly relationIdLoader: RelationIdLoader
136

137
    // -------------------------------------------------------------------------
138
    // Constructor
139
    // -------------------------------------------------------------------------
140

141
    constructor(options: DataSourceOptions) {
142
        registerQueryBuilders()
17,412✔
143
        this.name = options.name || "default"
17,412✔
144
        this.options = options
17,412✔
145
        this.logger = new LoggerFactory().create(
17,412✔
146
            this.options.logger,
147
            this.options.logging,
148
        )
149
        this.driver = new DriverFactory().create(this)
17,412✔
150
        this.manager = this.createEntityManager()
17,412✔
151
        this.namingStrategy =
17,412✔
152
            options.namingStrategy || new DefaultNamingStrategy()
34,717✔
153
        this.metadataTableName = options.metadataTableName || "typeorm_metadata"
17,412✔
154
        this.queryResultCache = options.cache
17,412✔
155
            ? new QueryResultCacheFactory(this).create()
156
            : undefined
157
        this.relationLoader = new RelationLoader(this)
17,412✔
158
        this.relationIdLoader = new RelationIdLoader(this)
17,412✔
159
        this.isInitialized = false
17,412✔
160
    }
161

162
    // -------------------------------------------------------------------------
163
    // Public Accessors
164
    // -------------------------------------------------------------------------
165

166
    /**
167
     Indicates if DataSource is initialized or not.
168
     *
169
     * @deprecated use .isInitialized instead
170
     */
171
    get isConnected() {
172
        return this.isInitialized
×
173
    }
174

175
    /**
176
     * Gets the mongodb entity manager that allows to perform mongodb-specific repository operations
177
     * with any entity in this connection.
178
     *
179
     * Available only in mongodb connections.
180
     */
181
    get mongoManager(): MongoEntityManager {
182
        if (!InstanceChecker.isMongoEntityManager(this.manager))
15!
183
            throw new TypeORMError(
×
184
                `MongoEntityManager is only available for MongoDB databases.`,
185
            )
186

187
        return this.manager as MongoEntityManager
15✔
188
    }
189

190
    /**
191
     * Gets a sql.js specific Entity Manager that allows to perform special load and save operations
192
     *
193
     * Available only in connection with the sqljs driver.
194
     */
195
    get sqljsManager(): SqljsEntityManager {
196
        if (!InstanceChecker.isSqljsEntityManager(this.manager))
20!
197
            throw new TypeORMError(
×
198
                `SqljsEntityManager is only available for Sqljs databases.`,
199
            )
200

201
        return this.manager
20✔
202
    }
203

204
    // -------------------------------------------------------------------------
205
    // Public Methods
206
    // -------------------------------------------------------------------------
207
    /**
208
     * Updates current connection options with provided options.
209
     */
210
    setOptions(options: Partial<DataSourceOptions>): this {
211
        Object.assign(this.options, options)
99✔
212

213
        if (options.logger || options.logging) {
99!
UNCOV
214
            this.logger = new LoggerFactory().create(
×
215
                options.logger || this.options.logger,
×
216
                options.logging || this.options.logging,
×
217
            )
218
        }
219

220
        if (options.namingStrategy) {
99!
221
            this.namingStrategy = options.namingStrategy
×
222
        }
223

224
        if (options.cache) {
99!
225
            this.queryResultCache = new QueryResultCacheFactory(this).create()
×
226
        }
227

228
        // todo: we must update the database in the driver as well, if it was set by setOptions method
229
        //  in the future we need to refactor the code and remove "database" from the driver, and instead
230
        //  use database (and options) from a single place - data source.
231
        if (options.database) {
99✔
232
            this.driver.database = DriverUtils.buildDriverOptions(
6✔
233
                this.options,
234
            ).database
235
        }
236

237
        // todo: need to take a look if we need to update schema and other "poor" properties
238

239
        return this
99✔
240
    }
241

242
    /**
243
     * Performs connection to the database.
244
     * This method should be called once on application bootstrap.
245
     * This method not necessarily creates database connection (depend on database type),
246
     * but it also can setup a connection pool with database to use.
247
     */
248
    async initialize(): Promise<this> {
249
        if (this.isInitialized)
16,983✔
250
            throw new CannotConnectAlreadyConnectedError(this.name)
35✔
251

252
        // connect to the database via its driver
253
        await this.driver.connect()
16,948✔
254

255
        // connect to the cache-specific database if cache is enabled
256
        if (this.queryResultCache) await this.queryResultCache.connect()
16,948✔
257

258
        // set connected status for the current connection
259
        ObjectUtils.assign(this, { isInitialized: true })
16,948✔
260

261
        try {
16,948✔
262
            // build all metadatas registered in the current connection
263
            await this.buildMetadatas()
16,948✔
264

265
            await this.driver.afterConnect()
16,882✔
266

267
            // if option is set - drop schema once connection is done
268
            if (this.options.dropSchema) await this.dropDatabase()
16,882✔
269

270
            // if option is set - automatically synchronize a schema
271
            if (this.options.migrationsRun)
16,882!
272
                await this.runMigrations({
×
273
                    transaction: this.options.migrationsTransactionMode,
274
                })
275

276
            // if option is set - automatically synchronize a schema
277
            if (this.options.synchronize) await this.synchronize()
16,882✔
278
        } catch (error) {
279
            // if for some reason build metadata fail (for example validation error during entity metadata check)
280
            // connection needs to be closed
281
            await this.destroy()
66✔
282
            throw error
66✔
283
        }
284

285
        return this
16,882✔
286
    }
287

288
    /**
289
     * Performs connection to the database.
290
     * This method should be called once on application bootstrap.
291
     * This method not necessarily creates database connection (depend on database type),
292
     * but it also can setup a connection pool with database to use.
293
     *
294
     * @deprecated use .initialize method instead
295
     */
296
    async connect(): Promise<this> {
297
        return this.initialize()
53✔
298
    }
299

300
    /**
301
     * Closes connection with the database.
302
     * Once connection is closed, you cannot use repositories or perform any operations except opening connection again.
303
     */
304
    async destroy(): Promise<void> {
305
        if (!this.isInitialized)
16,979✔
306
            throw new CannotExecuteNotConnectedError(this.name)
38✔
307

308
        await this.driver.disconnect()
16,941✔
309

310
        // disconnect from the cache-specific database if cache was enabled
311
        if (this.queryResultCache) await this.queryResultCache.disconnect()
16,940✔
312

313
        ObjectUtils.assign(this, { isInitialized: false })
16,940✔
314
    }
315

316
    /**
317
     * Closes connection with the database.
318
     * Once connection is closed, you cannot use repositories or perform any operations except opening connection again.
319
     *
320
     * @deprecated use .destroy method instead
321
     */
322
    async close(): Promise<void> {
323
        return this.destroy()
174✔
324
    }
325

326
    /**
327
     * Creates database schema for all entities registered in this connection.
328
     * Can be used only after connection to the database is established.
329
     *
330
     * @param dropBeforeSync If set to true then it drops the database with all its tables and data
331
     */
332
    async synchronize(dropBeforeSync: boolean = false): Promise<void> {
6,213✔
333
        if (!this.isInitialized)
47,607✔
334
            throw new CannotExecuteNotConnectedError(this.name)
3✔
335

336
        if (dropBeforeSync) await this.dropDatabase()
47,604✔
337

338
        const schemaBuilder = this.driver.createSchemaBuilder()
47,604✔
339
        await schemaBuilder.build()
47,604✔
340
    }
341

342
    /**
343
     * Drops the database and all its data.
344
     * Be careful with this method on production since this method will erase all your database tables and their data.
345
     * Can be used only after connection to the database is established.
346
     */
347
    // TODO rename
348
    async dropDatabase(): Promise<void> {
349
        const queryRunner = this.createQueryRunner()
46,948✔
350
        try {
46,948✔
351
            if (
46,948✔
352
                this.driver.options.type === "mssql" ||
135,049✔
353
                DriverUtils.isMySQLFamily(this.driver) ||
354
                this.driver.options.type === "aurora-mysql" ||
355
                DriverUtils.isSQLiteFamily(this.driver)
356
            ) {
357
                const databases: string[] = []
35,415✔
358
                this.entityMetadatas.forEach((metadata) => {
35,415✔
359
                    if (
125,464✔
360
                        metadata.database &&
125,665✔
361
                        databases.indexOf(metadata.database) === -1
362
                    )
363
                        databases.push(metadata.database)
152✔
364
                })
365
                if (databases.length === 0 && this.driver.database) {
35,415✔
366
                    databases.push(this.driver.database)
30,562✔
367
                }
368

369
                if (databases.length === 0) {
35,415✔
370
                    await queryRunner.clearDatabase()
4,756✔
371
                } else {
372
                    for (const database of databases) {
30,659✔
373
                        await queryRunner.clearDatabase(database)
30,714✔
374
                    }
375
                }
376
            } else {
377
                await queryRunner.clearDatabase()
11,533✔
378
            }
379
        } finally {
380
            await queryRunner.release()
46,948✔
381
        }
382
    }
383

384
    /**
385
     * Runs all pending migrations.
386
     * Can be used only after connection to the database is established.
387
     */
388
    async runMigrations(options?: {
389
        transaction?: "all" | "none" | "each"
390
        fake?: boolean
391
    }): Promise<Migration[]> {
392
        if (!this.isInitialized)
253!
393
            throw new CannotExecuteNotConnectedError(this.name)
×
394

395
        const migrationExecutor = new MigrationExecutor(this)
253✔
396
        migrationExecutor.transaction =
253✔
397
            options?.transaction ||
491✔
398
            this.options?.migrationsTransactionMode ||
399
            "all"
400
        migrationExecutor.fake = (options && options.fake) || false
253✔
401

402
        const successMigrations =
403
            await migrationExecutor.executePendingMigrations()
253✔
404
        return successMigrations
174✔
405
    }
406

407
    /**
408
     * Reverts last executed migration.
409
     * Can be used only after connection to the database is established.
410
     */
411
    async undoLastMigration(options?: {
412
        transaction?: "all" | "none" | "each"
413
        fake?: boolean
414
    }): Promise<void> {
415
        if (!this.isInitialized)
73!
416
            throw new CannotExecuteNotConnectedError(this.name)
×
417

418
        const migrationExecutor = new MigrationExecutor(this)
73✔
419
        migrationExecutor.transaction =
73✔
420
            (options && options.transaction) || "all"
146✔
421
        migrationExecutor.fake = (options && options.fake) || false
73✔
422

423
        await migrationExecutor.undoLastMigration()
73✔
424
    }
425

426
    /**
427
     * Lists all migrations and whether they have been run.
428
     * Returns true if there are pending migrations
429
     */
430
    async showMigrations(): Promise<boolean> {
431
        if (!this.isInitialized) {
65!
432
            throw new CannotExecuteNotConnectedError(this.name)
×
433
        }
434
        const migrationExecutor = new MigrationExecutor(this)
65✔
435
        return await migrationExecutor.showMigrations()
65✔
436
    }
437

438
    /**
439
     * Checks if entity metadata exist for the given entity class, target name or table name.
440
     */
441
    hasMetadata(target: EntityTarget<any>): boolean {
442
        return !!this.findMetadata(target)
1,154,039✔
443
    }
444

445
    /**
446
     * Gets entity metadata for the given entity class or schema name.
447
     */
448
    getMetadata(target: EntityTarget<any>): EntityMetadata {
449
        const metadata = this.findMetadata(target)
5,214,844✔
450
        if (!metadata) throw new EntityMetadataNotFoundError(target)
5,214,844!
451

452
        return metadata
5,214,844✔
453
    }
454

455
    /**
456
     * Gets repository for the given entity.
457
     */
458
    getRepository<Entity extends ObjectLiteral>(
459
        target: EntityTarget<Entity>,
460
    ): Repository<Entity> {
461
        return this.manager.getRepository(target)
381,391✔
462
    }
463

464
    /**
465
     * Gets tree repository for the given entity class or name.
466
     * Only tree-type entities can have a TreeRepository, like ones decorated with @Tree decorator.
467
     */
468
    getTreeRepository<Entity extends ObjectLiteral>(
469
        target: EntityTarget<Entity>,
470
    ): TreeRepository<Entity> {
471
        return this.manager.getTreeRepository(target)
3,659✔
472
    }
473

474
    /**
475
     * Gets mongodb-specific repository for the given entity class or name.
476
     * Works only if connection is mongodb-specific.
477
     */
478
    getMongoRepository<Entity extends ObjectLiteral>(
479
        target: EntityTarget<Entity>,
480
    ): MongoRepository<Entity> {
481
        if (!(this.driver.options.type === "mongodb"))
132!
482
            throw new TypeORMError(
×
483
                `You can use getMongoRepository only for MongoDB connections.`,
484
            )
485

486
        return this.manager.getRepository(target) as any
132✔
487
    }
488

489
    /**
490
     * Gets custom entity repository marked with @EntityRepository decorator.
491
     *
492
     * @deprecated use Repository.extend function to create a custom repository
493
     */
494
    getCustomRepository<T>(customRepository: ObjectType<T>): T {
495
        return this.manager.getCustomRepository(customRepository)
×
496
    }
497

498
    /**
499
     * Wraps given function execution (and all operations made there) into a transaction.
500
     * All database operations must be executed using provided entity manager.
501
     */
502
    async transaction<T>(
503
        runInTransaction: (entityManager: EntityManager) => Promise<T>,
504
    ): Promise<T>
505
    async transaction<T>(
506
        isolationLevel: IsolationLevel,
507
        runInTransaction: (entityManager: EntityManager) => Promise<T>,
508
    ): Promise<T>
509
    async transaction<T>(
510
        isolationOrRunInTransaction:
511
            | IsolationLevel
512
            | ((entityManager: EntityManager) => Promise<T>),
513
        runInTransactionParam?: (entityManager: EntityManager) => Promise<T>,
514
    ): Promise<any> {
515
        return this.manager.transaction(
153✔
516
            isolationOrRunInTransaction as any,
517
            runInTransactionParam as any,
518
        )
519
    }
520

521
    /**
522
     * Executes raw SQL query and returns raw database results.
523
     *
524
     * @see [Official docs](https://typeorm.io/data-source-api) for examples.
525
     */
526
    async query<T = any>(
527
        query: string,
528
        parameters?: any[],
529
        queryRunner?: QueryRunner,
530
    ): Promise<T> {
531
        if (InstanceChecker.isMongoEntityManager(this.manager))
2,036!
532
            throw new TypeORMError(`Queries aren't supported by MongoDB.`)
×
533

534
        if (queryRunner && queryRunner.isReleased)
2,036!
535
            throw new QueryRunnerProviderAlreadyReleasedError()
×
536

537
        const usedQueryRunner = queryRunner || this.createQueryRunner()
2,036✔
538

539
        try {
2,036✔
540
            return await usedQueryRunner.query(query, parameters) // await is needed here because we are using finally
2,036✔
541
        } finally {
542
            if (!queryRunner) await usedQueryRunner.release()
2,036✔
543
        }
544
    }
545

546
    /**
547
     * Creates a new query builder that can be used to build a SQL query.
548
     */
549
    createQueryBuilder<Entity extends ObjectLiteral>(
550
        entityClass: EntityTarget<Entity>,
551
        alias: string,
552
        queryRunner?: QueryRunner,
553
    ): SelectQueryBuilder<Entity>
554

555
    /**
556
     * Creates a new query builder that can be used to build a SQL query.
557
     */
558
    createQueryBuilder(queryRunner?: QueryRunner): SelectQueryBuilder<any>
559

560
    /**
561
     * Creates a new query builder that can be used to build a SQL query.
562
     */
563
    createQueryBuilder<Entity extends ObjectLiteral>(
564
        entityOrRunner?: EntityTarget<Entity> | QueryRunner,
565
        alias?: string,
566
        queryRunner?: QueryRunner,
567
    ): SelectQueryBuilder<Entity> {
568
        if (InstanceChecker.isMongoEntityManager(this.manager))
934,129!
569
            throw new TypeORMError(`Query Builder is not supported by MongoDB.`)
×
570

571
        if (alias) {
934,129✔
572
            alias = DriverUtils.buildAlias(this.driver, undefined, alias)
585,812✔
573
            const metadata = this.getMetadata(
585,812✔
574
                entityOrRunner as EntityTarget<Entity>,
575
            )
576
            return new SelectQueryBuilder(this, queryRunner)
585,812✔
577
                .select(alias)
578
                .from(metadata.target, alias)
579
        } else {
580
            return new SelectQueryBuilder(
348,317✔
581
                this,
582
                entityOrRunner as QueryRunner | undefined,
583
            )
584
        }
585
    }
586

587
    /**
588
     * Creates a query runner used for perform queries on a single database connection.
589
     * Using query runners you can control your queries to execute using single database connection and
590
     * manually control your database transaction.
591
     *
592
     * Mode is used in replication mode and indicates whatever you want to connect
593
     * to master database or any of slave databases.
594
     * If you perform writes you must use master database,
595
     * if you perform reads you can use slave databases.
596
     */
597
    createQueryRunner(mode: ReplicationMode = "master"): QueryRunner {
347,074✔
598
        const queryRunner = this.driver.createQueryRunner(mode)
404,852✔
599
        const manager = this.createEntityManager(queryRunner)
404,852✔
600
        Object.assign(queryRunner, { manager: manager })
404,852✔
601
        return queryRunner
404,852✔
602
    }
603

604
    /**
605
     * Gets entity metadata of the junction table (many-to-many table).
606
     */
607
    getManyToManyMetadata(
608
        entityTarget: EntityTarget<any>,
609
        relationPropertyPath: string,
610
    ) {
611
        const relationMetadata =
612
            this.getMetadata(entityTarget).findRelationWithPropertyPath(
50✔
613
                relationPropertyPath,
614
            )
615
        if (!relationMetadata)
50!
616
            throw new TypeORMError(
×
617
                `Relation "${relationPropertyPath}" was not found in ${entityTarget} entity.`,
618
            )
619
        if (!relationMetadata.isManyToMany)
50!
620
            throw new TypeORMError(
×
621
                `Relation "${entityTarget}#${relationPropertyPath}" does not have a many-to-many relationship.` +
622
                    `You can use this method only on many-to-many relations.`,
623
            )
624

625
        return relationMetadata.junctionEntityMetadata
50✔
626
    }
627

628
    /**
629
     * Creates an Entity Manager for the current connection with the help of the EntityManagerFactory.
630
     */
631
    createEntityManager(queryRunner?: QueryRunner): EntityManager {
632
        return new EntityManagerFactory().create(this, queryRunner)
422,553✔
633
    }
634

635
    // -------------------------------------------------------------------------
636
    // Protected Methods
637
    // -------------------------------------------------------------------------
638

639
    /**
640
     * Finds exist entity metadata by the given entity class, target name or table name.
641
     */
642
    protected findMetadata(
643
        target: EntityTarget<any>,
644
    ): EntityMetadata | undefined {
645
        const metadataFromMap = this.entityMetadatasMap.get(target)
6,368,883✔
646
        if (metadataFromMap) return metadataFromMap
6,368,883✔
647

648
        for (const [_, metadata] of this.entityMetadatasMap) {
185,695✔
649
            if (
422,309✔
650
                InstanceChecker.isEntitySchema(target) &&
423,244✔
651
                metadata.name === target.options.name
652
            ) {
653
                return metadata
810✔
654
            }
655
            if (typeof target === "string") {
421,499✔
656
                if (target.indexOf(".") !== -1) {
411,886✔
657
                    if (metadata.tablePath === target) {
40,185✔
658
                        return metadata
756✔
659
                    }
660
                } else {
661
                    if (
371,701✔
662
                        metadata.name === target ||
689,358✔
663
                        metadata.tableName === target
664
                    ) {
665
                        return metadata
163,300✔
666
                    }
667
                }
668
            }
669
            if (
257,443!
670
                ObjectUtils.isObjectWithName(target) &&
257,443!
671
                typeof target.name === "string"
672
            ) {
673
                if (target.name.indexOf(".") !== -1) {
×
674
                    if (metadata.tablePath === target.name) {
×
675
                        return metadata
×
676
                    }
677
                } else {
678
                    if (
×
679
                        metadata.name === target.name ||
×
680
                        metadata.tableName === target.name
681
                    ) {
682
                        return metadata
×
683
                    }
684
                }
685
            }
686
        }
687

688
        return undefined
20,829✔
689
    }
690

691
    /**
692
     * Builds metadatas for all registered classes inside this connection.
693
     */
694
    protected async buildMetadatas(): Promise<void> {
695
        const connectionMetadataBuilder = new ConnectionMetadataBuilder(this)
16,948✔
696
        const entityMetadataValidator = new EntityMetadataValidator()
16,948✔
697

698
        // create subscribers instances if they are not disallowed from high-level (for example they can disallowed from migrations run process)
699
        const flattenedSubscribers = ObjectUtils.mixedListToArray(
16,948✔
700
            this.options.subscribers || [],
16,962✔
701
        )
702
        const subscribers = await connectionMetadataBuilder.buildSubscribers(
16,948✔
703
            flattenedSubscribers,
704
        )
705
        ObjectUtils.assign(this, { subscribers: subscribers })
16,948✔
706

707
        // build entity metadatas
708
        const flattenedEntities = ObjectUtils.mixedListToArray(
16,948✔
709
            this.options.entities || [],
16,956✔
710
        )
711
        const entityMetadatas =
712
            await connectionMetadataBuilder.buildEntityMetadatas(
16,948✔
713
                flattenedEntities,
714
            )
715
        ObjectUtils.assign(this, {
16,948✔
716
            entityMetadatas: entityMetadatas,
717
            entityMetadatasMap: new Map(
718
                entityMetadatas.map((metadata) => [metadata.target, metadata]),
43,229✔
719
            ),
720
        })
721

722
        // create migration instances
723
        const flattenedMigrations = ObjectUtils.mixedListToArray(
16,948✔
724
            this.options.migrations || [],
16,962✔
725
        )
726
        const migrations = await connectionMetadataBuilder.buildMigrations(
16,948✔
727
            flattenedMigrations,
728
        )
729
        ObjectUtils.assign(this, { migrations: migrations })
16,948✔
730

731
        // validate all created entity metadatas to make sure user created entities are valid and correct
732
        entityMetadataValidator.validateMany(
16,948✔
733
            this.entityMetadatas.filter(
734
                (metadata) => metadata.tableType !== "view",
43,229✔
735
            ),
736
            this.driver,
737
        )
738

739
        // set current data source to the entities
740
        for (const entityMetadata of entityMetadatas) {
16,882✔
741
            if (
43,065✔
742
                InstanceChecker.isBaseEntityConstructor(entityMetadata.target)
743
            ) {
744
                entityMetadata.target.useDataSource(this)
1,442✔
745
            }
746
        }
747
    }
748

749
    /**
750
     * Get the replication mode SELECT queries should use for this datasource by default
751
     */
752
    defaultReplicationModeForReads(): ReplicationMode {
753
        if ("replication" in this.driver.options) {
57,366✔
754
            const value = (
755
                this.driver.options.replication as {
6✔
756
                    defaultMode?: ReplicationMode
757
                }
758
            ).defaultMode
759
            if (value) {
6✔
760
                return value
3✔
761
            }
762
        }
763
        return "slave"
57,363✔
764
    }
765
}
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