• 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

94.01
/src/query-runner/BaseQueryRunner.ts
1
import { PostgresConnectionOptions } from "../driver/postgres/PostgresConnectionOptions"
26✔
2
import { Query } from "../driver/Query"
26✔
3
import { SqlInMemory } from "../driver/SqlInMemory"
26✔
4
import { SqlServerConnectionOptions } from "../driver/sqlserver/SqlServerConnectionOptions"
26✔
5
import { TableIndex } from "../schema-builder/table/TableIndex"
26✔
6
import { View } from "../schema-builder/view/View"
26✔
7
import { DataSource } from "../data-source/DataSource"
26✔
8
import { Table } from "../schema-builder/table/Table"
26✔
9
import { EntityManager } from "../entity-manager/EntityManager"
26✔
10
import { TableColumn } from "../schema-builder/table/TableColumn"
26✔
11
import { Broadcaster } from "../subscriber/Broadcaster"
26✔
12
import { ReplicationMode } from "../driver/types/ReplicationMode"
26✔
13
import { TypeORMError } from "../error/TypeORMError"
26✔
14
import { EntityMetadata } from "../metadata/EntityMetadata"
26✔
15
import { TableForeignKey } from "../schema-builder/table/TableForeignKey"
26✔
16
import { OrmUtils } from "../util/OrmUtils"
26✔
17
import { MetadataTableType } from "../driver/types/MetadataTableType"
26✔
18
import { InstanceChecker } from "../util/InstanceChecker"
26✔
19
import { buildSqlTag } from "../util/SqlTagUtils"
26✔
20

