• 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

95.73
/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
     * SQLite underlying library.
26✔
29
     */
26✔
30
    sqlite: any
26✔
31

26✔
32
    // -------------------------------------------------------------------------
26✔
33
    // Constructor
26✔
34
    // -------------------------------------------------------------------------
26✔
35

26✔
36
    constructor(connection: DataSource) {
26✔
37
        super(connection)
1,494✔
38
        this.connection = connection
1,494✔
39
        this.options = connection.options as SqliteConnectionOptions
1,494✔
40
        this.database = this.options.database
1,494✔
41

1,494✔
42
        // load sqlite package
1,494✔
43
        this.loadDependencies()
1,494✔
44
    }
1,494✔
45

26✔
46
    // -------------------------------------------------------------------------
26✔
47
    // Public Methods
26✔
48
    // -------------------------------------------------------------------------
26✔
49

26✔
50
    /**
26✔
51
     * Closes connection with database.
26✔
52
     */
26✔
53
    async disconnect(): Promise<void> {
26✔
54
        return new Promise<void>((ok, fail) => {
1,488✔
55
            this.queryRunner = undefined
1,488✔
56
            this.databaseConnection.close((err: any) =>
1,488✔
57
                err ? fail(err) : ok(),
1,488!
58
            )
1,488✔
59
        })
1,488✔
60
    }
1,488✔
61

26✔
62
    /**
26✔
63
     * Creates a query runner used to execute database queries.
26✔
64
     */
26✔
65
    createQueryRunner(mode: ReplicationMode): QueryRunner {
26✔
66
        if (!this.queryRunner) this.queryRunner = new SqliteQueryRunner(this)
37,572✔
67

37,572✔
68
        return this.queryRunner
37,572✔
69
    }
37,572✔
70

26✔
71
    normalizeType(column: {
26✔
72
        type?: ColumnType
104,190✔
73
        length?: number | string
104,190✔
74
        precision?: number | null
104,190✔
75
        scale?: number
104,190✔
76
    }): string {
104,190✔
77
        if ((column.type as any) === Buffer) {
104,190✔
78
            return "blob"
15✔
79
        }
15✔
80

104,175✔
81
        return super.normalizeType(column)
104,175✔
82
    }
104,175✔
83

26✔
84
    async afterConnect(): Promise<void> {
26✔
85
        return this.attachDatabases()
1,488✔
86
    }
1,488✔
87

26✔
88
    /**
26✔
89
     * For SQLite, the database may be added in the decorator metadata. It will be a filepath to a database file.
26✔
90
     */
26✔
91
    buildTableName(
26✔
92
        tableName: string,
973,449✔
93
        _schema?: string,
973,449✔
94
        database?: string,
973,449✔
95
    ): string {
973,449✔
96
        if (!database) return tableName
973,449✔
97
        if (this.getAttachedDatabaseHandleByRelativePath(database))
955,620✔
98
            return `${this.getAttachedDatabaseHandleByRelativePath(
973,449✔
99
                database,
1,929✔
100
            )}.${tableName}`
1,929✔
101

953,691✔
102
        if (database === this.options.database) return tableName
973,449✔
103

9✔
104
        // we use the decorated name as supplied when deriving attach handle (ideally without non-portable absolute path)
9✔
105
        const identifierHash = filepathToName(database)
9✔
106
        // decorated name will be assumed relative to main database file when non absolute. Paths supplied as absolute won't be portable
9✔
107
        const absFilepath = isAbsolute(database)
9✔
108
            ? database
973,449!
109
            : path.join(this.getMainDatabasePath(), database)
973,449✔
110

973,449✔
111
        this.attachedDatabases[database] = {
973,449✔
112
            attachFilepathAbsolute: absFilepath,
973,449✔
113
            attachFilepathRelative: database,
973,449✔
114
            attachHandle: identifierHash,
973,449✔
115
        }
973,449✔
116

973,449✔
117
        return `${identifierHash}.${tableName}`
973,449✔
118
    }
973,449✔
119

26✔
120
    // -------------------------------------------------------------------------
26✔
121
    // Protected Methods
26✔
122
    // -------------------------------------------------------------------------
26✔
123

26✔
124
    /**
26✔
125
     * Creates connection with the database.
26✔
126
     */
26✔
127
    protected async createDatabaseConnection() {
26✔
128
        if (
1,494✔
129
            this.options.flags === undefined ||
1,494✔
130
            !(this.options.flags & this.sqlite.OPEN_URI)
3✔
131
        ) {
1,494✔
132
            await this.createDatabaseDirectory(this.options.database)
1,491✔
133
        }
1,491✔
134

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

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

1,494✔
171
        if (this.options.enableWAL) {
1,494✔
172
            await run(`PRAGMA journal_mode = WAL`)
3✔
173
        }
3✔
174

1,494✔
175
        if (
1,494✔
176
            this.options.busyTimeout &&
1,494✔
177
            typeof this.options.busyTimeout === "number" &&
1,494✔
178
            this.options.busyTimeout > 0
3✔
179
        ) {
1,494✔
180
            await run(`PRAGMA busy_timeout = ${this.options.busyTimeout}`)
3✔
181
        }
3✔
182

1,494✔
183
        // we need to enable foreign keys in sqlite to make sure all foreign key related features
1,494✔
184
        // working properly. this also makes onDelete to work with sqlite.
1,494✔
185
        await run(`PRAGMA foreign_keys = ON`)
1,494✔
186

1,494✔
187
        return databaseConnection
1,494✔
188
    }
1,494✔
189

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

26✔
202
    /**
26✔
203
     * Auto creates database directory if it does not exist.
26✔
204
     */
26✔
205
    protected async createDatabaseDirectory(fullPath: string): Promise<void> {
26✔
206
        await fs.mkdir(path.dirname(fullPath), { recursive: true })
1,500✔
207
    }
1,500✔
208

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

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