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

typeorm / typeorm / 16405830134

21 Jul 2025 12:22AM UTC coverage: 76.442% (+0.002%) from 76.44%
16405830134

Pull #11576

github

web-flow
Merge ccddce2d3 into d57fe3bd8
Pull Request #11576: fix(sqlserver): queries returning multiple record sets

9324 of 12885 branches covered (72.36%)

Branch coverage included in aggregate %.

55 of 78 new or added lines in 25 files covered. (70.51%)

2073 existing lines in 24 files now uncovered.

19016 of 24189 relevant lines covered (78.61%)

119538.23 hits per line

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

86.05
/src/driver/better-sqlite3/BetterSqlite3QueryRunner.ts
1
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError"
24✔
2
import { QueryFailedError } from "../../error/QueryFailedError"
24✔
3
import { AbstractSqliteQueryRunner } from "../sqlite-abstract/AbstractSqliteQueryRunner"
24✔
4
import { Broadcaster } from "../../subscriber/Broadcaster"
24✔
5
import { BetterSqlite3Driver } from "./BetterSqlite3Driver"
6
import { QueryResult } from "../../query-runner/QueryResult"
24✔
7
import { BroadcasterResult } from "../../subscriber/BroadcasterResult"
24✔
8

9
/**
10
 * Runs queries on a single sqlite database connection.
11
 *
12
 * Does not support compose primary keys with autoincrement field.
13
 * todo: need to throw exception for this case.
14
 */
15
export class BetterSqlite3QueryRunner extends AbstractSqliteQueryRunner {
24✔
16
    /**
17
     * Database driver used by connection.
18
     */
19
    driver: BetterSqlite3Driver
20

21
    // -------------------------------------------------------------------------
22
    // Constructor
23
    // -------------------------------------------------------------------------
24

25
    constructor(driver: BetterSqlite3Driver) {
26
        super()
1,377✔
27
        this.driver = driver
1,377✔
28
        this.connection = driver.connection
1,377✔
29
        this.broadcaster = new Broadcaster(this)
1,377✔
30
        if (typeof this.driver.options.statementCacheSize === "number") {
1,377!
UNCOV
31
            this.cacheSize = this.driver.options.statementCacheSize
×
32
        } else {
33
            this.cacheSize = 100
1,377✔
34
        }
35
    }
36

37
    private cacheSize: number
38
    private stmtCache = new Map<string, any>()
1,377✔
39

40
    private async getStmt(query: string) {
41
        if (this.cacheSize > 0) {
212,049!
42
            let stmt = this.stmtCache.get(query)
212,049✔
43
            if (!stmt) {
212,049✔
44
                const databaseConnection = await this.connect()
60,588✔
45
                stmt = databaseConnection.prepare(query)
60,588✔
46
                this.stmtCache.set(query, stmt)
60,579✔
47
                while (this.stmtCache.size > this.cacheSize) {
60,579✔
48
                    // since es6 map keeps the insertion order,
49
                    // it comes to be FIFO cache
50
                    const key = this.stmtCache.keys().next().value!
17,871✔
51
                    this.stmtCache.delete(key)
17,871✔
52
                }
53
            }
54
            return stmt
212,040✔
55
        } else {
UNCOV
56
            const databaseConnection = await this.connect()
×
57
            return databaseConnection.prepare(query)
×
58
        }
59
    }
60

61
    /**
62
     * Called before migrations are run.
63
     */
64
    async beforeMigration(): Promise<void> {
65
        await this.query(`PRAGMA foreign_keys = OFF`)
3,972✔
66
    }
67

68
    /**
69
     * Called after migrations are run.
70
     */
71
    async afterMigration(): Promise<void> {
72
        await this.query(`PRAGMA foreign_keys = ON`)
3,963✔
73
    }
74

75
    /**
76
     * Executes a given SQL query.
77
     */
78
    async query(
79
        query: string,
80
        parameters: any[] = [],
160,350✔
81
        useStructuredResult = false,
160,599✔
82
    ): Promise<any> {
83
        if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
212,049!
84

85
        const connection = this.driver.connection
212,049✔
86

87
        const broadcasterResult = new BroadcasterResult()
212,049✔
88

89
        this.driver.connection.logger.logQuery(query, parameters, this)
212,049✔
90
        this.broadcaster.broadcastBeforeQueryEvent(
212,049✔
91
            broadcasterResult,
92
            query,
93
            parameters,
94
        )
95
        const queryStartTime = Date.now()
212,049✔
96

97
        const stmt = await this.getStmt(query)
212,049✔
98

99
        try {
212,040✔
100
            const result = new QueryResult()
212,040✔
101

102
            if (stmt.reader) {
212,040✔
103
                const raw = stmt.all(...parameters)
47,634✔
104

105
                result.raw = raw
47,634✔
106

107
                if (Array.isArray(raw)) {
47,634✔
108
                    result.records = raw
47,634✔
109
                }
110
            } else {
111
                const raw = stmt.run(...parameters)
164,406✔
112
                result.affected = raw.changes
164,388✔
113
                result.raw = raw.lastInsertRowid
164,388✔
114
            }
115

116
            // log slow queries if maxQueryExecution time is set
117
            const maxQueryExecutionTime =
118
                this.driver.options.maxQueryExecutionTime
212,022✔
119
            const queryEndTime = Date.now()
212,022✔
120
            const queryExecutionTime = queryEndTime - queryStartTime
212,022✔
121
            if (
212,022!
122
                maxQueryExecutionTime &&
212,022!
123
                queryExecutionTime > maxQueryExecutionTime
124
            )
UNCOV
125
                connection.logger.logQuerySlow(
×
126
                    queryExecutionTime,
127
                    query,
128
                    parameters,
129
                    this,
130
                )
131

132
            this.broadcaster.broadcastAfterQueryEvent(
212,022✔
133
                broadcasterResult,
134
                query,
135
                parameters,
136
                true,
137
                queryExecutionTime,
138
                result.raw,
139
                undefined,
140
            )
141

142
            if (!useStructuredResult) {
212,022✔
143
                return result.raw
160,650✔
144
            }
145

146
            return result
51,372✔
147
        } catch (err) {
148
            connection.logger.logQueryError(err, query, parameters, this)
18✔
149
            throw new QueryFailedError(query, parameters, err)
18✔
150
        }
151
    }
152

153
    // -------------------------------------------------------------------------
154
    // Protected Methods
155
    // -------------------------------------------------------------------------
156

157
    protected async loadTableRecords(
158
        tablePath: string,
159
        tableOrIndex: "table" | "index",
160
    ) {
161
        const [database, tableName] = this.splitTablePath(tablePath)
6✔
162
        const res = await this.query(
6✔
163
            `SELECT ${
164
                database ? `'${database}'` : null
6!
165
            } as database, * FROM ${this.escapePath(
166
                `${database ? `${database}.` : ""}sqlite_master`,
6!
167
            )} WHERE "type" = '${tableOrIndex}' AND "${
168
                tableOrIndex === "table" ? "name" : "tbl_name"
6✔
169
            }" IN ('${tableName}')`,
170
        )
171
        return res
6✔
172
    }
173
    protected async loadPragmaRecords(tablePath: string, pragma: string) {
174
        const [database, tableName] = this.splitTablePath(tablePath)
3,780✔
175
        const res = await this.query(
3,780✔
176
            `PRAGMA ${
177
                database ? `"${database}".` : ""
3,780!
178
            }${pragma}("${tableName}")`,
179
        )
180
        return res
3,780✔
181
    }
182
}
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