26✔
21
export abstract class BaseQueryRunner {
244,340✔
22
    // -------------------------------------------------------------------------
244,340✔
23
    // Public Properties
244,340✔
24
    // -------------------------------------------------------------------------
244,340✔
25

244,340✔
26
    /**
244,340✔
27
     * Connection used by this query runner.
244,340✔
28
     */
244,340✔
29
    connection: DataSource
244,340✔
30

244,340✔
31
    /**
244,340✔
32
     * Entity manager working only with current query runner.
244,340✔
33
     */
244,340✔
34
    manager: EntityManager
244,340✔
35

244,340✔
36
    /**
244,340✔
37
     * Indicates if connection for this query runner is released.
244,340✔
38
     * Once its released, query runner cannot run queries anymore.
244,340✔
39
     */
244,340✔
40
    isReleased = false
244,340✔
41

244,340✔
42
    /**
244,340✔
43
     * Indicates if transaction is in progress.
244,340✔
44
     */
244,340✔
45
    isTransactionActive = false
244,340✔
46

244,340✔
47
    /**
244,340✔
48
     * Stores temporarily user data.
244,340✔
49
     * Useful for sharing data with subscribers.
244,340✔
50
     */
244,340✔
51
    data = {}
244,340✔
52

244,340✔
53
    /**
244,340✔
54
     * All synchronized tables in the database.
244,340✔
55
     */
244,340✔
56
    loadedTables: Table[] = []
244,340✔
57

244,340✔
58
    /**
244,340✔
59
     * All synchronized views in the database.
244,340✔
60
     */
244,340✔
61
    loadedViews: View[] = []
244,340✔
62

244,340✔
63
    /**
244,340✔
64
     * Broadcaster used on this query runner to broadcast entity events.
244,340✔
65
     */
244,340✔
66
    broadcaster: Broadcaster
244,340✔
67

244,340✔
68
    // -------------------------------------------------------------------------
244,340✔
69
    // Protected Properties
244,340✔
70
    // -------------------------------------------------------------------------
244,340✔
71

244,340✔
72
    /**
244,340✔
73
     * Real database connection from a connection pool used to perform queries.
244,340✔
74
     */
244,340✔
75
    protected databaseConnection: any
244,340✔
76

244,340✔
77
    /**
244,340✔
78
     * Indicates if special query runner mode in which sql queries won't be executed is enabled.
244,340✔
79
     */
244,340✔
80
    protected sqlMemoryMode: boolean = false
244,340✔
81

244,340✔
82
    /**
244,340✔
83
     * Sql-s stored if "sql in memory" mode is enabled.
244,340✔
84
     */
244,340✔
85
    protected sqlInMemory: SqlInMemory = new SqlInMemory()
244,340✔
86

244,340✔
87
    /**
244,340✔
88
     * Mode in which query runner executes.
244,340✔
89
     * Used for replication.
244,340✔
90
     * If replication is not setup its value is ignored.
244,340✔
91
     */
244,340✔
92
    protected mode: ReplicationMode
244,340✔
93

244,340✔
94
    /**
244,340✔
95
     * current depth of transaction.
244,340✔
96
     * for transactionDepth > 0 will use SAVEPOINT to start and commit/rollback transaction blocks
244,340✔
97
     */
244,340✔
98
    protected transactionDepth = 0
244,340✔
99

244,340✔
100
    private cachedTablePaths: Record<string, string> = {}
244,340✔
101

244,340✔
102
    // -------------------------------------------------------------------------
244,340✔
103
    // Public Abstract Methods
244,340✔
104
    // -------------------------------------------------------------------------
244,340✔
105

244,340✔
106
    /**
244,340✔
107
     * Executes a given SQL query.
244,340✔
108
     */
244,340✔
109
    abstract query(
244,340✔
110
        query: string,
244,340✔
111
        parameters?: any[],
244,340✔
112
        useStructuredResult?: boolean,
244,340✔
113
    ): Promise<any>
244,340✔
114

244,340✔
115
    /**
244,340✔
116
     * Tagged template function that executes raw SQL query and returns raw database results.
244,340✔
117
     * Template expressions are automatically transformed into database parameters.
244,340✔
118
     * Raw query execution is supported only by relational databases (MongoDB is not supported).
244,340✔
119
     * Note: Don't call this as a regular function, it is meant to be used with backticks to tag a template literal.
244,340✔
120
     * Example: queryRunner.sql`SELECT * FROM table_name WHERE id = ${id}`
244,340✔
121
     */
244,340✔
122
    async sql<T = any>(
244,340✔
123
        strings: TemplateStringsArray,
6✔
124
        ...values: unknown[]
6✔
125
    ): Promise<T> {
6✔
126
        const { query, parameters } = buildSqlTag({
6✔
127
            driver: this.connection.driver,
6✔
128
            strings: strings,
6✔
129
            expressions: values,
6✔
130
        })
6✔
131

6✔
132
        return await this.query(query, parameters)
6✔
133
    }
6✔
134

244,340✔
135
    // -------------------------------------------------------------------------
244,340✔
136
    // Protected Abstract Methods
244,340✔
137
    // -------------------------------------------------------------------------
244,340✔
138

244,340✔
139
    protected abstract loadTables(tablePaths?: string[]): Promise<Table[]>
244,340✔
140

244,340✔
141
    protected abstract loadViews(tablePaths?: string[]): Promise<View[]>
244,340✔
142

244,340✔
143
    // -------------------------------------------------------------------------
244,340✔
144
    // Public Methods
244,340✔
145
    // -------------------------------------------------------------------------
244,340✔
146

244,340✔
147
    /**
244,340✔
148
     * Called before migrations are run.
244,340✔
149
     */
244,340✔
150
    async beforeMigration(): Promise<void> {
244,340✔
151
        // Do nothing
28,718✔
152
    }
28,718✔
153

244,340✔
154
    /**
244,340✔
155
     * Called after migrations are run.
244,340✔
156
     */
244,340✔
157
    async afterMigration(): Promise<void> {
244,340✔
158
        // Do nothing
28,657✔
159
    }
28,657✔
160

244,340✔
161
    /**
244,340✔
162
     * Loads given table's data from the database.
244,340✔
163
     */
244,340✔
164
    async getTable(tablePath: string): Promise<Table | undefined> {
244,340✔
165
        this.loadedTables = await this.loadTables([tablePath])
6,599✔
166
        return this.loadedTables.length > 0 ? this.loadedTables[0] : undefined
6,599✔
167
    }
6,599✔
168

244,340✔
169
    /**
244,340✔
170
     * Loads all tables (with given names) from the database.
244,340✔
171
     */
244,340✔
172
    async getTables(tableNames?: string[]): Promise<Table[]> {
244,340✔
173
        if (!tableNames) {
41,790!
174
            // Don't cache in this case.
6✔
175
            // This is the new case & isn't used anywhere else anyway.
6✔
176
            return await this.loadTables(tableNames)
6✔
177
        }
6✔
178

41,784✔
179
        this.loadedTables = await this.loadTables(tableNames)
41,784✔
180
        return this.loadedTables
41,784✔
181
    }
41,784✔
182

244,340✔
183
    /**
244,340✔
184
     * Loads given view's data from the database.
244,340✔
185
     */
244,340✔
186
    async getView(viewPath: string): Promise<View | undefined> {
244,340✔
187
        this.loadedViews = await this.loadViews([viewPath])
170✔
188
        return this.loadedViews.length > 0 ? this.loadedViews[0] : undefined
170!
189
    }
170✔
190

244,340✔
191
    /**
244,340✔
192
     * Loads given view's data from the database.
244,340✔
193
     */
244,340✔
194
    async getViews(viewPaths?: string[]): Promise<View[]> {
244,340✔
195
        this.loadedViews = await this.loadViews(viewPaths)
41,752✔
196
        return this.loadedViews
41,752✔
197
    }
41,752✔
198

244,340✔
199
    /**
244,340✔
200
     * Enables special query runner mode in which sql queries won't be executed,
244,340✔
201
     * instead they will be memorized into a special variable inside query runner.
244,340✔
202
     * You can get memorized sql using getMemorySql() method.
244,340✔
203
     */
244,340✔
204
    enableSqlMemory(): void {
244,340✔
205
        this.sqlInMemory = new SqlInMemory()
963✔
206
        this.sqlMemoryMode = true
963✔
207
    }
963✔
208

244,340✔
209
    /**
244,340✔
210
     * Disables special query runner mode in which sql queries won't be executed
244,340✔
211
     * started by calling enableSqlMemory() method.
244,340✔
212
     *
244,340✔
213
     * Previously memorized sql will be flushed.
244,340✔
214
     */
244,340✔
215
    disableSqlMemory(): void {
244,340✔
216
        this.sqlInMemory = new SqlInMemory()
963✔
217
        this.sqlMemoryMode = false
963✔
218
    }
963✔
219

244,340✔
220
    /**
244,340✔
221
     * Flushes all memorized sqls.
244,340✔
222
     */
244,340✔
223
    clearSqlMemory(): void {
244,340✔
224
        this.sqlInMemory = new SqlInMemory()
107,217✔
225
    }
107,217✔
226

244,340✔
227
    /**
244,340✔
228
     * Gets sql stored in the memory. Parameters in the sql are already replaced.
244,340✔
229
     */
244,340✔
230
    getMemorySql(): SqlInMemory {
244,340✔
231
        return this.sqlInMemory
967✔
232
    }
967✔
233

244,340✔
234
    /**
244,340✔
235
     * Executes up sql queries.
244,340✔
236
     */
244,340✔
237
    async executeMemoryUpSql(): Promise<void> {
244,340✔
238
        for (const { query, parameters } of this.sqlInMemory.upQueries) {
×
239
            await this.query(query, parameters)
×
240
        }
×
241
    }
×
242

244,340✔
243
    /**
244,340✔
244
     * Executes down sql queries.
244,340✔
245
     */
244,340✔
246
    async executeMemoryDownSql(): Promise<void> {
244,340✔
247
        for (const {
1,020✔
248
            query,
1,020✔
249
            parameters,
1,020✔
250
        } of this.sqlInMemory.downQueries.reverse()) {
1,020✔
251
            await this.query(query, parameters)
4,158✔
252
        }
4,158✔
253
    }
1,020✔
254

244,340✔
255
    getReplicationMode(): ReplicationMode {
244,340✔
256
        return this.mode
428✔
257
    }
428✔
258

244,340✔
259
    // -------------------------------------------------------------------------
244,340✔
260
    // Protected Methods
244,340✔
261
    // -------------------------------------------------------------------------
244,340✔
262

244,340✔
263
    /**
244,340✔
264
     * Gets view from previously loaded views, otherwise loads it from database.
244,340✔
265
     */
244,340✔
266
    protected async getCachedView(viewName: string): Promise<View> {
244,340✔
267
        const view = this.loadedViews.find((view) => view.name === viewName)
36✔
268
        if (view) return view
36✔
269

×
270
        const foundViews = await this.loadViews([viewName])
×
271
        if (foundViews.length > 0) {
×
272
            this.loadedViews.push(foundViews[0])
×
273
            return foundViews[0]
×
274
        } else {
×
275
            throw new TypeORMError(`View "${viewName}" does not exist.`)
×
276
        }
×
277
    }
36✔
278

244,340✔
279
    /**
244,340✔
280
     * Gets table from previously loaded tables, otherwise loads it from database.
244,340✔
281
     */
244,340✔
282
    protected async getCachedTable(tableName: string): Promise<Table> {
244,340✔
283
        if (tableName in this.cachedTablePaths) {
1,582✔
284
            const tablePath = this.cachedTablePaths[tableName]
441✔
285
            const table = this.loadedTables.find(
441✔
286
                (table) => this.getTablePath(table) === tablePath,
441✔
287
            )
441✔
288

441✔
289
            if (table) {
441✔
290
                return table
423✔
291
            }
423✔
292
        }
441✔
293

1,159✔
294
        const foundTables = await this.loadTables([tableName])
1,159✔
295

1,159✔
296
        if (foundTables.length > 0) {
1,159✔
297
            const foundTablePath = this.getTablePath(foundTables[0])
1,159✔
298

1,159✔
299
            const cachedTable = this.loadedTables.find(
1,159✔
300
                (table) => this.getTablePath(table) === foundTablePath,
1,159✔
301
            )
1,159✔
302

1,159✔
303
            if (!cachedTable) {
1,159✔
304
                this.cachedTablePaths[tableName] = this.getTablePath(
852✔
305
                    foundTables[0],
852✔
306
                )
852✔
307
                this.loadedTables.push(foundTables[0])
852✔
308
                return foundTables[0]
852✔
309
            } else {
1,159✔
310
                return cachedTable
307✔
311
            }
307✔
312
        } else {
1,582!
313
            throw new TypeORMError(`Table "${tableName}" does not exist.`)
×
314
        }
×
315
    }
1,582✔
316

244,340✔
317
    /**
244,340✔
318
     * Replaces loaded table with given changed table.
244,340✔
319
     */
244,340✔
320
    protected replaceCachedTable(table: Table, changedTable: Table): void {
244,340✔
321
        const oldTablePath = this.getTablePath(table)
18,666✔
322
        const foundTable = this.loadedTables.find(
18,666✔
323
            (loadedTable) => this.getTablePath(loadedTable) === oldTablePath,
18,666✔
324
        )
18,666✔
325

18,666✔
326
        // Clean up the lookup cache..
18,666✔
327
        for (const [key, cachedPath] of Object.entries(this.cachedTablePaths)) {
18,666✔
328
            if (cachedPath === oldTablePath) {
815✔
329
                this.cachedTablePaths[key] = this.getTablePath(changedTable)
379✔
330
            }
379✔
331
        }
815✔
332

18,666✔
333
        if (foundTable) {
18,666✔
334
            foundTable.database = changedTable.database
18,666✔
335
            foundTable.schema = changedTable.schema
18,666✔
336
            foundTable.name = changedTable.name
18,666✔
337
            foundTable.columns = changedTable.columns
18,666✔
338
            foundTable.indices = changedTable.indices
18,666✔
339
            foundTable.foreignKeys = changedTable.foreignKeys
18,666✔
340
            foundTable.uniques = changedTable.uniques
18,666✔
341
            foundTable.checks = changedTable.checks
18,666✔
342
            foundTable.justCreated = changedTable.justCreated
18,666✔
343
            foundTable.engine = changedTable.engine
18,666✔
344
            foundTable.comment = changedTable.comment
18,666✔
345
        }
18,666✔
346
    }
18,666✔
347

244,340✔
348
    protected getTablePath(
244,340✔
349
        target: EntityMetadata | Table | View | TableForeignKey | string,
255,001✔
350
    ): string {
255,001✔
351
        const parsed = this.connection.driver.parseTableName(target)
255,001✔
352

255,001✔
353
        return this.connection.driver.buildTableName(
255,001✔
354
            parsed.tableName,
255,001✔
355
            parsed.schema,
255,001✔
356
            parsed.database,
255,001✔
357
        )
255,001✔
358
    }
255,001✔
359

244,340✔
360
    protected getTypeormMetadataTableName(): string {
244,340✔
361
        const options = <
46,014✔
362
            SqlServerConnectionOptions | PostgresConnectionOptions
46,014✔
363
        >this.connection.driver.options
46,014✔
364
        return this.connection.driver.buildTableName(
46,014✔
365
            this.connection.metadataTableName,
46,014✔
366
            options.schema,
46,014✔
367
            options.database,
46,014✔
368
        )
46,014✔
369
    }
46,014✔
370

244,340✔
371
    /**
244,340✔
372
     * Generates SQL query to select record from typeorm metadata table.
244,340✔
373
     */
244,340✔
374
    protected selectTypeormMetadataSql({
244,340✔
375
        database,
1,044✔
376
        schema,
1,044✔
377
        table,
1,044✔
378
        type,
1,044✔
379
        name,
1,044✔
380
    }: {
1,044✔
381
        database?: string
1,044✔
382
        schema?: string
1,044✔
383
        table?: string
1,044✔
384
        type: MetadataTableType
1,044✔
385
        name: string
1,044✔
386
    }): Query {
1,044✔
387
        const qb = this.connection.createQueryBuilder()
1,044✔
388
        const selectQb = qb
1,044✔
389
            .select()
1,044✔
390
            .from(this.getTypeormMetadataTableName(), "t")
1,044✔
391
            .where(`${qb.escape("type")} = :type`, { type })
1,044✔
392
            .andWhere(`${qb.escape("name")} = :name`, { name })
1,044✔
393

1,044✔
394
        if (database) {
1,044!
395
            selectQb.andWhere(`${qb.escape("database")} = :database`, {
262✔
396
                database,
262✔
397
            })
262✔
398
        }
262✔
399

1,044✔
400
        if (schema) {
1,044!
401
            selectQb.andWhere(`${qb.escape("schema")} = :schema`, { schema })
869✔
402
        }
869✔
403

1,044✔
404
        if (table) {
1,044✔
405
            selectQb.andWhere(`${qb.escape("table")} = :table`, { table })
1,044✔
406
        }
1,044✔
407

1,044✔
408
        const [query, parameters] = selectQb.getQueryAndParameters()
1,044✔
409
        return new Query(query, parameters)
1,044✔
410
    }
1,044✔
411

244,340✔
412
    /**
244,340✔
413
     * Generates SQL query to insert a record into typeorm metadata table.
244,340✔
414
     */
244,340✔
415
    protected insertTypeormMetadataSql({
244,340✔
416
        database,
1,232✔
417
        schema,
1,232✔
418
        table,
1,232✔
419
        type,
1,232✔
420
        name,
1,232✔
421
        value,
1,232✔
422
    }: {
1,232✔
423
        database?: string
1,232✔
424
        schema?: string
1,232✔
425
        table?: string
1,232✔
426
        type: MetadataTableType
1,232✔
427
        name: string
1,232✔
428
        value?: string
1,232✔
429
    }): Query {
1,232✔
430
        const [query, parameters] = this.connection
1,232✔
431
            .createQueryBuilder()
1,232✔
432
            .insert()
1,232✔
433
            .into(this.getTypeormMetadataTableName())
1,232✔
434
            .values({
1,232✔
435
                database: database,
1,232✔
436
                schema: schema,
1,232✔
437
                table: table,
1,232✔
438
                type: type,
1,232✔
439
                name: name,
1,232✔
440
                value: value,
1,232✔
441
            })
1,232✔
442
            .getQueryAndParameters()
1,232✔
443

1,232✔
444
        return new Query(query, parameters)
1,232✔
445
    }
1,232✔
446

244,340✔
447
    /**
244,340✔
448
     * Generates SQL query to delete a record from typeorm metadata table.
244,340✔
449
     */
244,340✔
450
    protected deleteTypeormMetadataSql({
244,340✔
451
        database,
1,232✔
452
        schema,
1,232✔
453
        table,
1,232✔
454
        type,
1,232✔
455
        name,
1,232✔
456
    }: {
1,232✔
457
        database?: string
1,232✔
458
        schema?: string
1,232✔
459
        table?: string
1,232✔
460
        type: MetadataTableType
1,232✔
461
        name: string
1,232✔
462
    }): Query {
1,232✔
463
        const qb = this.connection.createQueryBuilder()
1,232✔
464
        const deleteQb = qb
1,232✔
465
            .delete()
1,232✔
466
            .from(this.getTypeormMetadataTableName())
1,232✔
467
            .where(`${qb.escape("type")} = :type`, { type })
1,232✔
468
            .andWhere(`${qb.escape("name")} = :name`, { name })
1,232✔
469

1,232✔
470
        if (database) {
1,232!
471
            deleteQb.andWhere(`${qb.escape("database")} = :database`, {
226✔
472
                database,
226✔
473
            })
226✔
474
        }
226✔
475

1,232✔
476
        if (schema) {
1,232!
477
            deleteQb.andWhere(`${qb.escape("schema")} = :schema`, { schema })
959✔
478
        }
959✔
479

1,232✔
480
        if (table) {
1,232!
481
            deleteQb.andWhere(`${qb.escape("table")} = :table`, { table })
800✔
482
        }
800✔
483

1,232✔
484
        const [query, parameters] = deleteQb.getQueryAndParameters()
1,232✔
485
        return new Query(query, parameters)
1,232✔
486
    }
1,232✔
487

244,340✔
488
    /**
244,340✔
489
     * Checks if at least one of column properties was changed.
244,340✔
490
     * Does not checks column type, length and autoincrement, because these properties changes separately.
244,340✔
491
     */
244,340✔
492
    protected isColumnChanged(
244,340✔
493
        oldColumn: TableColumn,
692✔
494
        newColumn: TableColumn,
692✔
495
        checkDefault?: boolean,
692✔
496
        checkComment?: boolean,
692✔
497
        checkEnum = true,
692✔
498
    ): boolean {
692✔
499
        // this logs need to debug issues in column change detection. Do not delete it!
692✔
500

692✔
501
        // console.log("charset ---------------");
692✔
502
        // console.log(oldColumn.charset !== newColumn.charset);
692✔
503
        // console.log(oldColumn.charset, newColumn.charset);
692✔
504
        // console.log("collation ---------------");
692✔
505
        // console.log(oldColumn.collation !== newColumn.collation);
692✔
506
        // console.log(oldColumn.collation, newColumn.collation);
692✔
507
        // console.log("precision ---------------");
692✔
508
        // console.log(oldColumn.precision !== newColumn.precision);
692✔
509
        // console.log(oldColumn.precision, newColumn.precision);
692✔
510
        // console.log("scale ---------------");
692✔
511
        // console.log(oldColumn.scale !== newColumn.scale);
692✔
512
        // console.log(oldColumn.scale, newColumn.scale);
692✔
513
        // console.log("default ---------------");
692✔
514
        // console.log((checkDefault && oldColumn.default !== newColumn.default));
692✔
515
        // console.log(oldColumn.default, newColumn.default);
692✔
516
        // console.log("isNullable ---------------");
692✔
517
        // console.log(oldColumn.isNullable !== newColumn.isNullable);
692✔
518
        // console.log(oldColumn.isNullable, newColumn.isNullable);
692✔
519
        // console.log("comment ---------------");
692✔
520
        // console.log((checkComment && oldColumn.comment !== newColumn.comment));
692✔
521
        // console.log(oldColumn.comment, newColumn.comment);
692✔
522
        // console.log("enum ---------------");
692✔
523
        // console.log(!OrmUtils.isArraysEqual(oldColumn.enum || [], newColumn.enum || []));
692✔
524
        // console.log(oldColumn.enum, newColumn.enum);
692✔
525

692✔
526
        return (
692✔
527
            oldColumn.charset !== newColumn.charset ||
692✔
528
            oldColumn.collation !== newColumn.collation ||
692✔
529
            oldColumn.precision !== newColumn.precision ||
692✔
530
            oldColumn.scale !== newColumn.scale ||
692✔
531
            oldColumn.width !== newColumn.width || // MySQL only
692✔
532
            oldColumn.zerofill !== newColumn.zerofill || // MySQL only
692✔
533
            oldColumn.unsigned !== newColumn.unsigned || // MySQL only
692✔
534
            oldColumn.asExpression !== newColumn.asExpression ||
692✔
535
            (checkDefault && oldColumn.default !== newColumn.default) ||
692!
536
            oldColumn.onUpdate !== newColumn.onUpdate || // MySQL only
692✔
537
            oldColumn.isNullable !== newColumn.isNullable ||
692✔
538
            (checkComment && oldColumn.comment !== newColumn.comment) ||
692!
539
            (checkEnum && this.isEnumChanged(oldColumn, newColumn))
558!
540
        )
692✔
541
    }
692✔
542

244,340✔
543
    protected isEnumChanged(oldColumn: TableColumn, newColumn: TableColumn) {
244,340✔
544
        return !OrmUtils.isArraysEqual(
558✔
545
            oldColumn.enum || [],
558✔
546
            newColumn.enum || [],
558✔
547
        )
558✔
548
    }
558✔
549

244,340✔
550
    /**
244,340✔
551
     * Checks if column length is by default.
244,340✔
552
     */
244,340✔
553
    protected isDefaultColumnLength(
244,340✔
554
        table: Table,
12,892✔
555
        column: TableColumn,
12,892✔
556
        length: string,
12,892✔
557
    ): boolean {
12,892✔
558
        // if table have metadata, we check if length is specified in column metadata
12,892✔
559
        if (this.connection.hasMetadata(table.name)) {
12,892✔
560
            const metadata = this.connection.getMetadata(table.name)
11,511✔
561
            const columnMetadata = metadata.findColumnWithDatabaseName(
11,511✔
562
                column.name,
11,511✔
563
            )
11,511✔
564

11,511✔
565
            if (columnMetadata) {
11,511✔
566
                const columnMetadataLength =
11,264✔
567
                    this.connection.driver.getColumnLength(columnMetadata)
11,264✔
568
                if (columnMetadataLength) return false
11,264✔
569
            }
11,264✔
570
        }
11,511✔
571

1,746✔
572
        if (
1,746✔
573
            this.connection.driver.dataTypeDefaults &&
1,746✔
574
            this.connection.driver.dataTypeDefaults[column.type] &&
12,892✔
575
            this.connection.driver.dataTypeDefaults[column.type].length
1,522✔
576
        ) {
12,892✔
577
            return (
1,522✔
578
                this.connection.driver.dataTypeDefaults[
1,522✔
579
                    column.type
1,522✔
580
                ].length!.toString() === length.toString()
1,522✔
581
            )
1,522✔
582
        }
1,522✔
583

224!
584
        return false
224✔
585
    }
224✔
586

244,340✔
587
    /**
244,340✔
588
     * Checks if column precision is by default.
244,340✔
589
     */
244,340✔
590
    protected isDefaultColumnPrecision(
244,340✔
591
        table: Table,
1,047✔
592
        column: TableColumn,
1,047✔
593
        precision: number,
1,047✔
594
    ): boolean {
1,047✔
595
        // if table have metadata, we check if length is specified in column metadata
1,047✔
596
        if (this.connection.hasMetadata(table.name)) {
1,047✔
597
            const metadata = this.connection.getMetadata(table.name)
1,047✔
598
            const columnMetadata = metadata.findColumnWithDatabaseName(
1,047✔
599
                column.name,
1,047✔
600
            )
1,047✔
601
            if (
1,047✔
602
                columnMetadata &&
1,047✔
603
                columnMetadata.precision !== null &&
1,047✔
604
                columnMetadata.precision !== undefined
1,031✔
605
            )
1,047✔
606
                return false
1,047✔
607
        }
1,047✔
608

650!
609
        if (
650✔
610
            this.connection.driver.dataTypeDefaults &&
650✔
611
            this.connection.driver.dataTypeDefaults[column.type] &&
1,047!
612
            this.connection.driver.dataTypeDefaults[column.type].precision !==
650✔
613
                null &&
1,047!
614
            this.connection.driver.dataTypeDefaults[column.type].precision !==
650✔
615
                undefined
650✔
616
        )
1,047✔
617
            return (
1,047!
618
                this.connection.driver.dataTypeDefaults[column.type]
650✔
619
                    .precision === precision
650✔
620
            )
650✔
621

×
622
        return false
×
623
    }
×
624

244,340✔
625
    /**
244,340✔
626
     * Checks if column scale is by default.
244,340✔
627
     */
244,340✔
628
    protected isDefaultColumnScale(
244,340✔
629
        table: Table,
351✔
630
        column: TableColumn,
351✔
631
        scale: number,
351✔
632
    ): boolean {
351✔
633
        // if table have metadata, we check if length is specified in column metadata
351✔
634
        if (this.connection.hasMetadata(table.name)) {
351✔
635
            const metadata = this.connection.getMetadata(table.name)
143✔
636
            const columnMetadata = metadata.findColumnWithDatabaseName(
143✔
637
                column.name,
143✔
638
            )
143✔
639
            if (
143✔
640
                columnMetadata &&
143✔
641
                columnMetadata.scale !== null &&
143✔
642
                columnMetadata.scale !== undefined
139✔
643
            )
143✔
644
                return false
143✔
645
        }
143✔
646

263✔
647
        if (
263✔
648
            this.connection.driver.dataTypeDefaults &&
263✔
649
            this.connection.driver.dataTypeDefaults[column.type] &&
351!
650
            this.connection.driver.dataTypeDefaults[column.type].scale !==
46✔
651
                null &&
351!
652
            this.connection.driver.dataTypeDefaults[column.type].scale !==
46✔
653
                undefined
46✔
654
        )
351✔
655
            return (
351!
656
                this.connection.driver.dataTypeDefaults[column.type].scale ===
46✔
657
                scale
46✔
658
            )
46✔
659

217!
660
        return false
217✔
661
    }
217✔
662

244,340✔
663
    /**
244,340✔
664
     * Executes sql used special for schema build.
244,340✔
665
     */
244,340✔
666
    protected async executeQueries(
244,340✔
667
        upQueries: Query | Query[],
214,391✔
668
        downQueries: Query | Query[],
214,391✔
669
    ): Promise<void> {
214,391✔
670
        if (InstanceChecker.isQuery(upQueries)) upQueries = [upQueries]
214,391✔
671
        if (InstanceChecker.isQuery(downQueries)) downQueries = [downQueries]
214,391✔
672

214,391✔
673
        this.sqlInMemory.upQueries.push(...upQueries)
214,391✔
674
        this.sqlInMemory.downQueries.push(...downQueries)
214,391✔
675

214,391✔
676
        // if sql-in-memory mode is enabled then simply store sql in memory and return
214,391✔
677
        if (this.sqlMemoryMode === true)
214,391✔
678
            return Promise.resolve() as Promise<any>
214,391✔
679

213,558✔
680
        for (const { query, parameters } of upQueries) {
214,391✔
681
            await this.query(query, parameters)
329,764✔
682
        }
329,734✔
683
    }
213,528✔
684

244,340✔
685
    /**
244,340✔
686
     * Generated an index name for a table and index
244,340✔
687
     */
244,340✔
688
    protected generateIndexName(
244,340✔
689
        table: Table | View,
104✔
690
        index: TableIndex,
104✔
691
    ): string {
104✔
692
        // new index may be passed without name. In this case we generate index name manually.
104✔
693
        return this.connection.namingStrategy.indexName(
104✔
694
            table,
104✔
695
            index.columnNames,
104✔
696
            index.where,
104✔
697
        )
104✔
698
    }
104✔
699
}
244,340✔
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