• 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

77.13
/src/data-source/DataSource.ts
1
import { Driver } from "../driver/Driver"
2
import { registerQueryBuilders } from "../query-builder"
4✔
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"
4✔
9
import {
4✔
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"
4✔
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"
4✔
26
import { DataSourceOptions } from "./DataSourceOptions"
27
import { EntityManagerFactory } from "../entity-manager/EntityManagerFactory"
4✔
28
import { DriverFactory } from "../driver/DriverFactory"
4✔
29
import { ConnectionMetadataBuilder } from "../connection/ConnectionMetadataBuilder"
4✔
30
import { QueryRunner } from "../query-runner/QueryRunner"
31
import { SelectQueryBuilder } from "../query-builder/SelectQueryBuilder"
4✔
32
import { LoggerFactory } from "../logger/LoggerFactory"
4✔
33
import { QueryResultCacheFactory } from "../cache/QueryResultCacheFactory"
4✔
34
import { QueryResultCache } from "../cache/QueryResultCache"
35
import { SqljsEntityManager } from "../entity-manager/SqljsEntityManager"
36
import { RelationLoader } from "../query-builder/RelationLoader"
4✔
37
import { ObjectUtils } from "../util/ObjectUtils"
4✔
38
import { IsolationLevel } from "../driver/types/IsolationLevel"
39
import { ReplicationMode } from "../driver/types/ReplicationMode"
40
import { RelationIdLoader } from "../query-builder/RelationIdLoader"
4✔
41
import { DriverUtils } from "../driver/DriverUtils"
4✔
42
import { InstanceChecker } from "../util/InstanceChecker"
4✔
43
import { ObjectLiteral } from "../common/ObjectLiteral"
44

45
registerQueryBuilders()
4✔
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 {
4✔
56
    readonly "@instanceof" = Symbol.for("DataSource")
1,852✔
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[] = []
1,852✔
108

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

114
    /**
115
     * All entity metadatas that are registered for this connection.
116
     */
117
    readonly entityMetadatas: EntityMetadata[] = []
1,852✔
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>()
1,852✔
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()
1,852✔
143
        this.name = options.name || "default"
1,852✔
144
        this.options = options
1,852✔
145
        this.logger = new LoggerFactory().create(
1,852✔
146
            this.options.logger,
147
            this.options.logging,
148
        )
149
        this.driver = new DriverFactory().create(this)
1,852✔
150
        this.manager = this.createEntityManager()
1,852✔
151
        this.namingStrategy =
1,852✔
152
            options.namingStrategy || new DefaultNamingStrategy()
3,691✔
153
        this.metadataTableName = options.metadataTableName || "typeorm_metadata"
1,852✔
154
        this.queryResultCache = options.cache
1,852✔
155
            ? new QueryResultCacheFactory(this).create()
156
            : undefined
157
        this.relationLoader = new RelationLoader(this)
1,852✔
158
        this.relationIdLoader = new RelationIdLoader(this)
1,852✔
159
        this.isInitialized = false
1,852✔
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))
×
183
            throw new TypeORMError(
×
184
                `MongoEntityManager is only available for MongoDB databases.`,
185
            )
186

187
        return this.manager as MongoEntityManager
×
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))
5!
197
            throw new TypeORMError(
×
198
                `SqljsEntityManager is only available for Sqljs databases.`,
199
            )
200

201
        return this.manager
5✔
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)
9✔
212

213
        if (options.logger || options.logging) {
9!
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) {
9!
221
            this.namingStrategy = options.namingStrategy
×
222
        }
223

224
        if (options.cache) {
9!
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) {
9!
232
            this.driver.database = DriverUtils.buildDriverOptions(
×
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
9✔
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)
1,804✔
250
            throw new CannotConnectAlreadyConnectedError(this.name)
4✔
251

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

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

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

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

265
            await this.driver.afterConnect()
1,791✔
266

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

270
            // if option is set - automatically synchronize a schema
271
            if (this.options.migrationsRun)
1,791!
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()
1,791✔
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()
9✔
282
            throw error
9✔
283
        }
284

285
        return this
1,791✔
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()
4✔
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)
1,802✔
306
            throw new CannotExecuteNotConnectedError(this.name)
4✔
307

308
        await this.driver.disconnect()
1,798✔
309

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

313
        ObjectUtils.assign(this, { isInitialized: false })
1,798✔
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()
17✔
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> {
635✔
333
        if (!this.isInitialized)
5,119!
334
            throw new CannotExecuteNotConnectedError(this.name)
×
335

336
        if (dropBeforeSync) await this.dropDatabase()
5,119✔
337

338
        const schemaBuilder = this.driver.createSchemaBuilder()
5,119✔
339
        await schemaBuilder.build()
5,119✔
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()
5,037✔
350
        try {
5,037✔
351
            if (
5,037✔
352
                this.driver.options.type === "mssql" ||
20,148✔
353
                DriverUtils.isMySQLFamily(this.driver) ||
354
                this.driver.options.type === "aurora-mysql" ||
355
                DriverUtils.isSQLiteFamily(this.driver)
356
            ) {
357
                const databases: string[] = []
3,800✔
358
                this.entityMetadatas.forEach((metadata) => {
3,800✔
359
                    if (
13,465✔
360
                        metadata.database &&
13,483✔
361
                        databases.indexOf(metadata.database) === -1
362
                    )
363
                        databases.push(metadata.database)
11✔
364
                })
365
                if (databases.length === 0 && this.driver.database) {
3,800✔
366
                    databases.push(this.driver.database)
2,599✔
367
                }
368

369
                if (databases.length === 0) {
3,800✔
370
                    await queryRunner.clearDatabase()
1,194✔
371
                } else {
372
                    for (const database of databases) {
2,606✔
373
                        await queryRunner.clearDatabase(database)
2,610✔
374
                    }
375
                }
376
            } else {
377
                await queryRunner.clearDatabase()
1,237✔
378
            }
379
        } finally {
380
            await queryRunner.release()
5,037✔
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)
27!
393
            throw new CannotExecuteNotConnectedError(this.name)
×
394

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

402
        const successMigrations =
403
            await migrationExecutor.executePendingMigrations()
27✔
404
        return successMigrations
19✔
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)
8!
416
            throw new CannotExecuteNotConnectedError(this.name)
