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

typeorm / typeorm / 22853215566

09 Mar 2026 12:22PM UTC coverage: 74.77%. First build
22853215566

push

github

web-flow
refactor(ConnectionOptionsReader)!: remove deprecated DataSource.name and simplify API (#12136)

26510 of 31976 branches covered (82.91%)

Branch coverage included in aggregate %.

10 of 11 new or added lines in 4 files covered. (90.91%)

84163 of 116041 relevant lines covered (72.53%)

65728.19 hits per line

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

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

23✔
45
registerQueryBuilders()
23✔
46

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

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

23✔
62
    /**
23✔
63
     * Connection options.
23✔
64
     */
23✔
65
    readonly options: DataSourceOptions
23✔
66

23✔
67
    /**
23✔
68
     * Indicates if DataSource is initialized or not.
23✔
69
     */
23✔
70
    readonly isInitialized: boolean
23✔
71

23✔
72
    /**
23✔
73
     * Database driver used by this connection.
23✔
74
     */
23✔
75
    driver: Driver
23✔
76

23✔
77
    /**
23✔
78
     * EntityManager of this connection.
23✔
79
     */
23✔
80
    readonly manager: EntityManager
23✔
81

23✔
82
    /**
23✔
83
     * Naming strategy used in the connection.
23✔
84
     */
23✔
85
    namingStrategy: NamingStrategyInterface
23✔
86

23✔
87
    /**
23✔
88
     * Name for the metadata table
23✔
89
     */
23✔
90
    readonly metadataTableName: string
23✔
91

23✔
92
    /**
23✔
93
     * Logger used to log orm events.
23✔
94
     */
23✔
95
    logger: Logger
23✔
96

23✔
97
    /**
23✔
98
     * Migration instances that are registered for this connection.
23✔
99
     */
23✔
100
    readonly migrations: MigrationInterface[] = []
23✔
101

23✔
102
    /**
23✔
103
     * Entity subscriber instances that are registered for this connection.
23✔
104
     */
23✔
105
    readonly subscribers: EntitySubscriberInterface<any>[] = []
23✔
106

23✔
107
    /**
23✔
108
     * All entity metadatas that are registered for this connection.
23✔
109
     */
23✔
110
    readonly entityMetadatas: EntityMetadata[] = []
23✔
111

23✔
112
    /**
23✔
113
     * All entity metadatas that are registered for this connection.
23✔
114
     * This is a copy of #.entityMetadatas property -> used for more performant searches.
23✔
115
     */
23✔
116
    readonly entityMetadatasMap = new Map<EntityTarget<any>, EntityMetadata>()
23✔
117

23✔
118
    /**
23✔
119
     * Used to work with query result cache.
23✔
120
     */
23✔
121
    queryResultCache?: QueryResultCache
23✔
122

23✔
123
    /**
23✔
124
     * Used to load relations and work with lazy relations.
23✔
125
     */
23✔
126
    readonly relationLoader: RelationLoader
23✔
127

23✔
128
    readonly relationIdLoader: RelationIdLoader
23✔
129

23✔
130
    // -------------------------------------------------------------------------
23✔
131
    // Constructor
23✔
132
    // -------------------------------------------------------------------------
23✔
133

23✔
134
    constructor(options: DataSourceOptions) {
23✔
135
        registerQueryBuilders()
13,392✔
136
        this.options = options
13,392✔
137
        this.logger = new LoggerFactory().create(
13,392✔
138
            this.options.logger,
13,392✔
139
            this.options.logging,
13,392✔
140
        )
13,392✔
141
        this.driver = new DriverFactory().create(this)
13,392✔
142
        this.manager = this.createEntityManager()
13,392✔
143
        this.namingStrategy =
13,392✔
144
            options.namingStrategy || new DefaultNamingStrategy()
13,392✔
145
        this.metadataTableName = options.metadataTableName || "typeorm_metadata"
13,392✔
146
        this.queryResultCache = options.cache
13,392✔
147
            ? new QueryResultCacheFactory(this).create()
13,392!
148
            : undefined
13,392✔
149
        this.relationLoader = new RelationLoader(this)
13,392✔
150
        this.relationIdLoader = new RelationIdLoader(this)
13,392✔
151
        this.isInitialized = false
13,392✔
152
    }
13,392✔
153

23✔
154
    // -------------------------------------------------------------------------
23✔
155
    // Public Accessors
23✔
156
    // -------------------------------------------------------------------------
23✔
157

23✔
158
    /**
23✔
159
     * Gets the mongodb entity manager that allows to perform mongodb-specific repository operations
23✔
160
     * with any entity in this connection.
23✔
161
     *
23✔
162
     * Available only in mongodb connections.
23✔
163
     * @returns the mongodb entity manager
23✔
164
     */
23✔
165
    get mongoManager(): MongoEntityManager {
23✔
166
        if (!InstanceChecker.isMongoEntityManager(this.manager))
10✔
167
            throw new TypeORMError(
10!
168
                `MongoEntityManager is only available for MongoDB databases.`,
×
169
            )
×
170

10✔
171
        return this.manager as MongoEntityManager
10✔
172
    }
10✔
173

23✔
174
    /**
23✔
175
     * Gets a sql.js specific Entity Manager that allows to perform special load and save operations
23✔
176
     *
23✔
177
     * Available only in connection with the sqljs driver.
23✔
178
     * @returns an sqljs specific Entity Manager
23✔
179
     */
23✔
180
    get sqljsManager(): SqljsEntityManager {
23✔
181
        if (!InstanceChecker.isSqljsEntityManager(this.manager))
15✔
182
            throw new TypeORMError(
15!
183
                `SqljsEntityManager is only available for Sqljs databases.`,
×
184
            )
×
185

15✔
186
        return this.manager
15✔
187
    }
15✔
188

23✔
189
    // -------------------------------------------------------------------------
23✔
190
    // Public Methods
23✔
191
    // -------------------------------------------------------------------------
23✔
192
    /**
23✔
193
     * Updates current connection options with provided options.
23✔
194
     * @param options
23✔
195
     */
23✔
196
    setOptions(options: Partial<DataSourceOptions>): this {
23✔
197
        Object.assign(this.options, options)
68✔
198

68✔
199
        if (options.logger || options.logging) {
68!
200
            this.logger = new LoggerFactory().create(
×
201
                options.logger || this.options.logger,
×
202
                options.logging || this.options.logging,
×
203
            )
×
204
        }
×
205

68✔
206
        if (options.namingStrategy) {
68!
207
            this.namingStrategy = options.namingStrategy
×
208
        }
×
209

68✔
210
        if (options.cache) {
68!
211
            this.queryResultCache = new QueryResultCacheFactory(this).create()
×
212
        }
×
213

68✔
214
        // todo: we must update the database in the driver as well, if it was set by setOptions method
68✔
215
        //  in the future we need to refactor the code and remove "database" from the driver, and instead
68✔
216
        //  use database (and options) from a single place - data source.
68✔
217
        if (options.database) {
68!
218
            this.driver.database = DriverUtils.buildDriverOptions(
8✔
219
                this.options,
8✔
220
            ).database
8✔
221
        }
8✔
222

68✔
223
        // todo: need to take a look if we need to update schema and other "poor" properties
68✔
224

68✔
225
        return this
68✔
226
    }
68✔
227

23✔
228
    /**
23✔
229
     * Performs connection to the database.
23✔
230
     * This method should be called once on application bootstrap.
23✔
231
     * This method not necessarily creates database connection (depend on database type),
23✔
232
     * but it also can setup a connection pool with database to use.
23✔
233
     */
23✔
234
    async initialize(): Promise<this> {
23✔
235
        if (this.isInitialized) throw new CannotConnectAlreadyConnectedError()
13,256✔
236

13,231✔
237
        // connect to the database via its driver
13,231✔
238
        await this.driver.connect()
13,231✔
239

13,231✔
240
        // connect to the cache-specific database if cache is enabled
13,231✔
241
        if (this.queryResultCache) await this.queryResultCache.connect()
13,256!
242

13,231✔
243
        // set connected status for the current connection
13,231✔
244
        ObjectUtils.assign(this, { isInitialized: true })
13,231✔
245

13,231✔
246
        try {
13,231✔
247
            // build all metadatas registered in the current connection
13,231✔
248
            await this.buildMetadatas()
13,231✔
249

13,179✔
250
            await this.driver.afterConnect()
13,179✔
251

13,179✔
252
            // if option is set - drop schema once connection is done
13,179✔
253
            if (this.options.dropSchema) await this.dropDatabase()
13,256✔
254

13,179✔
255
            // if option is set - automatically synchronize a schema
13,179✔
256
            if (this.options.migrationsRun)
13,179✔
257
                await this.runMigrations({
13,256!
258
                    transaction: this.options.migrationsTransactionMode,
×
259
                })
×
260

13,179✔
261
            // if option is set - automatically synchronize a schema
13,179✔
262
            if (this.options.synchronize) await this.synchronize()
13,256✔
263
        } catch (error) {
13,256!
264
            // if for some reason build metadata fail (for example validation error during entity metadata check)
52✔
265
            // connection needs to be closed
52✔
266
            await this.destroy()
52✔
267
            throw error
52✔
268
        }
52✔
269

13,179✔
270
        return this
13,179✔
271
    }
13,179✔
272

23✔
273
    /**
23✔
274
     * Closes connection with the database.
23✔
275
     * Once connection is closed, you cannot use repositories or perform any operations except opening connection again.
23✔
276
     */
23✔
277
    async destroy(): Promise<void> {
23✔
278
        if (!this.isInitialized) throw new CannotExecuteNotConnectedError()
13,217!
279

13,188✔
280
        await this.driver.disconnect()
13,188✔
281

13,188✔
282
        // disconnect from the cache-specific database if cache was enabled
13,188✔
283
        if (this.queryResultCache) await this.queryResultCache.disconnect()
13,217!
284

13,188✔
285
        ObjectUtils.assign(this, { isInitialized: false })
13,188✔
286
    }
13,188✔
287

23✔
288
    /**
23✔
289
     * Creates database schema for all entities registered in this connection.
23✔
290
     * Can be used only after connection to the database is established.
23✔
291
     * @param dropBeforeSync If set to true then it drops the database with all its tables and data
23✔
292
     */
23✔
293
    async synchronize(dropBeforeSync: boolean = false): Promise<void> {
23✔
294
        if (!this.isInitialized) throw new CannotExecuteNotConnectedError()
38,688!
295

38,684✔
296
        if (dropBeforeSync) await this.dropDatabase()
38,688✔
297

38,684✔
298
        const schemaBuilder = this.driver.createSchemaBuilder()
38,684✔
299
        await schemaBuilder.build()
38,684✔
300
    }
38,682✔
301

23✔
302
    /**
23✔
303
     * Drops the database and all its data.
23✔
304
     * Be careful with this method on production since this method will erase all your database tables and their data.
23✔
305
     * Can be used only after connection to the database is established.
23✔
306
     */
23✔
307
    // TODO rename
23✔
308
    async dropDatabase(): Promise<void> {
23✔
309
        const queryRunner = this.createQueryRunner()
38,223✔
310
        try {
38,223✔
311
            if (
38,223✔
312
                this.driver.options.type === "mssql" ||
38,223!
313
                DriverUtils.isMySQLFamily(this.driver) ||
38,223!
314
                this.driver.options.type === "aurora-mysql" ||
38,223!
315
                DriverUtils.isSQLiteFamily(this.driver)
23,051✔
316
            ) {
38,223!
317
                const databases: string[] = []
23,605✔
318
                this.entityMetadatas.forEach((metadata) => {
23,605✔
319
                    if (
83,327✔
320
                        metadata.database &&
83,327✔
321
                        databases.indexOf(metadata.database) === -1
110✔
322
                    )
83,327✔
323
                        databases.push(metadata.database)
83,327✔
324
                })
23,605✔
325
                if (databases.length === 0 && this.driver.database) {
23,605!
326
                    databases.push(this.driver.database)
19,610✔
327
                }
19,610✔
328

23,605✔
329
                if (databases.length === 0) {
23,605!
330
                    await queryRunner.clearDatabase()
3,945✔
331
                } else {
23,605✔
332
                    for (const database of databases) {
19,660✔
333
                        await queryRunner.clearDatabase(database)
19,684✔
334
                    }
19,684✔
335
                }
19,660✔
336
            } else {
38,223!
337
                await queryRunner.clearDatabase()
14,618✔
338
            }
14,618✔
339
        } finally {
38,223✔
340
            await queryRunner.release()
38,223✔
341
        }
38,223✔
342
    }
38,223✔
343

23✔
344
    /**
23✔
345
     * Runs all pending migrations.
23✔
346
     * Can be used only after connection to the database is established.
23✔
347
     * @param options
23✔
348
     * @param options.transaction
23✔
349
     * @param options.fake
23✔
350
     */
23✔
351
    async runMigrations(options?: {
23✔
352
        transaction?: "all" | "none" | "each"
225✔
353
        fake?: boolean
225✔
354
    }): Promise<Migration[]> {
225✔
355
        if (!this.isInitialized) throw new CannotExecuteNotConnectedError()
225!
356

225✔
357
        const migrationExecutor = new MigrationExecutor(this)
225✔
358
        migrationExecutor.transaction =
225✔
359
            options?.transaction ||
225!
360
            this.options?.migrationsTransactionMode ||
225✔
361
            "all"
119✔
362
        migrationExecutor.fake = (options && options.fake) || false
225!
363

225✔
364
        const successMigrations =
225✔
365
            await migrationExecutor.executePendingMigrations()
225✔
366
        return successMigrations
163✔
367
    }
163✔
368

23✔
369
    /**
23✔
370
     * Reverts last executed migration.
23✔
371
     * Can be used only after connection to the database is established.
23✔
372
     * @param options
23✔
373
     * @param options.transaction
23✔
374
     * @param options.fake
23✔
375
     */
23✔
376
    async undoLastMigration(options?: {
23✔
377
        transaction?: "all" | "none" | "each"
54✔
378
        fake?: boolean
54✔
379
    }): Promise<void> {
54✔
380
        if (!this.isInitialized) throw new CannotExecuteNotConnectedError()
54!
381

54✔
382
        const migrationExecutor = new MigrationExecutor(this)
54✔
383
        migrationExecutor.transaction =
54✔
384
            (options && options.transaction) || "all"
54!
385
        migrationExecutor.fake = (options && options.fake) || false
54!
386

54✔
387
        await migrationExecutor.undoLastMigration()
54✔
388
    }
29✔
389

23✔
390
    /**
23✔
391
     * Lists all migrations and whether they have been run.
23✔
392
     * Returns true if there are pending migrations
23✔
393
     */
23✔
394
    async showMigrations(): Promise<boolean> {
23✔
395
        if (!this.isInitialized) {
45!
NEW
396
            throw new CannotExecuteNotConnectedError()
×
397
        }
×
398
        const migrationExecutor = new MigrationExecutor(this)
45✔
399
        return await migrationExecutor.showMigrations()
45✔
400
    }
45✔
401

23✔
402
    /**
23✔
403
     * Checks if entity metadata exist for the given entity class, target name or table name.
23✔
404
     * @param target
23✔
405
     */
23✔
406
    hasMetadata(target: EntityTarget<any>): boolean {
23✔
407
        return !!this.findMetadata(target)
1,331,065✔
408
    }
1,331,065✔
409

23✔
410
    /**
23✔
411
     * Gets entity metadata for the given entity class or schema name.
23✔
412
     * @param target
23✔
413
     */
23✔
414
    getMetadata(target: EntityTarget<any>): EntityMetadata {
23✔
415
        const metadata = this.findMetadata(target)
3,520,773✔
416
        if (!metadata) throw new EntityMetadataNotFoundError(target)
3,520,773!
417

3,520,773✔
418
        return metadata
3,520,773✔
419
    }
3,520,773✔
420

23✔
421
    /**
23✔
422
     * Gets repository for the given entity.
23✔
423
     * @param target
23✔
424
     */
23✔
425
    getRepository<Entity extends ObjectLiteral>(
23✔
426
        target: EntityTarget<Entity>,
66,364✔
427
    ): Repository<Entity> {
66,364✔
428
        return this.manager.getRepository(target)
66,364✔
429
    }
66,364✔
430

23✔
431
    /**
23✔
432
     * Gets tree repository for the given entity class or name.
23✔
433
     * Only tree-type entities can have a TreeRepository, like ones decorated with `@Tree` decorator.
23✔
434
     * @param target
23✔
435
     */
23✔
436
    getTreeRepository<Entity extends ObjectLiteral>(
23✔
437
        target: EntityTarget<Entity>,
2,598✔
438
    ): TreeRepository<Entity> {
2,598✔
439
        return this.manager.getTreeRepository(target)
2,598✔
440
    }
2,598✔
441

23✔
442
    /**
23✔
443
     * Gets mongodb-specific repository for the given entity class or name.
23✔
444
     * Works only if connection is mongodb-specific.
23✔
445
     * @param target
23✔
446
     */
23✔
447
    getMongoRepository<Entity extends ObjectLiteral>(
23✔
448
        target: EntityTarget<Entity>,
90✔
449
    ): MongoRepository<Entity> {
90✔
450
        if (!(this.driver.options.type === "mongodb"))
90✔
451
            throw new TypeORMError(
90!
452
                `You can use getMongoRepository only for MongoDB connections.`,
×
453
            )
×
454

90✔
455
        return this.manager.getRepository(target) as any
90✔
456
    }
90✔
457

23✔
458
    /**
23✔
459
     * Wraps given function execution (and all operations made there) into a transaction.
23✔
460
     * All database operations must be executed using provided entity manager.
23✔
461
     */
23✔
462
    async transaction<T>(
23✔
463
        runInTransaction: (entityManager: EntityManager) => Promise<T>,
23✔
464
    ): Promise<T>
23✔
465
    async transaction<T>(
23✔
466
        isolationLevel: IsolationLevel,
23✔
467
        runInTransaction: (entityManager: EntityManager) => Promise<T>,
23✔
468
    ): Promise<T>
23✔
469
    async transaction<T>(
23✔
470
        isolationOrRunInTransaction:
116✔
471
            | IsolationLevel
116✔
472
            | ((entityManager: EntityManager) => Promise<T>),
116✔
473
        runInTransactionParam?: (entityManager: EntityManager) => Promise<T>,
116✔
474
    ): Promise<any> {
116✔
475
        return this.manager.transaction(
116✔
476
            isolationOrRunInTransaction as any,
116✔
477
            runInTransactionParam as any,
116✔
478
        )
116✔
479
    }
116✔
480

23✔
481
    /**
23✔
482
     * Executes raw SQL query and returns raw database results.
23✔
483
     * @param query
23✔
484
     * @param parameters
23✔
485
     * @param queryRunner
23✔
486
     * @returns a raw response from the database client
23✔
487
     * @see {@link https://typeorm.io/data-source-api | Official docs} for examples.
23✔
488
     */
23✔
489
    async query<T = any>(
23✔
490
        query: string,
1,278✔
491
        parameters?: any[],
1,278✔
492
        queryRunner?: QueryRunner,
1,278✔
493
    ): Promise<T> {
1,278✔
494
        if (InstanceChecker.isMongoEntityManager(this.manager))
1,278✔
495
            throw new TypeORMError(`Queries aren't supported by MongoDB.`)
1,278!
496

1,278✔
497
        if (queryRunner && queryRunner.isReleased)
1,278✔
498
            throw new QueryRunnerProviderAlreadyReleasedError()
1,278!
499

1,278✔
500
        const usedQueryRunner = queryRunner || this.createQueryRunner()
1,278✔
501

1,278✔
502
        try {
1,278✔
503
            return await usedQueryRunner.query(query, parameters) // await is needed here because we are using finally
1,278✔
504
        } finally {
1,278✔
505
            if (!queryRunner) await usedQueryRunner.release()
1,278✔
506
        }
1,278✔
507
    }
1,278✔
508

23✔
509
    /**
23✔
510
     * Tagged template function that executes raw SQL query and returns raw database results.
23✔
511
     * Template expressions are automatically transformed into database parameters.
23✔
512
     * Raw query execution is supported only by relational databases (MongoDB is not supported).
23✔
513
     * Note: Don't call this as a regular function, it is meant to be used with backticks to tag a template literal.
23✔
514
     * Example: dataSource.sql`SELECT * FROM table_name WHERE id = ${id}`
23✔
515
     * @param strings
23✔
516
     * @param values
23✔
517
     * @returns a raw response from the database client
23✔
518
     */
23✔
519
    async sql<T = any>(
23✔
520
        strings: TemplateStringsArray,
120✔
521
        ...values: unknown[]
120✔
522
    ): Promise<T> {
120✔
523
        const { query, parameters } = buildSqlTag({
120✔
524
            driver: this.driver,
120✔
525
            strings: strings,
120✔
526
            expressions: values,
120✔
527
        })
120✔
528

120✔
529
        return await this.query(query, parameters)
120✔
530
    }
120✔
531

23✔
532
    /**
23✔
533
     * Creates a new query builder that can be used to build a SQL query.
23✔
534
     */
23✔
535
    createQueryBuilder<Entity extends ObjectLiteral>(
23✔
536
        entityClass: EntityTarget<Entity>,
23✔
537
        alias: string,
23✔
538
        queryRunner?: QueryRunner,
23✔
539
    ): SelectQueryBuilder<Entity>
23✔
540

23✔
541
    /**
23✔
542
     * Creates a new query builder that can be used to build a SQL query.
23✔
543
     */
23✔
544
    createQueryBuilder(queryRunner?: QueryRunner): SelectQueryBuilder<any>
23✔
545

23✔
546
    /**
23✔
547
     * Creates a new query builder that can be used to build a SQL query.
23✔
548
     * @param entityOrRunner
23✔
549
     * @param alias
23✔
550
     * @param queryRunner
23✔
551
     */
23✔
552
    createQueryBuilder<Entity extends ObjectLiteral>(
23✔
553
        entityOrRunner?: EntityTarget<Entity> | QueryRunner,
507,585✔
554
        alias?: string,
507,585✔
555
        queryRunner?: QueryRunner,
507,585✔
556
    ): SelectQueryBuilder<Entity> {
507,585✔
557
        if (InstanceChecker.isMongoEntityManager(this.manager))
507,585✔
558
            throw new TypeORMError(`Query Builder is not supported by MongoDB.`)
507,585!
559

507,585✔
560
        if (alias) {
507,585✔
561
            alias = DriverUtils.buildAlias(this.driver, undefined, alias)
233,206✔
562
            const metadata = this.getMetadata(
233,206✔
563
                entityOrRunner as EntityTarget<Entity>,
233,206✔
564
            )
233,206✔
565
            return new SelectQueryBuilder(this, queryRunner)
233,206✔
566
                .select(alias)
233,206✔
567
                .from(metadata.target, alias)
233,206✔
568
        } else {
507,585✔
569
            return new SelectQueryBuilder(
274,379✔
570
                this,
274,379✔
571
                entityOrRunner as QueryRunner | undefined,
274,379✔
572
            )
274,379✔
573
        }
274,379✔
574
    }
507,585✔
575

23✔
576
    /**
23✔
577
     * Creates a query runner used for perform queries on a single database connection.
23✔
578
     * Using query runners you can control your queries to execute using single database connection and
23✔
579
     * manually control your database transaction.
23✔
580
     *
23✔
581
     * Mode is used in replication mode and indicates whatever you want to connect
23✔
582
     * to master database or any of slave databases.
23✔
583
     * If you perform writes you must use master database,
23✔
584
     * if you perform reads you can use slave databases.
23✔
585
     * @param mode
23✔
586
     */
23✔
587
    createQueryRunner(mode: ReplicationMode = "master"): QueryRunner {
23✔
588
        const queryRunner = this.driver.createQueryRunner(mode)
315,956✔
589
        const manager = this.createEntityManager(queryRunner)
315,956✔
590
        Object.assign(queryRunner, { manager: manager })
315,956✔
591
        return queryRunner
315,956✔
592
    }
315,956✔
593

23✔
594
    /**
23✔
595
     * Gets entity metadata of the junction table (many-to-many table).
23✔
596
     * @param entityTarget
23✔
597
     * @param relationPropertyPath
23✔
598
     */
23✔
599
    getManyToManyMetadata(
23✔
600
        entityTarget: EntityTarget<any>,
35✔
601
        relationPropertyPath: string,
35✔
602
    ) {
35✔
603
        const relationMetadata =
35✔
604
            this.getMetadata(entityTarget).findRelationWithPropertyPath(
35✔
605
                relationPropertyPath,
35✔
606
            )
35✔
607
        if (!relationMetadata)
35✔
608
            throw new TypeORMError(
35!
609
                `Relation "${relationPropertyPath}" was not found in ${entityTarget} entity.`,
×
610
            )
×
611
        if (!relationMetadata.isManyToMany)
35✔
612
            throw new TypeORMError(
35!
613
                `Relation "${entityTarget}#${relationPropertyPath}" does not have a many-to-many relationship.` +
×
614
                    `You can use this method only on many-to-many relations.`,
×
615
            )
×
616

35✔
617
        return relationMetadata.junctionEntityMetadata
35✔
618
    }
35✔
619

23✔
620
    /**
23✔
621
     * Creates an Entity Manager for the current connection with the help of the EntityManagerFactory.
23✔
622
     * @param queryRunner
23✔
623
     */
23✔
624
    createEntityManager(queryRunner?: QueryRunner): EntityManager {
23✔
625
        return new EntityManagerFactory().create(this, queryRunner)
329,560✔
626
    }
329,560✔
627

23✔
628
    // -------------------------------------------------------------------------
23✔
629
    // Protected Methods
23✔
630
    // -------------------------------------------------------------------------
23✔
631

23✔
632
    /**
23✔
633
     * Finds exist entity metadata by the given entity class, target name or table name.
23✔
634
     * @param target
23✔
635
     */
23✔
636
    protected findMetadata(
23✔
637
        target: EntityTarget<any>,
4,851,838✔
638
    ): EntityMetadata | undefined {
4,851,838✔
639
        const metadataFromMap = this.entityMetadatasMap.get(target)
4,851,838✔
640
        if (metadataFromMap) return metadataFromMap
4,851,838✔
641

782,915✔
642
        for (const [_, metadata] of this.entityMetadatasMap) {
4,851,838✔
643
            if (
4,819,459✔
644
                InstanceChecker.isEntitySchema(target) &&
4,819,459✔
645
                metadata.name === target.options.name
1,055✔
646
            ) {
4,819,459✔
647
                return metadata
794✔
648
            }
794✔
649
            if (typeof target === "string") {
4,819,459!
650
                if (target.indexOf(".") !== -1) {
4,801,092✔
651
                    if (metadata.tablePath === target) {
4,555,014!
652
                        return metadata
308✔
653
                    }
308✔
654
                } else {
4,801,092✔
655
                    if (
246,078✔
656
                        metadata.name === target ||
246,078✔
657
                        metadata.tableName === target
205,813✔
658
                    ) {
246,078✔
659
                        return metadata
104,385✔
660
                    }
104,385✔
661
                }
246,078✔
662
            }
4,801,092✔
663
            if (
4,713,972✔
664
                ObjectUtils.isObjectWithName(target) &&
4,713,972!
665
                typeof target.name === "string"
×
666
            ) {
4,819,459!
667
                if (target.name.indexOf(".") !== -1) {
×
668
                    if (metadata.tablePath === target.name) {
×
669
                        return metadata
×
670
                    }
×
671
                } else {
×
672
                    if (
×
673
                        metadata.name === target.name ||
×
674
                        metadata.tableName === target.name
×
675
                    ) {
×
676
                        return metadata
×
677
                    }
×
678
                }
×
679
            }
×
680
        }
4,819,459✔
681

677,428!
682
        return undefined
677,428✔
683
    }
677,428✔
684

23✔
685
    /**
23✔
686
     * Builds metadatas for all registered classes inside this connection.
23✔
687
     */
23✔
688
    protected async buildMetadatas(): Promise<void> {
23✔
689
        const connectionMetadataBuilder = new ConnectionMetadataBuilder(this)
13,231✔
690
        const entityMetadataValidator = new EntityMetadataValidator()
13,231✔
691

13,231✔
692
        // create subscribers instances if they are not disallowed from high-level (for example they can disallowed from migrations run process)
13,231✔
693
        const flattenedSubscribers = ObjectUtils.mixedListToArray(
13,231✔
694
            this.options.subscribers || [],
13,231!
695
        )
13,231✔
696
        const subscribers =
13,231✔
697
            await connectionMetadataBuilder.buildSubscribers(
13,231✔
698
                flattenedSubscribers,
13,231✔
699
            )
13,231✔
700
        ObjectUtils.assign(this, { subscribers: subscribers })
13,231✔
701

13,231✔
702
        // build entity metadatas
13,231✔
703
        const flattenedEntities = ObjectUtils.mixedListToArray(
13,231✔
704
            this.options.entities || [],
13,231!
705
        )
13,231✔
706
        const entityMetadatas =
13,231✔
707
            await connectionMetadataBuilder.buildEntityMetadatas(
13,231✔
708
                flattenedEntities,
13,231✔
709
            )
13,231✔
710
        ObjectUtils.assign(this, {
13,223✔
711
            entityMetadatas: entityMetadatas,
13,223✔
712
            entityMetadatasMap: new Map(
13,223✔
713
                entityMetadatas.map((metadata) => [metadata.target, metadata]),
13,223✔
714
            ),
13,223✔
715
        })
13,223✔
716

13,223✔
717
        // create migration instances
13,223✔
718
        const flattenedMigrations = ObjectUtils.mixedListToArray(
13,223✔
719
            this.options.migrations || [],
13,231!
720
        )
13,231✔
721
        const migrations =
13,231✔
722
            await connectionMetadataBuilder.buildMigrations(flattenedMigrations)
13,231✔
723
        ObjectUtils.assign(this, { migrations: migrations })
13,223✔
724

13,223✔
725
        // validate all created entity metadatas to make sure user created entities are valid and correct
13,223✔
726
        entityMetadataValidator.validateMany(
13,223✔
727
            this.entityMetadatas.filter(
13,223✔
728
                (metadata) => metadata.tableType !== "view",
13,223✔
729
            ),
13,223✔
730
            this.driver,
13,223✔
731
        )
13,223✔
732

13,223✔
733
        // set current data source to the entities
13,223✔
734
        for (const entityMetadata of entityMetadatas) {
13,231✔
735
            if (
34,182✔
736
                InstanceChecker.isBaseEntityConstructor(entityMetadata.target)
34,182✔
737
            ) {
34,182!
738
                entityMetadata.target.useDataSource(this)
1,089✔
739
            }
1,089✔
740
        }
34,182✔
741
    }
13,179✔
742

23✔
743
    /**
23✔
744
     * Get the replication mode SELECT queries should use for this datasource by default
23✔
745
     */
23✔
746
    defaultReplicationModeForReads(): ReplicationMode {
23✔
747
        if (
45,463✔
748
            "replication" in this.driver.options &&
45,463!
749
            this.driver.options.replication
16✔
750
        ) {
45,463!
751
            const value = (
8✔
752
                this.driver.options.replication as {
8✔
753
                    defaultMode?: ReplicationMode
8✔
754
                }
8✔
755
            ).defaultMode
8✔
756
            if (value) {
8✔
757
                return value
4✔
758
            }
4✔
759
        }
8✔
760
        return "slave"
45,459✔
761
    }
45,459✔
762
}
23✔
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