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

typeorm / typeorm / 23275127489

19 Mar 2026 01:18AM UTC coverage: 73.259% (-0.02%) from 73.282%
23275127489

push

github

web-flow
refactor(find-options)!: remove deprecated string-based select from find methods (#12214)

37319 of 47623 branches covered (78.36%)

Branch coverage included in aggregate %.

25 of 34 new or added lines in 4 files covered. (73.53%)

3 existing lines in 1 file now uncovered.

83819 of 117732 relevant lines covered (71.19%)

64465.63 hits per line

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

84.48
/src/query-builder/SelectQueryBuilder.ts
1
import { RawSqlResultsToEntityTransformer } from "./transformer/RawSqlResultsToEntityTransformer"
28✔
2
import type { ObjectLiteral } from "../common/ObjectLiteral"
28✔
3
import { PessimisticLockTransactionRequiredError } from "../error/PessimisticLockTransactionRequiredError"
28✔
4
import { NoVersionOrUpdateDateColumnError } from "../error/NoVersionOrUpdateDateColumnError"
28✔
5
import { OptimisticLockVersionMismatchError } from "../error/OptimisticLockVersionMismatchError"
28✔
6
import { OptimisticLockCanNotBeUsedError } from "../error/OptimisticLockCanNotBeUsedError"
28✔
7
import { JoinAttribute } from "./JoinAttribute"
28✔
8
import { RelationIdAttribute } from "./relation-id/RelationIdAttribute"
28✔
9
import { RelationIdLoader } from "./relation-id/RelationIdLoader"
28✔
10
import { RelationIdLoader as QueryStrategyRelationIdLoader } from "./RelationIdLoader"
28✔
11
import { RelationIdMetadataToAttributeTransformer } from "./relation-id/RelationIdMetadataToAttributeTransformer"
28✔
12
import { QueryBuilder } from "./QueryBuilder"
28✔
13
import type { ReadStream } from "../platform/PlatformTools"
28✔
14
import { LockNotSupportedOnGivenDriverError } from "../error/LockNotSupportedOnGivenDriverError"
28✔
15
import type { MysqlDriver } from "../driver/mysql/MysqlDriver"
28✔
16
import type { SelectQuery } from "./SelectQuery"
28✔
17
import type { EntityMetadata } from "../metadata/EntityMetadata"
28✔
18
import type { ColumnMetadata } from "../metadata/ColumnMetadata"
28✔
19
import type { OrderByCondition } from "../find-options/OrderByCondition"
28✔
20
import type { QueryExpressionMap } from "./QueryExpressionMap"
28✔
21
import type { EntityTarget } from "../common/EntityTarget"
28✔
22
import type { QueryRunner } from "../query-runner/QueryRunner"
28✔
23
import type { WhereExpressionBuilder } from "./WhereExpressionBuilder"
28✔
24
import type { Brackets } from "./Brackets"
28✔
25
import type { QueryResultCacheOptions } from "../cache/QueryResultCacheOptions"
28✔
26
import { OffsetWithoutLimitNotSupportedError } from "../error/OffsetWithoutLimitNotSupportedError"
28✔
27
import type { SelectQueryBuilderOption } from "./SelectQueryBuilderOption"
28✔
28
import { ObjectUtils } from "../util/ObjectUtils"
28✔
29
import { DriverUtils } from "../driver/DriverUtils"
28✔
30
import type { AbstractSqliteDriver } from "../driver/sqlite-abstract/AbstractSqliteDriver"
28✔
31
import { EntityNotFoundError } from "../error/EntityNotFoundError"
28✔
32
import { TypeORMError } from "../error"
28✔
33
import type { FindManyOptions } from "../find-options/FindManyOptions"
28✔
34
import type { FindOptionsSelect } from "../find-options/FindOptionsSelect"
28✔
35
import type { RelationMetadata } from "../metadata/RelationMetadata"
28✔
36
import type { FindOptionsOrder } from "../find-options/FindOptionsOrder"
28✔
37
import type { FindOptionsWhere } from "../find-options/FindOptionsWhere"
28✔
38
import { FindOptionsUtils } from "../find-options/FindOptionsUtils"
28✔
39
import type { FindOptionsRelations } from "../find-options/FindOptionsRelations"
28✔
40
import { OrmUtils } from "../util/OrmUtils"
28✔
41
import { EntityPropertyNotFoundError } from "../error/EntityPropertyNotFoundError"
28✔
42
import type { AuroraMysqlDriver } from "../driver/aurora-mysql/AuroraMysqlDriver"
28✔
43
import { InstanceChecker } from "../util/InstanceChecker"
28✔
44
import { ApplyValueTransformers } from "../util/ApplyValueTransformers"
28✔
45
import type { SqlServerDriver } from "../driver/sqlserver/SqlServerDriver"
28✔
46
import type { ReactNativeDriver } from "../driver/react-native/ReactNativeDriver"
28✔
47

28✔
48
/**
28✔
49
 * Allows to build complex sql queries in a fashion way and execute those queries.
28✔
50
 */
28✔
51
export class SelectQueryBuilder<Entity extends ObjectLiteral>
569,908✔
52
    extends QueryBuilder<Entity>
569,908✔
53
    implements WhereExpressionBuilder
569,908✔
54
{
569,908✔
55
    readonly "@instanceof" = Symbol.for("SelectQueryBuilder")
569,908✔
56

569,908✔
57
    protected findOptions: FindManyOptions = {}
569,908✔
58
    protected selects: string[] = []
569,908✔
59
    protected joins: {
569,908✔
60
        type: "inner" | "left"
569,908✔
61
        alias: string
569,908✔
62
        parentAlias: string
569,908✔
63
        relationMetadata: RelationMetadata
569,908✔
64
        select: boolean
569,908✔
65
        selection: FindOptionsSelect<any> | undefined
569,908✔
66
    }[] = []
569,908✔
67
    protected conditions: string = ""
569,908✔
68
    protected orderBys: {
569,908✔
69
        alias: string
569,908✔
70
        direction: "ASC" | "DESC"
569,908✔
71
        nulls?: "NULLS FIRST" | "NULLS LAST"
569,908✔
72
    }[] = []
569,908✔
73
    protected relationMetadatas: RelationMetadata[] = []
569,908✔
74

569,908✔
75
    // -------------------------------------------------------------------------
569,908✔
76
    // Public Implemented Methods
569,908✔
77
    // -------------------------------------------------------------------------
569,908✔
78

569,908✔
79
    /**
569,908✔
80
     * Gets generated SQL query without parameters being replaced.
569,908✔
81
     */
569,908✔
82
    getQuery(): string {
569,908✔
83
        let sql = this.createComment()
278,600✔
84
        sql += this.createCteExpression()
278,600✔
85
        sql += this.createSelectExpression()
278,600✔
86
        sql += this.createJoinExpression()
278,600✔
87
        sql += this.createWhereExpression()
278,600✔
88
        sql += this.createGroupByExpression()
278,600✔
89
        sql += this.createHavingExpression()
278,600✔
90
        sql += this.createOrderByExpression()
278,600✔
91
        sql += this.createLimitOffsetExpression()
278,600✔
92
        sql += this.createLockExpression()
278,600✔
93
        sql = sql.trim()
278,600✔
94
        if (this.expressionMap.subQuery) sql = "(" + sql + ")"
278,600✔
95
        return this.replacePropertyNamesForTheWholeQuery(sql)
278,516✔
96
    }
278,516✔
97

569,908✔
98
    // -------------------------------------------------------------------------
569,908✔
99
    // Public Methods
569,908✔
100
    // -------------------------------------------------------------------------
569,908✔
101

569,908✔
102
    setFindOptions(findOptions: FindManyOptions<Entity>) {
569,908✔
103
        FindOptionsUtils.rejectJoinOption(findOptions)
175,202✔
104
        FindOptionsUtils.rejectStringArraySelect(findOptions)
175,202✔
105
        this.findOptions = findOptions
175,202✔
106
        this.applyFindOptions()
175,202✔
107
        return this
175,202✔
108
    }
175,202✔
109

569,908✔
110
    /**
569,908✔
111
     * Creates a subquery - query that can be used inside other queries.
569,908✔
112
     */
569,908✔
113
    subQuery(): SelectQueryBuilder<any> {
569,908✔
114
        const qb = this.createQueryBuilder()
2,646✔
115
        qb.expressionMap.subQuery = true
2,646✔
116
        qb.parentQueryBuilder = this
2,646✔
117
        return qb
2,646✔
118
    }
2,646✔
119

569,908✔
120
    /**
569,908✔
121
     * Creates SELECT query.
569,908✔
122
     * Replaces all previous selections if they exist.
569,908✔
123
     */
569,908✔
124
    select(): this
569,908✔
125

569,908✔
126
    /**
569,908✔
127
     * Creates SELECT query.
569,908✔
128
     * Replaces all previous selections if they exist.
569,908✔
129
     */
569,908✔
130
    select(
569,908✔
131
        selection: (qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>,
569,908✔
132
        selectionAliasName?: string,
569,908✔
133
    ): this
569,908✔
134

569,908✔
135
    /**
569,908✔
136
     * Creates SELECT query and selects given data.
569,908✔
137
     * Replaces all previous selections if they exist.
569,908✔
138
     */
569,908✔
139
    select(selection: string, selectionAliasName?: string): this
569,908✔
140

569,908✔
141
    /**
569,908✔
142
     * Creates SELECT query and selects given data.
569,908✔
143
     * Replaces all previous selections if they exist.
569,908✔
144
     */
569,908✔
145
    select(selection: string[]): this
569,908✔
146

569,908✔
147
    /**
569,908✔
148
     * Creates SELECT query and selects given data.
569,908✔
149
     * Replaces all previous selections if they exist.
569,908✔
150
     * @param selection
569,908✔
151
     * @param selectionAliasName
569,908✔
152
     */
569,908✔
153
    select(
569,908✔
154
        selection?:
275,171✔
155
            | string
275,171✔
156
            | string[]
275,171✔
157
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
275,171✔
158
        selectionAliasName?: string,
275,171✔
159
    ): SelectQueryBuilder<Entity> {
275,171✔
160
        this.expressionMap.queryType = "select"
275,171✔
161
        if (Array.isArray(selection)) {
275,171✔
162
            this.expressionMap.selects = selection.map((selection) => ({
9,571✔
163
                selection: selection,
10,989✔
164
            }))
9,571✔
165
        } else if (typeof selection === "function") {
275,171!
166
            const subQueryBuilder = selection(this.subQuery())
×
167
            this.setParameters(subQueryBuilder.getParameters())
×
168
            this.expressionMap.selects.push({
×
169
                selection: subQueryBuilder.getQuery(),
×
170
                aliasName: selectionAliasName,
×
171
            })
×
172
        } else if (selection) {
265,600✔
173
            this.expressionMap.selects = [
263,096✔
174
                { selection: selection, aliasName: selectionAliasName },
263,096✔
175
            ]
263,096✔
176
        }
263,096✔
177

275,171✔
178
        return this
275,171✔
179
    }
275,171✔
180

569,908✔
181
    /**
569,908✔
182
     * Adds new selection to the SELECT query.
569,908✔
183
     */
569,908✔
184
    addSelect(
569,908✔
185
        selection: (qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>,
569,908✔
186
        selectionAliasName?: string,
569,908✔
187
    ): this
569,908✔
188

569,908✔
189
    /**
569,908✔
190
     * Adds new selection to the SELECT query.
569,908✔
191
     */
569,908✔
192
    addSelect(selection: string, selectionAliasName?: string): this
569,908✔
193

569,908✔
194
    /**
569,908✔
195
     * Adds new selection to the SELECT query.
569,908✔
196
     */
569,908✔
197
    addSelect(selection: string[]): this
569,908✔
198

569,908✔
199
    /**
569,908✔
200
     * Adds new selection to the SELECT query.
569,908✔
201
     * @param selection
569,908✔
202
     * @param selectionAliasName
569,908✔
203
     */
569,908✔
204
    addSelect(
569,908✔
205
        selection:
695,479✔
206
            | string
695,479✔
207
            | string[]
695,479✔
208
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
695,479✔
209
        selectionAliasName?: string,
695,479✔
210
    ): this {
695,479✔
211
        if (!selection) return this
695,479✔
212

688,862✔
213
        if (Array.isArray(selection)) {
695,479!
214
            this.expressionMap.selects = this.expressionMap.selects.concat(
8,667✔
215
                selection.map((selection) => ({ selection: selection })),
8,667✔
216
            )
8,667✔
217
        } else if (typeof selection === "function") {
695,479✔
218
            const subQueryBuilder = selection(this.subQuery())
25✔
219
            this.setParameters(subQueryBuilder.getParameters())
25✔
220
            this.expressionMap.selects.push({
25✔
221
                selection: subQueryBuilder.getQuery(),
25✔
222
                aliasName: selectionAliasName,
25✔
223
            })
25✔
224
        } else if (selection) {
680,195✔
225
            this.expressionMap.selects.push({
680,170✔
226
                selection: selection,
680,170✔
227
                aliasName: selectionAliasName,
680,170✔
228
            })
680,170✔
229
        }
680,170✔
230

688,862✔
231
        return this
688,862✔
232
    }
688,862✔
233

569,908✔
234
    /**
569,908✔
235
     * Set max execution time.
569,908✔
236
     * @param milliseconds
569,908✔
237
     */
569,908✔
238
    maxExecutionTime(milliseconds: number): this {
569,908✔
239
        this.expressionMap.maxExecutionTime = milliseconds
×
240
        return this
×
241
    }
×
242

569,908✔
243
    /**
569,908✔
244
     * Sets whether the selection is DISTINCT.
569,908✔
245
     * @param distinct
569,908✔
246
     */
569,908✔
247
    distinct(distinct: boolean = true): this {
569,908✔
248
        this.expressionMap.selectDistinct = distinct
28✔
249
        return this
28✔
250
    }
28✔
251

569,908✔
252
    /**
569,908✔
253
     * Sets the distinct on clause for Postgres.
569,908✔
254
     * @param distinctOn
569,908✔
255
     */
569,908✔
256
    distinctOn(distinctOn: string[]): this {
569,908✔
257
        this.expressionMap.selectDistinctOn = distinctOn
12✔
258
        return this
12✔
259
    }
12✔
260

569,908✔
261
    fromDummy(): SelectQueryBuilder<any> {
569,908✔
262
        return this.from(
221✔
263
            this.connection.driver.dummyTableName ??
221!
264
                "(SELECT 1 AS dummy_column)",
221✔
265
            "dummy_table",
221✔
266
        )
221✔
267
    }
221✔
268

569,908✔
269
    /**
569,908✔
270
     * Specifies FROM which entity's table select/update/delete will be executed.
569,908✔
271
     * Also sets a main string alias of the selection data.
569,908✔
272
     * Removes all previously set from-s.
569,908✔
273
     */
569,908✔
274
    from<T extends ObjectLiteral>(
569,908✔
275
        entityTarget: (qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>,
569,908✔
276
        aliasName: string,
569,908✔
277
    ): SelectQueryBuilder<T>
569,908✔
278

569,908✔
279
    /**
569,908✔
280
     * Specifies FROM which entity's table select/update/delete will be executed.
569,908✔
281
     * Also sets a main string alias of the selection data.
569,908✔
282
     * Removes all previously set from-s.
569,908✔
283
     */
569,908✔
284
    from<T extends ObjectLiteral>(
569,908✔
285
        entityTarget: EntityTarget<T>,
569,908✔
286
        aliasName: string,
569,908✔
287
    ): SelectQueryBuilder<T>
569,908✔
288

569,908✔
289
    /**
569,908✔
290
     * Specifies FROM which entity's table select/update/delete will be executed.
569,908✔
291
     * Also sets a main string alias of the selection data.
569,908✔
292
     * Removes all previously set from-s.
569,908✔
293
     * @param entityTarget
569,908✔
294
     * @param aliasName
569,908✔
295
     */
569,908✔
296
    from<T extends ObjectLiteral>(
569,908✔
297
        entityTarget:
274,463✔
298
            | EntityTarget<T>
274,463✔
299
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
274,463✔
300
        aliasName: string,
274,463✔
301
    ): SelectQueryBuilder<T> {
274,463✔
302
        const mainAlias = this.createFromAlias(entityTarget, aliasName)
274,463✔
303
        this.expressionMap.setMainAlias(mainAlias)
274,463✔
304
        return this as any as SelectQueryBuilder<T>
274,463✔
305
    }
274,463✔
306

569,908✔
307
    /**
569,908✔
308
     * Specifies FROM which entity's table select/update/delete will be executed.
569,908✔
309
     * Also sets a main string alias of the selection data.
569,908✔
310
     */
569,908✔
311
    addFrom<T extends ObjectLiteral>(
569,908✔
312
        entityTarget: (qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>,
569,908✔
313
        aliasName: string,
569,908✔
314
    ): SelectQueryBuilder<T>
569,908✔
315

569,908✔
316
    /**
569,908✔
317
     * Specifies FROM which entity's table select/update/delete will be executed.
569,908✔
318
     * Also sets a main string alias of the selection data.
569,908✔
319
     */
569,908✔
320
    addFrom<T extends ObjectLiteral>(
569,908✔
321
        entityTarget: EntityTarget<T>,
569,908✔
322
        aliasName: string,
569,908✔
323
    ): SelectQueryBuilder<T>
569,908✔
324

569,908✔
325
    /**
569,908✔
326
     * Specifies FROM which entity's table select/update/delete will be executed.
569,908✔
327
     * Also sets a main string alias of the selection data.
569,908✔
328
     * @param entityTarget
569,908✔
329
     * @param aliasName
569,908✔
330
     */
569,908✔
331
    addFrom<T extends ObjectLiteral>(
569,908✔
332
        entityTarget:
39✔
333
            | EntityTarget<T>
39✔
334
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
39✔
335
        aliasName: string,
39✔
336
    ): SelectQueryBuilder<T> {
39✔
337
        const alias = this.createFromAlias(entityTarget, aliasName)
39✔
338
        if (!this.expressionMap.mainAlias)
39✔
339
            this.expressionMap.setMainAlias(alias)
39!
340

39✔
341
        return this as any as SelectQueryBuilder<T>
39✔
342
    }
39✔
343

569,908✔
344
    /**
569,908✔
345
     * INNER JOINs (without selection) given subquery.
569,908✔
346
     * You also need to specify an alias of the joined data.
569,908✔
347
     * Optionally, you can add condition and parameters used in condition.
569,908✔
348
     */
569,908✔
349
    innerJoin(
569,908✔
350
        subQueryFactory: (
569,908✔
351
            qb: SelectQueryBuilder<any>,
569,908✔
352
        ) => SelectQueryBuilder<any>,
569,908✔
353
        alias: string,
569,908✔
354
        condition?: string,
569,908✔
355
        parameters?: ObjectLiteral,
569,908✔
356
    ): this
569,908✔
357

569,908✔
358
    /**
569,908✔
359
     * INNER JOINs (without selection) entity's property.
569,908✔
360
     * Given entity property should be a relation.
569,908✔
361
     * You also need to specify an alias of the joined data.
569,908✔
362
     * Optionally, you can add condition and parameters used in condition.
569,908✔
363
     */
569,908✔
364
    innerJoin(
569,908✔
365
        property: string,
569,908✔
366
        alias: string,
569,908✔
367
        condition?: string,
569,908✔
368
        parameters?: ObjectLiteral,
569,908✔
369
    ): this
569,908✔
370

569,908✔
371
    /**
569,908✔
372
     * INNER JOINs (without selection) given entity's table.
569,908✔
373
     * You also need to specify an alias of the joined data.
569,908✔
374
     * Optionally, you can add condition and parameters used in condition.
569,908✔
375
     */
569,908✔
376
    innerJoin(
569,908✔
377
        entity: Function | string,
569,908✔
378
        alias: string,
569,908✔
379
        condition?: string,
569,908✔
380
        parameters?: ObjectLiteral,
569,908✔
381
    ): this
569,908✔
382

569,908✔
383
    /**
569,908✔
384
     * INNER JOINs (without selection) given table.
569,908✔
385
     * You also need to specify an alias of the joined data.
569,908✔
386
     * Optionally, you can add condition and parameters used in condition.
569,908✔
387
     */
569,908✔
388
    innerJoin(
569,908✔
389
        tableName: string,
569,908✔
390
        alias: string,
569,908✔
391
        condition?: string,
569,908✔
392
        parameters?: ObjectLiteral,
569,908✔
393
    ): this
569,908✔
394

569,908✔
395
    /**
569,908✔
396
     * INNER JOINs (without selection).
569,908✔
397
     * You also need to specify an alias of the joined data.
569,908✔
398
     * Optionally, you can add condition and parameters used in condition.
569,908✔
399
     * @param entityOrProperty
569,908✔
400
     * @param alias
569,908✔
401
     * @param condition
569,908✔
402
     * @param parameters
569,908✔
403
     */
569,908✔
404
    innerJoin(
569,908✔
405
        entityOrProperty:
8,250✔
406
            | Function
8,250✔
407
            | string
8,250✔
408
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
8,250✔
409
        alias: string,
8,250✔
410
        condition?: string,
8,250✔
411
        parameters?: ObjectLiteral,
8,250✔
412
    ): this {
8,250✔
413
        this.join("INNER", entityOrProperty, alias, condition, parameters)
8,250✔
414
        return this
8,250✔
415
    }
8,250✔
416

569,908✔
417
    /**
569,908✔
418
     * LEFT JOINs (without selection) given subquery.
569,908✔
419
     * You also need to specify an alias of the joined data.
569,908✔
420
     * Optionally, you can add condition and parameters used in condition.
569,908✔
421
     */
569,908✔
422
    leftJoin(
569,908✔
423
        subQueryFactory: (
569,908✔
424
            qb: SelectQueryBuilder<any>,
569,908✔
425
        ) => SelectQueryBuilder<any>,
569,908✔
426
        alias: string,
569,908✔
427
        condition?: string,
569,908✔
428
        parameters?: ObjectLiteral,
569,908✔
429
    ): this
569,908✔
430

569,908✔
431
    /**
569,908✔
432
     * LEFT JOINs (without selection) entity's property.
569,908✔
433
     * Given entity property should be a relation.
569,908✔
434
     * You also need to specify an alias of the joined data.
569,908✔
435
     * Optionally, you can add condition and parameters used in condition.
569,908✔
436
     */
569,908✔
437
    leftJoin(
569,908✔
438
        property: string,
569,908✔
439
        alias: string,
569,908✔
440
        condition?: string,
569,908✔
441
        parameters?: ObjectLiteral,
569,908✔
442
    ): this
569,908✔
443

569,908✔
444
    /**
569,908✔
445
     * LEFT JOINs (without selection) entity's table.
569,908✔
446
     * You also need to specify an alias of the joined data.
569,908✔
447
     * Optionally, you can add condition and parameters used in condition.
569,908✔
448
     */
569,908✔
449
    leftJoin(
569,908✔
450
        entity: Function | string,
569,908✔
451
        alias: string,
569,908✔
452
        condition?: string,
569,908✔
453
        parameters?: ObjectLiteral,
569,908✔
454
    ): this
569,908✔
455

569,908✔
456
    /**
569,908✔
457
     * LEFT JOINs (without selection) given table.
569,908✔
458
     * You also need to specify an alias of the joined data.
569,908✔
459
     * Optionally, you can add condition and parameters used in condition.
569,908✔
460
     */
569,908✔
461
    leftJoin(
569,908✔
462
        tableName: string,
569,908✔
463
        alias: string,
569,908✔
464
        condition?: string,
569,908✔
465
        parameters?: ObjectLiteral,
569,908✔
466
    ): this
569,908✔
467

569,908✔
468
    /**
569,908✔
469
     * LEFT JOINs (without selection).
569,908✔
470
     * You also need to specify an alias of the joined data.
569,908✔
471
     * Optionally, you can add condition and parameters used in condition.
569,908✔
472
     * @param entityOrProperty
569,908✔
473
     * @param alias
569,908✔
474
     * @param condition
569,908✔
475
     * @param parameters
569,908✔
476
     */
569,908✔
477
    leftJoin(
569,908✔
478
        entityOrProperty:
659,777✔
479
            | Function
659,777✔
480
            | string
659,777✔
481
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
659,777✔
482
        alias: string,
659,777✔
483
        condition?: string,
659,777✔
484
        parameters?: ObjectLiteral,
659,777✔
485
    ): this {
659,777✔
486
        this.join("LEFT", entityOrProperty, alias, condition, parameters)
659,777✔
487
        return this
659,777✔
488
    }
659,777✔
489

569,908✔
490
    /**
569,908✔
491
     * INNER JOINs given subquery and adds all selection properties to SELECT..
569,908✔
492
     * You also need to specify an alias of the joined data.
569,908✔
493
     * Optionally, you can add condition and parameters used in condition.
569,908✔
494
     */
569,908✔
495
    innerJoinAndSelect(
569,908✔
496
        subQueryFactory: (
569,908✔
497
            qb: SelectQueryBuilder<any>,
569,908✔
498
        ) => SelectQueryBuilder<any>,
569,908✔
499
        alias: string,
569,908✔
500
        condition?: string,
569,908✔
501
        parameters?: ObjectLiteral,
569,908✔
502
    ): this
569,908✔
503

569,908✔
504
    /**
569,908✔
505
     * INNER JOINs entity's property and adds all selection properties to SELECT.
569,908✔
506
     * Given entity property should be a relation.
569,908✔
507
     * You also need to specify an alias of the joined data.
569,908✔
508
     * Optionally, you can add condition and parameters used in condition.
569,908✔
509
     */
569,908✔
510
    innerJoinAndSelect(
569,908✔
511
        property: string,
569,908✔
512
        alias: string,
569,908✔
513
        condition?: string,
569,908✔
514
        parameters?: ObjectLiteral,
569,908✔
515
    ): this
569,908✔
516

569,908✔
517
    /**
569,908✔
518
     * INNER JOINs entity and adds all selection properties to SELECT.
569,908✔
519
     * You also need to specify an alias of the joined data.
569,908✔
520
     * Optionally, you can add condition and parameters used in condition.
569,908✔
521
     */
569,908✔
522
    innerJoinAndSelect(
569,908✔
523
        entity: Function | string,
569,908✔
524
        alias: string,
569,908✔
525
        condition?: string,
569,908✔
526
        parameters?: ObjectLiteral,
569,908✔
527
    ): this
569,908✔
528

569,908✔
529
    /**
569,908✔
530
     * INNER JOINs table and adds all selection properties to SELECT.
569,908✔
531
     * You also need to specify an alias of the joined data.
569,908✔
532
     * Optionally, you can add condition and parameters used in condition.
569,908✔
533
     */
569,908✔
534
    innerJoinAndSelect(
569,908✔
535
        tableName: string,
569,908✔
536
        alias: string,
569,908✔
537
        condition?: string,
569,908✔
538
        parameters?: ObjectLiteral,
569,908✔
539
    ): this
569,908✔
540

569,908✔
541
    /**
569,908✔
542
     * INNER JOINs and adds all selection properties to SELECT.
569,908✔
543
     * You also need to specify an alias of the joined data.
569,908✔
544
     * Optionally, you can add condition and parameters used in condition.
569,908✔
545
     * @param entityOrProperty
569,908✔
546
     * @param alias
569,908✔
547
     * @param condition
569,908✔
548
     * @param parameters
569,908✔
549
     */
569,908✔
550
    innerJoinAndSelect(
569,908✔
551
        entityOrProperty:
398✔
552
            | Function
398✔
553
            | string
398✔
554
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
398✔
555
        alias: string,
398✔
556
        condition?: string,
398✔
557
        parameters?: ObjectLiteral,
398✔
558
    ): this {
398✔
559
        this.addSelect(alias)
398✔
560
        this.innerJoin(entityOrProperty, alias, condition, parameters)
398✔
561
        return this
398✔
562
    }
398✔
563

569,908✔
564
    /**
569,908✔
565
     * LEFT JOINs given subquery and adds all selection properties to SELECT..
569,908✔
566
     * You also need to specify an alias of the joined data.
569,908✔
567
     * Optionally, you can add condition and parameters used in condition.
569,908✔
568
     */
569,908✔
569
    leftJoinAndSelect(
569,908✔
570
        subQueryFactory: (
569,908✔
571
            qb: SelectQueryBuilder<any>,
569,908✔
572
        ) => SelectQueryBuilder<any>,
569,908✔
573
        alias: string,
569,908✔
574
        condition?: string,
569,908✔
575
        parameters?: ObjectLiteral,
569,908✔
576
    ): this
569,908✔
577

569,908✔
578
    /**
569,908✔
579
     * LEFT JOINs entity's property and adds all selection properties to SELECT.
569,908✔
580
     * Given entity property should be a relation.
569,908✔
581
     * You also need to specify an alias of the joined data.
569,908✔
582
     * Optionally, you can add condition and parameters used in condition.
569,908✔
583
     */
569,908✔
584
    leftJoinAndSelect(
569,908✔
585
        property: string,
569,908✔
586
        alias: string,
569,908✔
587
        condition?: string,
569,908✔
588
        parameters?: ObjectLiteral,
569,908✔
589
    ): this
569,908✔
590

569,908✔
591
    /**
569,908✔
592
     * LEFT JOINs entity and adds all selection properties to SELECT.
569,908✔
593
     * You also need to specify an alias of the joined data.
569,908✔
594
     * Optionally, you can add condition and parameters used in condition.
569,908✔
595
     */
569,908✔
596
    leftJoinAndSelect(
569,908✔
597
        entity: Function | string,
569,908✔
598
        alias: string,
569,908✔
599
        condition?: string,
569,908✔
600
        parameters?: ObjectLiteral,
569,908✔
601
    ): this
569,908✔
602

569,908✔
603
    /**
569,908✔
604
     * LEFT JOINs table and adds all selection properties to SELECT.
569,908✔
605
     * You also need to specify an alias of the joined data.
569,908✔
606
     * Optionally, you can add condition and parameters used in condition.
569,908✔
607
     */
569,908✔
608
    leftJoinAndSelect(
569,908✔
609
        tableName: string,
569,908✔
610
        alias: string,
569,908✔
611
        condition?: string,
569,908✔
612
        parameters?: ObjectLiteral,
569,908✔
613
    ): this
569,908✔
614

569,908✔
615
    /**
569,908✔
616
     * LEFT JOINs and adds all selection properties to SELECT.
569,908✔
617
     * You also need to specify an alias of the joined data.
569,908✔
618
     * Optionally, you can add condition and parameters used in condition.
569,908✔
619
     * @param entityOrProperty
569,908✔
620
     * @param alias
569,908✔
621
     * @param condition
569,908✔
622
     * @param parameters
569,908✔
623
     */
569,908✔
624
    leftJoinAndSelect(
569,908✔
625
        entityOrProperty:
655,296✔
626
            | Function
655,296✔
627
            | string
655,296✔
628
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
655,296✔
629
        alias: string,
655,296✔
630
        condition?: string,
655,296✔
631
        parameters?: ObjectLiteral,
655,296✔
632
    ): this {
655,296✔
633
        this.addSelect(alias)
655,296✔
634
        this.leftJoin(entityOrProperty, alias, condition, parameters)
655,296✔
635
        return this
655,296✔
636
    }
655,296✔
637

569,908✔
638
    /**
569,908✔
639
     * INNER JOINs given subquery, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
640
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
641
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
569,908✔
642
     * Given entity property should be a relation.
569,908✔
643
     * You also need to specify an alias of the joined data.
569,908✔
644
     * Optionally, you can add condition and parameters used in condition.
569,908✔
645
     */
569,908✔
646
    innerJoinAndMapMany(
569,908✔
647
        mapToProperty: string,
569,908✔
648
        subQueryFactory: (
569,908✔
649
            qb: SelectQueryBuilder<any>,
569,908✔
650
        ) => SelectQueryBuilder<any>,
569,908✔
651
        alias: string,
569,908✔
652
        condition?: string,
569,908✔
653
        parameters?: ObjectLiteral,
569,908✔
654
    ): this
569,908✔
655

569,908✔
656
    /**
569,908✔
657
     * INNER JOINs entity's property, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
658
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
659
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
569,908✔
660
     * Given entity property should be a relation.
569,908✔
661
     * You also need to specify an alias of the joined data.
569,908✔
662
     * Optionally, you can add condition and parameters used in condition.
569,908✔
663
     */
569,908✔
664
    innerJoinAndMapMany(
569,908✔
665
        mapToProperty: string,
569,908✔
666
        property: string,
569,908✔
667
        alias: string,
569,908✔
668
        condition?: string,
569,908✔
669
        parameters?: ObjectLiteral,
569,908✔
670
    ): this
569,908✔
671

569,908✔
672
    /**
569,908✔
673
     * INNER JOINs entity's table, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
674
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
675
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
569,908✔
676
     * You also need to specify an alias of the joined data.
569,908✔
677
     * Optionally, you can add condition and parameters used in condition.
569,908✔
678
     */
569,908✔
679
    innerJoinAndMapMany(
569,908✔
680
        mapToProperty: string,
569,908✔
681
        entity: Function | string,
569,908✔
682
        alias: string,
569,908✔
683
        condition?: string,
569,908✔
684
        parameters?: ObjectLiteral,
569,908✔
685
    ): this
569,908✔
686

569,908✔
687
    /**
569,908✔
688
     * INNER JOINs table, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
689
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
690
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
569,908✔
691
     * You also need to specify an alias of the joined data.
569,908✔
692
     * Optionally, you can add condition and parameters used in condition.
569,908✔
693
     */
569,908✔
694
    innerJoinAndMapMany(
569,908✔
695
        mapToProperty: string,
569,908✔
696
        tableName: string,
569,908✔
697
        alias: string,
569,908✔
698
        condition?: string,
569,908✔
699
        parameters?: ObjectLiteral,
569,908✔
700
    ): this
569,908✔
701

569,908✔
702
    /**
569,908✔
703
     * INNER JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
704
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
705
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
569,908✔
706
     * You also need to specify an alias of the joined data.
569,908✔
707
     * Optionally, you can add condition and parameters used in condition.
569,908✔
708
     * @param mapToProperty
569,908✔
709
     * @param entityOrProperty
569,908✔
710
     * @param alias
569,908✔
711
     * @param condition
569,908✔
712
     * @param parameters
569,908✔
713
     */
569,908✔
714
    innerJoinAndMapMany(
569,908✔
715
        mapToProperty: string,
250✔
716
        entityOrProperty:
250✔
717
            | Function
250✔
718
            | string
250✔
719
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
250✔
720
        alias: string,
250✔
721
        condition?: string,
250✔
722
        parameters?: ObjectLiteral,
250✔
723
    ): this {
250✔
724
        this.addSelect(alias)
250✔
725
        this.join(
250✔
726
            "INNER",
250✔
727
            entityOrProperty,
250✔
728
            alias,
250✔
729
            condition,
250✔
730
            parameters,
250✔
731
            mapToProperty,
250✔
732
            true,
250✔
733
        )
250✔
734
        return this
250✔
735
    }
250✔
736

569,908✔
737
    /**
569,908✔
738
     * INNER JOINs given subquery, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
739
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
740
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
569,908✔
741
     * Given entity property should be a relation.
569,908✔
742
     * You also need to specify an alias of the joined data.
569,908✔
743
     * Optionally, you can add condition and parameters used in condition.
569,908✔
744
     */
569,908✔
745
    innerJoinAndMapOne(
569,908✔
746
        mapToProperty: string,
569,908✔
747
        subQueryFactory: (
569,908✔
748
            qb: SelectQueryBuilder<any>,
569,908✔
749
        ) => SelectQueryBuilder<any>,
569,908✔
750
        alias: string,
569,908✔
751
        condition?: string,
569,908✔
752
        parameters?: ObjectLiteral,
569,908✔
753
        mapAsEntity?: Function | string,
569,908✔
754
    ): this
569,908✔
755

569,908✔
756
    /**
569,908✔
757
     * INNER JOINs entity's property, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
758
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
759
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
569,908✔
760
     * Given entity property should be a relation.
569,908✔
761
     * You also need to specify an alias of the joined data.
569,908✔
762
     * Optionally, you can add condition and parameters used in condition.
569,908✔
763
     */
569,908✔
764
    innerJoinAndMapOne(
569,908✔
765
        mapToProperty: string,
569,908✔
766
        property: string,
569,908✔
767
        alias: string,
569,908✔
768
        condition?: string,
569,908✔
769
        parameters?: ObjectLiteral,
569,908✔
770
    ): this
569,908✔
771

569,908✔
772
    /**
569,908✔
773
     * INNER JOINs entity's table, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
774
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
775
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
569,908✔
776
     * You also need to specify an alias of the joined data.
569,908✔
777
     * Optionally, you can add condition and parameters used in condition.
569,908✔
778
     */
569,908✔
779
    innerJoinAndMapOne(
569,908✔
780
        mapToProperty: string,
569,908✔
781
        entity: Function | string,
569,908✔
782
        alias: string,
569,908✔
783
        condition?: string,
569,908✔
784
        parameters?: ObjectLiteral,
569,908✔
785
    ): this
569,908✔
786

569,908✔
787
    /**
569,908✔
788
     * INNER JOINs table, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
789
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
790
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
569,908✔
791
     * You also need to specify an alias of the joined data.
569,908✔
792
     * Optionally, you can add condition and parameters used in condition.
569,908✔
793
     */
569,908✔
794
    innerJoinAndMapOne(
569,908✔
795
        mapToProperty: string,
569,908✔
796
        tableName: string,
569,908✔
797
        alias: string,
569,908✔
798
        condition?: string,
569,908✔
799
        parameters?: ObjectLiteral,
569,908✔
800
    ): this
569,908✔
801

569,908✔
802
    /**
569,908✔
803
     * INNER JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
804
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
805
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
569,908✔
806
     * You also need to specify an alias of the joined data.
569,908✔
807
     * Optionally, you can add condition and parameters used in condition.
569,908✔
808
     * @param mapToProperty
569,908✔
809
     * @param entityOrProperty
569,908✔
810
     * @param alias
569,908✔
811
     * @param condition
569,908✔
812
     * @param parameters
569,908✔
813
     * @param mapAsEntity
569,908✔
814
     */
569,908✔
815
    innerJoinAndMapOne(
569,908✔
816
        mapToProperty: string,
200✔
817
        entityOrProperty:
200✔
818
            | Function
200✔
819
            | string
200✔
820
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
200✔
821
        alias: string,
200✔
822
        condition?: string,
200✔
823
        parameters?: ObjectLiteral,
200✔
824
        mapAsEntity?: Function | string,
200✔
825
    ): this {
200✔
826
        this.addSelect(alias)
200✔
827
        this.join(
200✔
828
            "INNER",
200✔
829
            entityOrProperty,
200✔
830
            alias,
200✔
831
            condition,
200✔
832
            parameters,
200✔
833
            mapToProperty,
200✔
834
            false,
200✔
835
            mapAsEntity,
200✔
836
        )
200✔
837
        return this
200✔
838
    }
200✔
839

569,908✔
840
    /**
569,908✔
841
     * LEFT JOINs given subquery, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
842
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
843
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
569,908✔
844
     * Given entity property should be a relation.
569,908✔
845
     * You also need to specify an alias of the joined data.
569,908✔
846
     * Optionally, you can add condition and parameters used in condition.
569,908✔
847
     */
569,908✔
848
    leftJoinAndMapMany(
569,908✔
849
        mapToProperty: string,
569,908✔
850
        subQueryFactory: (
569,908✔
851
            qb: SelectQueryBuilder<any>,
569,908✔
852
        ) => SelectQueryBuilder<any>,
569,908✔
853
        alias: string,
569,908✔
854
        condition?: string,
569,908✔
855
        parameters?: ObjectLiteral,
569,908✔
856
    ): this
569,908✔
857

569,908✔
858
    /**
569,908✔
859
     * LEFT JOINs entity's property, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
860
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
861
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
569,908✔
862
     * Given entity property should be a relation.
569,908✔
863
     * You also need to specify an alias of the joined data.
569,908✔
864
     * Optionally, you can add condition and parameters used in condition.
569,908✔
865
     */
569,908✔
866
    leftJoinAndMapMany(
569,908✔
867
        mapToProperty: string,
569,908✔
868
        property: string,
569,908✔
869
        alias: string,
569,908✔
870
        condition?: string,
569,908✔
871
        parameters?: ObjectLiteral,
569,908✔
872
    ): this
569,908✔
873

569,908✔
874
    /**
569,908✔
875
     * LEFT JOINs entity's table, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
876
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
877
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
569,908✔
878
     * You also need to specify an alias of the joined data.
569,908✔
879
     * Optionally, you can add condition and parameters used in condition.
569,908✔
880
     */
569,908✔
881
    leftJoinAndMapMany(
569,908✔
882
        mapToProperty: string,
569,908✔
883
        entity: Function | string,
569,908✔
884
        alias: string,
569,908✔
885
        condition?: string,
569,908✔
886
        parameters?: ObjectLiteral,
569,908✔
887
    ): this
569,908✔
888

569,908✔
889
    /**
569,908✔
890
     * LEFT JOINs table, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
891
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
892
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
569,908✔
893
     * You also need to specify an alias of the joined data.
569,908✔
894
     * Optionally, you can add condition and parameters used in condition.
569,908✔
895
     */
569,908✔
896
    leftJoinAndMapMany(
569,908✔
897
        mapToProperty: string,
569,908✔
898
        tableName: string,
569,908✔
899
        alias: string,
569,908✔
900
        condition?: string,
569,908✔
901
        parameters?: ObjectLiteral,
569,908✔
902
    ): this
569,908✔
903

569,908✔
904
    /**
569,908✔
905
     * LEFT JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
906
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
907
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
569,908✔
908
     * You also need to specify an alias of the joined data.
569,908✔
909
     * Optionally, you can add condition and parameters used in condition.
569,908✔
910
     * @param mapToProperty
569,908✔
911
     * @param entityOrProperty
569,908✔
912
     * @param alias
569,908✔
913
     * @param condition
569,908✔
914
     * @param parameters
569,908✔
915
     */
569,908✔
916
    leftJoinAndMapMany(
569,908✔
917
        mapToProperty: string,
379✔
918
        entityOrProperty:
379✔
919
            | Function
379✔
920
            | string
379✔
921
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
379✔
922
        alias: string,
379✔
923
        condition?: string,
379✔
924
        parameters?: ObjectLiteral,
379✔
925
    ): this {
379✔
926
        this.addSelect(alias)
379✔
927
        this.join(
379✔
928
            "LEFT",
379✔
929
            entityOrProperty,
379✔
930
            alias,
379✔
931
            condition,
379✔
932
            parameters,
379✔
933
            mapToProperty,
379✔
934
            true,
379✔
935
        )
379✔
936
        return this
379✔
937
    }
379✔
938

569,908✔
939
    /**
569,908✔
940
     * LEFT JOINs given subquery, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
941
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
942
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
569,908✔
943
     * Given entity property should be a relation.
569,908✔
944
     * You also need to specify an alias of the joined data.
569,908✔
945
     * Optionally, you can add condition and parameters used in condition.
569,908✔
946
     */
569,908✔
947
    leftJoinAndMapOne(
569,908✔
948
        mapToProperty: string,
569,908✔
949
        subQueryFactory: (
569,908✔
950
            qb: SelectQueryBuilder<any>,
569,908✔
951
        ) => SelectQueryBuilder<any>,
569,908✔
952
        alias: string,
569,908✔
953
        condition?: string,
569,908✔
954
        parameters?: ObjectLiteral,
569,908✔
955
        mapAsEntity?: Function | string,
569,908✔
956
    ): this
569,908✔
957

569,908✔
958
    /**
569,908✔
959
     * LEFT JOINs entity's property, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
960
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
961
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
569,908✔
962
     * Given entity property should be a relation.
569,908✔
963
     * You also need to specify an alias of the joined data.
569,908✔
964
     * Optionally, you can add condition and parameters used in condition.
569,908✔
965
     */
569,908✔
966
    leftJoinAndMapOne(
569,908✔
967
        mapToProperty: string,
569,908✔
968
        property: string,
569,908✔
969
        alias: string,
569,908✔
970
        condition?: string,
569,908✔
971
        parameters?: ObjectLiteral,
569,908✔
972
    ): this
569,908✔
973

569,908✔
974
    /**
569,908✔
975
     * LEFT JOINs entity's table, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
976
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
977
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
569,908✔
978
     * You also need to specify an alias of the joined data.
569,908✔
979
     * Optionally, you can add condition and parameters used in condition.
569,908✔
980
     */
569,908✔
981
    leftJoinAndMapOne(
569,908✔
982
        mapToProperty: string,
569,908✔
983
        entity: Function | string,
569,908✔
984
        alias: string,
569,908✔
985
        condition?: string,
569,908✔
986
        parameters?: ObjectLiteral,
569,908✔
987
    ): this
569,908✔
988

569,908✔
989
    /**
569,908✔
990
     * LEFT JOINs table, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
991
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
992
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
569,908✔
993
     * You also need to specify an alias of the joined data.
569,908✔
994
     * Optionally, you can add condition and parameters used in condition.
569,908✔
995
     */
569,908✔
996
    leftJoinAndMapOne(
569,908✔
997
        mapToProperty: string,
569,908✔
998
        tableName: string,
569,908✔
999
        alias: string,
569,908✔
1000
        condition?: string,
569,908✔
1001
        parameters?: ObjectLiteral,
569,908✔
1002
    ): this
569,908✔
1003

569,908✔
1004
    /**
569,908✔
1005
     * LEFT JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property.
569,908✔
1006
     * This is extremely useful when you want to select some data and map it to some virtual property.
569,908✔
1007
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
569,908✔
1008
     * You also need to specify an alias of the joined data.
569,908✔
1009
     * Optionally, you can add condition and parameters used in condition.
569,908✔
1010
     * @param mapToProperty
569,908✔
1011
     * @param entityOrProperty
569,908✔
1012
     * @param alias
569,908✔
1013
     * @param condition
569,908✔
1014
     * @param parameters
569,908✔
1015
     * @param mapAsEntity
569,908✔
1016
     */
569,908✔
1017
    leftJoinAndMapOne(
569,908✔
1018
        mapToProperty: string,
279✔
1019
        entityOrProperty:
279✔
1020
            | Function
279✔
1021
            | string
279✔
1022
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
279✔
1023
        alias: string,
279✔
1024
        condition?: string,
279✔
1025
        parameters?: ObjectLiteral,
279✔
1026
        mapAsEntity?: Function | string,
279✔
1027
    ): this {
279✔
1028
        this.addSelect(alias)
279✔
1029
        this.join(
279✔
1030
            "LEFT",
279✔
1031
            entityOrProperty,
279✔
1032
            alias,
279✔
1033
            condition,
279✔
1034
            parameters,
279✔
1035
            mapToProperty,
279✔
1036
            false,
279✔
1037
            mapAsEntity,
279✔
1038
        )
279✔
1039
        return this
279✔
1040
    }
279✔
1041

569,908✔
1042
    /**
569,908✔
1043
     */
569,908✔
1044
    // selectAndMap(mapToProperty: string, property: string, aliasName: string, qbFactory: ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>)): this;
569,908✔
1045

569,908✔
1046
    /**
569,908✔
1047
     */
569,908✔
1048
    // selectAndMap(mapToProperty: string, entity: Function|string, aliasName: string, qbFactory: ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>)): this;
569,908✔
1049

569,908✔
1050
    /**
569,908✔
1051
     */
569,908✔
1052
    // selectAndMap(mapToProperty: string, tableName: string, aliasName: string, qbFactory: ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>)): this;
569,908✔
1053

569,908✔
1054
    /**
569,908✔
1055
     */
569,908✔
1056
    // selectAndMap(mapToProperty: string, entityOrProperty: Function|string, aliasName: string, qbFactory: ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>)): this {
569,908✔
1057
    //     const select = new SelectAttribute(this.expressionMap);
569,908✔
1058
    //     select.mapToProperty = mapToProperty;
569,908✔
1059
    //     select.entityOrProperty = entityOrProperty;
569,908✔
1060
    //     select.aliasName = aliasName;
569,908✔
1061
    //     select.qbFactory = qbFactory;
569,908✔
1062
    //     return this;
569,908✔
1063
    // }
569,908✔
1064

569,908✔
1065
    /**
569,908✔
1066
     * LEFT JOINs relation id and maps it into some entity's property.
569,908✔
1067
     * Optionally, you can add condition and parameters used in condition.
569,908✔
1068
     */
569,908✔
1069
    loadRelationIdAndMap(
569,908✔
1070
        mapToProperty: string,
569,908✔
1071
        relationName: string,
569,908✔
1072
        options?: { disableMixedMap?: boolean },
569,908✔
1073
    ): this
569,908✔
1074

569,908✔
1075
    /**
569,908✔
1076
     * LEFT JOINs relation id and maps it into some entity's property.
569,908✔
1077
     * Optionally, you can add condition and parameters used in condition.
569,908✔
1078
     */
569,908✔
1079
    loadRelationIdAndMap(
569,908✔
1080
        mapToProperty: string,
569,908✔
1081
        relationName: string,
569,908✔
1082
        alias: string,
569,908✔
1083
        queryBuilderFactory: (
569,908✔
1084
            qb: SelectQueryBuilder<any>,
569,908✔
1085
        ) => SelectQueryBuilder<any>,
569,908✔
1086
    ): this
569,908✔
1087

569,908✔
1088
    /**
569,908✔
1089
     * LEFT JOINs relation id and maps it into some entity's property.
569,908✔
1090
     * Optionally, you can add condition and parameters used in condition.
569,908✔
1091
     * @param mapToProperty
569,908✔
1092
     * @param relationName
569,908✔
1093
     * @param aliasNameOrOptions
569,908✔
1094
     * @param queryBuilderFactory
569,908✔
1095
     */
569,908✔
1096
    loadRelationIdAndMap(
569,908✔
1097
        mapToProperty: string,
28,815✔
1098
        relationName: string,
28,815✔
1099
        aliasNameOrOptions?: string | { disableMixedMap?: boolean },
28,815✔
1100
        queryBuilderFactory?: (
28,815✔
1101
            qb: SelectQueryBuilder<any>,
28,815✔
1102
        ) => SelectQueryBuilder<any>,
28,815✔
1103
    ): this {
28,815✔
1104
        const relationIdAttribute = new RelationIdAttribute(this.expressionMap)
28,815✔
1105
        relationIdAttribute.mapToProperty = mapToProperty
28,815✔
1106
        relationIdAttribute.relationName = relationName
28,815✔
1107
        if (typeof aliasNameOrOptions === "string")
28,815✔
1108
            relationIdAttribute.alias = aliasNameOrOptions
28,815!
1109
        if (
28,815✔
1110
            typeof aliasNameOrOptions === "object" &&
28,815✔
1111
            (aliasNameOrOptions as any).disableMixedMap
25,665✔
1112
        )
28,815✔
1113
            relationIdAttribute.disableMixedMap = true
28,815✔
1114

28,815✔
1115
        relationIdAttribute.queryBuilderFactory = queryBuilderFactory
28,815✔
1116
        this.expressionMap.relationIdAttributes.push(relationIdAttribute)
28,815✔
1117

28,815✔
1118
        if (relationIdAttribute.relation.junctionEntityMetadata) {
28,815✔
1119
            this.expressionMap.createAlias({
13,974✔
1120
                type: "other",
13,974✔
1121
                name: relationIdAttribute.junctionAlias,
13,974✔
1122
                metadata: relationIdAttribute.relation.junctionEntityMetadata,
13,974✔
1123
            })
13,974✔
1124
        }
13,974✔
1125
        return this
28,815✔
1126
    }
28,815✔
1127

569,908✔
1128
    /**
569,908✔
1129
     * Loads all relation ids for all relations of the selected entity.
569,908✔
1130
     * All relation ids will be mapped to relation property themself.
569,908✔
1131
     * If array of strings is given then loads only relation ids of the given properties.
569,908✔
1132
     * @param options
569,908✔
1133
     * @param options.relations
569,908✔
1134
     * @param options.disableMixedMap
569,908✔
1135
     */
569,908✔
1136
    loadAllRelationIds(options?: {
569,908✔
1137
        relations?: string[]
103,348✔
1138
        disableMixedMap?: boolean
103,348✔
1139
    }): this {
103,348✔
1140
        // todo: add skip relations
103,348✔
1141
        this.expressionMap.mainAlias!.metadata.relations.forEach((relation) => {
103,348✔
1142
            if (
54,591✔
1143
                options !== undefined &&
54,591✔
1144
                options.relations !== undefined &&
54,591✔
1145
                options.relations.indexOf(relation.propertyPath) === -1
54,566✔
1146
            )
54,591✔
1147
                return
54,591✔
1148

25,690✔
1149
            this.loadRelationIdAndMap(
25,690✔
1150
                this.expressionMap.mainAlias!.name +
25,690✔
1151
                    "." +
25,690✔
1152
                    relation.propertyPath,
25,690✔
1153
                this.expressionMap.mainAlias!.name +
25,690✔
1154
                    "." +
25,690✔
1155
                    relation.propertyPath,
25,690✔
1156
                options,
25,690✔
1157
            )
25,690✔
1158
        })
103,348✔
1159
        return this
103,348✔
1160
    }
103,348✔
1161

569,908✔
1162
    /**
569,908✔
1163
     * Sets WHERE condition in the query builder.
569,908✔
1164
     * If you had previously WHERE expression defined,
569,908✔
1165
     * calling this function will override previously set WHERE conditions.
569,908✔
1166
     * Additionally you can add parameters used in where expression.
569,908✔
1167
     * @param where
569,908✔
1168
     * @param parameters
569,908✔
1169
     */
569,908✔
1170
    where(
569,908✔
1171
        where:
199,362✔
1172
            | Brackets
199,362✔
1173
            | string
199,362✔
1174
            | ((qb: this) => string)
199,362✔
1175
            | ObjectLiteral
199,362✔
1176
            | ObjectLiteral[],
199,362✔
1177
        parameters?: ObjectLiteral,
199,362✔
1178
    ): this {
199,362✔
1179
        this.expressionMap.wheres = [] // don't move this block below since computeWhereParameter can add where expressions
199,362✔
1180
        const condition = this.getWhereCondition(where)
199,362✔
1181
        if (condition) {
199,362✔
1182
            this.expressionMap.wheres = [
199,362✔
1183
                { type: "simple", condition: condition },
199,362✔
1184
            ]
199,362✔
1185
        }
199,362✔
1186
        if (parameters) this.setParameters(parameters)
199,362✔
1187
        return this
199,337✔
1188
    }
199,337✔
1189

569,908✔
1190
    /**
569,908✔
1191
     * Adds new AND WHERE condition in the query builder.
569,908✔
1192
     * Additionally you can add parameters used in where expression.
569,908✔
1193
     * @param where
569,908✔
1194
     * @param parameters
569,908✔
1195
     */
569,908✔
1196
    andWhere(
569,908✔
1197
        where:
65,386✔
1198
            | string
65,386✔
1199
            | Brackets
65,386✔
1200
            | ((qb: this) => string)
65,386✔
1201
            | ObjectLiteral
65,386✔
1202
            | ObjectLiteral[],
65,386✔
1203
        parameters?: ObjectLiteral,
65,386✔
1204
    ): this {
65,386✔
1205
        this.expressionMap.wheres.push({
65,386✔
1206
            type: "and",
65,386✔
1207
            condition: this.getWhereCondition(where),
65,386✔
1208
        })
65,386✔
1209
        if (parameters) this.setParameters(parameters)
65,386✔
1210
        return this
65,386✔
1211
    }
65,386✔
1212

569,908✔
1213
    /**
569,908✔
1214
     * Adds new OR WHERE condition in the query builder.
569,908✔
1215
     * Additionally you can add parameters used in where expression.
569,908✔
1216
     * @param where
569,908✔
1217
     * @param parameters
569,908✔
1218
     */
569,908✔
1219
    orWhere(
569,908✔
1220
        where:
18,428✔
1221
            | Brackets
18,428✔
1222
            | string
18,428✔
1223
            | ((qb: this) => string)
18,428✔
1224
            | ObjectLiteral
18,428✔
1225
            | ObjectLiteral[],
18,428✔
1226
        parameters?: ObjectLiteral,
18,428✔
1227
    ): this {
18,428✔
1228
        this.expressionMap.wheres.push({
18,428✔
1229
            type: "or",
18,428✔
1230
            condition: this.getWhereCondition(where),
18,428✔
1231
        })
18,428✔
1232
        if (parameters) this.setParameters(parameters)
18,428!
1233
        return this
18,428✔
1234
    }
18,428✔
1235

569,908✔
1236
    /**
569,908✔
1237
     * Sets a new where EXISTS clause
569,908✔
1238
     * @param subQuery
569,908✔
1239
     */
569,908✔
1240
    whereExists(subQuery: SelectQueryBuilder<any>): this {
569,908✔
1241
        return this.where(...this.getExistsCondition(subQuery))
175✔
1242
    }
175✔
1243

569,908✔
1244
    /**
569,908✔
1245
     * Adds a new AND where EXISTS clause
569,908✔
1246
     * @param subQuery
569,908✔
1247
     */
569,908✔
1248
    andWhereExists(subQuery: SelectQueryBuilder<any>): this {
569,908✔
1249
        return this.andWhere(...this.getExistsCondition(subQuery))
×
1250
    }
×
1251

569,908✔
1252
    /**
569,908✔
1253
     * Adds a new OR where EXISTS clause
569,908✔
1254
     * @param subQuery
569,908✔
1255
     */
569,908✔
1256
    orWhereExists(subQuery: SelectQueryBuilder<any>): this {
569,908✔
1257
        return this.orWhere(...this.getExistsCondition(subQuery))
×
1258
    }
×
1259

569,908✔
1260
    /**
569,908✔
1261
     * Adds new AND WHERE with conditions for the given ids.
569,908✔
1262
     *
569,908✔
1263
     * Ids are mixed.
569,908✔
1264
     * It means if you have single primary key you can pass a simple id values, for example [1, 2, 3].
569,908✔
1265
     * If you have multiple primary keys you need to pass object with property names and values specified,
569,908✔
1266
     * for example [{ firstId: 1, secondId: 2 }, { firstId: 2, secondId: 3 }, ...]
569,908✔
1267
     * @param ids
569,908✔
1268
     */
569,908✔
1269
    whereInIds(ids: any | any[]): this {
569,908✔
1270
        return this.where(this.getWhereInIdsCondition(ids))
107,822✔
1271
    }
107,822✔
1272

569,908✔
1273
    /**
569,908✔
1274
     * Adds new AND WHERE with conditions for the given ids.
569,908✔
1275
     *
569,908✔
1276
     * Ids are mixed.
569,908✔
1277
     * It means if you have single primary key you can pass a simple id values, for example [1, 2, 3].
569,908✔
1278
     * If you have multiple primary keys you need to pass object with property names and values specified,
569,908✔
1279
     * for example [{ firstId: 1, secondId: 2 }, { firstId: 2, secondId: 3 }, ...]
569,908✔
1280
     * @param ids
569,908✔
1281
     */
569,908✔
1282
    andWhereInIds(ids: any | any[]): this {
569,908✔
1283
        return this.andWhere(this.getWhereInIdsCondition(ids))
×
1284
    }
×
1285

569,908✔
1286
    /**
569,908✔
1287
     * Adds new OR WHERE with conditions for the given ids.
569,908✔
1288
     *
569,908✔
1289
     * Ids are mixed.
569,908✔
1290
     * It means if you have single primary key you can pass a simple id values, for example [1, 2, 3].
569,908✔
1291
     * If you have multiple primary keys you need to pass object with property names and values specified,
569,908✔
1292
     * for example [{ firstId: 1, secondId: 2 }, { firstId: 2, secondId: 3 }, ...]
569,908✔
1293
     * @param ids
569,908✔
1294
     */
569,908✔
1295
    orWhereInIds(ids: any | any[]): this {
569,908✔
1296
        return this.orWhere(this.getWhereInIdsCondition(ids))
50✔
1297
    }
50✔
1298

569,908✔
1299
    /**
569,908✔
1300
     * Sets HAVING condition in the query builder.
569,908✔
1301
     * If you had previously HAVING expression defined,
569,908✔
1302
     * calling this function will override previously set HAVING conditions.
569,908✔
1303
     * Additionally you can add parameters used in where expression.
569,908✔
1304
     * @param having
569,908✔
1305
     * @param parameters
569,908✔
1306
     */
569,908✔
1307
    having(having: string, parameters?: ObjectLiteral): this {
569,908✔
1308
        this.expressionMap.havings.push({ type: "simple", condition: having })
304✔
1309
        if (parameters) this.setParameters(parameters)
304✔
1310
        return this
304✔
1311
    }
304✔
1312

569,908✔
1313
    /**
569,908✔
1314
     * Adds new AND HAVING condition in the query builder.
569,908✔
1315
     * Additionally you can add parameters used in where expression.
569,908✔
1316
     * @param having
569,908✔
1317
     * @param parameters
569,908✔
1318
     */
569,908✔
1319
    andHaving(having: string, parameters?: ObjectLiteral): this {
569,908✔
1320
        this.expressionMap.havings.push({ type: "and", condition: having })
×
1321
        if (parameters) this.setParameters(parameters)
×
1322
        return this
×
1323
    }
×
1324

569,908✔
1325
    /**
569,908✔
1326
     * Adds new OR HAVING condition in the query builder.
569,908✔
1327
     * Additionally you can add parameters used in where expression.
569,908✔
1328
     * @param having
569,908✔
1329
     * @param parameters
569,908✔
1330
     */
569,908✔
1331
    orHaving(having: string, parameters?: ObjectLiteral): this {
569,908✔
1332
        this.expressionMap.havings.push({ type: "or", condition: having })
4✔
1333
        if (parameters) this.setParameters(parameters)
4!
1334
        return this
4✔
1335
    }
4✔
1336

569,908✔
1337
    /**
569,908✔
1338
     * Sets GROUP BY condition in the query builder.
569,908✔
1339
     * If you had previously GROUP BY expression defined,
569,908✔
1340
     * calling this function will override previously set GROUP BY conditions.
569,908✔
1341
     */
569,908✔
1342
    groupBy(): this
569,908✔
1343

569,908✔
1344
    /**
569,908✔
1345
     * Sets GROUP BY condition in the query builder.
569,908✔
1346
     * If you had previously GROUP BY expression defined,
569,908✔
1347
     * calling this function will override previously set GROUP BY conditions.
569,908✔
1348
     */
569,908✔
1349
    groupBy(groupBy: string): this
569,908✔
1350

569,908✔
1351
    /**
569,908✔
1352
     * Sets GROUP BY condition in the query builder.
569,908✔
1353
     * If you had previously GROUP BY expression defined,
569,908✔
1354
     * calling this function will override previously set GROUP BY conditions.
569,908✔
1355
     * @param groupBy
569,908✔
1356
     */
569,908✔
1357
    groupBy(groupBy?: string): this {
569,908✔
1358
        if (groupBy) {
7,099!
1359
            this.expressionMap.groupBys = [groupBy]
440✔
1360
        } else {
7,098✔
1361
            this.expressionMap.groupBys = []
6,659✔
1362
        }
6,659✔
1363
        return this
7,099✔
1364
    }
7,099✔
1365

569,908✔
1366
    /**
569,908✔
1367
     * Adds GROUP BY condition in the query builder.
569,908✔
1368
     * @param groupBy
569,908✔
1369
     */
569,908✔
1370
    addGroupBy(groupBy: string): this {
569,908✔
1371
        this.expressionMap.groupBys.push(groupBy)
25✔
1372
        return this
25✔
1373
    }
25✔
1374

569,908✔
1375
    /**
569,908✔
1376
     * Enables time travelling for the current query (only supported by cockroach currently)
569,908✔
1377
     * @param timeTravelFn
569,908✔
1378
     */
569,908✔
1379
    timeTravelQuery(timeTravelFn?: string | boolean): this {
569,908✔
1380
        if (this.connection.driver.options.type === "cockroachdb") {
14,055!
1381
            if (timeTravelFn === undefined) {
569!
1382
                this.expressionMap.timeTravel = "follower_read_timestamp()"
1✔
1383
            } else {
569✔
1384
                this.expressionMap.timeTravel = timeTravelFn
568✔
1385
            }
568✔
1386
        }
569✔
1387

14,055✔
1388
        return this
14,055✔
1389
    }
14,055✔
1390

569,908✔
1391
    /**
569,908✔
1392
     * Sets ORDER BY condition in the query builder.
569,908✔
1393
     * If you had previously ORDER BY expression defined,
569,908✔
1394
     * calling this function will override previously set ORDER BY conditions.
569,908✔
1395
     *
569,908✔
1396
     * Calling order by without order set will remove all previously set order bys.
569,908✔
1397
     */
569,908✔
1398
    orderBy(): this
569,908✔
1399

569,908✔
1400
    /**
569,908✔
1401
     * Sets ORDER BY condition in the query builder.
569,908✔
1402
     * If you had previously ORDER BY expression defined,
569,908✔
1403
     * calling this function will override previously set ORDER BY conditions.
569,908✔
1404
     */
569,908✔
1405
    orderBy(
569,908✔
1406
        sort: string,
569,908✔
1407
        order?: "ASC" | "DESC",
569,908✔
1408
        nulls?: "NULLS FIRST" | "NULLS LAST",
569,908✔
1409
    ): this
569,908✔
1410

569,908✔
1411
    /**
569,908✔
1412
     * Sets ORDER BY condition in the query builder.
569,908✔
1413
     * If you had previously ORDER BY expression defined,
569,908✔
1414
     * calling this function will override previously set ORDER BY conditions.
569,908✔
1415
     */
569,908✔
1416
    orderBy(order: OrderByCondition): this
569,908✔
1417

569,908✔
1418
    /**
569,908✔
1419
     * Sets ORDER BY condition in the query builder.
569,908✔
1420
     * If you had previously ORDER BY expression defined,
569,908✔
1421
     * calling this function will override previously set ORDER BY conditions.
569,908✔
1422
     * @param sort
569,908✔
1423
     * @param order
569,908✔
1424
     * @param nulls
569,908✔
1425
     */
569,908✔
1426
    orderBy(
569,908✔
1427
        sort?: string | OrderByCondition,
27,346✔
1428
        order: "ASC" | "DESC" = "ASC",
27,346✔
1429
        nulls?: "NULLS FIRST" | "NULLS LAST",
27,346✔
1430
    ): this {
27,346✔
1431
        if (order !== undefined && order !== "ASC" && order !== "DESC")
27,346!
1432
            throw new TypeORMError(
27,346!
1433
                `SelectQueryBuilder.addOrderBy "order" can accept only "ASC" and "DESC" values.`,
25✔
1434
            )
25✔
1435
        if (
27,321✔
1436
            nulls !== undefined &&
27,321!
1437
            nulls !== "NULLS FIRST" &&
27,346!
1438
            nulls !== "NULLS LAST"
25✔
1439
        )
27,346✔
1440
            throw new TypeORMError(
27,346!
1441
                `SelectQueryBuilder.addOrderBy "nulls" can accept only "NULLS FIRST" and "NULLS LAST" values.`,
25✔
1442
            )
25✔
1443

27,296✔
1444
        if (sort) {
27,346✔
1445
            if (typeof sort === "object") {
13,612✔
1446
                this.expressionMap.orderBys = sort as OrderByCondition
7,055✔
1447
            } else {
13,612✔
1448
                if (nulls) {
6,557!
1449
                    this.expressionMap.orderBys = {
×
1450
                        [sort as string]: { order, nulls },
×
1451
                    }
×
1452
                } else {
6,557✔
1453
                    this.expressionMap.orderBys = { [sort as string]: order }
6,557✔
1454
                }
6,557✔
1455
            }
6,557✔
1456
        } else {
27,346✔
1457
            this.expressionMap.orderBys = {}
13,684✔
1458
        }
13,684✔
1459
        return this
27,296✔
1460
    }
27,296✔
1461

569,908✔
1462
    /**
569,908✔
1463
     * Adds ORDER BY condition in the query builder.
569,908✔
1464
     * @param sort
569,908✔
1465
     * @param order
569,908✔
1466
     * @param nulls
569,908✔
1467
     */
569,908✔
1468
    addOrderBy(
569,908✔
1469
        sort: string,
15,500✔
1470
        order: "ASC" | "DESC" = "ASC",
15,500✔
1471
        nulls?: "NULLS FIRST" | "NULLS LAST",
15,500✔
1472
    ): this {
15,500✔
1473
        if (order !== undefined && order !== "ASC" && order !== "DESC")
15,500!
1474
            throw new TypeORMError(
15,500!
1475
                `SelectQueryBuilder.addOrderBy "order" can accept only "ASC" and "DESC" values.`,
×
1476
            )
×
1477
        if (
15,500✔
1478
            nulls !== undefined &&
15,500!
1479
            nulls !== "NULLS FIRST" &&
15,500!
1480
            nulls !== "NULLS LAST"
22✔
1481
        )
15,500✔
1482
            throw new TypeORMError(
15,500!
1483
                `SelectQueryBuilder.addOrderBy "nulls" can accept only "NULLS FIRST" and "NULLS LAST" values.`,
×
1484
            )
×
1485

15,500✔
1486
        if (nulls) {
15,500!
1487
            this.expressionMap.orderBys[sort] = { order, nulls }
40✔
1488
        } else {
15,500✔
1489
            this.expressionMap.orderBys[sort] = order
15,460✔
1490
        }
15,460✔
1491
        return this
15,500✔
1492
    }
15,500✔
1493

569,908✔
1494
    /**
569,908✔
1495
     * Sets LIMIT - maximum number of rows to be selected.
569,908✔
1496
     * When joins are present, a two-query distinct-id strategy is used
569,908✔
1497
     * so that LIMIT applies to root entities rather than raw joined rows.
569,908✔
1498
     * @param limit
569,908✔
1499
     */
569,908✔
1500
    limit(limit?: number): this {
569,908✔
1501
        this.expressionMap.limit = this.normalizeNumber(limit)
14,104✔
1502
        if (
14,104✔
1503
            this.expressionMap.limit !== undefined &&
14,104✔
1504
            isNaN(this.expressionMap.limit)
7,420✔
1505
        )
14,104✔
1506
            throw new TypeORMError(
14,104!
1507
                `Provided "limit" value is not a number. Please provide a numeric value.`,
×
1508
            )
×
1509

14,104✔
1510
        return this
14,104✔
1511
    }
14,104✔
1512

569,908✔
1513
    /**
569,908✔
1514
     * Sets OFFSET - selection offset.
569,908✔
1515
     * When joins are present, a two-query distinct-id strategy is used
569,908✔
1516
     * so that OFFSET applies to root entities rather than raw joined rows.
569,908✔
1517
     * @param offset
569,908✔
1518
     */
569,908✔
1519
    offset(offset?: number): this {
569,908✔
1520
        this.expressionMap.offset = this.normalizeNumber(offset)
13,773✔
1521
        if (
13,773✔
1522
            this.expressionMap.offset !== undefined &&
13,773!
1523
            isNaN(this.expressionMap.offset)
426✔
1524
        )
13,773✔
1525
            throw new TypeORMError(
13,773!
1526
                `Provided "offset" value is not a number. Please provide a numeric value.`,
×
1527
            )
×
1528

13,773✔
1529
        return this
13,773✔
1530
    }
13,773✔
1531

569,908✔
1532
    /**
569,908✔
1533
     * Sets maximal number of entities to take.
569,908✔
1534
     * @param take
569,908✔
1535
     */
569,908✔
1536
    take(take?: number): this {
569,908✔
1537
        this.expressionMap.take = this.normalizeNumber(take)
23,333✔
1538
        if (
23,333✔
1539
            this.expressionMap.take !== undefined &&
23,333✔
1540
            isNaN(this.expressionMap.take)
16,674✔
1541
        )
23,333✔
1542
            throw new TypeORMError(
23,333!
1543
                `Provided "take" value is not a number. Please provide a numeric value.`,
50✔
1544
            )
50✔
1545

23,283✔
1546
        return this
23,283✔
1547
    }
23,283✔
1548

569,908✔
1549
    /**
569,908✔
1550
     * Sets number of entities to skip.
569,908✔
1551
     * @param skip
569,908✔
1552
     */
569,908✔
1553
    skip(skip?: number): this {
569,908✔
1554
        this.expressionMap.skip = this.normalizeNumber(skip)
7,657✔
1555
        if (
7,657✔
1556
            this.expressionMap.skip !== undefined &&
7,657!
1557
            isNaN(this.expressionMap.skip)
998✔
1558
        )
7,657✔
1559
            throw new TypeORMError(
7,657!
1560
                `Provided "skip" value is not a number. Please provide a numeric value.`,
50✔
1561
            )
50✔
1562

7,607✔
1563
        return this
7,607✔
1564
    }
7,607✔
1565

569,908✔
1566
    /**
569,908✔
1567
     * Set certain index to be used by the query.
569,908✔
1568
     * @param index Name of index to be used.
569,908✔
1569
     */
569,908✔
1570
    useIndex(index: string): this {
569,908✔
1571
        this.expressionMap.useIndex = index
8✔
1572

8✔
1573
        return this
8✔
1574
    }
8✔
1575

569,908✔
1576
    /**
569,908✔
1577
     * Sets locking mode.
569,908✔
1578
     */
569,908✔
1579
    setLock(lockMode: "optimistic", lockVersion: number | Date): this
569,908✔
1580

569,908✔
1581
    /**
569,908✔
1582
     * Sets locking mode.
569,908✔
1583
     */
569,908✔
1584
    setLock(
569,908✔
1585
        lockMode:
569,908✔
1586
            | "pessimistic_read"
569,908✔
1587
            | "pessimistic_write"
569,908✔
1588
            | "dirty_read"
569,908✔
1589
            | "for_no_key_update"
569,908✔
1590
            | "for_key_share",
569,908✔
1591
        lockVersion?: undefined,
569,908✔
1592
        lockTables?: string[],
569,908✔
1593
    ): this
569,908✔
1594

569,908✔
1595
    /**
569,908✔
1596
     * Sets locking mode.
569,908✔
1597
     * @param lockMode
569,908✔
1598
     * @param lockVersion
569,908✔
1599
     * @param lockTables
569,908✔
1600
     */
569,908✔
1601
    setLock(
569,908✔
1602
        lockMode:
849✔
1603
            | "optimistic"
849✔
1604
            | "pessimistic_read"
849✔
1605
            | "pessimistic_write"
849✔
1606
            | "dirty_read"
849✔
1607
            | "for_no_key_update"
849✔
1608
            | "for_key_share",
849✔
1609
        lockVersion?: number | Date,
849✔
1610
        lockTables?: string[],
849✔
1611
    ): this {
849✔
1612
        this.expressionMap.lockMode = lockMode
849✔
1613
        this.expressionMap.lockVersion = lockVersion
849✔
1614
        this.expressionMap.lockTables = lockTables
849✔
1615
        return this
849✔
1616
    }
849✔
1617

569,908✔
1618
    /**
569,908✔
1619
     * Sets lock handling by adding NO WAIT or SKIP LOCKED.
569,908✔
1620
     * @param onLocked
569,908✔
1621
     */
569,908✔
1622
    setOnLocked(onLocked: "nowait" | "skip_locked"): this {
569,908✔
1623
        this.expressionMap.onLocked = onLocked
50✔
1624
        return this
50✔
1625
    }
50✔
1626

569,908✔
1627
    /**
569,908✔
1628
     * Disables the global condition of "non-deleted" for the entity with delete date columns.
569,908✔
1629
     */
569,908✔
1630
    withDeleted(): this {
569,908✔
1631
        this.expressionMap.withDeleted = true
107,758✔
1632
        return this
107,758✔
1633
    }
107,758✔
1634

569,908✔
1635
    /**
569,908✔
1636
     * Gets first raw result returned by execution of generated query builder sql.
569,908✔
1637
     */
569,908✔
1638
    async getRawOne<T = any>(): Promise<T | undefined> {
569,908✔
1639
        return (await this.getRawMany())[0]
7,022!
1640
    }
6,997✔
1641

569,908✔
1642
    /**
569,908✔
1643
     * Gets all raw results returned by execution of generated query builder sql.
569,908✔
1644
     */
569,908✔
1645
    async getRawMany<T = any>(): Promise<T[]> {
569,908✔
1646
        if (this.expressionMap.lockMode === "optimistic")
22,383✔
1647
            throw new OptimisticLockCanNotBeUsedError()
22,383!
1648

22,333✔
1649
        this.expressionMap.queryEntity = false
22,333✔
1650
        const queryRunner = this.obtainQueryRunner()
22,333✔
1651
        let transactionStartedByUs: boolean = false
22,333✔
1652
        try {
22,333✔
1653
            // start transaction if it was enabled
22,333✔
1654
            if (
22,333✔
1655
                this.expressionMap.useTransaction === true &&
22,333!
1656
                queryRunner.isTransactionActive === false
×
1657
            ) {
22,383!
1658
                await queryRunner.startTransaction()
×
1659
                transactionStartedByUs = true
×
1660
            }
×
1661

22,333✔
1662
            const results = await this.loadRawResults(queryRunner)
22,333✔
1663

22,242✔
1664
            // close transaction if we started it
22,242✔
1665
            if (transactionStartedByUs) {
22,383!
1666
                await queryRunner.commitTransaction()
×
1667
            }
×
1668

22,242✔
1669
            return results
22,242✔
1670
        } catch (error) {
22,383!
1671
            // rollback transaction if we started it
91✔
1672
            if (transactionStartedByUs) {
91!
1673
                try {
×
1674
                    await queryRunner.rollbackTransaction()
×
1675
                } catch (rollbackError) {}
×
1676
            }
×
1677
            throw error
91✔
1678
        } finally {
16,834!
1679
            if (queryRunner !== this.queryRunner) {
22,333✔
1680
                // means we created our own query runner
1,386✔
1681
                await queryRunner.release()
1,386✔
1682
            }
1,386✔
1683
        }
22,333✔
1684
    }
22,383✔
1685

569,908✔
1686
    /**
569,908✔
1687
     * Executes sql generated by query builder and returns object with raw results and entities created from them.
569,908✔
1688
     */
569,908✔
1689
    async getRawAndEntities<T = any>(): Promise<{
569,908✔
1690
        entities: Entity[]
155,649✔
1691
        raw: T[]
155,649✔
1692
    }> {
155,649✔
1693
        const queryRunner = this.obtainQueryRunner()
155,649✔
1694
        let transactionStartedByUs: boolean = false
155,649✔
1695
        try {
155,649✔
1696
            // start transaction if it was enabled
155,649✔
1697
            if (
155,649✔
1698
                this.expressionMap.useTransaction === true &&
155,649!
1699
                queryRunner.isTransactionActive === false
25✔
1700
            ) {
155,649!
1701
                await queryRunner.startTransaction()
25✔
1702
                transactionStartedByUs = true
25✔
1703
            }
25✔
1704

155,649✔
1705
            this.expressionMap.queryEntity = true
155,649✔
1706
            const results = await this.executeEntitiesAndRawResults(queryRunner)
155,649✔
1707

155,418✔
1708
            // close transaction if we started it
155,418✔
1709
            if (transactionStartedByUs) {
155,649!
1710
                await queryRunner.commitTransaction()
25✔
1711
            }
25✔
1712

155,418✔
1713
            return results
155,418✔
1714
        } catch (error) {
155,649!
1715
            // rollback transaction if we started it
231✔
1716
            if (transactionStartedByUs) {
231!
1717
                try {
×
1718
                    await queryRunner.rollbackTransaction()
×
1719
                } catch (rollbackError) {}
×
1720
            }
×
1721
            throw error
231✔
1722
        } finally {
150,448!
1723
            if (queryRunner !== this.queryRunner)
155,649✔
1724
                // means we created our own query runner
155,649✔
1725
                await queryRunner.release()
155,649✔
1726
        }
155,649✔
1727
    }
155,649✔
1728

569,908✔
1729
    /**
569,908✔
1730
     * Gets single entity returned by execution of generated query builder sql.
569,908✔
1731
     */
569,908✔
1732
    async getOne(): Promise<Entity | null> {
569,908✔
1733
        const results = await this.getRawAndEntities()
21,714✔
1734
        const result = results.entities[0] as any
21,503✔
1735

21,503✔
1736
        if (
21,503✔
1737
            result &&
21,503✔
1738
            this.expressionMap.lockMode === "optimistic" &&
21,714!
1739
            this.expressionMap.lockVersion
142✔
1740
        ) {
21,714!
1741
            const metadata = this.expressionMap.mainAlias!.metadata
142✔
1742

142✔
1743
            if (this.expressionMap.lockVersion instanceof Date) {
142!
1744
                const actualVersion =
69✔
1745
                    metadata.updateDateColumn!.getEntityValue(result) // what if columns arent set?
69✔
1746
                if (
69✔
1747
                    actualVersion.getTime() !==
69✔
1748
                    this.expressionMap.lockVersion.getTime()
69✔
1749
                )
69✔
1750
                    throw new OptimisticLockVersionMismatchError(
69✔
1751
                        metadata.name,
23✔
1752
                        this.expressionMap.lockVersion,
23✔
1753
                        actualVersion,
23✔
1754
                    )
23✔
1755
            } else {
73✔
1756
                const actualVersion =
73✔
1757
                    metadata.versionColumn!.getEntityValue(result) // what if columns arent set?
73✔
1758
                if (actualVersion !== this.expressionMap.lockVersion)
73✔
1759
                    throw new OptimisticLockVersionMismatchError(
73✔
1760
                        metadata.name,
25✔
1761
                        this.expressionMap.lockVersion,
25✔
1762
                        actualVersion,
25✔
1763
                    )
25✔
1764
            }
73✔
1765
        }
142✔
1766

21,455✔
1767
        if (result === undefined) {
21,714✔
1768
            return null
1,629✔
1769
        }
1,629✔
1770
        return result
19,826✔
1771
    }
19,826✔
1772

569,908✔
1773
    /**
569,908✔
1774
     * Gets the first entity returned by execution of generated query builder sql or rejects the returned promise on error.
569,908✔
1775
     */
569,908✔
1776
    async getOneOrFail(): Promise<Entity> {
569,908✔
1777
        const entity = await this.getOne()
18✔
1778

18✔
1779
        if (!entity) {
18!
1780
            throw new EntityNotFoundError(
3✔
1781
                this.expressionMap.mainAlias!.target,
3✔
1782
                this.expressionMap.parameters,
3✔
1783
            )
3✔
1784
        }
3✔
1785

15✔
1786
        return entity
15✔
1787
    }
15✔
1788

569,908✔
1789
    /**
569,908✔
1790
     * Gets entities returned by execution of generated query builder sql.
569,908✔
1791
     */
569,908✔
1792
    async getMany(): Promise<Entity[]> {
569,908✔
1793
        if (this.expressionMap.lockMode === "optimistic")
131,618✔
1794
            throw new OptimisticLockCanNotBeUsedError()
131,618!
1795

131,568✔
1796
        const results = await this.getRawAndEntities()
131,568✔
1797
        return results.entities
131,548✔
1798
    }
131,548✔
1799

569,908✔
1800
    /**
569,908✔
1801
     * Gets count - number of entities selected by sql generated by this query builder.
569,908✔
1802
     * Count excludes all limitations set by offset, limit, skip, and take.
569,908✔
1803
     */
569,908✔
1804
    async getCount(): Promise<number> {
569,908✔
1805
        if (this.expressionMap.lockMode === "optimistic")
6,330✔
1806
            throw new OptimisticLockCanNotBeUsedError()
6,330!
1807

6,305✔
1808
        const queryRunner = this.obtainQueryRunner()
6,305✔
1809
        let transactionStartedByUs: boolean = false
6,305✔
1810
        try {
6,305✔
1811
            // start transaction if it was enabled
6,305✔
1812
            if (
6,305✔
1813
                this.expressionMap.useTransaction === true &&
6,305!
1814
                queryRunner.isTransactionActive === false
×
1815
            ) {
6,330!
1816
                await queryRunner.startTransaction()
×
1817
                transactionStartedByUs = true
×
1818
            }
×
1819

6,305✔
1820
            this.expressionMap.queryEntity = false
6,305✔
1821
            const results = await this.executeCountQuery(queryRunner)
6,305✔
1822

6,305✔
1823
            // close transaction if we started it
6,305✔
1824
            if (transactionStartedByUs) {
6,330!
1825
                await queryRunner.commitTransaction()
×
1826
            }
×
1827

6,305✔
1828
            return results
6,305✔
1829
        } catch (error) {
6,330!
1830
            // rollback transaction if we started it
×
1831
            if (transactionStartedByUs) {
×
1832
                try {
×
1833
                    await queryRunner.rollbackTransaction()
×
1834
                } catch (rollbackError) {}
×
1835
            }
×
1836
            throw error
×
1837
        } finally {
✔
1838
            if (queryRunner !== this.queryRunner)
6,305✔
1839
                // means we created our own query runner
6,305✔
1840
                await queryRunner.release()
6,305✔
1841
        }
6,305✔
1842
    }
6,330✔
1843

569,908✔
1844
    /**
569,908✔
1845
     * Gets exists
569,908✔
1846
     * Returns whether any rows exists matching current query.
569,908✔
1847
     */
569,908✔
1848
    async getExists(): Promise<boolean> {
569,908✔
1849
        if (this.expressionMap.lockMode === "optimistic")
175✔
1850
            throw new OptimisticLockCanNotBeUsedError()
175!
1851

175✔
1852
        const queryRunner = this.obtainQueryRunner()
175✔
1853
        let transactionStartedByUs: boolean = false
175✔
1854
        try {
175✔
1855
            // start transaction if it was enabled
175✔
1856
            if (
175✔
1857
                this.expressionMap.useTransaction === true &&
175!
1858
                queryRunner.isTransactionActive === false
×
1859
            ) {
175!
1860
                await queryRunner.startTransaction()
×
1861
                transactionStartedByUs = true
×
1862
            }
×
1863

175✔
1864
            this.expressionMap.queryEntity = false
175✔
1865
            const results = await this.executeExistsQuery(queryRunner)
175✔
1866

175✔
1867
            // close transaction if we started it
175✔
1868
            if (transactionStartedByUs) {
175!
1869
                await queryRunner.commitTransaction()
×
1870
            }
×
1871

175✔
1872
            return results
175✔
1873
        } catch (error) {
175!
1874
            // rollback transaction if we started it
×
1875
            if (transactionStartedByUs) {
×
1876
                try {
×
1877
                    await queryRunner.rollbackTransaction()
×
1878
                } catch (rollbackError) {}
×
1879
            }
×
1880
            throw error
×
1881
        } finally {
×
1882
            if (queryRunner !== this.queryRunner)
175✔
1883
                // means we created our own query runner
175✔
1884
                await queryRunner.release()
175✔
1885
        }
175✔
1886
    }
175✔
1887

569,908✔
1888
    /**
569,908✔
1889
     * Executes built SQL query and returns entities and overall entities count (without limitation).
569,908✔
1890
     * This method is useful to build pagination.
569,908✔
1891
     */
569,908✔
1892
    async getManyAndCount(): Promise<[Entity[], number]> {
569,908✔
1893
        if (this.expressionMap.lockMode === "optimistic")
804✔
1894
            throw new OptimisticLockCanNotBeUsedError()
804!
1895

779!
1896
        const queryRunner = this.obtainQueryRunner()
779✔
1897
        let transactionStartedByUs: boolean = false
779✔
1898
        try {
779✔
1899
            // start transaction if it was enabled
779✔
1900
            if (
779✔
1901
                this.expressionMap.useTransaction === true &&
779!
1902
                queryRunner.isTransactionActive === false
×
1903
            ) {
804!
1904
                await queryRunner.startTransaction()
×
1905
                transactionStartedByUs = true
×
1906
            }
×
1907

779✔
1908
            this.expressionMap.queryEntity = true
779✔
1909
            const entitiesAndRaw =
779✔
1910
                await this.executeEntitiesAndRawResults(queryRunner)
779✔
1911
            this.expressionMap.queryEntity = false
769✔
1912

769✔
1913
            let count: number | undefined = this.lazyCount(entitiesAndRaw)
769✔
1914
            if (count === undefined) {
803!
1915
                const cacheId = this.expressionMap.cacheId
179✔
1916
                // Creates a new cacheId for the count query, or it will retrieve the above query results
179✔
1917
                // and count will return 0.
179✔
1918
                if (cacheId) {
179!
1919
                    this.expressionMap.cacheId = `${cacheId}-count`
×
1920
                }
×
1921
                count = await this.executeCountQuery(queryRunner)
179✔
1922
            }
179✔
1923
            const results: [Entity[], number] = [entitiesAndRaw.entities, count]
769✔
1924

769✔
1925
            // close transaction if we started it
769✔
1926
            if (transactionStartedByUs) {
803!
1927
                await queryRunner.commitTransaction()
×
1928
            }
×
1929

769✔
1930
            return results
769✔
1931
        } catch (error) {
803!
1932
            // rollback transaction if we started it
10✔
1933
            if (transactionStartedByUs) {
10!
1934
                try {
×
1935
                    await queryRunner.rollbackTransaction()
×
1936
                } catch (rollbackError) {}
×
1937
            }
×
1938
            throw error
10✔
1939
        } finally {
320!
1940
            if (queryRunner !== this.queryRunner)
779✔
1941
                // means we created our own query runner
779✔
1942
                await queryRunner.release()
779✔
1943
        }
779✔
1944
    }
804✔
1945

569,908✔
1946
    private lazyCount(entitiesAndRaw: {
569,908✔
1947
        entities: Entity[]
769✔
1948
        raw: any[]
769✔
1949
    }): number | undefined {
769✔
1950
        const hasLimit =
769✔
1951
            this.expressionMap.limit !== undefined &&
769!
1952
            this.expressionMap.limit !== null
125✔
1953
        if (this.expressionMap.joinAttributes.length > 0 && hasLimit) {
769!
1954
            return undefined
50✔
1955
        }
50✔
1956

719✔
1957
        const hasTake =
719✔
1958
            this.expressionMap.take !== undefined &&
719!
1959
            this.expressionMap.take !== null
204✔
1960

769✔
1961
        // limit overrides take when no join is defined
769✔
1962
        const maxResults = hasLimit
769✔
1963
            ? this.expressionMap.limit
769!
1964
            : hasTake
769✔
1965
              ? this.expressionMap.take
644!
1966
              : undefined
644!
1967

769✔
1968
        if (
769✔
1969
            maxResults !== undefined &&
769!
1970
            entitiesAndRaw.entities.length === maxResults
279✔
1971
        ) {
769!
1972
            // stop here when the result set contains the max number of rows; we need to execute a full count
79✔
1973
            return undefined
79✔
1974
        }
79✔
1975

640!
1976
        const hasSkip =
640✔
1977
            this.expressionMap.skip !== undefined &&
640!
1978
            this.expressionMap.skip !== null &&
769!
1979
            this.expressionMap.skip > 0
90✔
1980
        const hasOffset =
769✔
1981
            this.expressionMap.offset !== undefined &&
769!
1982
            this.expressionMap.offset !== null &&
769!
1983
            this.expressionMap.offset > 0
50✔
1984

769✔
1985
        if (entitiesAndRaw.entities.length === 0 && (hasSkip || hasOffset)) {
769!
1986
            // when skip or offset were used and no results found, we need to execute a full count
50✔
1987
            // (the given offset may have exceeded the actual number of rows)
50✔
1988
            return undefined
50✔
1989
        }
50✔
1990

590✔
1991
        // offset overrides skip when no join is defined
590✔
1992
        const previousResults: number = hasOffset
590✔
1993
            ? this.expressionMap.offset!
768!
1994
            : hasSkip
769!
1995
              ? this.expressionMap.skip!
565!
1996
              : 0
565✔
1997

769✔
1998
        return entitiesAndRaw.entities.length + previousResults
769✔
1999
    }
769✔
2000

569,908✔
2001
    /**
569,908✔
2002
     * Executes built SQL query and returns raw data stream.
569,908✔
2003
     */
569,908✔
2004
    async stream(): Promise<ReadStream> {
569,908✔
2005
        this.expressionMap.queryEntity = false
13✔
2006
        const [sql, parameters] = this.getQueryAndParameters()
13✔
2007
        const queryRunner = this.obtainQueryRunner()
13✔
2008
        let transactionStartedByUs: boolean = false
13✔
2009
        try {
13✔
2010
            // start transaction if it was enabled
13✔
2011
            if (
13✔
2012
                this.expressionMap.useTransaction === true &&
13!
2013
                queryRunner.isTransactionActive === false
×
2014
            ) {
13!
2015
                await queryRunner.startTransaction()
×
2016
                transactionStartedByUs = true
×
2017
            }
×
2018

13✔
2019
            const releaseFn = () => {
13✔
2020
                if (queryRunner !== this.queryRunner)
13✔
2021
                    // means we created our own query runner
13✔
2022
                    return queryRunner.release()
13✔
2023
                return
×
2024
            }
×
2025
            const results = queryRunner.stream(
13✔
2026
                sql,
13✔
2027
                parameters,
13✔
2028
                releaseFn,
13✔
2029
                releaseFn,
13✔
2030
            )
13✔
2031

13✔
2032
            // close transaction if we started it
13✔
2033
            if (transactionStartedByUs) {
13!
2034
                await queryRunner.commitTransaction()
×
2035
            }
×
2036

13✔
2037
            return results
13✔
2038
        } catch (error) {
13!
2039
            // rollback transaction if we started it
×
2040
            if (transactionStartedByUs) {
×
2041
                try {
×
2042
                    await queryRunner.rollbackTransaction()
×
2043
                } catch (rollbackError) {}
×
2044
            }
×
2045
            throw error
×
2046
        }
×
2047
    }
13✔
2048

569,908✔
2049
    /**
569,908✔
2050
     * Enables or disables query result caching.
569,908✔
2051
     */
569,908✔
2052
    cache(enabled: boolean): this
569,908✔
2053

569,908✔
2054
    /**
569,908✔
2055
     * Enables query result caching and sets in milliseconds in which cache will expire.
569,908✔
2056
     * If not set then global caching time will be used.
569,908✔
2057
     */
569,908✔
2058
    cache(milliseconds: number): this
569,908✔
2059

569,908✔
2060
    /**
569,908✔
2061
     * Enables query result caching and sets cache id and milliseconds in which cache will expire.
569,908✔
2062
     */
569,908✔
2063
    cache(id: any, milliseconds?: number): this
569,908✔
2064

569,908✔
2065
    /**
569,908✔
2066
     * Enables or disables query result caching.
569,908✔
2067
     * @param enabledOrMillisecondsOrId
569,908✔
2068
     * @param maybeMilliseconds
569,908✔
2069
     */
569,908✔
2070
    cache(
569,908✔
2071
        enabledOrMillisecondsOrId: boolean | number | string,
8,665✔
2072
        maybeMilliseconds?: number,
8,665✔
2073
    ): this {
8,665✔
2074
        if (typeof enabledOrMillisecondsOrId === "boolean") {
8,665!
2075
            this.expressionMap.cache = enabledOrMillisecondsOrId
1,215✔
2076
        } else if (typeof enabledOrMillisecondsOrId === "number") {
8,665!
2077
            this.expressionMap.cache = true
100✔
2078
            this.expressionMap.cacheDuration = enabledOrMillisecondsOrId
100✔
2079
        } else if (
7,450✔
2080
            typeof enabledOrMillisecondsOrId === "string" ||
7,350✔
2081
            typeof enabledOrMillisecondsOrId === "number"
6,950✔
2082
        ) {
7,350!
2083
            this.expressionMap.cache = true
400✔
2084
            this.expressionMap.cacheId = enabledOrMillisecondsOrId
400✔
2085
        }
400✔
2086

8,665✔
2087
        if (maybeMilliseconds) {
8,665!
2088
            this.expressionMap.cacheDuration = maybeMilliseconds
400✔
2089
        }
400✔
2090

8,665✔
2091
        return this
8,665✔
2092
    }
8,665✔
2093

569,908✔
2094
    /**
569,908✔
2095
     * Sets extra options that can be used to configure how query builder works.
569,908✔
2096
     * @param option
569,908✔
2097
     */
569,908✔
2098
    setOption(option: SelectQueryBuilderOption): this {
569,908✔
2099
        this.expressionMap.options.push(option)
15,592✔
2100
        return this
15,592✔
2101
    }
15,592✔
2102

569,908✔
2103
    // -------------------------------------------------------------------------
569,908✔
2104
    // Protected Methods
569,908✔
2105
    // -------------------------------------------------------------------------
569,908✔
2106

569,908✔
2107
    protected join(
569,908✔
2108
        direction: "INNER" | "LEFT",
669,135✔
2109
        entityOrProperty:
669,135✔
2110
            | Function
669,135✔
2111
            | string
669,135✔
2112
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
669,135✔
2113
        aliasName: string,
669,135✔
2114
        condition?: string,
669,135✔
2115
        parameters?: ObjectLiteral,
669,135✔
2116
        mapToProperty?: string,
669,135✔
2117
        isMappingMany?: boolean,
669,135✔
2118
        mapAsEntity?: Function | string,
669,135✔
2119
    ): void {
669,135✔
2120
        if (parameters) {
669,135!
2121
            this.setParameters(parameters)
×
2122
        }
×
2123

669,135✔
2124
        const joinAttribute = new JoinAttribute(
669,135✔
2125
            this.connection,
669,135✔
2126
            this.expressionMap,
669,135✔
2127
        )
669,135✔
2128
        joinAttribute.direction = direction
669,135✔
2129
        joinAttribute.mapAsEntity = mapAsEntity
669,135✔
2130
        joinAttribute.mapToProperty = mapToProperty
669,135✔
2131
        joinAttribute.isMappingMany = isMappingMany
669,135✔
2132
        joinAttribute.entityOrProperty = entityOrProperty // relationName
669,135✔
2133
        joinAttribute.condition = condition // joinInverseSideCondition
669,135✔
2134
        // joinAttribute.junctionAlias = joinAttribute.relation.isOwning ? parentAlias + "_" + destinationTableAlias : destinationTableAlias + "_" + parentAlias;
669,135✔
2135
        this.expressionMap.joinAttributes.push(joinAttribute)
669,135✔
2136
        const isEntity = this.connection.hasMetadata(entityOrProperty)
669,135✔
2137
        const isSubQuery =
669,135✔
2138
            (!isEntity && typeof entityOrProperty === "function") ||
669,135✔
2139
            (typeof entityOrProperty === "string" &&
668,996✔
2140
                entityOrProperty.startsWith("(") &&
668,996!
2141
                entityOrProperty.endsWith(")"))
668,996✔
2142

669,135✔
2143
        let subQuery: string = ""
669,135✔
2144
        if (isSubQuery) {
669,135!
2145
            if (typeof entityOrProperty === "string") {
168!
2146
                subQuery = entityOrProperty
29✔
2147
            } else {
167✔
2148
                const subQueryBuilder: SelectQueryBuilder<any> = (
139✔
2149
                    entityOrProperty as any
139✔
2150
                )((this as any as SelectQueryBuilder<any>).subQuery())
139✔
2151
                this.setParameters(subQueryBuilder.getParameters())
139✔
2152
                subQuery = subQueryBuilder.getQuery()
139✔
2153
            }
139✔
2154
        }
168✔
2155

669,135✔
2156
        const joinAttributeMetadata = joinAttribute.metadata
669,135✔
2157
        if (joinAttributeMetadata) {
669,135✔
2158
            if (
669,044✔
2159
                joinAttributeMetadata.deleteDateColumn &&
669,044!
2160
                !this.expressionMap.withDeleted
283✔
2161
            ) {
669,044!
2162
                const conditionDeleteColumn = `${aliasName}.${joinAttributeMetadata.deleteDateColumn.propertyName} IS NULL`
233✔
2163
                joinAttribute.condition = joinAttribute.condition
233✔
2164
                    ? ` ${joinAttribute.condition} AND ${conditionDeleteColumn}`
233!
2165
                    : `${conditionDeleteColumn}`
233✔
2166
            }
233✔
2167
            // todo: find and set metadata right there?
669,044✔
2168
            joinAttribute.alias = this.expressionMap.createAlias({
669,044✔
2169
                type: "join",
669,044✔
2170
                name: aliasName,
669,044✔
2171
                metadata: joinAttributeMetadata,
669,044✔
2172
                subQuery: isSubQuery ? subQuery : undefined,
669,044!
2173
            })
669,044✔
2174
            if (
669,044✔
2175
                joinAttribute.relation &&
669,044✔
2176
                joinAttribute.relation.junctionEntityMetadata
659,472✔
2177
            ) {
669,044✔
2178
                this.expressionMap.createAlias({
285,713✔
2179
                    type: "join",
285,713✔
2180
                    name: joinAttribute.junctionAlias,
285,713✔
2181
                    metadata: joinAttribute.relation.junctionEntityMetadata,
285,713✔
2182
                })
285,713✔
2183
            }
285,713✔
2184
        } else {
669,135!
2185
            joinAttribute.alias = this.expressionMap.createAlias({
91✔
2186
                type: "join",
91✔
2187
                name: aliasName,
91✔
2188
                tablePath:
91✔
2189
                    isSubQuery === false
91✔
2190
                        ? (entityOrProperty as string)
91!
2191
                        : undefined,
91!
2192
                subQuery: isSubQuery === true ? subQuery : undefined,
91!
2193
            })
91✔
2194
        }
91✔
2195
    }
669,135✔
2196

569,908✔
2197
    /**
569,908✔
2198
     * Creates "SELECT FROM" part of SQL query.
569,908✔
2199
     */
569,908✔
2200
    protected createSelectExpression() {
569,908✔
2201
        if (!this.expressionMap.mainAlias)
278,600✔
2202
            throw new TypeORMError(
278,600!
2203
                "Cannot build query because main alias is not set (call qb#from method)",
×
2204
            )
×
2205

278,600✔
2206
        // todo throw exception if selects or from is missing
278,600✔
2207

278,600✔
2208
        const allSelects: SelectQuery[] = []
278,600✔
2209
        const excludedSelects: SelectQuery[] = []
278,600✔
2210

278,600✔
2211
        if (this.expressionMap.mainAlias.hasMetadata) {
278,600✔
2212
            const metadata = this.expressionMap.mainAlias.metadata
268,610✔
2213
            allSelects.push(
268,610✔
2214
                ...this.buildEscapedEntityColumnSelects(
268,610✔
2215
                    this.expressionMap.mainAlias.name,
268,610✔
2216
                    metadata,
268,610✔
2217
                ),
268,610✔
2218
            )
268,610✔
2219
            excludedSelects.push(
268,610✔
2220
                ...this.findEntityColumnSelects(
268,610✔
2221
                    this.expressionMap.mainAlias.name,
268,610✔
2222
                    metadata,
268,610✔
2223
                ),
268,610✔
2224
            )
268,610✔
2225
        }
268,610✔
2226

278,600✔
2227
        // add selects from joins
278,600✔
2228
        this.expressionMap.joinAttributes.forEach((join) => {
278,600✔
2229
            if (join.metadata) {
677,855✔
2230
                allSelects.push(
677,764✔
2231
                    ...this.buildEscapedEntityColumnSelects(
677,764✔
2232
                        join.alias.name!,
677,764✔
2233
                        join.metadata,
677,764✔
2234
                    ),
677,764✔
2235
                )
677,764✔
2236
                excludedSelects.push(
677,764✔
2237
                    ...this.findEntityColumnSelects(
677,764✔
2238
                        join.alias.name!,
677,764✔
2239
                        join.metadata,
677,764✔
2240
                    ),
677,764✔
2241
                )
677,764✔
2242
            } else {
677,855!
2243
                const hasMainAlias = this.expressionMap.selects.some(
91✔
2244
                    (select) => select.selection === join.alias.name,
91✔
2245
                )
91✔
2246
                if (hasMainAlias) {
91!
2247
                    allSelects.push({
14✔
2248
                        selection: this.escape(join.alias.name!) + ".*",
14✔
2249
                    })
14✔
2250
                    const excludedSelect = this.expressionMap.selects.find(
14✔
2251
                        (select) => select.selection === join.alias.name,
14✔
2252
                    )
14✔
2253
                    excludedSelects.push(excludedSelect!)
14✔
2254
                }
14✔
2255
            }
91✔
2256
        })
278,600✔
2257

278,600✔
2258
        // add all other selects
278,600✔
2259
        this.expressionMap.selects
278,600✔
2260
            .filter((select) => excludedSelects.indexOf(select) === -1)
278,600✔
2261
            .forEach((select) =>
278,600✔
2262
                allSelects.push({
16,298✔
2263
                    selection: select.selection,
16,298✔
2264
                    aliasName: select.aliasName,
16,298✔
2265
                }),
278,600✔
2266
            )
278,600✔
2267

278,600✔
2268
        // if still selection is empty, then simply set it to all (*)
278,600✔
2269
        if (allSelects.length === 0) allSelects.push({ selection: "*" })
278,600✔
2270

278,600✔
2271
        // Use certain index
278,600✔
2272
        let useIndex: string = ""
278,600✔
2273
        if (this.expressionMap.useIndex) {
278,600!
2274
            if (DriverUtils.isMySQLFamily(this.connection.driver)) {
×
2275
                useIndex = ` USE INDEX (${this.expressionMap.useIndex})`
×
2276
            }
×
2277
        }
×
2278

278,600✔
2279
        // create a selection query
278,600✔
2280
        const froms = this.expressionMap.aliases
278,600✔
2281
            .filter(
278,600✔
2282
                (alias) =>
278,600✔
2283
                    alias.type === "from" &&
1,258,512✔
2284
                    (alias.tablePath || alias.subQuery),
278,600✔
2285
            )
278,600✔
2286
            .map((alias) => {
278,600✔
2287
                if (alias.subQuery)
278,703✔
2288
                    return alias.subQuery + " " + this.escape(alias.name)
278,703✔
2289

271,229✔
2290
                return (
271,229✔
2291
                    this.getTableName(alias.tablePath!) +
271,229✔
2292
                    " " +
271,229✔
2293
                    this.escape(alias.name)
271,229✔
2294
                )
271,229✔
2295
            })
278,600✔
2296

278,600✔
2297
        const select = this.createSelectDistinctExpression()
278,600✔
2298
        const selection = allSelects
278,600✔
2299
            .map(
278,600✔
2300
                (select) =>
278,600✔
2301
                    select.selection +
5,369,941✔
2302
                    (select.aliasName
5,369,941✔
2303
                        ? " AS " + this.escape(select.aliasName)
5,369,941✔
2304
                        : ""),
278,600✔
2305
            )
278,600✔
2306
            .join(", ")
278,600✔
2307

278,600✔
2308
        return (
278,600✔
2309
            select +
278,600✔
2310
            selection +
278,600✔
2311
            " FROM " +
278,600✔
2312
            froms.join(", ") +
278,600✔
2313
            this.createTableLockExpression() +
278,600✔
2314
            useIndex
278,600✔
2315
        )
278,600✔
2316
    }
278,600✔
2317

569,908✔
2318
    /**
569,908✔
2319
     * Creates select | select distinct part of SQL query.
569,908✔
2320
     */
569,908✔
2321
    protected createSelectDistinctExpression(): string {
569,908✔
2322
        const { selectDistinct, selectDistinctOn, maxExecutionTime } =
278,600✔
2323
            this.expressionMap
278,600✔
2324
        const { driver } = this.connection
278,600✔
2325

278,600✔
2326
        let select = "SELECT "
278,600✔
2327

278,600✔
2328
        if (maxExecutionTime > 0) {
278,600!
2329
            if (DriverUtils.isMySQLFamily(driver)) {
×
2330
                select += `/*+ MAX_EXECUTION_TIME(${this.expressionMap.maxExecutionTime}) */ `
×
2331
            }
×
2332
        }
×
2333

278,600✔
2334
        if (
278,600✔
2335
            DriverUtils.isPostgresFamily(driver) &&
278,600!
2336
            selectDistinctOn.length > 0
120,785✔
2337
        ) {
278,600!
2338
            const selectDistinctOnMap = selectDistinctOn.join(", ")
12✔
2339

12✔
2340
            select = `SELECT DISTINCT ON (${selectDistinctOnMap}) `
12✔
2341
        } else if (selectDistinct) {
278,600!
2342
            select = "SELECT DISTINCT "
53✔
2343
        }
53✔
2344

278,600✔
2345
        return select
278,600✔
2346
    }
278,600✔
2347

569,908✔
2348
    /**
569,908✔
2349
     * Creates "JOIN" part of SQL query.
569,908✔
2350
     */
569,908✔
2351
    protected createJoinExpression(): string {
569,908✔
2352
        // examples:
278,600✔
2353
        // select from owning side
278,600✔
2354
        // qb.select("post")
278,600✔
2355
        //     .leftJoinAndSelect("post.category", "category");
278,600✔
2356
        // select from non-owning side
278,600✔
2357
        // qb.select("category")
278,600✔
2358
        //     .leftJoinAndSelect("category.post", "post");
278,600✔
2359

278,600✔
2360
        const joins = this.expressionMap.joinAttributes.map((joinAttr) => {
278,600✔
2361
            const relation = joinAttr.relation
677,855✔
2362
            const destinationTableName = joinAttr.tablePath
677,855✔
2363
            const destinationTableAlias = joinAttr.alias.name
677,855✔
2364
            let appendedCondition = joinAttr.condition
677,855✔
2365
                ? " AND (" + joinAttr.condition + ")"
677,855✔
2366
                : ""
677,855✔
2367
            const parentAlias = joinAttr.parentAlias
677,855✔
2368

677,855✔
2369
            // if join was build without relation (e.g. without "post.category") then it means that we have direct
677,855✔
2370
            // table to join, without junction table involved. This means we simply join direct table.
677,855✔
2371
            if (!parentAlias || !relation) {
677,855✔
2372
                const destinationJoin = joinAttr.alias.subQuery
9,663✔
2373
                    ? joinAttr.alias.subQuery
9,663!
2374
                    : this.getTableName(destinationTableName)
9,663✔
2375
                return (
9,663✔
2376
                    " " +
9,663✔
2377
                    joinAttr.direction +
9,663✔
2378
                    " JOIN " +
9,663✔
2379
                    destinationJoin +
9,663✔
2380
                    " " +
9,663✔
2381
                    this.escape(destinationTableAlias) +
9,663✔
2382
                    this.createTableLockExpression() +
9,663✔
2383
                    (joinAttr.condition ? " ON " + joinAttr.condition : "")
9,663!
2384
                )
9,663✔
2385
            }
9,663✔
2386

668,192✔
2387
            // if real entity relation is involved
668,192✔
2388
            if (relation.isManyToOne || relation.isOneToOneOwner) {
677,855✔
2389
                // JOIN `category` `category` ON `category`.`id` = `post`.`categoryId`
14,689✔
2390
                const condition = relation.joinColumns
14,689✔
2391
                    .map((joinColumn) => {
14,689✔
2392
                        return (
15,722✔
2393
                            destinationTableAlias +
15,722✔
2394
                            "." +
15,722✔
2395
                            joinColumn.referencedColumn!.propertyPath +
15,722✔
2396
                            "=" +
15,722✔
2397
                            parentAlias +
15,722✔
2398
                            "." +
15,722✔
2399
                            relation.propertyPath +
15,722✔
2400
                            "." +
15,722✔
2401
                            joinColumn.referencedColumn!.propertyPath
15,722✔
2402
                        )
15,722✔
2403
                    })
14,689✔
2404
                    .join(" AND ")
14,689✔
2405

14,689✔
2406
                return (
14,689✔
2407
                    " " +
14,689✔
2408
                    joinAttr.direction +
14,689✔
2409
                    " JOIN " +
14,689✔
2410
                    this.getTableName(destinationTableName) +
14,689✔
2411
                    " " +
14,689✔
2412
                    this.escape(destinationTableAlias) +
14,689✔
2413
                    this.createTableLockExpression() +
14,689✔
2414
                    " ON " +
14,689✔
2415
                    condition +
14,689✔
2416
                    appendedCondition
14,689✔
2417
                )
14,689✔
2418
            } else if (relation.isOneToMany || relation.isOneToOneNotOwner) {
677,855✔
2419
                // JOIN `post` `post` ON `post`.`categoryId` = `category`.`id`
365,523✔
2420
                const condition = relation
365,523✔
2421
                    .inverseRelation!.joinColumns.map((joinColumn) => {
365,523✔
2422
                        if (
366,373✔
2423
                            relation.inverseEntityMetadata.tableType ===
366,373✔
2424
                                "entity-child" &&
366,373!
2425
                            relation.inverseEntityMetadata.discriminatorColumn
100✔
2426
                        ) {
366,373!
2427
                            appendedCondition +=
100✔
2428
                                " AND " +
100✔
2429
                                destinationTableAlias +
100✔
2430
                                "." +
100✔
2431
                                relation.inverseEntityMetadata
100✔
2432
                                    .discriminatorColumn.databaseName +
100✔
2433
                                "='" +
100✔
2434
                                relation.inverseEntityMetadata
100✔
2435
                                    .discriminatorValue +
100✔
2436
                                "'"
100✔
2437
                        }
100✔
2438

366,373✔
2439
                        return (
366,373✔
2440
                            destinationTableAlias +
366,373✔
2441
                            "." +
366,373✔
2442
                            relation.inverseRelation!.propertyPath +
366,373✔
2443
                            "." +
366,373✔
2444
                            joinColumn.referencedColumn!.propertyPath +
366,373✔
2445
                            "=" +
366,373✔
2446
                            parentAlias +
366,373✔
2447
                            "." +
366,373✔
2448
                            joinColumn.referencedColumn!.propertyPath
366,373✔
2449
                        )
366,373✔
2450
                    })
365,523✔
2451
                    .join(" AND ")
365,523✔
2452

365,523✔
2453
                if (!condition)
365,523✔
2454
                    throw new TypeORMError(
365,523!
2455
                        `Relation ${relation.entityMetadata.name}.${relation.propertyName} does not have join columns.`,
×
2456
                    )
×
2457

365,523✔
2458
                return (
365,523✔
2459
                    " " +
365,523✔
2460
                    joinAttr.direction +
365,523✔
2461
                    " JOIN " +
365,523✔
2462
                    this.getTableName(destinationTableName) +
365,523✔
2463
                    " " +
365,523✔
2464
                    this.escape(destinationTableAlias) +
365,523✔
2465
                    this.createTableLockExpression() +
365,523✔
2466
                    " ON " +
365,523✔
2467
                    condition +
365,523✔
2468
                    appendedCondition
365,523✔
2469
                )
365,523✔
2470
            } else {
653,503✔
2471
                // means many-to-many
287,980✔
2472
                const junctionTableName =
287,980✔
2473
                    relation.junctionEntityMetadata!.tablePath
287,980✔
2474

287,980✔
2475
                const junctionAlias = joinAttr.junctionAlias
287,980✔
2476
                let junctionCondition: string, destinationCondition: string
287,980✔
2477

287,980✔
2478
                if (relation.isOwning) {
287,980✔
2479
                    junctionCondition = relation.joinColumns
287,126✔
2480
                        .map((joinColumn) => {
287,126✔
2481
                            // `post_category`.`postId` = `post`.`id`
287,726✔
2482
                            return (
287,726✔
2483
                                junctionAlias +
287,726✔
2484
                                "." +
287,726✔
2485
                                joinColumn.propertyPath +
287,726✔
2486
                                "=" +
287,726✔
2487
                                parentAlias +
287,726✔
2488
                                "." +
287,726✔
2489
                                joinColumn.referencedColumn!.propertyPath
287,726✔
2490
                            )
287,726✔
2491
                        })
287,126✔
2492
                        .join(" AND ")
287,126✔
2493

287,126✔
2494
                    destinationCondition = relation.inverseJoinColumns
287,126✔
2495
                        .map((joinColumn) => {
287,126✔
2496
                            // `category`.`id` = `post_category`.`categoryId`
287,901✔
2497
                            return (
287,901✔
2498
                                destinationTableAlias +
287,901✔
2499
                                "." +
287,901✔
2500
                                joinColumn.referencedColumn!.propertyPath +
287,901✔
2501
                                "=" +
287,901✔
2502
                                junctionAlias +
287,901✔
2503
                                "." +
287,901✔
2504
                                joinColumn.propertyPath
287,901✔
2505
                            )
287,901✔
2506
                        })
287,126✔
2507
                        .join(" AND ")
287,126✔
2508
                } else {
287,980✔
2509
                    junctionCondition = relation
854✔
2510
                        .inverseRelation!.inverseJoinColumns.map(
854✔
2511
                            (joinColumn) => {
854✔
2512
                                // `post_category`.`categoryId` = `category`.`id`
1,404✔
2513
                                return (
1,404✔
2514
                                    junctionAlias +
1,404✔
2515
                                    "." +
1,404✔
2516
                                    joinColumn.propertyPath +
1,404✔
2517
                                    "=" +
1,404✔
2518
                                    parentAlias +
1,404✔
2519
                                    "." +
1,404✔
2520
                                    joinColumn.referencedColumn!.propertyPath
1,404✔
2521
                                )
1,404✔
2522
                            },
854✔
2523
                        )
854✔
2524
                        .join(" AND ")
854✔
2525

854✔
2526
                    destinationCondition = relation
854✔
2527
                        .inverseRelation!.joinColumns.map((joinColumn) => {
854✔
2528
                            // `post`.`id` = `post_category`.`postId`
1,354✔
2529
                            return (
1,354✔
2530
                                destinationTableAlias +
1,354✔
2531
                                "." +
1,354✔
2532
                                joinColumn.referencedColumn!.propertyPath +
1,354✔
2533
                                "=" +
1,354✔
2534
                                junctionAlias +
1,354✔
2535
                                "." +
1,354✔
2536
                                joinColumn.propertyPath
1,354✔
2537
                            )
1,354✔
2538
                        })
854✔
2539
                        .join(" AND ")
854✔
2540
                }
854✔
2541

287,980✔
2542
                return (
287,980✔
2543
                    " " +
287,980✔
2544
                    joinAttr.direction +
287,980✔
2545
                    " JOIN " +
287,980✔
2546
                    this.getTableName(junctionTableName) +
287,980✔
2547
                    " " +
287,980✔
2548
                    this.escape(junctionAlias) +
287,980✔
2549
                    this.createTableLockExpression() +
287,980✔
2550
                    " ON " +
287,980✔
2551
                    junctionCondition +
287,980✔
2552
                    " " +
287,980✔
2553
                    joinAttr.direction +
287,980✔
2554
                    " JOIN " +
287,980✔
2555
                    this.getTableName(destinationTableName) +
287,980✔
2556
                    " " +
287,980✔
2557
                    this.escape(destinationTableAlias) +
287,980✔
2558
                    this.createTableLockExpression() +
287,980✔
2559
                    " ON " +
287,980✔
2560
                    destinationCondition +
287,980✔
2561
                    appendedCondition
287,980✔
2562
                )
287,980✔
2563
            }
287,980✔
2564
        })
278,600✔
2565

278,600✔
2566
        return joins.join(" ")
278,600✔
2567
    }
278,600✔
2568

569,908✔
2569
    /**
569,908✔
2570
     * Creates "GROUP BY" part of SQL query.
569,908✔
2571
     */
569,908✔
2572
    protected createGroupByExpression() {
569,908✔
2573
        if (!this.expressionMap.groupBys || !this.expressionMap.groupBys.length)
278,600✔
2574
            return ""
278,600✔
2575
        return " GROUP BY " + this.expressionMap.groupBys.join(", ")
465!
2576
    }
465✔
2577

569,908✔
2578
    /**
569,908✔
2579
     * Creates "ORDER BY" part of SQL query.
569,908✔
2580
     */
569,908✔
2581
    protected createOrderByExpression() {
569,908✔
2582
        const orderBys = this.expressionMap.allOrderBys
278,600✔
2583
        if (Object.keys(orderBys).length === 0) return ""
278,600✔
2584

25,158✔
2585
        return (
25,158✔
2586
            " ORDER BY " +
25,158✔
2587
            Object.keys(orderBys)
25,158✔
2588
                .map((columnName) => {
25,158✔
2589
                    const orderValue =
33,134✔
2590
                        typeof orderBys[columnName] === "string"
33,134✔
2591
                            ? orderBys[columnName]
33,134✔
2592
                            : (orderBys[columnName] as any).order +
33,134!
2593
                              " " +
45✔
2594
                              (orderBys[columnName] as any).nulls
45✔
2595
                    const selectionByAlias = this.expressionMap.selects.find(
33,134✔
2596
                        (s) => s.aliasName === columnName,
33,134✔
2597
                    )
33,134✔
2598
                    if (selectionByAlias) {
33,134!
2599
                        return this.escape(columnName) + " " + orderValue
58✔
2600
                    }
58✔
2601
                    const selection = this.expressionMap.selects.find(
33,076✔
2602
                        (s) => s.selection === columnName,
33,076✔
2603
                    )
33,076✔
2604
                    if (
33,076✔
2605
                        selection &&
33,076✔
2606
                        !selection.aliasName &&
33,134!
2607
                        columnName.indexOf(".") !== -1
944✔
2608
                    ) {
33,134!
2609
                        const criteriaParts = columnName.split(".")
716✔
2610
                        const aliasName = criteriaParts[0]
716✔
2611
                        const propertyPath = criteriaParts.slice(1).join(".")
716✔
2612
                        const alias = this.expressionMap.aliases.find(
716✔
2613
                            (alias) => alias.name === aliasName,
716✔
2614
                        )
716✔
2615
                        if (alias?.hasMetadata) {
716!
2616
                            const column =
329✔
2617
                                alias.metadata.findColumnWithPropertyPath(
329✔
2618
                                    propertyPath,
329✔
2619
                                )
329✔
2620
                            if (column) {
329✔
2621
                                const orderAlias = DriverUtils.buildAlias(
329✔
2622
                                    this.connection.driver,
329✔
2623
                                    undefined,
329✔
2624
                                    aliasName,
329✔
2625
                                    column.databaseName,
329✔
2626
                                )
329✔
2627
                                return (
329✔
2628
                                    this.escape(orderAlias) + " " + orderValue
329✔
2629
                                )
329✔
2630
                            }
329✔
2631
                        }
329✔
2632
                    }
716✔
2633
                    return columnName + " " + orderValue
32,747✔
2634
                })
25,158✔
2635
                .join(", ")
25,158✔
2636
        )
25,158✔
2637
    }
25,158✔
2638

569,908✔
2639
    /**
569,908✔
2640
     * Creates "LIMIT" and "OFFSET" parts of SQL query.
569,908✔
2641
     */
569,908✔
2642
    protected createLimitOffsetExpression(): string {
569,908✔
2643
        // in the case if nothing is joined in the query builder we don't need to make two requests to get paginated results
278,600✔
2644
        // we can use regular limit / offset, that's why we add offset and limit construction here based on skip and take values
278,600✔
2645
        let offset: number | undefined = this.expressionMap.offset,
278,600✔
2646
            limit: number | undefined = this.expressionMap.limit
278,600✔
2647
        if (
278,600✔
2648
            offset === undefined &&
278,600✔
2649
            limit === undefined &&
278,600✔
2650
            this.expressionMap.joinAttributes.length === 0
271,207✔
2651
        ) {
278,600✔
2652
            offset = this.expressionMap.skip
160,217✔
2653
            limit = this.expressionMap.take
160,217✔
2654
        }
160,217✔
2655

278,600✔
2656
        // Helper functions to check if values are set (including 0)
278,600✔
2657
        const hasLimit = limit !== undefined && limit !== null
278,600✔
2658
        const hasOffset = offset !== undefined && offset !== null
278,600!
2659

278,600✔
2660
        if (this.connection.driver.options.type === "mssql") {
278,600!
2661
            // Due to a limitation in SQL Server's parser implementation it does not support using
15,290✔
2662
            // OFFSET or FETCH NEXT without an ORDER BY clause being provided. In cases where the
15,290✔
2663
            // user does not request one we insert a dummy ORDER BY that does nothing and should
15,290✔
2664
            // have no effect on the query planner or on the order of the results returned.
15,290✔
2665
            // https://dba.stackexchange.com/a/193799
15,290✔
2666
            let prefix = ""
15,290✔
2667
            if (
15,290✔
2668
                (hasLimit || hasOffset) &&
15,290✔
2669
                Object.keys(this.expressionMap.allOrderBys).length <= 0
1,260✔
2670
            ) {
15,290✔
2671
                prefix = " ORDER BY (SELECT NULL)"
640✔
2672
            }
640✔
2673

15,290✔
2674
            if (hasLimit && hasOffset)
15,290✔
2675
                return (
15,290✔
2676
                    prefix +
74✔
2677
                    " OFFSET " +
74✔
2678
                    offset +
74✔
2679
                    " ROWS FETCH NEXT " +
74✔
2680
                    limit +
74✔
2681
                    " ROWS ONLY"
74✔
2682
                )
74✔
2683
            if (hasLimit)
15,216✔
2684
                return (
15,290✔
2685
                    prefix + " OFFSET 0 ROWS FETCH NEXT " + limit + " ROWS ONLY"
1,184✔
2686
                )
1,184✔
2687
            if (hasOffset) return prefix + " OFFSET " + offset + " ROWS"
15,290✔
2688
        } else if (
278,600!
2689
            DriverUtils.isMySQLFamily(this.connection.driver) ||
263,310!
2690
            this.connection.driver.options.type === "aurora-mysql" ||
263,310!
2691
            this.connection.driver.options.type === "sap" ||
263,310!
2692
            this.connection.driver.options.type === "spanner"
182,920✔
2693
        ) {
263,310!
2694
            if (hasLimit && hasOffset)
80,390✔
2695
                return " LIMIT " + limit + " OFFSET " + offset
80,390✔
2696
            if (hasLimit) return " LIMIT " + limit
80,390✔
2697
            if (hasOffset) throw new OffsetWithoutLimitNotSupportedError()
80,390✔
2698
        } else if (DriverUtils.isSQLiteFamily(this.connection.driver)) {
263,310!
2699
            if (hasLimit && hasOffset)
47,691✔
2700
                return " LIMIT " + limit + " OFFSET " + offset
47,691✔
2701
            if (hasLimit) return " LIMIT " + limit
47,691✔
2702
            if (hasOffset) return " LIMIT -1 OFFSET " + offset
47,691✔
2703
        } else if (this.connection.driver.options.type === "oracle") {
182,920!
2704
            if (hasLimit && hasOffset)
14,444✔
2705
                return (
14,444✔
2706
                    " OFFSET " +
74✔
2707
                    offset +
74✔
2708
                    " ROWS FETCH NEXT " +
74✔
2709
                    limit +
74✔
2710
                    " ROWS ONLY"
74✔
2711
                )
74✔
2712
            if (hasLimit) return " FETCH NEXT " + limit + " ROWS ONLY"
14,444✔
2713
            if (hasOffset) return " OFFSET " + offset + " ROWS"
14,444✔
2714
        } else {
135,229!
2715
            if (hasLimit && hasOffset)
120,785✔
2716
                return " LIMIT " + limit + " OFFSET " + offset
120,785!
2717
            if (hasLimit) return " LIMIT " + limit
120,785✔
2718
            if (hasOffset) return " OFFSET " + offset
120,785!
2719
        }
120,785✔
2720

261,623✔
2721
        return ""
261,623✔
2722
    }
261,623✔
2723

569,908✔
2724
    /**
569,908✔
2725
     * Creates "LOCK" part of SELECT Query after table Clause
569,908✔
2726
     * ex.
569,908✔
2727
     *  SELECT 1
569,908✔
2728
     *  FROM USER U WITH (NOLOCK)
569,908✔
2729
     *  JOIN ORDER O WITH (NOLOCK)
569,908✔
2730
     *      ON U.ID=O.OrderID
569,908✔
2731
     */
569,908✔
2732
    private createTableLockExpression(): string {
569,908✔
2733
        if (this.connection.driver.options.type === "mssql") {
1,244,435!
2734
            switch (this.expressionMap.lockMode) {
18,908✔
2735
                case "pessimistic_read":
18,908✔
2736
                    return " WITH (HOLDLOCK, ROWLOCK)"
10✔
2737
                case "pessimistic_write":
18,908✔
2738
                    return " WITH (UPDLOCK, ROWLOCK)"
14✔
2739
                case "dirty_read":
18,908✔
2740
                    return " WITH (NOLOCK)"
22✔
2741
            }
18,908✔
2742
        }
18,908✔
2743

1,244,389✔
2744
        return ""
1,244,389✔
2745
    }
1,244,389✔
2746

569,908✔
2747
    /**
569,908✔
2748
     * @returns "LOCK" part of SQL query
569,908✔
2749
     */
569,908✔
2750
    protected createLockExpression(): string {
569,908✔
2751
        const driver = this.connection.driver
278,590✔
2752

278,590✔
2753
        let lockTablesClause = ""
278,590✔
2754

278,590✔
2755
        if (this.expressionMap.lockTables) {
278,590!
2756
            if (!DriverUtils.isPostgresFamily(driver)) {
78!
2757
                throw new TypeORMError(
×
2758
                    "Lock tables not supported in selected driver",
×
2759
                )
×
2760
            }
×
2761
            if (this.expressionMap.lockTables.length < 1) {
78✔
2762
                throw new TypeORMError("lockTables cannot be an empty array")
10✔
2763
            }
10✔
2764
            lockTablesClause = " OF " + this.expressionMap.lockTables.join(", ")
68✔
2765
        }
68✔
2766

278,580✔
2767
        let onLockExpression = ""
278,580✔
2768
        if (this.expressionMap.onLocked === "nowait") {
278,590!
2769
            onLockExpression = " NOWAIT"
22✔
2770
        } else if (this.expressionMap.onLocked === "skip_locked") {
278,590!
2771
            if (driver.options.type === "sap") {
28!
2772
                onLockExpression = " IGNORE LOCKED"
6✔
2773
            } else {
28!
2774
                onLockExpression = " SKIP LOCKED"
22✔
2775
            }
22✔
2776
        }
28✔
2777
        switch (this.expressionMap.lockMode) {
278,580✔
2778
            case "pessimistic_read":
278,590!
2779
                if (
129✔
2780
                    driver.options.type === "mysql" ||
129✔
2781
                    driver.options.type === "aurora-mysql"
103✔
2782
                ) {
129!
2783
                    if (
26✔
2784
                        DriverUtils.isReleaseVersionOrGreater(driver, "8.0.0")
26✔
2785
                    ) {
26!
2786
                        return (
16✔
2787
                            " FOR SHARE" + lockTablesClause + onLockExpression
16✔
2788
                        )
16✔
2789
                    } else {
26!
2790
                        return " LOCK IN SHARE MODE"
10✔
2791
                    }
10✔
2792
                } else if (driver.options.type === "mariadb") {
129!
2793
                    return " LOCK IN SHARE MODE"
16✔
2794
                } else if (DriverUtils.isPostgresFamily(driver)) {
103!
2795
                    return " FOR SHARE" + lockTablesClause + onLockExpression
41✔
2796
                } else if (driver.options.type === "sap") {
87!
2797
                    return (
16✔
2798
                        " FOR SHARE LOCK" + lockTablesClause + onLockExpression
16✔
2799
                    )
16✔
2800
                } else if (driver.options.type === "oracle") {
46!
2801
                    return " FOR UPDATE"
8✔
2802
                } else if (driver.options.type === "mssql") {
30!
2803
                    return ""
10✔
2804
                } else {
22!
2805
                    throw new LockNotSupportedOnGivenDriverError()
12✔
2806
                }
12✔
2807
            case "pessimistic_write":
278,590!
2808
                if (
162✔
2809
                    DriverUtils.isMySQLFamily(driver) ||
162!
2810
                    driver.options.type === "aurora-mysql" ||
162!
2811
                    driver.options.type === "oracle"
124✔
2812
                ) {
162!
2813
                    return " FOR UPDATE" + onLockExpression
46✔
2814
                } else if (
162!
2815
                    DriverUtils.isPostgresFamily(driver) ||
116!
2816
                    driver.options.type === "sap"
34✔
2817
                ) {
116!
2818
                    return " FOR UPDATE" + lockTablesClause + onLockExpression
92✔
2819
                } else if (driver.options.type === "mssql") {
116!
2820
                    return ""
12✔
2821
                } else {
24!
2822
                    throw new LockNotSupportedOnGivenDriverError()
12✔
2823
                }
12✔
2824
            case "for_no_key_update":
278,590!
2825
                if (DriverUtils.isPostgresFamily(driver)) {
42!
2826
                    return (
22✔
2827
                        " FOR NO KEY UPDATE" +
22✔
2828
                        lockTablesClause +
22✔
2829
                        onLockExpression
22✔
2830
                    )
22✔
2831
                } else {
42!
2832
                    throw new LockNotSupportedOnGivenDriverError()
20✔
2833
                }
20✔
2834
            case "for_key_share":
278,590!
2835
                if (DriverUtils.isPostgresFamily(driver)) {
42!
2836
                    return (
22✔
2837
                        " FOR KEY SHARE" + lockTablesClause + onLockExpression
22✔
2838
                    )
22✔
2839
                } else {
42!
2840
                    throw new LockNotSupportedOnGivenDriverError()
20✔
2841
                }
20✔
2842
            default:
278,590✔
2843
                return ""
278,205✔
2844
        }
278,590✔
2845
    }
278,590✔
2846

569,908✔
2847
    /**
569,908✔
2848
     * Creates "HAVING" part of SQL query.
569,908✔
2849
     */
569,908✔
2850
    protected createHavingExpression() {
569,908✔
2851
        if (!this.expressionMap.havings || !this.expressionMap.havings.length)
278,600✔
2852
            return ""
278,600✔
2853
        const conditions = this.expressionMap.havings
304!
2854
            .map((having, index) => {
304✔
2855
                switch (having.type) {
308✔
2856
                    case "and":
308!
2857
                        return (index > 0 ? "AND " : "") + having.condition
×
2858
                    case "or":
308!
2859
                        return (index > 0 ? "OR " : "") + having.condition
4!
2860
                    default:
308✔
2861
                        return having.condition
304✔
2862
                }
308✔
2863
            })
304✔
2864
            .join(" ")
304✔
2865

304✔
2866
        if (!conditions.length) return ""
272,181!
2867
        return " HAVING " + conditions
304✔
2868
    }
304✔
2869

569,908✔
2870
    protected buildEscapedEntityColumnSelects(
569,908✔
2871
        aliasName: string,
946,374✔
2872
        metadata: EntityMetadata,
946,374✔
2873
    ): SelectQuery[] {
946,374✔
2874
        const hasMainAlias = this.expressionMap.selects.some(
946,374✔
2875
            (select) => select.selection === aliasName,
946,374✔
2876
        )
946,374✔
2877

946,374✔
2878
        const columns: ColumnMetadata[] = []
946,374✔
2879
        if (hasMainAlias) {
946,374✔
2880
            columns.push(
901,740✔
2881
                ...metadata.columns.filter(
901,740✔
2882
                    (column) => column.isSelect === true,
901,740✔
2883
                ),
901,740✔
2884
            )
901,740✔
2885
        }
901,740✔
2886

946,374✔
2887
        const columnsMap = new Map(
946,374✔
2888
            metadata.columns.map((col) => [
946,374✔
2889
                `${aliasName}.${col.propertyPath}`,
5,474,316✔
2890
                col,
5,474,316✔
2891
            ]),
946,374✔
2892
        )
946,374✔
2893
        columns.push(
946,374✔
2894
            ...this.expressionMap.selects
946,374✔
2895
                .map((select) => columnsMap.get(select.selection))
946,374✔
2896
                .filter((col): col is ColumnMetadata => !!col),
946,374✔
2897
        )
946,374✔
2898

946,374✔
2899
        // if user used partial selection and did not select some primary columns which are required to be selected
946,374✔
2900
        // we select those primary columns and mark them as "virtual". Later virtual column values will be removed from final entity
946,374✔
2901
        // to make entity contain exactly what user selected
946,374✔
2902
        if (columns.length === 0)
946,374✔
2903
            // however not in the case when nothing (even partial) was selected from this target (for example joins without selection)
946,374✔
2904
            return []
946,374✔
2905

929,165✔
2906
        const nonSelectedPrimaryColumns = this.expressionMap.queryEntity
929,165✔
2907
            ? metadata.primaryColumns.filter(
946,374✔
2908
                  (primaryColumn) => columns.indexOf(primaryColumn) === -1,
159,529✔
2909
              )
946,374✔
2910
            : []
946,374✔
2911
        const allColumns = [...columns, ...nonSelectedPrimaryColumns]
946,374✔
2912
        const finalSelects: SelectQuery[] = []
946,374✔
2913

946,374✔
2914
        const escapedAliasName = this.escape(aliasName)
946,374✔
2915
        allColumns.forEach((column) => {
946,374✔
2916
            let selectionPath =
5,351,039✔
2917
                escapedAliasName + "." + this.escape(column.databaseName)
5,351,039✔
2918

5,351,039✔
2919
            if (column.isVirtualProperty && column.query) {
5,351,039!
2920
                selectionPath = `(${column.query(escapedAliasName)})`
481✔
2921
            }
481✔
2922

5,351,039✔
2923
            if (DriverUtils.isSQLiteFamily(this.connection.driver)) {
5,351,039!
2924
                selectionPath = (
169,218✔
2925
                    this.connection.driver as
169,218✔
2926
                        | AbstractSqliteDriver
169,218✔
2927
                        | ReactNativeDriver
169,218✔
2928
                ).wrapWithJsonFunction(selectionPath, column, false)
169,218✔
2929
            }
169,218✔
2930

5,351,039✔
2931
            if (
5,351,039✔
2932
                this.connection.driver.spatialTypes.indexOf(column.type) !== -1
5,351,039✔
2933
            ) {
5,351,039!
2934
                if (
272✔
2935
                    DriverUtils.isMySQLFamily(this.connection.driver) ||
272!
2936
                    this.connection.driver.options.type === "aurora-mysql"
196✔
2937
                ) {
272!
2938
                    const useLegacy = (
76✔
2939
                        this.connection.driver as
76✔
2940
                            | MysqlDriver
76✔
2941
                            | AuroraMysqlDriver
76✔
2942
                    ).options.legacySpatialSupport
76✔
2943
                    const asText = useLegacy ? "AsText" : "ST_AsText"
76✔
2944
                    selectionPath = `${asText}(${selectionPath})`
76✔
2945
                }
76✔
2946

272✔
2947
                if (DriverUtils.isPostgresFamily(this.connection.driver))
272✔
2948
                    if (column.precision) {
272!
2949
                        // cast to JSON to trigger parsing in the driver
×
2950
                        selectionPath = `ST_AsGeoJSON(${selectionPath}, ${column.precision})::json`
×
2951
                    } else {
168✔
2952
                        selectionPath = `ST_AsGeoJSON(${selectionPath})::json`
168✔
2953
                    }
168✔
2954
                if (this.connection.driver.options.type === "mssql")
272✔
2955
                    selectionPath = `${selectionPath}.ToString()`
272!
2956
            }
272✔
2957

5,351,039✔
2958
            const selections = this.expressionMap.selects.filter(
5,351,039✔
2959
                (select) =>
5,351,039✔
2960
                    select.selection === aliasName + "." + column.propertyPath,
5,351,039✔
2961
            )
5,351,039✔
2962
            if (selections.length) {
5,351,039✔
2963
                selections.forEach((selection) => {
52,865✔
2964
                    finalSelects.push({
52,865✔
2965
                        selection: selectionPath,
52,865✔
2966
                        aliasName: selection.aliasName
52,865✔
2967
                            ? selection.aliasName
52,865✔
2968
                            : DriverUtils.buildAlias(
52,865✔
2969
                                  this.connection.driver,
23,577✔
2970
                                  undefined,
23,577✔
2971
                                  aliasName,
23,577✔
2972
                                  column.databaseName,
23,577✔
2973
                              ),
52,865✔
2974
                        // todo: need to keep in mind that custom selection.aliasName breaks hydrator. fix it later!
52,865✔
2975
                        virtual: selection.virtual,
52,865✔
2976
                    })
52,865✔
2977
                })
52,865✔
2978
            } else {
5,351,039✔
2979
                finalSelects.push({
5,298,174✔
2980
                    selection: selectionPath,
5,298,174✔
2981
                    aliasName: DriverUtils.buildAlias(
5,298,174✔
2982
                        this.connection.driver,
5,298,174✔
2983
                        undefined,
5,298,174✔
2984
                        aliasName,
5,298,174✔
2985
                        column.databaseName,
5,298,174✔
2986
                    ),
5,298,174✔
2987
                    // todo: need to keep in mind that custom selection.aliasName breaks hydrator. fix it later!
5,298,174✔
2988
                    virtual: hasMainAlias,
5,298,174✔
2989
                })
5,298,174✔
2990
            }
5,298,174✔
2991
        })
946,374✔
2992
        return finalSelects
946,374✔
2993
    }
946,374✔
2994

569,908✔
2995
    protected findEntityColumnSelects(
569,908✔
2996
        aliasName: string,
946,374✔
2997
        metadata: EntityMetadata,
946,374✔
2998
    ): SelectQuery[] {
946,374✔
2999
        return this.expressionMap.selects.filter(
946,374✔
3000
            (select) =>
946,374✔
3001
                select.selection === aliasName ||
6,905,727✔
3002
                metadata.columns.some(
6,003,987✔
3003
                    (column) =>
6,003,987✔
3004
                        select.selection ===
40,982,323✔
3005
                        aliasName + "." + column.propertyPath,
6,003,987✔
3006
                ),
946,374✔
3007
        )
946,374✔
3008
    }
946,374✔
3009

569,908✔
3010
    private computeCountExpression() {
569,908✔
3011
        const mainAlias = this.expressionMap.mainAlias!.name // todo: will this work with "fromTableName"?
6,484✔
3012
        const metadata = this.expressionMap.mainAlias!.metadata
6,484✔
3013

6,484✔
3014
        const primaryColumns = metadata.primaryColumns
6,484✔
3015
        const distinctAlias = this.escape(mainAlias)
6,484✔
3016

6,484✔
3017
        // If we aren't doing anything that will create a join, we can use a simpler `COUNT` instead
6,484✔
3018
        // so we prevent poor query patterns in the most likely cases
6,484✔
3019
        if (
6,484✔
3020
            this.expressionMap.joinAttributes.length === 0 &&
6,484✔
3021
            this.expressionMap.relationIdAttributes.length === 0
6,359✔
3022
        ) {
6,484✔
3023
            return "COUNT(1)"
6,359✔
3024
        }
6,359✔
3025

125!
3026
        // For everything else, we'll need to do some hackery to get the correct count values.
125✔
3027

125✔
3028
        if (
125✔
3029
            this.connection.driver.options.type === "cockroachdb" ||
125!
3030
            DriverUtils.isPostgresFamily(this.connection.driver)
120✔
3031
        ) {
6,484!
3032
            // Postgres and CockroachDB can pass multiple parameters to the `DISTINCT` function
25✔
3033
            // https://www.postgresql.org/docs/9.5/sql-select.html#SQL-DISTINCT
25✔
3034
            return (
25✔
3035
                "COUNT(DISTINCT(" +
25✔
3036
                primaryColumns
25✔
3037
                    .map(
25✔
3038
                        (c) =>
25✔
3039
                            `${distinctAlias}.${this.escape(c.databaseName)}`,
25✔
3040
                    )
25✔
3041
                    .join(", ") +
25✔
3042
                "))"
25✔
3043
            )
25✔
3044
        }
25✔
3045

100!
3046
        if (DriverUtils.isMySQLFamily(this.connection.driver)) {
3,152!
3047
            // MySQL & MariaDB can pass multiple parameters to the `DISTINCT` language construct
40✔
3048
            // https://mariadb.com/kb/en/count-distinct/
40✔
3049
            return (
40✔
3050
                "COUNT(DISTINCT " +
40✔
3051
                primaryColumns
40✔
3052
                    .map(
40✔
3053
                        (c) =>
40✔
3054
                            `${distinctAlias}.${this.escape(c.databaseName)}`,
40✔
3055
                    )
40✔
3056
                    .join(", ") +
40✔
3057
                ")"
40✔
3058
            )
40✔
3059
        }
40✔
3060

60!
3061
        if (this.connection.driver.options.type === "mssql") {
2,606!
3062
            // SQL Server has gotta be different from everyone else.  They don't support
10✔
3063
            // distinct counting multiple columns & they don't have the same operator
10✔
3064
            // characteristic for concatenating, so we gotta use the `CONCAT` function.
10✔
3065
            // However, If it's exactly 1 column we can omit the `CONCAT` for better performance.
10✔
3066

10✔
3067
            const columnsExpression = primaryColumns
10✔
3068
                .map(
10✔
3069
                    (primaryColumn) =>
10✔
3070
                        `${distinctAlias}.${this.escape(
16✔
3071
                            primaryColumn.databaseName,
16✔
3072
                        )}`,
10✔
3073
                )
10✔
3074
                .join(", '|;|', ")
10✔
3075

10✔
3076
            if (primaryColumns.length === 1) {
10✔
3077
                return `COUNT(DISTINCT(${columnsExpression}))`
6✔
3078
            }
6✔
3079

4✔
3080
            return `COUNT(DISTINCT(CONCAT(${columnsExpression})))`
4✔
3081
        }
4✔
3082

50!
3083
        if (this.connection.driver.options.type === "spanner") {
2,596!
3084
            // spanner also has gotta be different from everyone else.
×
3085
            // they do not support concatenation of different column types without casting them to string
×
3086

×
3087
            if (primaryColumns.length === 1) {
×
3088
                return `COUNT(DISTINCT(${distinctAlias}.${this.escape(
×
3089
                    primaryColumns[0].databaseName,
×
3090
                )}))`
×
3091
            }
×
3092

×
3093
            const columnsExpression = primaryColumns
×
3094
                .map(
×
3095
                    (primaryColumn) =>
×
3096
                        `CAST(${distinctAlias}.${this.escape(
×
3097
                            primaryColumn.databaseName,
×
3098
                        )} AS STRING)`,
×
3099
                )
×
3100
                .join(", '|;|', ")
×
3101
            return `COUNT(DISTINCT(CONCAT(${columnsExpression})))`
×
3102
        }
×
3103

50✔
3104
        // If all else fails, fall back to a `COUNT` and `DISTINCT` across all the primary columns concatenated.
50✔
3105
        // Per the SQL spec, this is the canonical string concatenation mechanism which is most
50✔
3106
        // likely to work across servers implementing the SQL standard.
50✔
3107

50✔
3108
        // Please note, if there is only one primary column that the concatenation does not occur in this
50✔
3109
        // query and the query is a standard `COUNT DISTINCT` in that case.
50✔
3110

50✔
3111
        return (
50✔
3112
            `COUNT(DISTINCT(` +
50✔
3113
            primaryColumns
50✔
3114
                .map((c) => `${distinctAlias}.${this.escape(c.databaseName)}`)
50✔
3115
                .join(" || '|;|' || ") +
50✔
3116
            "))"
50✔
3117
        )
50✔
3118
    }
50✔
3119

569,908✔
3120
    protected async executeCountQuery(
569,908✔
3121
        queryRunner: QueryRunner,
6,484✔
3122
    ): Promise<number> {
6,484✔
3123
        const countSql = this.computeCountExpression()
6,484✔
3124

6,484✔
3125
        const results = await this.clone()
6,484✔
3126
            .orderBy()
6,484✔
3127
            .groupBy()
6,484✔
3128
            .offset(undefined)
6,484✔
3129
            .limit(undefined)
6,484✔
3130
            .skip(undefined)
6,484✔
3131
            .take(undefined)
6,484✔
3132
            .select(countSql, "cnt")
6,484✔
3133
            .setOption("disable-global-order")
6,484✔
3134
            .loadRawResults(queryRunner)
6,484✔
3135

6,484✔
3136
        if (!results || !results[0] || !results[0]["cnt"]) return 0
6,484!
3137

6,442✔
3138
        return parseInt(results[0]["cnt"])
6,442✔
3139
    }
6,442✔
3140

569,908✔
3141
    protected async executeExistsQuery(
569,908✔
3142
        queryRunner: QueryRunner,
175✔
3143
    ): Promise<boolean> {
175✔
3144
        const results = await this.connection
175✔
3145
            .createQueryBuilder()
175✔
3146
            .fromDummy()
175✔
3147
            .select("1", "row_exists")
175✔
3148
            .whereExists(this)
175✔
3149
            .limit(1)
175✔
3150
            .loadRawResults(queryRunner)
175✔
3151

175✔
3152
        return results.length > 0
175✔
3153
    }
175✔
3154

569,908✔
3155
    protected applyFindOptions() {
569,908✔
3156
        // todo: convert relations: string[] to object map to simplify code
175,202✔
3157
        // todo: same with selects
175,202✔
3158

175,202✔
3159
        if (this.expressionMap.mainAlias!.metadata) {
175,202✔
3160
            if (this.findOptions.relationLoadStrategy) {
175,202!
3161
                this.expressionMap.relationLoadStrategy =
32✔
3162
                    this.findOptions.relationLoadStrategy
32✔
3163
            }
32✔
3164

175,202✔
3165
            if (this.findOptions.comment) {
175,202!
3166
                this.comment(this.findOptions.comment)
25✔
3167
            }
25✔
3168

175,202✔
3169
            if (this.findOptions.withDeleted) {
175,202✔
3170
                this.withDeleted()
103,681✔
3171
            }
103,681✔
3172

175,202✔
3173
            if (this.findOptions.select) {
175,202!
3174
                this.buildSelect(
645✔
3175
                    this.findOptions.select,
645✔
3176
                    this.expressionMap.mainAlias!.metadata,
645✔
3177
                    this.expressionMap.mainAlias!.name,
645✔
3178
                )
645✔
3179
            }
645✔
3180

175,177✔
3181
            if (this.selects.length) {
175,202!
3182
                this.select(this.selects)
570✔
3183
            }
570✔
3184

175,177✔
3185
            this.selects = []
175,177✔
3186

175,177✔
3187
            if (this.findOptions.relations) {
175,202✔
3188
                const relations = Array.isArray(this.findOptions.relations)
47,284✔
3189
                    ? OrmUtils.propertyPathsToTruthyObject(
47,284!
3190
                          this.findOptions.relations,
133✔
3191
                      )
47,284✔
3192
                    : this.findOptions.relations
47,284✔
3193

47,284✔
3194
                this.buildRelations(
47,284✔
3195
                    relations,
47,284✔
3196
                    this.findOptions.select,
47,284✔
3197
                    this.expressionMap.mainAlias!.metadata,
47,284✔
3198
                    this.expressionMap.mainAlias!.name,
47,284✔
3199
                )
47,284✔
3200
                if (
47,284✔
3201
                    this.findOptions.loadEagerRelations !== false &&
47,284✔
3202
                    this.expressionMap.relationLoadStrategy === "join"
47,134✔
3203
                ) {
47,284✔
3204
                    this.buildEagerRelations(
46,977✔
3205
                        relations,
46,977✔
3206
                        this.findOptions.select,
46,977✔
3207
                        this.expressionMap.mainAlias!.metadata,
46,977✔
3208
                        this.expressionMap.mainAlias!.name,
46,977✔
3209
                    )
46,977✔
3210
                }
46,977✔
3211
            }
47,284✔
3212
            if (this.selects.length) {
175,202!
3213
                this.addSelect(this.selects)
200✔
3214
            }
200✔
3215

175,027✔
3216
            if (this.findOptions.where) {
175,202✔
3217
                this.conditions = this.buildWhere(
60,406✔
3218
                    this.findOptions.where,
60,406✔
3219
                    this.expressionMap.mainAlias!.metadata,
60,406✔
3220
                    this.expressionMap.mainAlias!.name,
60,406✔
3221
                )
60,406✔
3222

60,406✔
3223
                if (this.conditions.length)
60,406✔
3224
                    this.andWhere(
60,406✔
3225
                        this.conditions.startsWith("(")
58,961✔
3226
                            ? this.conditions
58,961✔
3227
                            : `(${this.conditions})`,
58,961!
3228
                    ) // temporary and where and braces
60,406✔
3229
            }
60,406✔
3230

174,352✔
3231
            if (this.findOptions.order) {
175,202✔
3232
                this.buildOrder(
2,468✔
3233
                    this.findOptions.order,
2,468✔
3234
                    this.expressionMap.mainAlias!.metadata,
2,468✔
3235
                    this.expressionMap.mainAlias!.name,
2,468✔
3236
                )
2,468✔
3237
            }
2,468✔
3238

174,327✔
3239
            // apply joins
174,327✔
3240
            if (this.joins.length) {
175,202✔
3241
                this.joins.forEach((join) => {
47,816✔
3242
                    if (join.select && !join.selection) {
369,943✔
3243
                        // if (join.selection) {
368,650✔
3244
                        //
368,650✔
3245
                        // } else {
368,650✔
3246
                        if (join.type === "inner") {
368,650!
3247
                            this.innerJoinAndSelect(
×
3248
                                `${join.parentAlias}.${join.relationMetadata.propertyPath}`,
×
3249
                                join.alias,
×
3250
                            )
×
3251
                        } else {
368,650✔
3252
                            this.leftJoinAndSelect(
368,650✔
3253
                                `${join.parentAlias}.${join.relationMetadata.propertyPath}`,
368,650✔
3254
                                join.alias,
368,650✔
3255
                            )
368,650✔
3256
                        }
368,650✔
3257
                        // }
368,650✔
3258
                    } else {
369,943!
3259
                        if (join.type === "inner") {
1,293!
3260
                            this.innerJoin(
×
3261
                                `${join.parentAlias}.${join.relationMetadata.propertyPath}`,
×
3262
                                join.alias,
×
3263
                            )
×
3264
                        } else {
1,293✔
3265
                            this.leftJoin(
1,293✔
3266
                                `${join.parentAlias}.${join.relationMetadata.propertyPath}`,
1,293✔
3267
                                join.alias,
1,293✔
3268
                            )
1,293✔
3269
                        }
1,293✔
3270
                    }
1,293✔
3271

369,943✔
3272
                    // if (join.select) {
369,943✔
3273
                    //     if (this.findOptions.loadEagerRelations !== false) {
369,943✔
3274
                    //         FindOptionsUtils.joinEagerRelations(
369,943✔
3275
                    //             this,
369,943✔
3276
                    //             join.alias,
369,943✔
3277
                    //             join.relationMetadata.inverseEntityMetadata
369,943✔
3278
                    //         );
369,943✔
3279
                    //     }
369,943✔
3280
                    // }
369,943✔
3281
                })
47,816✔
3282
            }
47,816✔
3283

174,327✔
3284
            // if (this.conditions.length) {
174,327✔
3285
            //     this.where(this.conditions.join(" AND "));
174,327✔
3286
            // }
174,327✔
3287

174,327✔
3288
            // apply offset
174,327✔
3289
            if (this.findOptions.skip !== undefined) {
175,202!
3290
                // if (this.findOptions.options && this.findOptions.options.pagination === false) {
154✔
3291
                //     this.offset(this.findOptions.skip);
154✔
3292
                // } else {
154✔
3293
                this.skip(this.findOptions.skip)
154✔
3294
                // }
154✔
3295
            }
154✔
3296

174,302✔
3297
            // apply limit
174,302✔
3298
            if (this.findOptions.take !== undefined) {
175,202✔
3299
                // if (this.findOptions.options && this.findOptions.options.pagination === false) {
15,634✔
3300
                //     this.limit(this.findOptions.take);
15,634✔
3301
                // } else {
15,634✔
3302
                this.take(this.findOptions.take)
15,634✔
3303
                // }
15,634✔
3304
            }
15,634✔
3305

174,277✔
3306
            // apply caching options
174,277✔
3307
            if (typeof this.findOptions.cache === "number") {
175,202!
3308
                this.cache(this.findOptions.cache)
50✔
3309
            } else if (typeof this.findOptions.cache === "boolean") {
175,202!
3310
                this.cache(this.findOptions.cache)
83✔
3311
            } else if (typeof this.findOptions.cache === "object") {
174,227!
3312
                this.cache(
125✔
3313
                    this.findOptions.cache.id,
125✔
3314
                    this.findOptions.cache.milliseconds,
125✔
3315
                )
125✔
3316
            }
125✔
3317

174,277✔
3318
            if (this.findOptions.lock) {
175,202!
3319
                if (this.findOptions.lock.mode === "optimistic") {
406✔
3320
                    this.setLock(
217✔
3321
                        this.findOptions.lock.mode,
217✔
3322
                        this.findOptions.lock.version,
217✔
3323
                    )
217✔
3324
                } else if (
406✔
3325
                    this.findOptions.lock.mode === "pessimistic_read" ||
189✔
3326
                    this.findOptions.lock.mode === "pessimistic_write" ||
189!
3327
                    this.findOptions.lock.mode === "dirty_read" ||
189!
3328
                    this.findOptions.lock.mode === "for_no_key_update" ||
189!
3329
                    this.findOptions.lock.mode === "for_key_share"
8✔
3330
                ) {
189✔
3331
                    const tableNames = this.findOptions.lock.tables
189✔
3332
                        ? this.findOptions.lock.tables.map((table) => {
189!
3333
                              const tableAlias =
26✔
3334
                                  this.expressionMap.aliases.find((alias) => {
26✔
3335
                                      return (
31✔
3336
                                          alias.metadata
31✔
3337
                                              .tableNameWithoutPrefix === table
31✔
3338
                                      )
31✔
3339
                                  })
26✔
3340
                              if (!tableAlias) {
26✔
3341
                                  throw new TypeORMError(
5✔
3342
                                      `"${table}" is not part of this query`,
5✔
3343
                                  )
5✔
3344
                              }
5✔
3345
                              return this.escape(tableAlias.name)
21✔
3346
                          })
31✔
3347
                        : undefined
189✔
3348
                    this.setLock(
189✔
3349
                        this.findOptions.lock.mode,
189✔
3350
                        undefined,
189✔
3351
                        tableNames,
189✔
3352
                    )
189✔
3353

189✔
3354
                    if (this.findOptions.lock.onLocked) {
189!
3355
                        this.setOnLocked(this.findOptions.lock.onLocked)
20✔
3356
                    }
20✔
3357
                }
189✔
3358
            }
406✔
3359

174,272✔
3360
            if (this.findOptions.loadRelationIds === true) {
175,202!
3361
                this.loadAllRelationIds()
25✔
3362
            } else if (typeof this.findOptions.loadRelationIds === "object") {
175,202✔
3363
                this.loadAllRelationIds(this.findOptions.loadRelationIds as any)
103,323✔
3364
            }
103,323✔
3365

174,272✔
3366
            if (this.findOptions.loadEagerRelations !== false) {
175,202✔
3367
                FindOptionsUtils.joinEagerRelations(
70,899✔
3368
                    this,
70,899✔
3369
                    this.expressionMap.mainAlias!.name,
70,899✔
3370
                    this.expressionMap.mainAlias!.metadata,
70,899✔
3371
                )
70,899✔
3372
            }
70,899✔
3373

174,272✔
3374
            if (this.findOptions.transaction === true) {
175,202!
3375
                this.expressionMap.useTransaction = true
25✔
3376
            }
25✔
3377

175,202✔
3378
            // if (this.orderBys.length) {
175,202✔
3379
            //     this.orderBys.forEach(orderBy => {
175,202✔
3380
            //         this.addOrderBy(orderBy.alias, orderBy.direction, orderBy.nulls);
175,202✔
3381
            //     });
175,202✔
3382
            // }
175,202✔
3383

175,202✔
3384
            // todo
175,202✔
3385
            // if (this.options.options && this.options.options.eagerRelations) {
175,202✔
3386
            //     this.queryBuilder
175,202✔
3387
            // }
175,202✔
3388

175,202✔
3389
            // todo
175,202✔
3390
            // if (this.findOptions.options && this.findOptions.listeners === false) {
175,202✔
3391
            //     this.callListeners(false);
175,202✔
3392
            // }
175,202✔
3393
        }
175,202✔
3394
    }
175,202✔
3395

569,908✔
3396
    public concatRelationMetadata(relationMetadata: RelationMetadata) {
569,908✔
3397
        this.relationMetadatas.push(relationMetadata)
99✔
3398
    }
99✔
3399

569,908✔
3400
    /**
569,908✔
3401
     * Executes sql generated by query builder and returns object with raw results and entities created from them.
569,908✔
3402
     * @param queryRunner
569,908✔
3403
     */
569,908✔
3404
    protected async executeEntitiesAndRawResults(
569,908✔
3405
        queryRunner: QueryRunner,
156,428✔
3406
    ): Promise<{ entities: Entity[]; raw: any[] }> {
156,428✔
3407
        if (!this.expressionMap.mainAlias)
156,428✔
3408
            throw new TypeORMError(
156,428!
3409
                `Alias is not set. Use "from" method to set an alias.`,
×
3410
            )
×
3411

156,428✔
3412
        if (
156,428✔
3413
            (this.expressionMap.lockMode === "pessimistic_read" ||
156,428✔
3414
                this.expressionMap.lockMode === "pessimistic_write" ||
156,428✔
3415
                this.expressionMap.lockMode === "for_no_key_update" ||
156,428✔
3416
                this.expressionMap.lockMode === "for_key_share") &&
156,428!
3417
            !queryRunner.isTransactionActive
388✔
3418
        )
156,428✔
3419
            throw new PessimisticLockTransactionRequiredError()
156,428!
3420

156,343✔
3421
        if (this.expressionMap.lockMode === "optimistic") {
156,428!
3422
            const metadata = this.expressionMap.mainAlias.metadata
217✔
3423
            if (!metadata.versionColumn && !metadata.updateDateColumn)
217✔
3424
                throw new NoVersionOrUpdateDateColumnError(metadata.name)
217✔
3425
        }
217✔
3426

156,318✔
3427
        const relationIdLoader = new RelationIdLoader(
156,318✔
3428
            this.connection,
156,318✔
3429
            queryRunner,
156,318✔
3430
            this.expressionMap.relationIdAttributes,
156,318✔
3431
        )
156,318✔
3432
        const relationIdMetadataTransformer =
156,318✔
3433
            new RelationIdMetadataToAttributeTransformer(this.expressionMap)
156,318✔
3434
        relationIdMetadataTransformer.transform()
156,318✔
3435

156,318✔
3436
        let rawResults: any[],
156,318✔
3437
            entities: any[] = []
156,318✔
3438

156,318✔
3439
        // for pagination enabled (e.g. skip and take) its much more complicated - its a special process
156,318✔
3440
        // where we make two queries to find the data we need
156,318✔
3441
        // first query find ids in skip and take range
156,318✔
3442
        // and second query loads the actual data in given ids range
156,318✔
3443
        if (
156,318✔
3444
            (this.expressionMap.skip ||
156,318✔
3445
                this.expressionMap.take ||
156,428✔
3446
                this.expressionMap.offset ||
156,428✔
3447
                this.expressionMap.limit) &&
156,428✔
3448
            this.expressionMap.joinAttributes.length > 0
16,675✔
3449
        ) {
156,428✔
3450
            // we are skipping order by here because its not working in subqueries anyway
7,025✔
3451
            // to make order by working we need to apply it on a distinct query
7,025✔
3452
            const [selects, orderBys] =
7,025✔
3453
                this.createOrderByCombinedWithSelectExpression("distinctAlias")
7,025✔
3454
            const metadata = this.expressionMap.mainAlias.metadata
7,025✔
3455
            const mainAliasName = this.expressionMap.mainAlias.name
7,025✔
3456

7,025✔
3457
            const querySelects = metadata.primaryColumns.map(
7,025✔
3458
                (primaryColumn) => {
7,025✔
3459
                    const distinctAlias = this.escape("distinctAlias")
7,129✔
3460
                    const columnAlias = this.escape(
7,129✔
3461
                        DriverUtils.buildAlias(
7,129✔
3462
                            this.connection.driver,
7,129✔
3463
                            undefined,
7,129✔
3464
                            mainAliasName,
7,129✔
3465
                            primaryColumn.databaseName,
7,129✔
3466
                        ),
7,129✔
3467
                    )
7,129✔
3468
                    if (!orderBys[columnAlias])
7,129✔
3469
                        // make sure we aren't overriding user-defined order in inverse direction
7,129✔
3470
                        orderBys[columnAlias] = "ASC"
7,129✔
3471

7,129✔
3472
                    const alias = DriverUtils.buildAlias(
7,129✔
3473
                        this.connection.driver,
7,129✔
3474
                        undefined,
7,129✔
3475
                        "ids_" + mainAliasName,
7,129✔
3476
                        primaryColumn.databaseName,
7,129✔
3477
                    )
7,129✔
3478

7,129✔
3479
                    return `${distinctAlias}.${columnAlias} AS ${this.escape(
7,129✔
3480
                        alias,
7,129✔
3481
                    )}`
7,129✔
3482
                },
7,025✔
3483
            )
7,025✔
3484

7,025✔
3485
            const originalQuery = this.clone()
7,025✔
3486

7,025✔
3487
            // clear limit/offset from the inner query since pagination is handled by the outer distinct query
7,025✔
3488
            originalQuery.expressionMap.limit = undefined
7,025✔
3489
            originalQuery.expressionMap.offset = undefined
7,025✔
3490

7,025✔
3491
            // preserve original timeTravel value since we set it to "false" in subquery
7,025✔
3492
            const originalQueryTimeTravel =
7,025✔
3493
                originalQuery.expressionMap.timeTravel
7,025✔
3494

7,025✔
3495
            const paginationQueryBuilder = new SelectQueryBuilder(
7,025✔
3496
                this.connection,
7,025✔
3497
                queryRunner,
7,025✔
3498
            )
7,025✔
3499
                .select(`DISTINCT ${querySelects.join(", ")}`)
7,025✔
3500
                .addSelect(selects)
7,025✔
3501
                .from(
7,025✔
3502
                    `(${originalQuery
7,025✔
3503
                        .orderBy()
7,025✔
3504
                        .timeTravelQuery(false) // set it to "false" since time travel clause must appear at the very end and applies to the entire SELECT clause.
7,025✔
3505
                        .getQuery()})`,
7,025✔
3506
                    "distinctAlias",
7,025✔
3507
                )
7,025✔
3508
                .timeTravelQuery(originalQueryTimeTravel)
7,025✔
3509
                .offset(this.expressionMap.skip ?? this.expressionMap.offset)
7,025✔
3510
                .limit(this.expressionMap.take ?? this.expressionMap.limit)
7,025!
3511
                .orderBy(orderBys)
7,025✔
3512
                .cache(
7,025✔
3513
                    this.expressionMap.cache && this.expressionMap.cacheId
7,025!
3514
                        ? `${this.expressionMap.cacheId}-pagination`
7,025!
3515
                        : this.expressionMap.cache,
7,025✔
3516
                    this.expressionMap.cacheDuration,
7,025✔
3517
                )
7,025✔
3518
                .setParameters(this.getParameters())
7,025✔
3519
            rawResults = await paginationQueryBuilder.getRawMany()
7,025✔
3520

7,010✔
3521
            if (rawResults.length > 0) {
7,025✔
3522
                let condition: string
6,885✔
3523
                const parameters: ObjectLiteral = {}
6,885✔
3524
                if (metadata.hasMultiplePrimaryKeys) {
6,885!
3525
                    condition = rawResults
104✔
3526
                        .map((result, index) => {
104✔
3527
                            return metadata.primaryColumns
429✔
3528
                                .map((primaryColumn) => {
429✔
3529
                                    const paramKey = `orm_distinct_ids_${index}_${primaryColumn.databaseName}`
858✔
3530
                                    const paramKeyResult =
858✔
3531
                                        DriverUtils.buildAlias(
858✔
3532
                                            this.connection.driver,
858✔
3533
                                            undefined,
858✔
3534
                                            "ids_" + mainAliasName,
858✔
3535
                                            primaryColumn.databaseName,
858✔
3536
                                        )
858✔
3537
                                    parameters[paramKey] =
858✔
3538
                                        result[paramKeyResult]
858✔
3539
                                    return `${mainAliasName}.${primaryColumn.propertyPath}=:${paramKey}`
858✔
3540
                                })
429✔
3541
                                .join(" AND ")
429✔
3542
                        })
104✔
3543
                        .join(" OR ")
104✔
3544
                } else {
6,885✔
3545
                    const alias = DriverUtils.buildAlias(
6,781✔
3546
                        this.connection.driver,
6,781✔
3547
                        undefined,
6,781✔
3548
                        "ids_" + mainAliasName,
6,781✔
3549
                        metadata.primaryColumns[0].databaseName,
6,781✔
3550
                    )
6,781✔
3551

6,781✔
3552
                    const ids = rawResults.map((result) => result[alias])
6,781✔
3553
                    const areAllNumbers = ids.every(
6,781✔
3554
                        (id: any) => typeof id === "number",
6,781✔
3555
                    )
6,781✔
3556
                    if (areAllNumbers) {
6,781!
3557
                        // fixes #190. if all numbers then its safe to perform query without parameter
6,433✔
3558
                        condition = `${mainAliasName}.${
6,433✔
3559
                            metadata.primaryColumns[0].propertyPath
6,433✔
3560
                        } IN (${ids.join(", ")})`
6,433✔
3561
                    } else {
6,781✔
3562
                        parameters["orm_distinct_ids"] = ids
348✔
3563
                        condition =
348✔
3564
                            mainAliasName +
348✔
3565
                            "." +
348✔
3566
                            metadata.primaryColumns[0].propertyPath +
348✔
3567
                            " IN (:...orm_distinct_ids)"
348✔
3568
                    }
348✔
3569
                }
6,781✔
3570
                const secondQuery = this.clone()
6,885✔
3571
                    .mergeExpressionMap({
6,885✔
3572
                        extraAppendedAndWhereCondition: condition,
6,885✔
3573
                    })
6,885✔
3574
                    .setParameters(parameters)
6,885✔
3575
                secondQuery.expressionMap.limit = undefined
6,885✔
3576
                secondQuery.expressionMap.offset = undefined
6,885✔
3577
                rawResults = await secondQuery.loadRawResults(queryRunner)
6,885✔
3578
            }
6,885✔
3579
        } else {
156,428✔
3580
            rawResults = await this.loadRawResults(queryRunner)
149,293✔
3581
        }
149,185✔
3582

156,195✔
3583
        if (rawResults.length > 0) {
156,428✔
3584
            // transform raw results into entities
56,026✔
3585
            const rawRelationIdResults = await relationIdLoader.load(rawResults)
56,026✔
3586
            const transformer = new RawSqlResultsToEntityTransformer(
56,026✔
3587
                this.expressionMap,
56,026✔
3588
                this.connection.driver,
56,026✔
3589
                rawRelationIdResults,
56,026✔
3590
                this.queryRunner,
56,026✔
3591
            )
56,026✔
3592
            entities = transformer.transform(
56,026✔
3593
                rawResults,
56,026✔
3594
                this.expressionMap.mainAlias!,
56,026✔
3595
            )
56,026✔
3596

56,026✔
3597
            // broadcast all "after load" events
56,026✔
3598
            if (
56,026✔
3599
                this.expressionMap.callListeners === true &&
56,026✔
3600
                this.expressionMap.mainAlias.hasMetadata
56,018✔
3601
            ) {
56,026✔
3602
                await queryRunner.broadcaster.broadcast(
56,018✔
3603
                    "Load",
56,018✔
3604
                    this.expressionMap.mainAlias.metadata,
56,018✔
3605
                    entities,
56,018✔
3606
                )
56,018✔
3607
            }
56,018✔
3608
        }
56,026✔
3609

156,187✔
3610
        if (this.expressionMap.relationLoadStrategy === "query") {
156,428!
3611
            const queryStrategyRelationIdLoader =
221✔
3612
                new QueryStrategyRelationIdLoader(this.connection, queryRunner)
221✔
3613

221✔
3614
            await Promise.all(
221✔
3615
                this.relationMetadatas.map(async (relation) => {
221✔
3616
                    const relationTarget = relation.inverseEntityMetadata.target
99✔
3617
                    const relationAlias =
99✔
3618
                        relation.inverseEntityMetadata.targetName
99✔
3619

99✔
3620
                    const relations = Array.isArray(this.findOptions.relations)
99✔
3621
                        ? OrmUtils.propertyPathsToTruthyObject(
99!
3622
                              this.findOptions.relations,
×
3623
                          )
99✔
3624
                        : this.findOptions.relations
99✔
3625

99✔
3626
                    const queryBuilder = this.createQueryBuilder(queryRunner)
99✔
3627
                        .select(relationAlias)
99✔
3628
                        .from(relationTarget, relationAlias)
99✔
3629
                        .setFindOptions({
99✔
3630
                            select: this.findOptions.select
99✔
3631
                                ? OrmUtils.deepValue(
99!
NEW
3632
                                      this.findOptions.select,
×
3633
                                      relation.propertyPath,
×
3634
                                  )
99✔
3635
                                : undefined,
99✔
3636
                            order: this.findOptions.order
99✔
3637
                                ? OrmUtils.deepValue(
99!
3638
                                      this.findOptions.order,
×
3639
                                      relation.propertyPath,
×
3640
                                  )
99✔
3641
                                : undefined,
99✔
3642
                            relations: relations
99✔
3643
                                ? OrmUtils.deepValue(
99✔
3644
                                      relations,
91✔
3645
                                      relation.propertyPath,
91✔
3646
                                  )
99✔
3647
                                : undefined,
99!
3648
                            withDeleted: this.findOptions.withDeleted,
99✔
3649
                            relationLoadStrategy:
99✔
3650
                                this.findOptions.relationLoadStrategy,
99✔
3651
                        })
99✔
3652
                    if (entities.length > 0) {
99✔
3653
                        const relatedEntityGroups: any[] =
99✔
3654
                            await queryStrategyRelationIdLoader.loadManyToManyRelationIdsAndGroup(
99✔
3655
                                relation,
99✔
3656
                                entities,
99✔
3657
                                undefined,
99✔
3658
                                queryBuilder,
99✔
3659
                            )
99✔
3660
                        entities.forEach((entity) => {
99✔
3661
                            const relatedEntityGroup = relatedEntityGroups.find(
107✔
3662
                                (group) => group.entity === entity,
107✔
3663
                            )
107✔
3664
                            if (relatedEntityGroup) {
107✔
3665
                                const value =
107✔
3666
                                    relatedEntityGroup.related === undefined
107✔
3667
                                        ? null
107!
3668
                                        : relatedEntityGroup.related
107✔
3669
                                relation.setEntityValue(entity, value)
107✔
3670
                            }
107✔
3671
                        })
99✔
3672
                    }
99✔
3673
                }),
221✔
3674
            )
221✔
3675
        }
221✔
3676

156,187✔
3677
        return {
156,187✔
3678
            raw: rawResults,
156,187✔
3679
            entities: entities,
156,187✔
3680
        }
156,187✔
3681
    }
156,187✔
3682

569,908✔
3683
    protected createOrderByCombinedWithSelectExpression(
569,908✔
3684
        parentAlias: string,
7,025✔
3685
    ): [string, OrderByCondition] {
7,025✔
3686
        // if table has a default order then apply it
7,025✔
3687
        const orderBys = this.expressionMap.allOrderBys
7,025✔
3688
        const selectString = Object.keys(orderBys)
7,025✔
3689
            .map((orderCriteria) => {
7,025✔
3690
                if (orderCriteria.indexOf(".") !== -1) {
441✔
3691
                    const criteriaParts = orderCriteria.split(".")
425✔
3692
                    const aliasName = criteriaParts[0]
425✔
3693
                    const propertyPath = criteriaParts.slice(1).join(".")
425✔
3694
                    const alias = this.expressionMap.findAliasByName(aliasName)
425✔
3695
                    const column =
425✔
3696
                        alias.metadata.findColumnWithPropertyPath(
425✔
3697
                            propertyPath,
425✔
3698
                        ) ??
425!
3699
                        alias.metadata.findColumnWithDatabaseName(propertyPath)
25✔
3700
                    const databaseName = column
425✔
3701
                        ? column.databaseName
425✔
3702
                        : propertyPath
425!
3703
                    return (
425✔
3704
                        this.escape(parentAlias) +
425✔
3705
                        "." +
425✔
3706
                        this.escape(
425✔
3707
                            DriverUtils.buildAlias(
425✔
3708
                                this.connection.driver,
425✔
3709
                                undefined,
425✔
3710
                                aliasName,
425✔
3711
                                databaseName,
425✔
3712
                            ),
425✔
3713
                        )
425✔
3714
                    )
425✔
3715
                } else {
441!
3716
                    if (
16✔
3717
                        this.expressionMap.selects.find(
16✔
3718
                            (select) =>
16✔
3719
                                select.selection === orderCriteria ||
32✔
3720
                                select.aliasName === orderCriteria,
16✔
3721
                        )
16✔
3722
                    )
16✔
3723
                        return (
16!
3724
                            this.escape(parentAlias) +
8✔
3725
                            "." +
8✔
3726
                            this.escape(orderCriteria)
8✔
3727
                        )
8✔
3728

8!
3729
                    return ""
8✔
3730
                }
8✔
3731
            })
7,025✔
3732
            .join(", ")
7,025✔
3733

7,025✔
3734
        const orderByObject: OrderByCondition = {}
7,025✔
3735
        Object.keys(orderBys).forEach((orderCriteria) => {
7,025✔
3736
            if (orderCriteria.indexOf(".") !== -1) {
441✔
3737
                const criteriaParts = orderCriteria.split(".")
425✔
3738
                const aliasName = criteriaParts[0]
425✔
3739
                const propertyPath = criteriaParts.slice(1).join(".")
425✔
3740
                const alias = this.expressionMap.findAliasByName(aliasName)
425✔
3741
                const column =
425✔
3742
                    alias.metadata.findColumnWithPropertyPath(propertyPath) ??
425!
3743
                    alias.metadata.findColumnWithDatabaseName(propertyPath)
25✔
3744
                const databaseName = column ? column.databaseName : propertyPath
425!
3745
                orderByObject[
425✔
3746
                    this.escape(parentAlias) +
425✔
3747
                        "." +
425✔
3748
                        this.escape(
425✔
3749
                            DriverUtils.buildAlias(
425✔
3750
                                this.connection.driver,
425✔
3751
                                undefined,
425✔
3752
                                aliasName,
425✔
3753
                                databaseName,
425✔
3754
                            ),
425✔
3755
                        )
425✔
3756
                ] = orderBys[orderCriteria]
425✔
3757
            } else {
441!
3758
                if (
16✔
3759
                    this.expressionMap.selects.find(
16✔
3760
                        (select) =>
16✔
3761
                            select.selection === orderCriteria ||
32✔
3762
                            select.aliasName === orderCriteria,
16✔
3763
                    )
16✔
3764
                ) {
16!
3765
                    orderByObject[
8✔
3766
                        this.escape(parentAlias) +
8✔
3767
                            "." +
8✔
3768
                            this.escape(orderCriteria)
8✔
3769
                    ] = orderBys[orderCriteria]
8✔
3770
                } else {
16!
3771
                    orderByObject[orderCriteria] = orderBys[orderCriteria]
8✔
3772
                }
8✔
3773
            }
16✔
3774
        })
7,025✔
3775

7,025✔
3776
        return [selectString, orderByObject]
7,025✔
3777
    }
7,025✔
3778

569,908✔
3779
    /**
569,908✔
3780
     * Loads raw results from the database.
569,908✔
3781
     * @param queryRunner
569,908✔
3782
     */
569,908✔
3783
    protected async loadRawResults(queryRunner: QueryRunner) {
569,908✔
3784
        const [sql, parameters] = this.getQueryAndParameters()
185,170✔
3785
        const queryId =
185,170✔
3786
            sql +
185,170✔
3787
            " -- PARAMETERS: " +
185,170✔
3788
            JSON.stringify(parameters, (_, value) =>
185,170✔
3789
                typeof value === "bigint" ? value.toString() : value,
185,170!
3790
            )
185,170✔
3791
        const cacheOptions =
185,170✔
3792
            typeof this.connection.options.cache === "object"
185,170✔
3793
                ? this.connection.options.cache
185,170!
3794
                : {}
185,170✔
3795
        let savedQueryResultCacheOptions: QueryResultCacheOptions | undefined =
185,170✔
3796
            undefined
185,170✔
3797
        const isCachingEnabled =
185,170✔
3798
            // Caching is enabled globally and isn't disabled locally.
185,170✔
3799
            (cacheOptions.alwaysEnabled &&
185,170!
3800
                this.expressionMap.cache !== false) ||
185,170✔
3801
            // ...or it's enabled locally explicitly.
185,036✔
3802
            this.expressionMap.cache === true
185,036✔
3803
        let cacheError = false
185,170✔
3804
        if (this.connection.queryResultCache && isCachingEnabled) {
185,170!
3805
            try {
1,041✔
3806
                savedQueryResultCacheOptions =
1,041✔
3807
                    await this.connection.queryResultCache.getFromCache(
1,041✔
3808
                        {
1,041✔
3809
                            identifier: this.expressionMap.cacheId,
1,041✔
3810
                            query: queryId,
1,041✔
3811
                            duration:
1,041✔
3812
                                this.expressionMap.cacheDuration ||
1,041!
3813
                                cacheOptions.duration ||
1,041!
3814
                                1000,
1,041✔
3815
                        },
1,041✔
3816
                        queryRunner,
1,041✔
3817
                    )
1,041✔
3818
                if (
1,041✔
3819
                    savedQueryResultCacheOptions &&
1,041✔
3820
                    !this.connection.queryResultCache.isExpired(
633✔
3821
                        savedQueryResultCacheOptions,
633✔
3822
                    )
1,041✔
3823
                ) {
1,041✔
3824
                    return JSON.parse(savedQueryResultCacheOptions.result)
408✔
3825
                }
408✔
3826
            } catch (error) {
1,041!
3827
                if (!cacheOptions.ignoreErrors) {
×
3828
                    throw error
×
3829
                }
×
3830
                cacheError = true
×
3831
            }
×
3832
        }
1,041✔
3833

184,678✔
3834
        const results = await queryRunner.query(sql, parameters, true)
184,678✔
3835

184,563✔
3836
        if (
184,563✔
3837
            !cacheError &&
184,563✔
3838
            this.connection.queryResultCache &&
185,170!
3839
            isCachingEnabled
2,024✔
3840
        ) {
185,170!
3841
            try {
633✔
3842
                await this.connection.queryResultCache.storeInCache(
633✔
3843
                    {
633✔
3844
                        identifier: this.expressionMap.cacheId,
633✔
3845
                        query: queryId,
633✔
3846
                        time: Date.now(),
633✔
3847
                        duration:
633✔
3848
                            this.expressionMap.cacheDuration ||
633!
3849
                            cacheOptions.duration ||
633!
3850
                            1000,
633✔
3851
                        result: JSON.stringify(results.records),
633✔
3852
                    },
633✔
3853
                    savedQueryResultCacheOptions,
633✔
3854
                    queryRunner,
633✔
3855
                )
633✔
3856
            } catch (error) {
633!
3857
                if (!cacheOptions.ignoreErrors) {
×
3858
                    throw error
×
3859
                }
×
3860
            }
×
3861
        }
633✔
3862

184,563✔
3863
        return results.records
184,563✔
3864
    }
184,563✔
3865

569,908✔
3866
    /**
569,908✔
3867
     * Merges into expression map given expression map properties.
569,908✔
3868
     * @param expressionMap
569,908✔
3869
     */
569,908✔
3870
    protected mergeExpressionMap(
569,908✔
3871
        expressionMap: Partial<QueryExpressionMap>,
6,885✔
3872
    ): this {
6,885✔
3873
        ObjectUtils.assign(this.expressionMap, expressionMap)
6,885✔
3874
        return this
6,885✔
3875
    }
6,885✔
3876

569,908✔
3877
    /**
569,908✔
3878
     * Normalizes a give number - converts to int if possible.
569,908✔
3879
     * @param num
569,908✔
3880
     */
569,908✔
3881
    protected normalizeNumber(num: any) {
569,908✔
3882
        if (typeof num === "number" || num === undefined || num === null)
58,867!
3883
            return num
58,867✔
3884

100!
3885
        return Number(num)
100✔
3886
    }
100✔
3887

569,908✔
3888
    /**
569,908✔
3889
     * Creates a query builder used to execute sql queries inside this query builder.
569,908✔
3890
     */
569,908✔
3891
    protected obtainQueryRunner() {
569,908✔
3892
        return (
185,316✔
3893
            this.queryRunner ||
185,316✔
3894
            this.connection.createQueryRunner(
51,881✔
3895
                this.connection.defaultReplicationModeForReads(),
51,881✔
3896
            )
185,316✔
3897
        )
185,316✔
3898
    }
185,316✔
3899

569,908✔
3900
    protected buildSelect(
569,908✔
3901
        select: FindOptionsSelect<any>,
985✔
3902
        metadata: EntityMetadata,
985✔
3903
        alias: string,
985✔
3904
        embedPrefix?: string,
985✔
3905
    ) {
985✔
3906
        for (const key in select) {
985✔
3907
            if (select[key] === undefined || select[key] === false) continue
1,780!
3908

1,705✔
3909
            const propertyPath = embedPrefix ? embedPrefix + "." + key : key
1,780!
3910
            const column =
1,780✔
3911
                metadata.findColumnWithPropertyPathStrict(propertyPath)
1,780✔
3912
            const embed = metadata.findEmbeddedWithPropertyPath(propertyPath)
1,780✔
3913
            const relation = metadata.findRelationWithPropertyPath(propertyPath)
1,780✔
3914

1,780✔
3915
            if (!embed && !column && !relation)
1,780!
3916
                throw new EntityPropertyNotFoundError(propertyPath, metadata)
1,780!
3917

1,680✔
3918
            if (column) {
1,778✔
3919
                this.selects.push(alias + "." + propertyPath)
1,290✔
3920
                // this.addSelect(alias + "." + propertyPath);
1,290✔
3921
            } else if (embed) {
1,780!
3922
                this.buildSelect(
65✔
3923
                    select[key] as FindOptionsSelect<any>,
65✔
3924
                    metadata,
65✔
3925
                    alias,
65✔
3926
                    propertyPath,
65✔
3927
                )
65✔
3928

65✔
3929
                // } else if (relation) {
65✔
3930
                //     const joinAlias = alias + "_" + relation.propertyName;
65✔
3931
                //     const existJoin = this.joins.find(join => join.alias === joinAlias);
65✔
3932
                //     if (!existJoin) {
65✔
3933
                //         this.joins.push({
65✔
3934
                //             type: "left",
65✔
3935
                //             select: false,
65✔
3936
                //             alias: joinAlias,
65✔
3937
                //             parentAlias: alias,
65✔
3938
                //             relationMetadata: relation
65✔
3939
                //         });
65✔
3940
                //     }
65✔
3941
                //     this.buildOrder(select[key] as FindOptionsOrder<any>, relation.inverseEntityMetadata, joinAlias);
65✔
3942
            }
65✔
3943
        }
1,780✔
3944
    }
960✔
3945

569,908✔
3946
    protected buildRelations(
569,908✔
3947
        relations: FindOptionsRelations<any>,
48,506✔
3948
        selection: FindOptionsSelect<any> | undefined,
48,506✔
3949
        metadata: EntityMetadata,
48,506✔
3950
        alias: string,
48,506✔
3951
        embedPrefix?: string,
48,506✔
3952
    ) {
48,506✔
3953
        if (!relations) return
48,506!
3954

48,506✔
3955
        Object.keys(relations).forEach((relationName) => {
48,506✔
3956
            const relationValue = (relations as any)[relationName]
369,087✔
3957
            const propertyPath = embedPrefix
369,087✔
3958
                ? embedPrefix + "." + relationName
369,087!
3959
                : relationName
369,087✔
3960
            const embed = metadata.findEmbeddedWithPropertyPath(propertyPath)
369,087✔
3961
            const relation = metadata.findRelationWithPropertyPath(propertyPath)
369,087✔
3962
            if (!embed && !relation)
369,087✔
3963
                throw new EntityPropertyNotFoundError(propertyPath, metadata)
369,087!
3964

368,937✔
3965
            if (embed) {
369,087!
3966
                this.buildRelations(
125✔
3967
                    relationValue,
125✔
3968
                    typeof selection === "object"
125✔
3969
                        ? OrmUtils.deepValue(selection, embed.propertyPath)
125!
3970
                        : undefined,
125✔
3971
                    metadata,
125✔
3972
                    alias,
125✔
3973
                    propertyPath,
125✔
3974
                )
125✔
3975
            } else if (relation) {
369,087✔
3976
                let joinAlias = alias + "_" + propertyPath.replace(".", "_")
368,812✔
3977
                joinAlias = DriverUtils.buildAlias(
368,812✔
3978
                    this.connection.driver,
368,812✔
3979
                    { joiner: "__" },
368,812✔
3980
                    alias,
368,812✔
3981
                    joinAlias,
368,812✔
3982
                )
368,812✔
3983
                if (
368,812✔
3984
                    relationValue === true ||
368,812✔
3985
                    typeof relationValue === "object"
1,122✔
3986
                ) {
368,812✔
3987
                    if (this.expressionMap.relationLoadStrategy === "query") {
368,812!
3988
                        this.concatRelationMetadata(relation)
91✔
3989
                    } else {
368,812✔
3990
                        // join
368,721✔
3991
                        this.joins.push({
368,721✔
3992
                            type: "left",
368,721✔
3993
                            select: true,
368,721✔
3994
                            selection:
368,721✔
3995
                                selection &&
368,721!
3996
                                typeof selection[relationName] === "object"
400✔
3997
                                    ? (selection[
368,721!
3998
                                          relationName
275✔
3999
                                      ] as FindOptionsSelect<any>)
368,721✔
4000
                                    : undefined,
368,721✔
4001
                            alias: joinAlias,
368,721✔
4002
                            parentAlias: alias,
368,721✔
4003
                            relationMetadata: relation,
368,721✔
4004
                        })
368,721✔
4005

368,721✔
4006
                        if (
368,721✔
4007
                            selection &&
368,721!
4008
                            typeof selection[relationName] === "object"
400✔
4009
                        ) {
368,721!
4010
                            this.buildSelect(
275✔
4011
                                selection[
275✔
4012
                                    relationName
275✔
4013
                                ] as FindOptionsSelect<any>,
275✔
4014
                                relation.inverseEntityMetadata,
275✔
4015
                                joinAlias,
275✔
4016
                            )
275✔
4017
                        }
275✔
4018
                    }
368,721✔
4019
                }
368,812✔
4020

368,812✔
4021
                if (
368,812✔
4022
                    typeof relationValue === "object" &&
368,812!
4023
                    this.expressionMap.relationLoadStrategy === "join"
1,122✔
4024
                ) {
368,812!
4025
                    this.buildRelations(
1,097✔
4026
                        relationValue,
1,097✔
4027
                        typeof selection === "object"
1,097✔
4028
                            ? OrmUtils.deepValue(
1,097!
4029
                                  selection,
150✔
4030
                                  relation.propertyPath,
150✔
4031
                              )
1,097✔
4032
                            : undefined,
1,097!
4033
                        relation.inverseEntityMetadata,
1,097✔
4034
                        joinAlias,
1,097✔
4035
                        undefined,
1,097✔
4036
                    )
1,097✔
4037
                }
1,097✔
4038
            }
368,812✔
4039
        })
48,506✔
4040
    }
48,506✔
4041

569,908✔
4042
    protected buildEagerRelations(
569,908✔
4043
        relations: FindOptionsRelations<any>,
48,124✔
4044
        selection: FindOptionsSelect<any> | undefined,
48,124✔
4045
        metadata: EntityMetadata,
48,124✔
4046
        alias: string,
48,124✔
4047
        embedPrefix?: string,
48,124✔
4048
    ) {
48,124✔
4049
        if (!relations) return
48,124!
4050

48,124✔
4051
        Object.keys(relations).forEach((relationName) => {
48,124✔
4052
            const relationValue = (relations as any)[relationName]
368,721✔
4053
            const propertyPath = embedPrefix
368,721✔
4054
                ? embedPrefix + "." + relationName
368,721!
4055
                : relationName
368,721✔
4056
            const embed = metadata.findEmbeddedWithPropertyPath(propertyPath)
368,721✔
4057
            const relation = metadata.findRelationWithPropertyPath(propertyPath)
368,721✔
4058
            if (!embed && !relation)
368,721✔
4059
                throw new EntityPropertyNotFoundError(propertyPath, metadata)
368,721!
4060

368,721✔
4061
            if (embed) {
368,721!
4062
                this.buildEagerRelations(
100✔
4063
                    relationValue,
100✔
4064
                    typeof selection === "object"
100✔
4065
                        ? OrmUtils.deepValue(selection, embed.propertyPath)
100!
4066
                        : undefined,
100✔
4067
                    metadata,
100✔
4068
                    alias,
100✔
4069
                    propertyPath,
100✔
4070
                )
100✔
4071
            } else if (relation) {
368,721✔
4072
                let joinAlias = alias + "_" + propertyPath.replace(".", "_")
368,621✔
4073
                joinAlias = DriverUtils.buildAlias(
368,621✔
4074
                    this.connection.driver,
368,621✔
4075
                    { joiner: "__" },
368,621✔
4076
                    alias,
368,621✔
4077
                    joinAlias,
368,621✔
4078
                )
368,621✔
4079

368,621✔
4080
                if (
368,621✔
4081
                    relationValue === true ||
368,621!
4082
                    typeof relationValue === "object"
1,047✔
4083
                ) {
368,621✔
4084
                    relation.inverseEntityMetadata.eagerRelations.forEach(
368,621✔
4085
                        (eagerRelation) => {
368,621✔
4086
                            let eagerRelationJoinAlias =
429✔
4087
                                joinAlias +
429✔
4088
                                "_" +
429✔
4089
                                eagerRelation.propertyPath.replace(".", "_")
429✔
4090
                            eagerRelationJoinAlias = DriverUtils.buildAlias(
429✔
4091
                                this.connection.driver,
429✔
4092
                                { joiner: "__" },
429✔
4093
                                joinAlias,
429✔
4094
                                eagerRelationJoinAlias,
429✔
4095
                            )
429✔
4096

429✔
4097
                            const existJoin = this.joins.find(
429✔
4098
                                (join) => join.alias === eagerRelationJoinAlias,
429✔
4099
                            )
429✔
4100
                            if (!existJoin) {
429✔
4101
                                this.joins.push({
304✔
4102
                                    type: "left",
304✔
4103
                                    select: true,
304✔
4104
                                    alias: eagerRelationJoinAlias,
304✔
4105
                                    parentAlias: joinAlias,
304✔
4106
                                    selection: undefined,
304✔
4107
                                    relationMetadata: eagerRelation,
304✔
4108
                                })
304✔
4109
                            }
304✔
4110

429✔
4111
                            if (
429✔
4112
                                selection &&
429!
4113
                                typeof selection[relationName] === "object"
×
4114
                            ) {
429!
4115
                                this.buildSelect(
×
4116
                                    selection[
×
4117
                                        relationName
×
4118
                                    ] as FindOptionsSelect<any>,
×
4119
                                    relation.inverseEntityMetadata,
×
4120
                                    joinAlias,
×
4121
                                )
×
4122
                            }
×
4123
                        },
368,621✔
4124
                    )
368,621✔
4125
                }
368,621✔
4126

368,621✔
4127
                if (typeof relationValue === "object") {
368,621!
4128
                    this.buildEagerRelations(
1,047✔
4129
                        relationValue,
1,047✔
4130
                        typeof selection === "object"
1,047✔
4131
                            ? OrmUtils.deepValue(
1,047!
4132
                                  selection,
150✔
4133
                                  relation.propertyPath,
150✔
4134
                              )
1,047✔
4135
                            : undefined,
1,047!
4136
                        relation.inverseEntityMetadata,
1,047✔
4137
                        joinAlias,
1,047✔
4138
                        undefined,
1,047✔
4139
                    )
1,047✔
4140
                }
1,047✔
4141
            }
368,621✔
4142
        })
48,124✔
4143
    }
48,124✔
4144

569,908✔
4145
    protected buildOrder(
569,908✔
4146
        order: FindOptionsOrder<any>,
3,043✔
4147
        metadata: EntityMetadata,
3,043✔
4148
        alias: string,
3,043✔
4149
        embedPrefix?: string,
3,043✔
4150
    ) {
3,043✔
4151
        for (const key in order) {
3,043✔
4152
            if (order[key] === undefined) continue
3,368!
4153

3,368✔
4154
            const propertyPath = embedPrefix ? embedPrefix + "." + key : key
3,368!
4155
            const column =
3,368✔
4156
                metadata.findColumnWithPropertyPathStrict(propertyPath)
3,368✔
4157
            const embed = metadata.findEmbeddedWithPropertyPath(propertyPath)
3,368✔
4158
            const relation = metadata.findRelationWithPropertyPath(propertyPath)
3,368✔
4159

3,368✔
4160
            if (!embed && !column && !relation)
3,368!
4161
                throw new EntityPropertyNotFoundError(propertyPath, metadata)
3,368!
4162

3,343✔
4163
            if (column) {
3,368✔
4164
                let direction =
2,768✔
4165
                    typeof order[key] === "object"
2,768✔
4166
                        ? (order[key] as any).direction
2,768!
4167
                        : order[key]
2,768✔
4168
                direction =
2,768✔
4169
                    direction === "DESC" ||
2,768✔
4170
                    direction === "desc" ||
2,768✔
4171
                    direction === -1
2,380✔
4172
                        ? "DESC"
2,768!
4173
                        : "ASC"
2,768✔
4174
                let nulls =
2,768✔
4175
                    typeof order[key] === "object"
2,768✔
4176
                        ? (order[key] as any).nulls
2,768!
4177
                        : undefined
2,768✔
4178
                nulls =
2,768✔
4179
                    nulls?.toLowerCase() === "first"
2,768!
4180
                        ? "NULLS FIRST"
2,768!
4181
                        : nulls?.toLowerCase() === "last"
2,768!
4182
                          ? "NULLS LAST"
2,754!
4183
                          : undefined
2,754✔
4184

2,768✔
4185
                const aliasPath = `${alias}.${propertyPath}`
2,768✔
4186
                // const selection = this.expressionMap.selects.find(
2,768✔
4187
                //     (s) => s.selection === aliasPath,
2,768✔
4188
                // )
2,768✔
4189
                // if (selection) {
2,768✔
4190
                //     // this is not building correctly now???
2,768✔
4191
                //     aliasPath = this.escape(
2,768✔
4192
                //         DriverUtils.buildAlias(
2,768✔
4193
                //             this.connection.driver,
2,768✔
4194
                //             undefined,
2,768✔
4195
                //             alias,
2,768✔
4196
                //             column.databaseName,
2,768✔
4197
                //         ),
2,768✔
4198
                //     )
2,768✔
4199
                //     // selection.aliasName = aliasPath
2,768✔
4200
                // } else {
2,768✔
4201
                //     if (column.isVirtualProperty && column.query) {
2,768✔
4202
                //         aliasPath = `(${column.query(alias)})`
2,768✔
4203
                //     }
2,768✔
4204
                // }
2,768✔
4205

2,768✔
4206
                // console.log("add sort", selection, aliasPath, direction, nulls)
2,768✔
4207
                this.addOrderBy(aliasPath, direction, nulls)
2,768✔
4208
                // this.orderBys.push({ alias: alias + "." + propertyPath, direction, nulls });
2,768✔
4209
            } else if (embed) {
3,368!
4210
                this.buildOrder(
75✔
4211
                    order[key] as FindOptionsOrder<any>,
75✔
4212
                    metadata,
75✔
4213
                    alias,
75✔
4214
                    propertyPath,
75✔
4215
                )
75✔
4216
            } else if (relation) {
575✔
4217
                let joinAlias = alias + "_" + propertyPath.replace(".", "_")
500✔
4218
                joinAlias = DriverUtils.buildAlias(
500✔
4219
                    this.connection.driver,
500✔
4220
                    { joiner: "__" },
500✔
4221
                    alias,
500✔
4222
                    joinAlias,
500✔
4223
                )
500✔
4224
                // console.log("joinAlias", joinAlias, joinAlias.length, this.connection.driver.maxAliasLength)
500✔
4225
                // todo: use expressionMap.joinAttributes, and create a new one using
500✔
4226
                //  const joinAttribute = new JoinAttribute(this.connection, this.expressionMap);
500✔
4227

500✔
4228
                const existJoin = this.joins.find(
500✔
4229
                    (join) => join.alias === joinAlias,
500✔
4230
                )
500✔
4231
                if (!existJoin) {
500!
4232
                    this.joins.push({
175✔
4233
                        type: "left",
175✔
4234
                        select: false,
175✔
4235
                        alias: joinAlias,
175✔
4236
                        parentAlias: alias,
175✔
4237
                        selection: undefined,
175✔
4238
                        relationMetadata: relation,
175✔
4239
                    })
175✔
4240
                }
175✔
4241
                this.buildOrder(
500✔
4242
                    order[key] as FindOptionsOrder<any>,
500✔
4243
                    relation.inverseEntityMetadata,
500✔
4244
                    joinAlias,
500✔
4245
                )
500✔
4246
            }
500✔
4247
        }
3,368✔
4248
    }
3,018✔
4249

569,908✔
4250
    protected buildWhere(
569,908✔
4251
        where: FindOptionsWhere<any>[] | FindOptionsWhere<any>,
62,424✔
4252
        metadata: EntityMetadata,
62,424✔
4253
        alias: string,
62,424✔
4254
        embedPrefix?: string,
62,424✔
4255
    ) {
62,424✔
4256
        let condition: string = ""
62,424✔
4257
        if (Array.isArray(where)) {
62,424!
4258
            if (where.length) {
204✔
4259
                condition = where
200✔
4260
                    .map((whereItem) => {
200✔
4261
                        return this.buildWhere(
450✔
4262
                            whereItem,
450✔
4263
                            metadata,
450✔
4264
                            alias,
450✔
4265
                            embedPrefix,
450✔
4266
                        )
450✔
4267
                    })
200✔
4268
                    .filter((condition) => !!condition)
200✔
4269
                    .map((condition) => "(" + condition + ")")
200✔
4270
                    .join(" OR ")
200✔
4271
            }
200✔
4272
        } else {
62,424✔
4273
            const andConditions: string[] = []
62,220✔
4274
            for (const key in where) {
62,220✔
4275
                let parameterValue = where[key]
63,207✔
4276

63,207✔
4277
                const propertyPath = embedPrefix ? embedPrefix + "." + key : key
63,207!
4278
                const column =
63,207✔
4279
                    metadata.findColumnWithPropertyPathStrict(propertyPath)
63,207✔
4280
                const embed =
63,207✔
4281
                    metadata.findEmbeddedWithPropertyPath(propertyPath)
63,207✔
4282
                const relation =
63,207✔
4283
                    metadata.findRelationWithPropertyPath(propertyPath)
63,207✔
4284

63,207✔
4285
                if (!embed && !column && !relation) {
63,207!
4286
                    throw new EntityPropertyNotFoundError(
50✔
4287
                        propertyPath,
50✔
4288
                        metadata,
50✔
4289
                    )
50✔
4290
                }
50✔
4291

63,157✔
4292
                if (parameterValue === undefined) {
63,207!
4293
                    const undefinedBehavior =
425✔
4294
                        this.connection.options.invalidWhereValuesBehavior
425✔
4295
                            ?.undefined || "throw"
425✔
4296
                    if (undefinedBehavior === "throw") {
425✔
4297
                        throw new TypeORMError(
325✔
4298
                            `Undefined value encountered in property '${alias}.${key}' of a where condition. ` +
325✔
4299
                                `Set 'invalidWhereValuesBehavior.undefined' to 'ignore' in connection options to skip properties with undefined values.`,
325✔
4300
                        )
325✔
4301
                    }
325✔
4302
                    continue
100✔
4303
                }
100✔
4304

62,732✔
4305
                if (parameterValue === null) {
63,207!
4306
                    const nullBehavior =
625✔
4307
                        this.connection.options.invalidWhereValuesBehavior
625✔
4308
                            ?.null || "throw"
625✔
4309
                    if (nullBehavior === "ignore") {
625✔
4310
                        continue
125✔
4311
                    } else if (nullBehavior === "throw") {
625✔
4312
                        throw new TypeORMError(
275✔
4313
                            `Null value encountered in property '${alias}.${key}' of a where condition. ` +
275✔
4314
                                `To match with SQL NULL, the IsNull() operator must be used. ` +
275✔
4315
                                `Set 'invalidWhereValuesBehavior.null' to 'ignore' or 'sql-null' in connection options to skip or handle null values.`,
275✔
4316
                        )
275✔
4317
                    }
275✔
4318
                    // 'sql-null' behavior continues to the next logic
625✔
4319
                }
625✔
4320

62,332✔
4321
                if (column) {
63,207✔
4322
                    let aliasPath = `${alias}.${propertyPath}`
60,039✔
4323
                    if (column.isVirtualProperty && column.query) {
60,039!
4324
                        aliasPath = `(${column.query(this.escape(alias))})`
100✔
4325
                    }
100✔
4326

60,039✔
4327
                    if (parameterValue === null) {
60,039!
4328
                        andConditions.push(`${aliasPath} IS NULL`)
125✔
4329
                        continue
125✔
4330
                    }
125✔
4331

59,914✔
4332
                    // const parameterName = alias + "_" + propertyPath.split(".").join("_") + "_" + parameterIndex;
59,914✔
4333

59,914✔
4334
                    // todo: we need to handle other operators as well?
59,914✔
4335
                    if (InstanceChecker.isEqualOperator(where[key])) {
60,039!
4336
                        parameterValue = where[key].value
52✔
4337
                    }
52✔
4338

59,914✔
4339
                    if (column.transformer) {
60,039!
4340
                        parameterValue = ApplyValueTransformers.transformTo(
114✔
4341
                            column.transformer,
114✔
4342
                            parameterValue,
114✔
4343
                        )
114✔
4344
                    }
114✔
4345

59,914✔
4346
                    // MSSQL requires parameters to carry extra type information
59,914✔
4347
                    if (this.connection.driver.options.type === "mssql") {
60,029!
4348
                        parameterValue = (
1,488✔
4349
                            this.connection.driver as SqlServerDriver
1,488✔
4350
                        ).parametrizeValues(column, parameterValue)
1,488✔
4351
                    }
1,488✔
4352

59,914✔
4353
                    andConditions.push(
59,914✔
4354
                        this.createWhereConditionExpression(
59,914✔
4355
                            this.getWherePredicateCondition(
59,914✔
4356
                                aliasPath,
59,914✔
4357
                                parameterValue,
59,914✔
4358
                            ),
59,914✔
4359
                        ),
59,914✔
4360
                        // parameterValue.toSql(this.connection, aliasPath, parameters));
59,914✔
4361
                    )
59,914✔
4362

59,914✔
4363
                    // this.conditions.push(`${alias}.${propertyPath} = :${paramName}`);
59,914✔
4364
                    // this.expressionMap.parameters[paramName] = where[key]; // todo: handle functions and other edge cases
59,914✔
4365
                } else if (embed) {
63,207!
4366
                    const condition = this.buildWhere(
500✔
4367
                        where[key],
500✔
4368
                        metadata,
500✔
4369
                        alias,
500✔
4370
                        propertyPath,
500✔
4371
                    )
500✔
4372
                    if (condition) andConditions.push(condition)
500!
4373
                } else if (relation) {
2,293!
4374
                    if (where[key] === null) {
1,793!
4375
                        const nullBehavior =
100✔
4376
                            this.connection.options.invalidWhereValuesBehavior
100✔
4377
                                ?.null || "throw"
100!
4378
                        if (nullBehavior === "sql-null") {
100✔
4379
                            andConditions.push(
100✔
4380
                                `${alias}.${propertyPath} IS NULL`,
100✔
4381
                            )
100✔
4382
                        } else if (nullBehavior === "throw") {
100!
4383
                            throw new TypeORMError(
×
4384
                                `Null value encountered in property '${alias}.${key}' of a where condition. ` +
×
4385
                                    `Set 'invalidWhereValuesBehavior.null' to 'ignore' or 'sql-null' in connection options to skip or handle null values.`,
×
4386
                            )
×
4387
                        }
×
4388
                        // 'ignore' behavior falls through to continue
100✔
4389
                        continue
100✔
4390
                    }
100✔
4391

1,693✔
4392
                    // if all properties of where are undefined we don't need to join anything
1,693✔
4393
                    // this can happen when user defines map with conditional queries inside
1,693✔
4394
                    if (typeof where[key] === "object") {
1,789✔
4395
                        const whereKeys = Object.keys(where[key])
1,668✔
4396

1,668✔
4397
                        // empty object — no predicates to apply, skip the join
1,668✔
4398
                        if (whereKeys.length === 0) {
1,668!
4399
                            continue
50✔
4400
                        }
50✔
4401

1,618✔
4402
                        const allUndefined = whereKeys.every(
1,618✔
4403
                            (k) => where[key][k] === undefined,
1,618✔
4404
                        )
1,618✔
4405
                        if (allUndefined) {
1,668!
4406
                            const undefinedBehavior =
25✔
4407
                                this.connection.options
25✔
4408
                                    .invalidWhereValuesBehavior?.undefined ||
25!
4409
                                "throw"
25✔
4410
                            if (undefinedBehavior === "throw") {
25✔
4411
                                throw new TypeORMError(
25✔
4412
                                    `Undefined value encountered in nested relation '${alias}.${key}' of a where condition. ` +
25✔
4413
                                        `All properties of the nested object are undefined. ` +
25✔
4414
                                        `Set 'invalidWhereValuesBehavior.undefined' to 'ignore' in connection options to skip properties with undefined values.`,
25✔
4415
                                )
25✔
4416
                            }
25✔
4417
                            continue
×
4418
                        }
×
4419
                    }
1,668✔
4420

1,618✔
4421
                    if (InstanceChecker.isFindOperator(where[key])) {
1,793!
4422
                        if (
550✔
4423
                            where[key].type === "moreThan" ||
550✔
4424
                            where[key].type === "lessThan" ||
550!
4425
                            where[key].type === "moreThanOrEqual" ||
550!
4426
                            where[key].type === "lessThanOrEqual"
225✔
4427
                        ) {
550!
4428
                            let sqlOperator = ""
350✔
4429
                            if (where[key].type === "moreThan") {
350!
4430
                                sqlOperator = ">"
150✔
4431
                            } else if (where[key].type === "lessThan") {
350!
4432
                                sqlOperator = "<"
25✔
4433
                            } else if (where[key].type === "moreThanOrEqual") {
200!
4434
                                sqlOperator = ">="
150✔
4435
                            } else if (where[key].type === "lessThanOrEqual") {
175✔
4436
                                sqlOperator = "<="
25✔
4437
                            }
25✔
4438
                            // basically relation count functionality
350✔
4439
                            const qb: QueryBuilder<any> = this.subQuery()
350✔
4440
                            if (relation.isManyToManyOwner) {
350✔
4441
                                qb.select("COUNT(*)")
150✔
4442
                                    .from(
150✔
4443
                                        relation.joinTableName,
150✔
4444
                                        relation.joinTableName,
150✔
4445
                                    )
150✔
4446
                                    .where(
150✔
4447
                                        relation.joinColumns
150✔
4448
                                            .map((column) => {
150✔
4449
                                                return `${
150✔
4450
                                                    relation.joinTableName
150✔
4451
                                                }.${
150✔
4452
                                                    column.propertyName
150✔
4453
                                                } = ${alias}.${
150✔
4454
                                                    column.referencedColumn!
150✔
4455
                                                        .propertyName
150✔
4456
                                                }`
150✔
4457
                                            })
150✔
4458
                                            .join(" AND "),
150✔
4459
                                    )
150✔
4460
                            } else if (relation.isManyToManyNotOwner) {
350✔
4461
                                qb.select("COUNT(*)")
100✔
4462
                                    .from(
100✔
4463
                                        relation.inverseRelation!.joinTableName,
100✔
4464
                                        relation.inverseRelation!.joinTableName,
100✔
4465
                                    )
100✔
4466
                                    .where(
100✔
4467
                                        relation
100✔
4468
                                            .inverseRelation!.inverseJoinColumns.map(
100✔
4469
                                                (column) => {
100✔
4470
                                                    return `${
100✔
4471
                                                        relation
100✔
4472
                                                            .inverseRelation!
100✔
4473
                                                            .joinTableName
100✔
4474
                                                    }.${
100✔
4475
                                                        column.propertyName
100✔
4476
                                                    } = ${alias}.${
100✔
4477
                                                        column.referencedColumn!
100✔
4478
                                                            .propertyName
100✔
4479
                                                    }`
100✔
4480
                                                },
100✔
4481
                                            )
100✔
4482
                                            .join(" AND "),
100✔
4483
                                    )
100✔
4484
                            } else if (relation.isOneToMany) {
100✔
4485
                                qb.select("COUNT(*)")
100✔
4486
                                    .from(
100✔
4487
                                        relation.inverseEntityMetadata.target,
100✔
4488
                                        relation.inverseEntityMetadata
100✔
4489
                                            .tableName,
100✔
4490
                                    )
100✔
4491
                                    .where(
100✔
4492
                                        relation
100✔
4493
                                            .inverseRelation!.joinColumns.map(
100✔
4494
                                                (column) => {
100✔
4495
                                                    return `${
100✔
4496
                                                        relation
100✔
4497
                                                            .inverseEntityMetadata
100✔
4498
                                                            .tableName
100✔
4499
                                                    }.${
100✔
4500
                                                        column.propertyName
100✔
4501
                                                    } = ${alias}.${
100✔
4502
                                                        column.referencedColumn!
100✔
4503
                                                            .propertyName
100✔
4504
                                                    }`
100✔
4505
                                                },
100✔
4506
                                            )
100✔
4507
                                            .join(" AND "),
100✔
4508
                                    )
100✔
4509
                            } else {
100!
4510
                                throw new Error(
×
4511
                                    `This relation isn't supported by given find operator`,
×
4512
                                )
×
4513
                            }
×
4514
                            // this
350✔
4515
                            //     .addSelect(qb.getSql(), relation.propertyAliasName + "_cnt")
350✔
4516
                            //     .andWhere(this.escape(relation.propertyAliasName + "_cnt") + " " + sqlOperator + " " + parseInt(where[key].value));
350✔
4517
                            this.andWhere(
350✔
4518
                                qb.getSql() +
350✔
4519
                                    " " +
350✔
4520
                                    sqlOperator +
350✔
4521
                                    " " +
350✔
4522
                                    parseInt(where[key].value),
350✔
4523
                            )
350✔
4524
                        } else {
550!
4525
                            if (
200✔
4526
                                relation.isManyToOne ||
200✔
4527
                                (relation.isOneToOne &&
100✔
4528
                                    relation.isOneToOneOwner)
100✔
4529
                            ) {
200✔
4530
                                const aliasPath = `${alias}.${propertyPath}`
200✔
4531

200✔
4532
                                andConditions.push(
200✔
4533
                                    this.createWhereConditionExpression(
200✔
4534
                                        this.getWherePredicateCondition(
200✔
4535
                                            aliasPath,
200✔
4536
                                            where[key],
200✔
4537
                                        ),
200✔
4538
                                    ),
200✔
4539
                                )
200✔
4540
                            } else {
200!
4541
                                throw new Error(
×
4542
                                    `This relation isn't supported by given find operator`,
×
4543
                                )
×
4544
                            }
×
4545
                        }
200✔
4546
                    } else {
1,793✔
4547
                        // const joinAlias = alias + "_" + relation.propertyName;
1,068✔
4548
                        let joinAlias =
1,068✔
4549
                            alias +
1,068✔
4550
                            "_" +
1,068✔
4551
                            relation.propertyPath.replace(".", "_")
1,068✔
4552
                        joinAlias = DriverUtils.buildAlias(
1,068✔
4553
                            this.connection.driver,
1,068✔
4554
                            { joiner: "__" },
1,068✔
4555
                            alias,
1,068✔
4556
                            joinAlias,
1,068✔
4557
                        )
1,068✔
4558

1,068✔
4559
                        const existJoin = this.joins.find(
1,068✔
4560
                            (join) => join.alias === joinAlias,
1,068✔
4561
                        )
1,068✔
4562
                        if (!existJoin) {
1,068✔
4563
                            this.joins.push({
893✔
4564
                                type: "left",
893✔
4565
                                select: false,
893✔
4566
                                selection: undefined,
893✔
4567
                                alias: joinAlias,
893✔
4568
                                parentAlias: alias,
893✔
4569
                                relationMetadata: relation,
893✔
4570
                            })
893✔
4571
                        }
893✔
4572

1,068✔
4573
                        const condition = this.buildWhere(
1,068✔
4574
                            where[key],
1,068✔
4575
                            relation.inverseEntityMetadata,
1,068✔
4576
                            joinAlias,
1,068✔
4577
                        )
1,068✔
4578
                        if (condition) {
1,068!
4579
                            andConditions.push(condition)
918✔
4580
                        }
918✔
4581
                    }
1,068✔
4582
                }
1,793✔
4583
            }
63,207✔
4584
            condition = andConditions.length
61,495✔
4585
                ? "(" + andConditions.join(") AND (") + ")"
62,220✔
4586
                : andConditions.join(" AND ")
62,220!
4587
        }
62,220✔
4588
        return condition.length ? "(" + condition + ")" : condition
62,424!
4589
    }
62,424✔
4590
}
569,908✔
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