• 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

91.23
/src/query-builder/DeleteQueryBuilder.ts
1
import { QueryBuilder } from "./QueryBuilder"
26✔
2
import { ObjectLiteral } from "../common/ObjectLiteral"
26✔
3
import { EntityTarget } from "../common/EntityTarget"
26✔
4
import { DataSource } from "../data-source/DataSource"
26✔
5
import { QueryRunner } from "../query-runner/QueryRunner"
26✔
6
import { WhereExpressionBuilder } from "./WhereExpressionBuilder"
26✔
7
import { Brackets } from "./Brackets"
26✔
8
import { DeleteResult } from "./result/DeleteResult"
26✔
9
import { ReturningStatementNotSupportedError } from "../error/ReturningStatementNotSupportedError"
26✔
10
import { InstanceChecker } from "../util/InstanceChecker"
26✔
11

26✔
12
/**
26✔
13
 * Allows to build complex sql queries in a fashion way and execute those queries.
26✔
14
 */
26✔
15
export class DeleteQueryBuilder<Entity extends ObjectLiteral>
26✔
16
    extends QueryBuilder<Entity>
26✔
17
    implements WhereExpressionBuilder
26✔
18
{
26✔
19
    readonly "@instanceof" = Symbol.for("DeleteQueryBuilder")
26✔
20

26✔
21
    // -------------------------------------------------------------------------
26✔
22
    // Constructor
26✔
23
    // -------------------------------------------------------------------------
26✔
24

26✔
25
    constructor(
26✔
26
        connectionOrQueryBuilder: DataSource | QueryBuilder<any>,
4,849✔
27
        queryRunner?: QueryRunner,
4,849✔
28
    ) {
4,849✔
29
        super(connectionOrQueryBuilder as any, queryRunner)
4,849✔
30
        this.expressionMap.aliasNamePrefixingEnabled = false
4,849✔
31
    }
4,849✔
32

26✔
33
    // -------------------------------------------------------------------------
26✔
34
    // Public Implemented Methods
26✔
35
    // -------------------------------------------------------------------------
26✔
36

26✔
37
    /**
26✔
38
     * Gets generated SQL query without parameters being replaced.
26✔
39
     */
26✔
40
    getQuery(): string {
26✔
41
        let sql = this.createComment()
4,367✔
42
        sql += this.createCteExpression()
4,367✔
43
        sql += this.createDeleteExpression()
4,367✔
44
        return this.replacePropertyNamesForTheWholeQuery(sql.trim())
4,367✔
45
    }
4,367✔
46

26✔
47
    /**
26✔
48
     * Executes sql generated by query builder and returns raw database results.
26✔
49
     */
26✔
50
    async execute(): Promise<DeleteResult> {
26✔
51
        const [sql, parameters] = this.getQueryAndParameters()
3,101✔
52
        const queryRunner = this.obtainQueryRunner()
3,101✔
53
        let transactionStartedByUs: boolean = false
3,101✔
54

3,101✔
55
        try {
3,101✔
56
            // start transaction if it was enabled
3,101✔
57
            if (
3,101✔
58
                this.expressionMap.useTransaction === true &&
3,101!
59
                queryRunner.isTransactionActive === false
×
60
            ) {
3,101!
61
                await queryRunner.startTransaction()
×
62
                transactionStartedByUs = true
×
63
            }
×
64

3,101✔
65
            // call before deletion methods in listeners and subscribers
3,101✔
66
            if (
3,101✔
67
                this.expressionMap.callListeners === true &&
3,101✔
68
                this.expressionMap.mainAlias!.hasMetadata
875✔
69
            ) {
3,101✔
70
                await queryRunner.broadcaster.broadcast(
847✔
71
                    "BeforeRemove",
847✔
72
                    this.expressionMap.mainAlias!.metadata,
847✔
73
                )
847✔
74
            }
847✔
75

3,101✔
76
            // execute query
3,101✔
77
            const queryResult = await queryRunner.query(sql, parameters, true)
3,101✔
78
            const deleteResult = DeleteResult.from(queryResult)
3,073✔
79

3,073✔
80
            // call after deletion methods in listeners and subscribers
3,073✔
81
            if (
3,073✔
82
                this.expressionMap.callListeners === true &&
3,073✔
83
                this.expressionMap.mainAlias!.hasMetadata
847✔
84
            ) {
3,101✔
85
                await queryRunner.broadcaster.broadcast(
819✔
86
                    "AfterRemove",
819✔
87
                    this.expressionMap.mainAlias!.metadata,
819✔
88
                )
819✔
89
            }
819✔
90

3,073✔
91
            // close transaction if we started it
3,073✔
92
            if (transactionStartedByUs) await queryRunner.commitTransaction()
3,101!
93

3,073✔
94
            return deleteResult
3,073✔
95
        } catch (error) {
3,101✔
96
            // rollback transaction if we started it
28✔
97
            if (transactionStartedByUs) {
28!
98
                try {
×
99
                    await queryRunner.rollbackTransaction()
×
100
                } catch (rollbackError) {}
×
101
            }
×
102
            throw error
28✔
103
        } finally {
3,101!
104
            if (queryRunner !== this.queryRunner) {
3,101✔
105
                // means we created our own query runner
765✔
106
                await queryRunner.release()
765✔
107
            }
765✔
108
        }
3,101✔
109
    }
3,101✔
110

26✔
111
    // -------------------------------------------------------------------------
26✔
112
    // Public Methods
26✔
113
    // -------------------------------------------------------------------------
26✔
114

26✔
115
    /**
26✔
116
     * Specifies FROM which entity's table select/update/delete will be executed.
26✔
117
     * Also sets a main string alias of the selection data.
26✔
118
     */
26✔
119
    from<T extends ObjectLiteral>(
26✔
120
        entityTarget: EntityTarget<T>,
4,437✔
121
        aliasName?: string,
4,437✔
122
    ): DeleteQueryBuilder<T> {
4,437✔
123
        entityTarget = InstanceChecker.isEntitySchema(entityTarget)
4,437✔
124
            ? entityTarget.options.name
4,437!
125
            : entityTarget
4,437✔
126
        const mainAlias = this.createFromAlias(entityTarget, aliasName)
4,437✔
127
        this.expressionMap.setMainAlias(mainAlias)
4,437✔
128
        return this as any as DeleteQueryBuilder<T>
4,437✔
129
    }
4,437✔
130

26✔
131
    /**
26✔
132
     * Sets WHERE condition in the query builder.
26✔
133
     * If you had previously WHERE expression defined,
26✔
134
     * calling this function will override previously set WHERE conditions.
26✔
135
     * Additionally you can add parameters used in where expression.
26✔
136
     */
26✔
137
    where(
26✔
138
        where:
4,473✔
139
            | Brackets
4,473✔
140
            | string
4,473✔
141
            | ((qb: this) => string)
4,473✔
142
            | ObjectLiteral
4,473✔
143
            | ObjectLiteral[],
4,473✔
144
        parameters?: ObjectLiteral,
4,473✔
145
    ): this {
4,473✔
146
        this.expressionMap.wheres = [] // don't move this block below since computeWhereParameter can add where expressions
4,473✔
147
        const condition = this.getWhereCondition(where)
4,473✔
148
        if (condition)
4,473✔
149
            this.expressionMap.wheres = [
4,473✔
150
                { type: "simple", condition: condition },
4,305✔
151
            ]
4,305✔
152
        if (parameters) this.setParameters(parameters)
4,473✔
153
        return this
4,305✔
154
    }
4,305✔
155

26✔
156
    /**
26✔
157
     * Adds new AND WHERE condition in the query builder.
26✔
158
     * Additionally you can add parameters used in where expression.
26✔
159
     */
26✔
160
    andWhere(
26✔
161
        where:
3,325✔
162
            | Brackets
3,325✔
163
            | string
3,325✔
164
            | ((qb: this) => string)
3,325✔
165
            | ObjectLiteral
3,325✔
166
            | ObjectLiteral[],
3,325✔
167
        parameters?: ObjectLiteral,
3,325✔
168
    ): this {
3,325✔
169
        this.expressionMap.wheres.push({
3,325✔
170
            type: "and",
3,325✔
171
            condition: this.getWhereCondition(where),
3,325✔
172
        })
3,325✔
173
        if (parameters) this.setParameters(parameters)
3,325✔
174
        return this
3,325✔
175
    }
3,325✔
176

26✔
177
    /**
26✔
178
     * Adds new OR WHERE condition in the query builder.
26✔
179
     * Additionally you can add parameters used in where expression.
26✔
180
     */
26✔
181
    orWhere(
26✔
182
        where:
2✔
183
            | Brackets
2✔
184
            | string
2✔
185
            | ((qb: this) => string)
2✔
186
            | ObjectLiteral
2✔
187
            | ObjectLiteral[],
2✔
188
        parameters?: ObjectLiteral,
2✔
189
    ): this {
2✔
190
        this.expressionMap.wheres.push({
2✔
191
            type: "or",
2✔
192
            condition: this.getWhereCondition(where),
2✔
193
        })
2✔
194
        if (parameters) this.setParameters(parameters)
2!
195
        return this
2✔
196
    }
2✔
197

26✔
198
    /**
26✔
199
     * Sets WHERE condition in the query builder with a condition for the given ids.
26✔
200
     * If you had previously WHERE expression defined,
26✔
201
     * calling this function will override previously set WHERE conditions.
26✔
202
     */
26✔
203
    whereInIds(ids: any | any[]): this {
26✔
204
        return this.where(this.getWhereInIdsCondition(ids))
158✔
205
    }
158✔
206

26✔
207
    /**
26✔
208
     * Adds new AND WHERE with conditions for the given ids.
26✔
209
     */
26✔
210
    andWhereInIds(ids: any | any[]): this {
26✔
211
        return this.andWhere(this.getWhereInIdsCondition(ids))
×
212
    }
×
213

26✔
214
    /**
26✔
215
     * Adds new OR WHERE with conditions for the given ids.
26✔
216
     */
26✔
217
    orWhereInIds(ids: any | any[]): this {
26✔
218
        return this.orWhere(this.getWhereInIdsCondition(ids))
×
219
    }
×
220
    /**
26✔
221
     * Optional returning/output clause.
26✔
222
     * This will return given column values.
26✔
223
     */
26✔
224
    output(columns: string[]): this
26✔
225

26✔
226
    /**
26✔
227
     * Optional returning/output clause.
26✔
228
     * Returning is a SQL string containing returning statement.
26✔
229
     */
26✔
230
    output(output: string): this
26✔
231

26✔
232
    /**
26✔
233
     * Optional returning/output clause.
26✔
234
     */
26✔
235
    output(output: string | string[]): this
26✔
236

26✔
237
    /**
26✔
238
     * Optional returning/output clause.
26✔
239
     */
26✔
240
    output(output: string | string[]): this {
26✔
241
        return this.returning(output)
×
242
    }
×
243

26✔
244
    /**
26✔
245
     * Optional returning/output clause.
26✔
246
     * This will return given column values.
26✔
247
     */
26✔
248
    returning(columns: string[]): this
26✔
249

26✔
250
    /**
26✔
251
     * Optional returning/output clause.
26✔
252
     * Returning is a SQL string containing returning statement.
26✔
253
     */
26✔
254
    returning(returning: string): this
26✔
255

26✔
256
    /**
26✔
257
     * Optional returning/output clause.
26✔
258
     */
26✔
259
    returning(returning: string | string[]): this
26✔
260

26✔
261
    /**
26✔
262
     * Optional returning/output clause.
26✔
263
     */
26✔
264
    returning(returning: string | string[]): this {
26✔
265
        // not all databases support returning/output cause
14✔
266
        if (!this.connection.driver.isReturningSqlSupported("delete")) {
14!
267
            throw new ReturningStatementNotSupportedError()
×
268
        }
×
269

14✔
270
        this.expressionMap.returning = returning
14✔
271
        return this
14✔
272
    }
14✔
273

26✔
274
    // -------------------------------------------------------------------------
26✔
275
    // Protected Methods
26✔
276
    // -------------------------------------------------------------------------
26✔
277

26✔
278
    /**
26✔
279
     * Creates DELETE express used to perform query.
26✔
280
     */
26✔
281
    protected createDeleteExpression() {
26✔
282
        const tableName = this.getTableName(this.getMainTableName())
4,367✔
283
        const whereExpression = this.createWhereExpression()
4,367✔
284
        const returningExpression = this.createReturningExpression("delete")
4,367✔
285

4,367✔
286
        if (returningExpression === "") {
4,367✔
287
            return `DELETE FROM ${tableName}${whereExpression}`
4,347✔
288
        }
4,347✔
289
        if (this.connection.driver.options.type === "mssql") {
2,268!
290
            return `DELETE FROM ${tableName} OUTPUT ${returningExpression}${whereExpression}`
4✔
291
        }
4✔
292
        if (this.connection.driver.options.type === "spanner") {
2,264!
293
            return `DELETE FROM ${tableName}${whereExpression} THEN RETURN ${returningExpression}`
×
294
        }
×
295
        return `DELETE FROM ${tableName}${whereExpression} RETURNING ${returningExpression}`
16✔
296
    }
16✔
297
}
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