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

typeorm / typeorm / 14796576772

02 May 2025 01:52PM UTC coverage: 45.367% (-30.9%) from 76.309%
14796576772

Pull #11434

github

web-flow
Merge ec4ce2d00 into fadad1a74
Pull Request #11434: feat: release PR releases using pkg.pr.new

5216 of 12761 branches covered (40.87%)

Branch coverage included in aggregate %.

11439 of 23951 relevant lines covered (47.76%)

15712.55 hits per line

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

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

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

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

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

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

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

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

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

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

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

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

91
            // close transaction if we started it
92
            if (transactionStartedByUs) await queryRunner.commitTransaction()
387!
93

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

286
        if (returningExpression === "") {
506✔
287
            return `DELETE FROM ${tableName}${whereExpression}`
505✔
288
        }
289
        if (this.connection.driver.options.type === "mssql") {
1!
290
            return `DELETE FROM ${tableName} OUTPUT ${returningExpression}${whereExpression}`
×
291
        }
292
        return `DELETE FROM ${tableName}${whereExpression} RETURNING ${returningExpression}`
1✔
293
    }
294
}
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

© 2025 Coveralls, Inc