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

typeorm / typeorm / 19549987525

20 Nov 2025 08:11PM UTC coverage: 80.769% (+4.3%) from 76.433%
19549987525

push

github

web-flow
ci: run tests on commits to master and next (#11783)

Co-authored-by: Oleg "OSA413" Sokolov <OSA413@users.noreply.github.com>

26500 of 32174 branches covered (82.36%)

Branch coverage included in aggregate %.

91252 of 113615 relevant lines covered (80.32%)

88980.79 hits per line

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

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

26✔
46
registerQueryBuilders()
26✔
47

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

26✔
59
    // -------------------------------------------------------------------------
26✔
60
    // Public Readonly Properties
26✔
61
    // -------------------------------------------------------------------------
26✔
62

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

26✔
70
    /**
26✔
71
     * Connection options.
26✔
72
     */
26✔
73
    readonly options: DataSourceOptions
26✔
74

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

26✔
80
    /**
26✔
81
     * Database driver used by this connection.
26✔
82
     */
26✔
83
    driver: Driver
26✔
84

26✔
85
    /**
26✔
86
     * EntityManager of this connection.
26✔
87
     */
26✔
88
    readonly manager: EntityManager
26✔
89

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

26✔
95
    /**
26✔
96
     * Name for the metadata table
26✔
97
     */
26✔
98
    readonly metadataTableName: string
26✔
99

26✔
100
    /**
26✔
101
     * Logger used to log orm events.
26✔
102
     */
26✔
103
    logger: Logger
26✔
104

26✔
105
    /**
26✔
106
     * Migration instances that are registered for this connection.
26✔
107
     */
26✔
108
    readonly migrations: MigrationInterface[] = []
26✔
109

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

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

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

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

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

26✔
136
    readonly relationIdLoader: RelationIdLoader
26✔
137

26✔
138
    // -------------------------------------------------------------------------
26✔
139
    // Constructor
26✔
140
    // -------------------------------------------------------------------------
26✔
141

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

26✔
163
    // -------------------------------------------------------------------------
26✔
164
    // Public Accessors
26✔
165
    // -------------------------------------------------------------------------
26✔
166

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

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

10✔
188
        return this.manager as MongoEntityManager
10✔
189
    }
10✔
190

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

15✔
202
        return this.manager
15✔
203
    }
15✔
204

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

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

77✔
221
        if (options.namingStrategy) {
77!
222
            this.namingStrategy = options.namingStrategy
×
223
        }
×
224

77✔
225
        if (options.cache) {
77!
226
            this.queryResultCache = new QueryResultCacheFactory(this).create()
×
227
        }
×
228

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

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

77✔
240
        return this
77✔
241
    }
77✔
242

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

14,395✔
253
        // connect to the database via its driver
14,395✔
254
        await this.driver.connect()
14,395✔
255

14,395✔
256
        // connect to the cache-specific database if cache is enabled
14,395✔
257
        if (this.queryResultCache) await this.queryResultCache.connect()
14,423!
258

14,395✔
259
        // set connected status for the current connection
14,395✔
260
        ObjectUtils.assign(this, { isInitialized: true })
14,395✔
261

14,395✔
262
        try {
14,395✔
263
            // build all metadatas registered in the current connection
14,395✔
264
            await this.buildMetadatas()
14,395✔
265

14,337✔
266
            await this.driver.afterConnect()
14,337✔
267

14,337✔
268
            // if option is set - drop schema once connection is done
14,337✔
269
            if (this.options.dropSchema) await this.dropDatabase()
14,423✔
270

14,337✔
271
            // if option is set - automatically synchronize a schema
14,337✔
272
            if (this.options.migrationsRun)
14,337✔
273
                await this.runMigrations({
14,423!
274
                    transaction: this.options.migrationsTransactionMode,
×
275
                })
×
276

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

14,337✔
286
        return this
14,337✔
287
    }
14,337✔
288

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

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

14,389✔
309
        await this.driver.disconnect()
14,389✔
310

14,389✔
311
        // disconnect from the cache-specific database if cache was enabled
14,389✔
312
        if (this.queryResultCache) await this.queryResultCache.disconnect()
14,421!
313

14,389✔
314
        ObjectUtils.assign(this, { isInitialized: false })
14,389✔
315
    }
14,389✔
316

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

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

40,567✔
337
        if (dropBeforeSync) await this.dropDatabase()
40,571✔
338

40,567✔
339
        const schemaBuilder = this.driver.createSchemaBuilder()