×
417

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

423
        await migrationExecutor.undoLastMigration()
8✔
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) {
10!
432
            throw new CannotExecuteNotConnectedError(this.name)
×
433
        }
434
        const migrationExecutor = new MigrationExecutor(this)
10✔
435
        return await migrationExecutor.showMigrations()
10✔
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)
125,048✔
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)
519,154✔
450
        if (!metadata) throw new EntityMetadataNotFoundError(target)
519,154!
451

452
        return metadata
519,154✔
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)
43,436✔
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)
330✔
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"))
×
482
            throw new TypeORMError(
×
483
                `You can use getMongoRepository only for MongoDB connections.`,
484
            )
485

486
        return this.manager.getRepository(target) as any
×
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(
15✔
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))
46!
532
            throw new TypeORMError(`Queries aren't supported by MongoDB.`)
×
533

534
        if (queryRunner && queryRunner.isReleased)
46!
535
            throw new QueryRunnerProviderAlreadyReleasedError()
×
536

537
        const usedQueryRunner = queryRunner || this.createQueryRunner()
46✔
538

539
        try {
46✔
540
            return await usedQueryRunner.query(query, parameters) // await is needed here because we are using finally
46✔
541
        } finally {
542
            if (!queryRunner) await usedQueryRunner.release()
46✔
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))
105,706!
569
            throw new TypeORMError(`Query Builder is not supported by MongoDB.`)
×
570

571
        if (alias) {
105,706✔
572
            alias = DriverUtils.buildAlias(this.driver, undefined, alias)
63,016✔
573
            const metadata = this.getMetadata(
63,016✔
574
                entityOrRunner as EntityTarget<Entity>,
575
            )
576
            return new SelectQueryBuilder(this, queryRunner)
63,016✔
577
                .select(alias)
578
                .from(metadata.target, alias)
579
        } else {
580
            return new SelectQueryBuilder(
42,690✔
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 {
38,911✔
598
        const queryRunner = this.driver.createQueryRunner(mode)
45,220✔
599
        const manager = this.createEntityManager(queryRunner)
45,220✔
600
        Object.assign(queryRunner, { manager: manager })
45,220✔
601
        return queryRunner
45,220✔
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(
4✔
613
                relationPropertyPath,
614
            )
615
        if (!relationMetadata)
4!
616
            throw new TypeORMError(
×
617
                `Relation "${relationPropertyPath}" was not found in ${entityTarget} entity.`,
618
            )
619
        if (!relationMetadata.isManyToMany)
4!
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
4✔
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)
47,104✔
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)
644,202✔
646
        if (metadataFromMap) return metadataFromMap
644,202✔
647

648
        for (const [_, metadata] of this.entityMetadatasMap) {
13,994✔
649
            if (
28,653✔
650
                InstanceChecker.isEntitySchema(target) &&
28,812✔
651
                metadata.name === target.options.name
652
            ) {
653
                return metadata
114✔
654
            }
655
            if (typeof target === "string") {
28,539✔
656
                if (target.indexOf(".") !== -1) {
27,404✔
657
                    if (metadata.tablePath === target) {
3,416!
658
                        return metadata
×
659
                    }
660
                } else {
661
                    if (
23,988✔
662
                        metadata.name === target ||
42,752✔
663
                        metadata.tableName === target
664
                    ) {
665
                        return metadata
11,773✔
666
                    }
667
                }
668
            }
669
            if (
16,766!
670
                ObjectUtils.isObjectWithName(target) &&
16,766!
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
2,107✔
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)
1,800✔
696
        const entityMetadataValidator = new EntityMetadataValidator()
1,800✔
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(
1,800✔
700
            this.options.subscribers || [],
1,802✔
701
        )
702
        const subscribers = await connectionMetadataBuilder.buildSubscribers(
1,800✔
703
            flattenedSubscribers,
704
        )
705
        ObjectUtils.assign(this, { subscribers: subscribers })
1,800✔
706

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

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

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

739
        // set current data source to the entities
740
        for (const entityMetadata of entityMetadatas) {
1,791✔
741
            if (
4,682✔
742
                InstanceChecker.isBaseEntityConstructor(entityMetadata.target)
743
            ) {
744
                entityMetadata.target.useDataSource(this)
156✔
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 (
6,292!
754
            "replication" in this.driver.options &&
6,292!
755
            this.driver.options.replication
756
        ) {
757
            const value = (
758
                this.driver.options.replication as {
×
759
                    defaultMode?: ReplicationMode
760
                }
761
            ).defaultMode
762
            if (value) {
×
763
                return value
×
764
            }
765
        }
766
        return "slave"
6,292✔
767
    }
768
}
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