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

typeorm / typeorm / 20153290793

12 Dec 2025 01:29AM UTC coverage: 80.807% (+0.04%) from 80.764%
20153290793

push

github

alumni
refactor(mysql)!: drop support for mysql package and default to mysql2 (#11766)

Co-authored-by: Lucian Mocanu <alumni@users.noreply.github.com>

26912 of 32666 branches covered (82.39%)

Branch coverage included in aggregate %.

13 of 15 new or added lines in 2 files covered. (86.67%)

694 existing lines in 23 files now uncovered.

91350 of 113685 relevant lines covered (80.35%)

68942.63 hits per line

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

95.65
/src/driver/sqlite/SqliteDriver.ts
1
import fs from "fs/promises"
26✔
2
import path from "path"
26✔
3
import { DriverPackageNotInstalledError } from "../../error/DriverPackageNotInstalledError"
26✔
4
import { SqliteQueryRunner } from "./SqliteQueryRunner"
26✔
5
import { PlatformTools } from "../../platform/PlatformTools"
26✔
6
import { DataSource } from "../../data-source/DataSource"
26✔
7
import { SqliteConnectionOptions } from "./SqliteConnectionOptions"
26✔
8
import { ColumnType } from "../types/ColumnTypes"
26✔
9
import { QueryRunner } from "../../query-runner/QueryRunner"
26✔
10
import { AbstractSqliteDriver } from "../sqlite-abstract/AbstractSqliteDriver"
26✔
11
import { ReplicationMode } from "../types/ReplicationMode"
26✔
12
import { filepathToName, isAbsolute } from "../../util/PathUtils"
26✔
13

26✔
14
/**
26✔
15
 * Organizes communication with sqlite DBMS.
26✔
16
 */
26✔
17
export class SqliteDriver extends AbstractSqliteDriver {
26✔
18
    // -------------------------------------------------------------------------
26✔
19
    // Public Properties
26✔
20
    // -------------------------------------------------------------------------
26✔
21

26✔
22
    /**
26✔
23
     * Connection options.
26✔
24
     */
26✔
25
    options: SqliteConnectionOptions
26✔
26

26✔
27
    // -------------------------------------------------------------------------
26✔
28
    // Constructor
26✔
29
    // -------------------------------------------------------------------------
26✔
30

26✔
31
    constructor(connection: DataSource) {
26✔
32
        super(connection)
1,497✔
33
        this.connection = connection
1,497✔
34
        this.options = connection.options as SqliteConnectionOptions
1,497✔
35
        this.database = this.options.database
1,497✔
36

1,497✔
37
        // load sqlite package
1,497✔
38
        this.loadDependencies()
1,497✔
39
    }
1,497✔
40

26✔
41
    // -------------------------------------------------------------------------
26✔
42
    // Public Methods
26✔
43
    // -------------------------------------------------------------------------
26✔
44

26✔
45
    /**
26✔
46
     * Closes connection with database.
26✔
47
     */
26✔
48
    async disconnect(): Promise<void> {
26✔
49
        return new Promise<void>((ok, fail) => {
1,491✔
50
            this.queryRunner = undefined
1,491✔
51
            this.databaseConnection.close((err: any) =>
1,491✔
52
                err ? fail(err) : ok(),
1,491!
53
            )
1,491✔
54
        })
1,491✔
55
    }
1,491✔
56

26✔
57
    /**
26✔
58
     * Creates a query runner used to execute database queries.
26✔
59
     */
26✔
60
    createQueryRunner(mode: ReplicationMode): QueryRunner {
26✔
61
        if (!this.queryRunner) this.queryRunner = new SqliteQueryRunner(this)
37,788✔
62

37,788✔
63
        return this.queryRunner
37,788✔
64
    }
37,788✔
65

26✔
66
    normalizeType(column: {
26✔
67
        type?: ColumnType
106,041✔
68
        length?: number | string
106,041✔
69
        precision?: number | null
106,041✔
70
        scale?: number
106,041✔
71
    }): string {
106,041✔
72
        if ((column.type as any) === Buffer) {
106,041✔
73
            return "blob"
15✔
74
        }
15✔
75

106,026✔
76
        return super.normalizeType(column)
106,026✔
77
    }
106,026✔
78

26✔
79
    async afterConnect(): Promise<void> {
26✔
80
        return this.attachDatabases()
1,491✔
81
    }
1,491✔
82

26✔
83
    /**
26✔
84
     * For SQLite, the database may be added in the decorator metadata. It will be a filepath to a database file.
26✔
85
     */
26✔
86
    buildTableName(
26✔
87
        tableName: string,
1,011,060✔
88
        _schema?: string,
1,011,060✔
89
        database?: string,
1,011,060✔
90
    ): string {
1,011,060✔
91
        if (!database) return tableName
1,011,060✔
92
        if (this.getAttachedDatabaseHandleByRelativePath(database))
992,838✔
93
            return `${this.getAttachedDatabaseHandleByRelativePath(
1,011,060✔
94
                database,
1,929✔
95
            )}.${tableName}`
1,929✔
96

990,909✔
97
        if (database === this.options.database) return tableName
1,011,060✔
98

9✔
99
        // we use the decorated name as supplied when deriving attach handle (ideally without non-portable absolute path)
9✔
100
        const identifierHash = filepathToName(database)
9✔
101
        // decorated name will be assumed relative to main database file when non absolute. Paths supplied as absolute won't be portable
9✔
102
        const absFilepath = isAbsolute(database)
9✔
103
            ? database
1,011,060!
104
            : path.join(this.getMainDatabasePath(), database)
1,011,060✔
105

1,011,060✔
106
        this.attachedDatabases[database] = {
1,011,060✔
107
            attachFilepathAbsolute: absFilepath,
1,011,060✔
108
            attachFilepathRelative: database,
1,011,060✔
109
            attachHandle: identifierHash,
1,011,060✔
110
        }
1,011,060✔
111

1,011,060✔
112
        return `${identifierHash}.${tableName}`
1,011,060✔
113
    }
1,011,060✔
114

26✔
115
    // -------------------------------------------------------------------------
26✔
116
    // Protected Methods
26✔
117
    // -------------------------------------------------------------------------
26✔
118

26✔
119
    /**
26✔
120
     * Creates connection with the database.
26✔
121
     */
26✔
122
    protected async createDatabaseConnection() {
26✔
123
        if (
1,497✔
124
            this.options.flags === undefined ||
1,497✔
125
            !(this.options.flags & this.sqlite.OPEN_URI)
3✔
126
        ) {
1,497✔
127
            await this.createDatabaseDirectory(this.options.database)
1,494✔
128
        }
1,494✔
129

1,497✔
130
        const databaseConnection: any = await new Promise((ok, fail) => {
1,497✔
131
            if (this.options.flags === undefined) {
1,497✔
132
                const connection = new this.sqlite.Database(
1,494✔
133
                    this.options.database,
1,494✔
134
                    (err: any) => {
1,494✔
135
                        if (err) return fail(err)
1,494!
136
                        ok(connection)
1,494✔
137
                    },
1,494✔
138
                )
1,494✔
139
            } else {
1,497✔
140
                const connection = new this.sqlite.Database(
3✔
141
                    this.options.database,
3✔
142
                    this.options.flags,
3✔
143
                    (err: any) => {
3✔
144
                        if (err) return fail(err)
3!
145
                        ok(connection)
3✔
146
                    },
3✔
147
                )
3✔
148
            }
3✔
149
        })
1,497✔
150

1,497✔
151
        // Internal function to run a command on the connection and fail if an error occured.
1,497✔
152
        function run(line: string): Promise<void> {
1,497✔
153
            return new Promise((ok, fail) => {
1,503✔
154
                databaseConnection.run(line, (err: any) => {
1,503✔
155
                    if (err) return fail(err)
1,503!
156
                    ok()
1,503✔
157
                })
1,503✔
158
            })
1,503✔
159
        }
1,503✔
160
        // in the options, if encryption key for SQLCipher is setted.
1,497✔
161
        // Must invoke key pragma before trying to do any other interaction with the database.
1,497✔
162
        if (this.options.key) {
1,497!
UNCOV
163
            await run(`PRAGMA key = ${JSON.stringify(this.options.key)}`)
×
UNCOV
164
        }
×
165

1,497✔
166
        if (this.options.enableWAL) {
1,497✔
167
            await run(`PRAGMA journal_mode = WAL`)
3✔
168
        }
3✔
169

1,497✔
170
        if (
1,497✔
171
            this.options.busyTimeout &&
1,497✔
172
            typeof this.options.busyTimeout === "number" &&
1,497✔
173
            this.options.busyTimeout > 0
3✔
174
        ) {
1,497✔
175
            await run(`PRAGMA busy_timeout = ${this.options.busyTimeout}`)
3✔
176
        }
3✔
177

1,497✔
178
        // we need to enable foreign keys in sqlite to make sure all foreign key related features
1,497✔
179
        // working properly. this also makes onDelete to work with sqlite.
1,497✔
180
        await run(`PRAGMA foreign_keys = ON`)
1,497✔
181

1,497✔
182
        return databaseConnection
1,497✔
183
    }
1,497✔
184

26✔
185
    /**
26✔
186
     * If driver dependency is not given explicitly, then try to load it via "require".
26✔
187
     */
26✔
188
    protected loadDependencies(): void {
26✔
189
        try {
1,497✔
190
            const sqlite = this.options.driver || PlatformTools.load("sqlite3")
1,497✔
191
            this.sqlite = sqlite.verbose()
1,497✔
192
        } catch (e) {
1,497!
UNCOV
193
            throw new DriverPackageNotInstalledError("SQLite", "sqlite3")
×
UNCOV
194
        }
×
195
    }
1,497✔
196

26✔
197
    /**
26✔
198
     * Auto creates database directory if it does not exist.
26✔
199
     */
26✔
200
    protected async createDatabaseDirectory(fullPath: string): Promise<void> {
26✔
201
        await fs.mkdir(path.dirname(fullPath), { recursive: true })
1,503✔
202
    }
1,503✔
203

26✔
204
    /**
26✔
205
     * Performs the attaching of the database files. The attachedDatabase should have been populated during calls to #buildTableName
26✔
206
     * during EntityMetadata production (see EntityMetadata#buildTablePath)
26✔
207
     *
26✔
208
     * https://sqlite.org/lang_attach.html
26✔
209
     */
26✔
210
    protected async attachDatabases() {
26✔
211
        // @todo - possibly check number of databases (but unqueriable at runtime sadly) - https://www.sqlite.org/limits.html#max_attached
1,491✔
212
        for (const { attachHandle, attachFilepathAbsolute } of Object.values(
1,491✔
213
            this.attachedDatabases,
1,491✔
214
        )) {
1,491✔
215
            await this.createDatabaseDirectory(attachFilepathAbsolute)
9✔
216
            await this.connection.query(
9✔
217
                `ATTACH "${attachFilepathAbsolute}" AS "${attachHandle}"`,
9✔
218
            )
9✔
219
        }
9✔
220
    }
1,491✔
221

26✔
222
    protected getMainDatabasePath(): string {
26✔
223
        const optionsDb = this.options.database
9✔
224
        return path.dirname(
9✔
225
            isAbsolute(optionsDb)
9✔
226
                ? optionsDb
9✔
227
                : path.join(process.cwd(), optionsDb),
9!
228
        )
9✔
229
    }
9✔
230
}
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