40,567✔
340
        await schemaBuilder.build()
40,567✔
341
    }
40,565✔
342

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

26,264✔
370
                if (databases.length === 0) {
26,264!
371
                    await queryRunner.clearDatabase()
3,741✔
372
                } else {
26,264✔
373
                    for (const database of databases) {
22,523✔
374
                        await queryRunner.clearDatabase(database)
22,547✔
375
                    }
22,547✔
376
                }
22,523✔
377
            } else {
39,986!
378
                await queryRunner.clearDatabase()
13,722✔
379
            }
13,722✔
380
        } finally {
39,986✔
381
            await queryRunner.release()
39,986✔
382
        }
39,986✔
383
    }
39,986✔
384

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

221✔
396
        const migrationExecutor = new MigrationExecutor(this)
221✔
397
        migrationExecutor.transaction =
221✔
398
            options?.transaction ||
221!
399
            this.options?.migrationsTransactionMode ||
221✔
400
            "all"
103✔
401
        migrationExecutor.fake = (options && options.fake) || false
221!
402

221✔
403
        const successMigrations =
221✔
404
            await migrationExecutor.executePendingMigrations()
221✔
405
        return successMigrations
153✔
406
    }
153✔
407

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

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

58✔
424
        await migrationExecutor.undoLastMigration()
58✔
425
    }
30✔
426

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

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

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

4,661,370✔
453
        return metadata
4,661,370✔
454
    }
4,661,370✔
455

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

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

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

88✔
487
        return this.manager.getRepository(target) as any
88✔
488
    }
88✔
489

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

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

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

1,268✔
535
        if (queryRunner && queryRunner.isReleased)
1,268✔
536
            throw new QueryRunnerProviderAlreadyReleasedError()
1,268!
537

1,268✔
538
        const usedQueryRunner = queryRunner || this.createQueryRunner()
1,268✔
539

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

26✔
547
    /**
26✔
548
     * Tagged template function that executes raw SQL query and returns raw database results.
26✔
549
     * Template expressions are automatically transformed into database parameters.
26✔
550
     * Raw query execution is supported only by relational databases (MongoDB is not supported).
26✔
551
     * Note: Don't call this as a regular function, it is meant to be used with backticks to tag a template literal.
26✔
552
     * Example: dataSource.sql`SELECT * FROM table_name WHERE id = ${id}`
26✔
553
     */
26✔
554
    async sql<T = any>(
26✔
555
        strings: TemplateStringsArray,
120✔
556
        ...values: unknown[]
120✔
557
    ): Promise<T> {
120✔
558
        const { query, parameters } = buildSqlTag({
120✔
559
            driver: this.driver,
120✔
560
            strings: strings,
120✔
561
            expressions: values,
120✔
562
        })
120✔
563

120✔
564
        return await this.query(query, parameters)
120✔
565
    }
120✔
566

26✔
567
    /**
26✔
568
     * Creates a new query builder that can be used to build a SQL query.
26✔
569
     */
26✔
570
    createQueryBuilder<Entity extends ObjectLiteral>(
26✔
571
        entityClass: EntityTarget<Entity>,
26✔
572
        alias: string,
26✔
573
        queryRunner?: QueryRunner,
26✔
574
    ): SelectQueryBuilder<Entity>
26✔
575

26✔
576
    /**
26✔
577
     * Creates a new query builder that can be used to build a SQL query.
26✔
578
     */
26✔
579
    createQueryBuilder(queryRunner?: QueryRunner): SelectQueryBuilder<any>
26✔
580

26✔
581
    /**
26✔
582
     * Creates a new query builder that can be used to build a SQL query.
26✔
583
     */
26✔
584
    createQueryBuilder<Entity extends ObjectLiteral>(
26✔
585
        entityOrRunner?: EntityTarget<Entity> | QueryRunner,
783,584✔
586
        alias?: string,
783,584✔
587
        queryRunner?: QueryRunner,
783,584✔
588
    ): SelectQueryBuilder<Entity> {
783,584✔
589
        if (InstanceChecker.isMongoEntityManager(this.manager))
783,584✔
590
            throw new TypeORMError(`Query Builder is not supported by MongoDB.`)
783,584!
591

783,584✔
592
        if (alias) {
783,584✔
593
            alias = DriverUtils.buildAlias(this.driver, undefined, alias)
488,165✔
594
            const metadata = this.getMetadata(
488,165✔
595
                entityOrRunner as EntityTarget<Entity>,
488,165✔
596
            )
488,165✔
597
            return new SelectQueryBuilder(this, queryRunner)
488,165✔
598
                .select(alias)
488,165✔
599
                .from(metadata.target, alias)
488,165✔
600
        } else {
783,584✔
601
            return new SelectQueryBuilder(
295,419✔
602
                this,
295,419✔
603
                entityOrRunner as QueryRunner | undefined,
295,419✔
604
            )
295,419✔
605
        }
295,419✔
606
    }
783,584✔
607

26✔
608
    /**
26✔
609
     * Creates a query runner used for perform queries on a single database connection.
26✔
610
     * Using query runners you can control your queries to execute using single database connection and
26✔
611
     * manually control your database transaction.
26✔
612
     *
26✔
613
     * Mode is used in replication mode and indicates whatever you want to connect
26✔
614
     * to master database or any of slave databases.
26✔
615
     * If you perform writes you must use master database,
26✔
616
     * if you perform reads you can use slave databases.
26✔
617
     */
26✔
618
    createQueryRunner(mode: ReplicationMode = "master"): QueryRunner {
26✔
619
        const queryRunner = this.driver.createQueryRunner(mode)
337,618✔
620
        const manager = this.createEntityManager(queryRunner)
337,618✔
621
        Object.assign(queryRunner, { manager: manager })
337,618✔
622
        return queryRunner
337,618✔
623
    }
337,618✔
624

26✔
625
    /**
26✔
626
     * Gets entity metadata of the junction table (many-to-many table).
26✔
627
     */
26✔
628
    getManyToManyMetadata(
26✔
629
        entityTarget: EntityTarget<any>,
38✔
630
        relationPropertyPath: string,
38✔
631
    ) {
38✔
632
        const relationMetadata =
38✔
633
            this.getMetadata(entityTarget).findRelationWithPropertyPath(
38✔
634
                relationPropertyPath,
38✔
635
            )
38✔
636
        if (!relationMetadata)
38✔
637
            throw new TypeORMError(
38!
638
                `Relation "${relationPropertyPath}" was not found in ${entityTarget} entity.`,
×
639
            )
×
640
        if (!relationMetadata.isManyToMany)
38✔
641
            throw new TypeORMError(
38!
642
                `Relation "${entityTarget}#${relationPropertyPath}" does not have a many-to-many relationship.` +
×
643
                    `You can use this method only on many-to-many relations.`,
×
644
            )
×
645

38✔
646
        return relationMetadata.junctionEntityMetadata
38✔
647
    }
38✔
648

26✔
649
    /**
26✔
650
     * Creates an Entity Manager for the current connection with the help of the EntityManagerFactory.
26✔
651
     */
26✔
652
    createEntityManager(queryRunner?: QueryRunner): EntityManager {
26✔
653
        return new EntityManagerFactory().create(this, queryRunner)
352,443✔
654
    }
352,443✔
655

26✔
656
    // -------------------------------------------------------------------------
26✔
657
    // Protected Methods
26✔
658
    // -------------------------------------------------------------------------
26✔
659

26✔
660
    /**
26✔
661
     * Finds exist entity metadata by the given entity class, target name or table name.
26✔
662
     */
26✔
663
    protected findMetadata(
26✔
664
        target: EntityTarget<any>,
5,609,480✔
665
    ): EntityMetadata | undefined {
5,609,480✔
666
        const metadataFromMap = this.entityMetadatasMap.get(target)
5,609,480✔
667
        if (metadataFromMap) return metadataFromMap
5,609,480✔
668

135,458✔
669
        for (const [_, metadata] of this.entityMetadatasMap) {
5,609,480✔
670
            if (
304,811✔
671
                InstanceChecker.isEntitySchema(target) &&
304,811✔
672
                metadata.name === target.options.name
1,197✔
673
            ) {
304,811✔
674
                return metadata
878✔
675
            }
878✔
676
            if (typeof target === "string") {
304,811!
677
                if (target.indexOf(".") !== -1) {
296,008✔
678
                    if (metadata.tablePath === target) {
31,885!
679
                        return metadata
384✔
680
                    }
384✔
681
                } else {
296,008✔
682
                    if (
264,123✔
683
                        metadata.name === target ||
264,123✔
684
                        metadata.tableName === target
221,121✔
685
                    ) {
264,123✔
686
                        return metadata
116,414✔
687
                    }
116,414✔
688
                }
264,123✔
689
            }
296,008✔
690
            if (
187,135✔
691
                ObjectUtils.isObjectWithName(target) &&
187,135!
692
                typeof target.name === "string"
×
693
            ) {
304,811!
694
                if (target.name.indexOf(".") !== -1) {
×
695
                    if (metadata.tablePath === target.name) {
×
696
                        return metadata
×
697
                    }
×
698
                } else {
×
699
                    if (
×
700
                        metadata.name === target.name ||
×
701
                        metadata.tableName === target.name
×
702
                    ) {
×
703
                        return metadata
×
704
                    }
×
705
                }
×
706
            }
×
707
        }
304,811✔
708

17,782!
709
        return undefined
17,782✔
710
    }
17,782✔
711

26✔
712
    /**
26✔
713
     * Builds metadatas for all registered classes inside this connection.
26✔
714
     */
26✔
715
    protected async buildMetadatas(): Promise<void> {
26✔
716
        const connectionMetadataBuilder = new ConnectionMetadataBuilder(this)
14,395✔
717
        const entityMetadataValidator = new EntityMetadataValidator()
14,395✔
718

14,395✔
719
        // create subscribers instances if they are not disallowed from high-level (for example they can disallowed from migrations run process)
14,395✔
720
        const flattenedSubscribers = ObjectUtils.mixedListToArray(
14,395✔
721
            this.options.subscribers || [],
14,395!
722
        )
14,395✔
723
        const subscribers = await connectionMetadataBuilder.buildSubscribers(
14,395✔
724
            flattenedSubscribers,
14,395✔
725
        )
14,395✔
726
        ObjectUtils.assign(this, { subscribers: subscribers })
14,395✔
727

14,395✔
728
        // build entity metadatas
14,395✔
729
        const flattenedEntities = ObjectUtils.mixedListToArray(
14,395✔
730
            this.options.entities || [],
14,395!
731
        )
14,395✔
732
        const entityMetadatas =
14,395✔
733
            await connectionMetadataBuilder.buildEntityMetadatas(
14,395✔
734
                flattenedEntities,
14,395✔
735
            )
14,395✔
736
        ObjectUtils.assign(this, {
14,387✔
737
            entityMetadatas: entityMetadatas,
14,387✔
738
            entityMetadatasMap: new Map(
14,387✔
739
                entityMetadatas.map((metadata) => [metadata.target, metadata]),
14,387✔
740
            ),
14,387✔
741
        })
14,387✔
742

14,387✔
743
        // create migration instances
14,387✔
744
        const flattenedMigrations = ObjectUtils.mixedListToArray(
14,387✔
745
            this.options.migrations || [],
14,395!
746
        )
14,395✔
747
        const migrations = await connectionMetadataBuilder.buildMigrations(
14,395✔
748
            flattenedMigrations,
14,395✔
749
        )
14,395✔
750
        ObjectUtils.assign(this, { migrations: migrations })
14,387✔
751

14,387✔
752
        // validate all created entity metadatas to make sure user created entities are valid and correct
14,387✔
753
        entityMetadataValidator.validateMany(
14,387✔
754
            this.entityMetadatas.filter(
14,387✔
755
                (metadata) => metadata.tableType !== "view",
14,387✔
756
            ),
14,387✔
757
            this.driver,
14,387✔
758
        )
14,387✔
759

14,387✔
760
        // set current data source to the entities
14,387✔
761
        for (const entityMetadata of entityMetadatas) {
14,395✔
762
            if (
35,994✔
763
                InstanceChecker.isBaseEntityConstructor(entityMetadata.target)
35,994✔
764
            ) {
35,994!
765
                entityMetadata.target.useDataSource(this)
1,198✔
766
            }
1,198✔
767
        }
35,994✔
768
    }
14,337✔
769

26✔
770
    /**
26✔
771
     * Get the replication mode SELECT queries should use for this datasource by default
26✔
772
     */
26✔
773
    defaultReplicationModeForReads(): ReplicationMode {
26✔
774
        if (
48,269✔
775
            "replication" in this.driver.options &&
48,269!
776
            this.driver.options.replication
16✔
777
        ) {
48,269!
778
            const value = (
8✔
779
                this.driver.options.replication as {
8✔
780
                    defaultMode?: ReplicationMode
8✔
781
                }
8✔
782
            ).defaultMode
8✔
783
            if (value) {
8✔
784
                return value
4✔
785
            }
4✔
786
        }
8✔
787
        return "slave"
48,265✔
788
    }
48,265✔
789
}
26✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc