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

typeorm / typeorm / 19549987525

20 Nov 2025 08:11PM UTC coverage: 80.769% (+4.3%) from 76.433%
19549987525

push

github

web-flow
ci: run tests on commits to master and next (#11783)

Co-authored-by: Oleg "OSA413" Sokolov <OSA413@users.noreply.github.com>

26500 of 32174 branches covered (82.36%)

Branch coverage included in aggregate %.

91252 of 113615 relevant lines covered (80.32%)

88980.79 hits per line

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

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

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

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

848,396✔
77
    // -------------------------------------------------------------------------
848,396✔
78
    // Public Implemented Methods
848,396✔
79
    // -------------------------------------------------------------------------
848,396✔
80

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

848,396✔
100
    // -------------------------------------------------------------------------
848,396✔
101
    // Public Methods
848,396✔
102
    // -------------------------------------------------------------------------
848,396✔
103

848,396✔
104
    setFindOptions(findOptions: FindManyOptions<Entity>) {
848,396✔
105
        this.findOptions = findOptions
183,772✔
106
        this.applyFindOptions()
183,772✔
107
        return this
183,772✔
108
    }
183,772✔
109

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

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

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

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

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

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

523,793✔
176
        return this
523,793✔
177
    }
523,793✔
178

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

848,396✔
187
    /**
848,396✔
188
     * Adds new selection to the SELECT query.
848,396✔
189
     */
848,396✔
190
    addSelect(selection: string, selectionAliasName?: string): this
848,396✔
191

848,396✔
192
    /**
848,396✔
193
     * Adds new selection to the SELECT query.
848,396✔
194
     */
848,396✔
195
    addSelect(selection: string[]): this
848,396✔
196

848,396✔
197
    /**
848,396✔
198
     * Adds new selection to the SELECT query.
848,396✔
199
     */
848,396✔
200
    addSelect(
848,396✔
201
        selection:
2,383,300✔
202
            | string
2,383,300✔
203
            | string[]
2,383,300✔
204
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
2,383,300✔
205
        selectionAliasName?: string,
2,383,300✔
206
    ): this {
2,383,300✔
207
        if (!selection) return this
2,383,300✔
208

2,376,217✔
209
        if (Array.isArray(selection)) {
2,383,300✔
210
            this.expressionMap.selects = this.expressionMap.selects.concat(
8,777✔
211
                selection.map((selection) => ({ selection: selection })),
8,777✔
212
            )
8,777✔
213
        } else if (typeof selection === "function") {
2,383,300✔
214
            const subQueryBuilder = selection(this.subQuery())
28✔
215
            this.setParameters(subQueryBuilder.getParameters())
28✔
216
            this.expressionMap.selects.push({
28✔
217
                selection: subQueryBuilder.getQuery(),
28✔
218
                aliasName: selectionAliasName,
28✔
219
            })
28✔
220
        } else if (selection) {
2,367,440✔
221
            this.expressionMap.selects.push({
2,367,412✔
222
                selection: selection,
2,367,412✔
223
                aliasName: selectionAliasName,
2,367,412✔
224
            })
2,367,412✔
225
        }
2,367,412✔
226

2,376,217✔
227
        return this
2,376,217✔
228
    }
2,376,217✔
229

848,396✔
230
    /**
848,396✔
231
     * Set max execution time.
848,396✔
232
     * @param milliseconds
848,396✔
233
     */
848,396✔
234
    maxExecutionTime(milliseconds: number): this {
848,396✔
235
        this.expressionMap.maxExecutionTime = milliseconds
×
236
        return this
×
237
    }
×
238

848,396✔
239
    /**
848,396✔
240
     * Sets whether the selection is DISTINCT.
848,396✔
241
     */
848,396✔
242
    distinct(distinct: boolean = true): this {
848,396✔
243
        this.expressionMap.selectDistinct = distinct
31✔
244
        return this
31✔
245
    }
31✔
246

848,396✔
247
    /**
848,396✔
248
     * Sets the distinct on clause for Postgres.
848,396✔
249
     */
848,396✔
250
    distinctOn(distinctOn: string[]): this {
848,396✔
251
        this.expressionMap.selectDistinctOn = distinctOn
12✔
252
        return this
12✔
253
    }
12✔
254

848,396✔
255
    fromDummy(): SelectQueryBuilder<any> {
848,396✔
256
        return this.from(
248✔
257
            this.connection.driver.dummyTableName ??
248!
258
                "(SELECT 1 AS dummy_column)",
248✔
259
            "dummy_table",
248✔
260
        )
248✔
261
    }
248✔
262

848,396✔
263
    /**
848,396✔
264
     * Specifies FROM which entity's table select/update/delete will be executed.
848,396✔
265
     * Also sets a main string alias of the selection data.
848,396✔
266
     * Removes all previously set from-s.
848,396✔
267
     */
848,396✔
268
    from<T extends ObjectLiteral>(
848,396✔
269
        entityTarget: (qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>,
848,396✔
270
        aliasName: string,
848,396✔
271
    ): SelectQueryBuilder<T>
848,396✔
272

848,396✔
273
    /**
848,396✔
274
     * Specifies FROM which entity's table select/update/delete will be executed.
848,396✔
275
     * Also sets a main string alias of the selection data.
848,396✔
276
     * Removes all previously set from-s.
848,396✔
277
     */
848,396✔
278
    from<T extends ObjectLiteral>(
848,396✔
279
        entityTarget: EntityTarget<T>,
848,396✔
280
        aliasName: string,
848,396✔
281
    ): SelectQueryBuilder<T>
848,396✔
282

848,396✔
283
    /**
848,396✔
284
     * Specifies FROM which entity's table select/update/delete will be executed.
848,396✔
285
     * Also sets a main string alias of the selection data.
848,396✔
286
     * Removes all previously set from-s.
848,396✔
287
     */
848,396✔
288
    from<T extends ObjectLiteral>(
848,396✔
289
        entityTarget:
529,506✔
290
            | EntityTarget<T>
529,506✔
291
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
529,506✔
292
        aliasName: string,
529,506✔
293
    ): SelectQueryBuilder<T> {
529,506✔
294
        const mainAlias = this.createFromAlias(entityTarget, aliasName)
529,506✔
295
        this.expressionMap.setMainAlias(mainAlias)
529,506✔
296
        return this as any as SelectQueryBuilder<T>
529,506✔
297
    }
529,506✔
298

848,396✔
299
    /**
848,396✔
300
     * Specifies FROM which entity's table select/update/delete will be executed.
848,396✔
301
     * Also sets a main string alias of the selection data.
848,396✔
302
     */
848,396✔
303
    addFrom<T extends ObjectLiteral>(
848,396✔
304
        entityTarget: (qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>,
848,396✔
305
        aliasName: string,
848,396✔
306
    ): SelectQueryBuilder<T>
848,396✔
307

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

848,396✔
317
    /**
848,396✔
318
     * Specifies FROM which entity's table select/update/delete will be executed.
848,396✔
319
     * Also sets a main string alias of the selection data.
848,396✔
320
     */
848,396✔
321
    addFrom<T extends ObjectLiteral>(
848,396✔
322
        entityTarget:
42✔
323
            | EntityTarget<T>
42✔
324
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
42✔
325
        aliasName: string,
42✔
326
    ): SelectQueryBuilder<T> {
42✔
327
        const alias = this.createFromAlias(entityTarget, aliasName)
42✔
328
        if (!this.expressionMap.mainAlias)
42✔
329
            this.expressionMap.setMainAlias(alias)
42!
330

42✔
331
        return this as any as SelectQueryBuilder<T>
42✔
332
    }
42✔
333

848,396✔
334
    /**
848,396✔
335
     * INNER JOINs (without selection) given subquery.
848,396✔
336
     * You also need to specify an alias of the joined data.
848,396✔
337
     * Optionally, you can add condition and parameters used in condition.
848,396✔
338
     */
848,396✔
339
    innerJoin(
848,396✔
340
        subQueryFactory: (
848,396✔
341
            qb: SelectQueryBuilder<any>,
848,396✔
342
        ) => SelectQueryBuilder<any>,
848,396✔
343
        alias: string,
848,396✔
344
        condition?: string,
848,396✔
345
        parameters?: ObjectLiteral,
848,396✔
346
    ): this
848,396✔
347

848,396✔
348
    /**
848,396✔
349
     * INNER JOINs (without selection) entity's property.
848,396✔
350
     * Given entity property should be a relation.
848,396✔
351
     * You also need to specify an alias of the joined data.
848,396✔
352
     * Optionally, you can add condition and parameters used in condition.
848,396✔
353
     */
848,396✔
354
    innerJoin(
848,396✔
355
        property: string,
848,396✔
356
        alias: string,
848,396✔
357
        condition?: string,
848,396✔
358
        parameters?: ObjectLiteral,
848,396✔
359
    ): this
848,396✔
360

848,396✔
361
    /**
848,396✔
362
     * INNER JOINs (without selection) given entity's table.
848,396✔
363
     * You also need to specify an alias of the joined data.
848,396✔
364
     * Optionally, you can add condition and parameters used in condition.
848,396✔
365
     */
848,396✔
366
    innerJoin(
848,396✔
367
        entity: Function | string,
848,396✔
368
        alias: string,
848,396✔
369
        condition?: string,
848,396✔
370
        parameters?: ObjectLiteral,
848,396✔
371
    ): this
848,396✔
372

848,396✔
373
    /**
848,396✔
374
     * INNER JOINs (without selection) given table.
848,396✔
375
     * You also need to specify an alias of the joined data.
848,396✔
376
     * Optionally, you can add condition and parameters used in condition.
848,396✔
377
     */
848,396✔
378
    innerJoin(
848,396✔
379
        tableName: string,
848,396✔
380
        alias: string,
848,396✔
381
        condition?: string,
848,396✔
382
        parameters?: ObjectLiteral,
848,396✔
383
    ): this
848,396✔
384

848,396✔
385
    /**
848,396✔
386
     * INNER JOINs (without selection).
848,396✔
387
     * You also need to specify an alias of the joined data.
848,396✔
388
     * Optionally, you can add condition and parameters used in condition.
848,396✔
389
     */
848,396✔
390
    innerJoin(
848,396✔
391
        entityOrProperty:
11,838✔
392
            | Function
11,838✔
393
            | string
11,838✔
394
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
11,838✔
395
        alias: string,
11,838✔
396
        condition?: string,
11,838✔
397
        parameters?: ObjectLiteral,
11,838✔
398
    ): this {
11,838✔
399
        this.join("INNER", entityOrProperty, alias, condition, parameters)
11,838✔
400
        return this
11,838✔
401
    }
11,838✔
402

848,396✔
403
    /**
848,396✔
404
     * LEFT JOINs (without selection) given subquery.
848,396✔
405
     * You also need to specify an alias of the joined data.
848,396✔
406
     * Optionally, you can add condition and parameters used in condition.
848,396✔
407
     */
848,396✔
408
    leftJoin(
848,396✔
409
        subQueryFactory: (
848,396✔
410
            qb: SelectQueryBuilder<any>,
848,396✔
411
        ) => SelectQueryBuilder<any>,
848,396✔
412
        alias: string,
848,396✔
413
        condition?: string,
848,396✔
414
        parameters?: ObjectLiteral,
848,396✔
415
    ): this
848,396✔
416

848,396✔
417
    /**
848,396✔
418
     * LEFT JOINs (without selection) entity's property.
848,396✔
419
     * Given entity property should be a relation.
848,396✔
420
     * You also need to specify an alias of the joined data.
848,396✔
421
     * Optionally, you can add condition and parameters used in condition.
848,396✔
422
     */
848,396✔
423
    leftJoin(
848,396✔
424
        property: string,
848,396✔
425
        alias: string,
848,396✔
426
        condition?: string,
848,396✔
427
        parameters?: ObjectLiteral,
848,396✔
428
    ): this
848,396✔
429

848,396✔
430
    /**
848,396✔
431
     * LEFT JOINs (without selection) entity's table.
848,396✔
432
     * You also need to specify an alias of the joined data.
848,396✔
433
     * Optionally, you can add condition and parameters used in condition.
848,396✔
434
     */
848,396✔
435
    leftJoin(
848,396✔
436
        entity: Function | string,
848,396✔
437
        alias: string,
848,396✔
438
        condition?: string,
848,396✔
439
        parameters?: ObjectLiteral,
848,396✔
440
    ): this
848,396✔
441

848,396✔
442
    /**
848,396✔
443
     * LEFT JOINs (without selection) given table.
848,396✔
444
     * You also need to specify an alias of the joined data.
848,396✔
445
     * Optionally, you can add condition and parameters used in condition.
848,396✔
446
     */
848,396✔
447
    leftJoin(
848,396✔
448
        tableName: string,
848,396✔
449
        alias: string,
848,396✔
450
        condition?: string,
848,396✔
451
        parameters?: ObjectLiteral,
848,396✔
452
    ): this
848,396✔
453

848,396✔
454
    /**
848,396✔
455
     * LEFT JOINs (without selection).
848,396✔
456
     * You also need to specify an alias of the joined data.
848,396✔
457
     * Optionally, you can add condition and parameters used in condition.
848,396✔
458
     */
848,396✔
459
    leftJoin(
848,396✔
460
        entityOrProperty:
2,341,210✔
461
            | Function
2,341,210✔
462
            | string
2,341,210✔
463
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
2,341,210✔
464
        alias: string,
2,341,210✔
465
        condition?: string,
2,341,210✔
466
        parameters?: ObjectLiteral,
2,341,210✔
467
    ): this {
2,341,210✔
468
        this.join("LEFT", entityOrProperty, alias, condition, parameters)
2,341,210✔
469
        return this
2,341,210✔
470
    }
2,341,210✔
471

848,396✔
472
    /**
848,396✔
473
     * INNER JOINs given subquery and adds all selection properties to SELECT..
848,396✔
474
     * You also need to specify an alias of the joined data.
848,396✔
475
     * Optionally, you can add condition and parameters used in condition.
848,396✔
476
     */
848,396✔
477
    innerJoinAndSelect(
848,396✔
478
        subQueryFactory: (
848,396✔
479
            qb: SelectQueryBuilder<any>,
848,396✔
480
        ) => SelectQueryBuilder<any>,
848,396✔
481
        alias: string,
848,396✔
482
        condition?: string,
848,396✔
483
        parameters?: ObjectLiteral,
848,396✔
484
    ): this
848,396✔
485

848,396✔
486
    /**
848,396✔
487
     * INNER JOINs entity's property and adds all selection properties to SELECT.
848,396✔
488
     * Given entity property should be a relation.
848,396✔
489
     * You also need to specify an alias of the joined data.
848,396✔
490
     * Optionally, you can add condition and parameters used in condition.
848,396✔
491
     */
848,396✔
492
    innerJoinAndSelect(
848,396✔
493
        property: string,
848,396✔
494
        alias: string,
848,396✔
495
        condition?: string,
848,396✔
496
        parameters?: ObjectLiteral,
848,396✔
497
    ): this
848,396✔
498

848,396✔
499
    /**
848,396✔
500
     * INNER JOINs entity and adds all selection properties to SELECT.
848,396✔
501
     * You also need to specify an alias of the joined data.
848,396✔
502
     * Optionally, you can add condition and parameters used in condition.
848,396✔
503
     */
848,396✔
504
    innerJoinAndSelect(
848,396✔
505
        entity: Function | string,
848,396✔
506
        alias: string,
848,396✔
507
        condition?: string,
848,396✔
508
        parameters?: ObjectLiteral,
848,396✔
509
    ): this
848,396✔
510

848,396✔
511
    /**
848,396✔
512
     * INNER JOINs table and adds all selection properties to SELECT.
848,396✔
513
     * You also need to specify an alias of the joined data.
848,396✔
514
     * Optionally, you can add condition and parameters used in condition.
848,396✔
515
     */
848,396✔
516
    innerJoinAndSelect(
848,396✔
517
        tableName: string,
848,396✔
518
        alias: string,
848,396✔
519
        condition?: string,
848,396✔
520
        parameters?: ObjectLiteral,
848,396✔
521
    ): this
848,396✔
522

848,396✔
523
    /**
848,396✔
524
     * INNER JOINs and adds all selection properties to SELECT.
848,396✔
525
     * You also need to specify an alias of the joined data.
848,396✔
526
     * Optionally, you can add condition and parameters used in condition.
848,396✔
527
     */
848,396✔
528
    innerJoinAndSelect(
848,396✔
529
        entityOrProperty:
738✔
530
            | Function
738✔
531
            | string
738✔
532
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
738✔
533
        alias: string,
738✔
534
        condition?: string,
738✔
535
        parameters?: ObjectLiteral,
738✔
536
    ): this {
738✔
537
        this.addSelect(alias)
738✔
538
        this.innerJoin(entityOrProperty, alias, condition, parameters)
738✔
539
        return this
738✔
540
    }
738✔
541

848,396✔
542
    /**
848,396✔
543
     * LEFT JOINs given subquery and adds all selection properties to SELECT..
848,396✔
544
     * You also need to specify an alias of the joined data.
848,396✔
545
     * Optionally, you can add condition and parameters used in condition.
848,396✔
546
     */
848,396✔
547
    leftJoinAndSelect(
848,396✔
548
        subQueryFactory: (
848,396✔
549
            qb: SelectQueryBuilder<any>,
848,396✔
550
        ) => SelectQueryBuilder<any>,
848,396✔
551
        alias: string,
848,396✔
552
        condition?: string,
848,396✔
553
        parameters?: ObjectLiteral,
848,396✔
554
    ): this
848,396✔
555

848,396✔
556
    /**
848,396✔
557
     * LEFT JOINs entity's property and adds all selection properties to SELECT.
848,396✔
558
     * Given entity property should be a relation.
848,396✔
559
     * You also need to specify an alias of the joined data.
848,396✔
560
     * Optionally, you can add condition and parameters used in condition.
848,396✔
561
     */
848,396✔
562
    leftJoinAndSelect(
848,396✔
563
        property: string,
848,396✔
564
        alias: string,
848,396✔
565
        condition?: string,
848,396✔
566
        parameters?: ObjectLiteral,
848,396✔
567
    ): this
848,396✔
568

848,396✔
569
    /**
848,396✔
570
     * LEFT JOINs entity and adds all selection properties to SELECT.
848,396✔
571
     * You also need to specify an alias of the joined data.
848,396✔
572
     * Optionally, you can add condition and parameters used in condition.
848,396✔
573
     */
848,396✔
574
    leftJoinAndSelect(
848,396✔
575
        entity: Function | string,
848,396✔
576
        alias: string,
848,396✔
577
        condition?: string,
848,396✔
578
        parameters?: ObjectLiteral,
848,396✔
579
    ): this
848,396✔
580

848,396✔
581
    /**
848,396✔
582
     * LEFT JOINs table and adds all selection properties to SELECT.
848,396✔
583
     * You also need to specify an alias of the joined data.
848,396✔
584
     * Optionally, you can add condition and parameters used in condition.
848,396✔
585
     */
848,396✔
586
    leftJoinAndSelect(
848,396✔
587
        tableName: string,
848,396✔
588
        alias: string,
848,396✔
589
        condition?: string,
848,396✔
590
        parameters?: ObjectLiteral,
848,396✔
591
    ): this
848,396✔
592

848,396✔
593
    /**
848,396✔
594
     * LEFT JOINs and adds all selection properties to SELECT.
848,396✔
595
     * You also need to specify an alias of the joined data.
848,396✔
596
     * Optionally, you can add condition and parameters used in condition.
848,396✔
597
     */
848,396✔
598
    leftJoinAndSelect(
848,396✔
599
        entityOrProperty:
2,336,846✔
600
            | Function
2,336,846✔
601
            | string
2,336,846✔
602
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
2,336,846✔
603
        alias: string,
2,336,846✔
604
        condition?: string,
2,336,846✔
605
        parameters?: ObjectLiteral,
2,336,846✔
606
    ): this {
2,336,846✔
607
        this.addSelect(alias)
2,336,846✔
608
        this.leftJoin(entityOrProperty, alias, condition, parameters)
2,336,846✔
609
        return this
2,336,846✔
610
    }
2,336,846✔
611

848,396✔
612
    /**
848,396✔
613
     * INNER JOINs given subquery, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
614
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
615
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
848,396✔
616
     * Given entity property should be a relation.
848,396✔
617
     * You also need to specify an alias of the joined data.
848,396✔
618
     * Optionally, you can add condition and parameters used in condition.
848,396✔
619
     */
848,396✔
620
    innerJoinAndMapMany(
848,396✔
621
        mapToProperty: string,
848,396✔
622
        subQueryFactory: (
848,396✔
623
            qb: SelectQueryBuilder<any>,
848,396✔
624
        ) => SelectQueryBuilder<any>,
848,396✔
625
        alias: string,
848,396✔
626
        condition?: string,
848,396✔
627
        parameters?: ObjectLiteral,
848,396✔
628
    ): this
848,396✔
629

848,396✔
630
    /**
848,396✔
631
     * INNER JOINs entity's property, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
632
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
633
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
848,396✔
634
     * Given entity property should be a relation.
848,396✔
635
     * You also need to specify an alias of the joined data.
848,396✔
636
     * Optionally, you can add condition and parameters used in condition.
848,396✔
637
     */
848,396✔
638
    innerJoinAndMapMany(
848,396✔
639
        mapToProperty: string,
848,396✔
640
        property: string,
848,396✔
641
        alias: string,
848,396✔
642
        condition?: string,
848,396✔
643
        parameters?: ObjectLiteral,
848,396✔
644
    ): this
848,396✔
645

848,396✔
646
    /**
848,396✔
647
     * INNER JOINs entity's table, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
648
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
649
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
848,396✔
650
     * You also need to specify an alias of the joined data.
848,396✔
651
     * Optionally, you can add condition and parameters used in condition.
848,396✔
652
     */
848,396✔
653
    innerJoinAndMapMany(
848,396✔
654
        mapToProperty: string,
848,396✔
655
        entity: Function | string,
848,396✔
656
        alias: string,
848,396✔
657
        condition?: string,
848,396✔
658
        parameters?: ObjectLiteral,
848,396✔
659
    ): this
848,396✔
660

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

848,396✔
676
    /**
848,396✔
677
     * INNER JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
678
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
679
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
848,396✔
680
     * You also need to specify an alias of the joined data.
848,396✔
681
     * Optionally, you can add condition and parameters used in condition.
848,396✔
682
     */
848,396✔
683
    innerJoinAndMapMany(
848,396✔
684
        mapToProperty: string,
280✔
685
        entityOrProperty:
280✔
686
            | Function
280✔
687
            | string
280✔
688
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
280✔
689
        alias: string,
280✔
690
        condition?: string,
280✔
691
        parameters?: ObjectLiteral,
280✔
692
    ): this {
280✔
693
        this.addSelect(alias)
280✔
694
        this.join(
280✔
695
            "INNER",
280✔
696
            entityOrProperty,
280✔
697
            alias,
280✔
698
            condition,
280✔
699
            parameters,
280✔
700
            mapToProperty,
280✔
701
            true,
280✔
702
        )
280✔
703
        return this
280✔
704
    }
280✔
705

848,396✔
706
    /**
848,396✔
707
     * INNER JOINs given subquery, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
708
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
709
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
848,396✔
710
     * Given entity property should be a relation.
848,396✔
711
     * You also need to specify an alias of the joined data.
848,396✔
712
     * Optionally, you can add condition and parameters used in condition.
848,396✔
713
     */
848,396✔
714
    innerJoinAndMapOne(
848,396✔
715
        mapToProperty: string,
848,396✔
716
        subQueryFactory: (
848,396✔
717
            qb: SelectQueryBuilder<any>,
848,396✔
718
        ) => SelectQueryBuilder<any>,
848,396✔
719
        alias: string,
848,396✔
720
        condition?: string,
848,396✔
721
        parameters?: ObjectLiteral,
848,396✔
722
        mapAsEntity?: Function | string,
848,396✔
723
    ): this
848,396✔
724

848,396✔
725
    /**
848,396✔
726
     * INNER JOINs entity's property, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
727
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
728
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
848,396✔
729
     * Given entity property should be a relation.
848,396✔
730
     * You also need to specify an alias of the joined data.
848,396✔
731
     * Optionally, you can add condition and parameters used in condition.
848,396✔
732
     */
848,396✔
733
    innerJoinAndMapOne(
848,396✔
734
        mapToProperty: string,
848,396✔
735
        property: string,
848,396✔
736
        alias: string,
848,396✔
737
        condition?: string,
848,396✔
738
        parameters?: ObjectLiteral,
848,396✔
739
    ): this
848,396✔
740

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

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

848,396✔
771
    /**
848,396✔
772
     * INNER JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
773
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
774
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
848,396✔
775
     * You also need to specify an alias of the joined data.
848,396✔
776
     * Optionally, you can add condition and parameters used in condition.
848,396✔
777
     */
848,396✔
778
    innerJoinAndMapOne(
848,396✔
779
        mapToProperty: string,
196✔
780
        entityOrProperty:
196✔
781
            | Function
196✔
782
            | string
196✔
783
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
196✔
784
        alias: string,
196✔
785
        condition?: string,
196✔
786
        parameters?: ObjectLiteral,
196✔
787
        mapAsEntity?: Function | string,
196✔
788
    ): this {
196✔
789
        this.addSelect(alias)
196✔
790
        this.join(
196✔
791
            "INNER",
196✔
792
            entityOrProperty,
196✔
793
            alias,
196✔
794
            condition,
196✔
795
            parameters,
196✔
796
            mapToProperty,
196✔
797
            false,
196✔
798
            mapAsEntity,
196✔
799
        )
196✔
800
        return this
196✔
801
    }
196✔
802

848,396✔
803
    /**
848,396✔
804
     * LEFT JOINs given subquery, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
805
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
806
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
848,396✔
807
     * Given entity property should be a relation.
848,396✔
808
     * You also need to specify an alias of the joined data.
848,396✔
809
     * Optionally, you can add condition and parameters used in condition.
848,396✔
810
     */
848,396✔
811
    leftJoinAndMapMany(
848,396✔
812
        mapToProperty: string,
848,396✔
813
        subQueryFactory: (
848,396✔
814
            qb: SelectQueryBuilder<any>,
848,396✔
815
        ) => SelectQueryBuilder<any>,
848,396✔
816
        alias: string,
848,396✔
817
        condition?: string,
848,396✔
818
        parameters?: ObjectLiteral,
848,396✔
819
    ): this
848,396✔
820

848,396✔
821
    /**
848,396✔
822
     * LEFT JOINs entity's property, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
823
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
824
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
848,396✔
825
     * Given entity property should be a relation.
848,396✔
826
     * You also need to specify an alias of the joined data.
848,396✔
827
     * Optionally, you can add condition and parameters used in condition.
848,396✔
828
     */
848,396✔
829
    leftJoinAndMapMany(
848,396✔
830
        mapToProperty: string,
848,396✔
831
        property: string,
848,396✔
832
        alias: string,
848,396✔
833
        condition?: string,
848,396✔
834
        parameters?: ObjectLiteral,
848,396✔
835
    ): this
848,396✔
836

848,396✔
837
    /**
848,396✔
838
     * LEFT JOINs entity's table, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
839
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
840
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
848,396✔
841
     * You also need to specify an alias of the joined data.
848,396✔
842
     * Optionally, you can add condition and parameters used in condition.
848,396✔
843
     */
848,396✔
844
    leftJoinAndMapMany(
848,396✔
845
        mapToProperty: string,
848,396✔
846
        entity: Function | string,
848,396✔
847
        alias: string,
848,396✔
848
        condition?: string,
848,396✔
849
        parameters?: ObjectLiteral,
848,396✔
850
    ): this
848,396✔
851

848,396✔
852
    /**
848,396✔
853
     * LEFT JOINs table, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
854
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
855
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
848,396✔
856
     * You also need to specify an alias of the joined data.
848,396✔
857
     * Optionally, you can add condition and parameters used in condition.
848,396✔
858
     */
848,396✔
859
    leftJoinAndMapMany(
848,396✔
860
        mapToProperty: string,
848,396✔
861
        tableName: string,
848,396✔
862
        alias: string,
848,396✔
863
        condition?: string,
848,396✔
864
        parameters?: ObjectLiteral,
848,396✔
865
    ): this
848,396✔
866

848,396✔
867
    /**
848,396✔
868
     * LEFT JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
869
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
870
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
848,396✔
871
     * You also need to specify an alias of the joined data.
848,396✔
872
     * Optionally, you can add condition and parameters used in condition.
848,396✔
873
     */
848,396✔
874
    leftJoinAndMapMany(
848,396✔
875
        mapToProperty: string,
424✔
876
        entityOrProperty:
424✔
877
            | Function
424✔
878
            | string
424✔
879
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
424✔
880
        alias: string,
424✔
881
        condition?: string,
424✔
882
        parameters?: ObjectLiteral,
424✔
883
    ): this {
424✔
884
        this.addSelect(alias)
424✔
885
        this.join(
424✔
886
            "LEFT",
424✔
887
            entityOrProperty,
424✔
888
            alias,
424✔
889
            condition,
424✔
890
            parameters,
424✔
891
            mapToProperty,
424✔
892
            true,
424✔
893
        )
424✔
894
        return this
424✔
895
    }
424✔
896

848,396✔
897
    /**
848,396✔
898
     * LEFT JOINs given subquery, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
899
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
900
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
848,396✔
901
     * Given entity property should be a relation.
848,396✔
902
     * You also need to specify an alias of the joined data.
848,396✔
903
     * Optionally, you can add condition and parameters used in condition.
848,396✔
904
     */
848,396✔
905
    leftJoinAndMapOne(
848,396✔
906
        mapToProperty: string,
848,396✔
907
        subQueryFactory: (
848,396✔
908
            qb: SelectQueryBuilder<any>,
848,396✔
909
        ) => SelectQueryBuilder<any>,
848,396✔
910
        alias: string,
848,396✔
911
        condition?: string,
848,396✔
912
        parameters?: ObjectLiteral,
848,396✔
913
        mapAsEntity?: Function | string,
848,396✔
914
    ): this
848,396✔
915

848,396✔
916
    /**
848,396✔
917
     * LEFT JOINs entity's property, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
918
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
919
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
848,396✔
920
     * Given entity property should be a relation.
848,396✔
921
     * You also need to specify an alias of the joined data.
848,396✔
922
     * Optionally, you can add condition and parameters used in condition.
848,396✔
923
     */
848,396✔
924
    leftJoinAndMapOne(
848,396✔
925
        mapToProperty: string,
848,396✔
926
        property: string,
848,396✔
927
        alias: string,
848,396✔
928
        condition?: string,
848,396✔
929
        parameters?: ObjectLiteral,
848,396✔
930
    ): this
848,396✔
931

848,396✔
932
    /**
848,396✔
933
     * LEFT JOINs entity's table, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
934
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
935
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
848,396✔
936
     * You also need to specify an alias of the joined data.
848,396✔
937
     * Optionally, you can add condition and parameters used in condition.
848,396✔
938
     */
848,396✔
939
    leftJoinAndMapOne(
848,396✔
940
        mapToProperty: string,
848,396✔
941
        entity: Function | string,
848,396✔
942
        alias: string,
848,396✔
943
        condition?: string,
848,396✔
944
        parameters?: ObjectLiteral,
848,396✔
945
    ): this
848,396✔
946

848,396✔
947
    /**
848,396✔
948
     * LEFT JOINs table, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
949
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
950
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
848,396✔
951
     * You also need to specify an alias of the joined data.
848,396✔
952
     * Optionally, you can add condition and parameters used in condition.
848,396✔
953
     */
848,396✔
954
    leftJoinAndMapOne(
848,396✔
955
        mapToProperty: string,
848,396✔
956
        tableName: string,
848,396✔
957
        alias: string,
848,396✔
958
        condition?: string,
848,396✔
959
        parameters?: ObjectLiteral,
848,396✔
960
    ): this
848,396✔
961

848,396✔
962
    /**
848,396✔
963
     * LEFT JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property.
848,396✔
964
     * This is extremely useful when you want to select some data and map it to some virtual property.
848,396✔
965
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
848,396✔
966
     * You also need to specify an alias of the joined data.
848,396✔
967
     * Optionally, you can add condition and parameters used in condition.
848,396✔
968
     */
848,396✔
969
    leftJoinAndMapOne(
848,396✔
970
        mapToProperty: string,
284✔
971
        entityOrProperty:
284✔
972
            | Function
284✔
973
            | string
284✔
974
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
284✔
975
        alias: string,
284✔
976
        condition?: string,
284✔
977
        parameters?: ObjectLiteral,
284✔
978
        mapAsEntity?: Function | string,
284✔
979
    ): this {
284✔
980
        this.addSelect(alias)
284✔
981
        this.join(
284✔
982
            "LEFT",
284✔
983
            entityOrProperty,
284✔
984
            alias,
284✔
985
            condition,
284✔
986
            parameters,
284✔
987
            mapToProperty,
284✔
988
            false,
284✔
989
            mapAsEntity,
284✔
990
        )
284✔
991
        return this
284✔
992
    }
284✔
993

848,396✔
994
    /**
848,396✔
995
     */
848,396✔
996
    // selectAndMap(mapToProperty: string, property: string, aliasName: string, qbFactory: ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>)): this;
848,396✔
997

848,396✔
998
    /**
848,396✔
999
     */
848,396✔
1000
    // selectAndMap(mapToProperty: string, entity: Function|string, aliasName: string, qbFactory: ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>)): this;
848,396✔
1001

848,396✔
1002
    /**
848,396✔
1003
     */
848,396✔
1004
    // selectAndMap(mapToProperty: string, tableName: string, aliasName: string, qbFactory: ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>)): this;
848,396✔
1005

848,396✔
1006
    /**
848,396✔
1007
     */
848,396✔
1008
    // selectAndMap(mapToProperty: string, entityOrProperty: Function|string, aliasName: string, qbFactory: ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>)): this {
848,396✔
1009
    //     const select = new SelectAttribute(this.expressionMap);
848,396✔
1010
    //     select.mapToProperty = mapToProperty;
848,396✔
1011
    //     select.entityOrProperty = entityOrProperty;
848,396✔
1012
    //     select.aliasName = aliasName;
848,396✔
1013
    //     select.qbFactory = qbFactory;
848,396✔
1014
    //     return this;
848,396✔
1015
    // }
848,396✔
1016

848,396✔
1017
    /**
848,396✔
1018
     * LEFT JOINs relation id and maps it into some entity's property.
848,396✔
1019
     * Optionally, you can add condition and parameters used in condition.
848,396✔
1020
     */
848,396✔
1021
    loadRelationIdAndMap(
848,396✔
1022
        mapToProperty: string,
848,396✔
1023
        relationName: string,
848,396✔
1024
        options?: { disableMixedMap?: boolean },
848,396✔
1025
    ): this
848,396✔
1026

848,396✔
1027
    /**
848,396✔
1028
     * LEFT JOINs relation id and maps it into some entity's property.
848,396✔
1029
     * Optionally, you can add condition and parameters used in condition.
848,396✔
1030
     */
848,396✔
1031
    loadRelationIdAndMap(
848,396✔
1032
        mapToProperty: string,
848,396✔
1033
        relationName: string,
848,396✔
1034
        alias: string,
848,396✔
1035
        queryBuilderFactory: (
848,396✔
1036
            qb: SelectQueryBuilder<any>,
848,396✔
1037
        ) => SelectQueryBuilder<any>,
848,396✔
1038
    ): this
848,396✔
1039

848,396✔
1040
    /**
848,396✔
1041
     * LEFT JOINs relation id and maps it into some entity's property.
848,396✔
1042
     * Optionally, you can add condition and parameters used in condition.
848,396✔
1043
     */
848,396✔
1044
    loadRelationIdAndMap(
848,396✔
1045
        mapToProperty: string,
33,254✔
1046
        relationName: string,
33,254✔
1047
        aliasNameOrOptions?: string | { disableMixedMap?: boolean },
33,254✔
1048
        queryBuilderFactory?: (
33,254✔
1049
            qb: SelectQueryBuilder<any>,
33,254✔
1050
        ) => SelectQueryBuilder<any>,
33,254✔
1051
    ): this {
33,254✔
1052
        const relationIdAttribute = new RelationIdAttribute(this.expressionMap)
33,254✔
1053
        relationIdAttribute.mapToProperty = mapToProperty
33,254✔
1054
        relationIdAttribute.relationName = relationName
33,254✔
1055
        if (typeof aliasNameOrOptions === "string")
33,254✔
1056
            relationIdAttribute.alias = aliasNameOrOptions
33,254✔
1057
        if (
33,254✔
1058
            typeof aliasNameOrOptions === "object" &&
33,254✔
1059
            (aliasNameOrOptions as any).disableMixedMap
29,726✔
1060
        )
33,254✔
1061
            relationIdAttribute.disableMixedMap = true
33,254✔
1062

33,254✔
1063
        relationIdAttribute.queryBuilderFactory = queryBuilderFactory
33,254✔
1064
        this.expressionMap.relationIdAttributes.push(relationIdAttribute)
33,254✔
1065

33,254✔
1066
        if (relationIdAttribute.relation.junctionEntityMetadata) {
33,254✔
1067
            this.expressionMap.createAlias({
16,936✔
1068
                type: "other",
16,936✔
1069
                name: relationIdAttribute.junctionAlias,
16,936✔
1070
                metadata: relationIdAttribute.relation.junctionEntityMetadata,
16,936✔
1071
            })
16,936✔
1072
        }
16,936✔
1073
        return this
33,254✔
1074
    }
33,254✔
1075

848,396✔
1076
    /**
848,396✔
1077
     * Counts number of entities of entity's relation and maps the value into some entity's property.
848,396✔
1078
     * Optionally, you can add condition and parameters used in condition.
848,396✔
1079
     */
848,396✔
1080
    loadRelationCountAndMap(
848,396✔
1081
        mapToProperty: string,
1,512✔
1082
        relationName: string,
1,512✔
1083
        aliasName?: string,
1,512✔
1084
        queryBuilderFactory?: (
1,512✔
1085
            qb: SelectQueryBuilder<any>,
1,512✔
1086
        ) => SelectQueryBuilder<any>,
1,512✔
1087
    ): this {
1,512✔
1088
        const relationCountAttribute = new RelationCountAttribute(
1,512✔
1089
            this.expressionMap,
1,512✔
1090
        )
1,512✔
1091
        relationCountAttribute.mapToProperty = mapToProperty
1,512✔
1092
        relationCountAttribute.relationName = relationName
1,512✔
1093
        relationCountAttribute.alias = aliasName
1,512✔
1094
        relationCountAttribute.queryBuilderFactory = queryBuilderFactory
1,512✔
1095
        this.expressionMap.relationCountAttributes.push(relationCountAttribute)
1,512✔
1096

1,512✔
1097
        this.expressionMap.createAlias({
1,512✔
1098
            type: "other",
1,512✔
1099
            name: relationCountAttribute.junctionAlias,
1,512✔
1100
        })
1,512✔
1101
        if (relationCountAttribute.relation.junctionEntityMetadata) {
1,512✔
1102
            this.expressionMap.createAlias({
1,232✔
1103
                type: "other",
1,232✔
1104
                name: relationCountAttribute.junctionAlias,
1,232✔
1105
                metadata:
1,232✔
1106
                    relationCountAttribute.relation.junctionEntityMetadata,
1,232✔
1107
            })
1,232✔
1108
        }
1,232✔
1109
        return this
1,512✔
1110
    }
1,512✔
1111

848,396✔
1112
    /**
848,396✔
1113
     * Loads all relation ids for all relations of the selected entity.
848,396✔
1114
     * All relation ids will be mapped to relation property themself.
848,396✔
1115
     * If array of strings is given then loads only relation ids of the given properties.
848,396✔
1116
     */
848,396✔
1117
    loadAllRelationIds(options?: {
848,396✔
1118
        relations?: string[]
117,713✔
1119
        disableMixedMap?: boolean
117,713✔
1120
    }): this {
117,713✔
1121
        // todo: add skip relations
117,713✔
1122
        this.expressionMap.mainAlias!.metadata.relations.forEach((relation) => {
117,713✔
1123
            if (
64,808✔
1124
                options !== undefined &&
64,808✔
1125
                options.relations !== undefined &&
64,808✔
1126
                options.relations.indexOf(relation.propertyPath) === -1
64,780✔
1127
            )
64,808✔
1128
                return
64,808✔
1129

29,754✔
1130
            this.loadRelationIdAndMap(
29,754✔
1131
                this.expressionMap.mainAlias!.name +
29,754✔
1132
                    "." +
29,754✔
1133
                    relation.propertyPath,
29,754✔
1134
                this.expressionMap.mainAlias!.name +
29,754✔
1135
                    "." +
29,754✔
1136
                    relation.propertyPath,
29,754✔
1137
                options,
29,754✔
1138
            )
29,754✔
1139
        })
117,713✔
1140
        return this
117,713✔
1141
    }
117,713✔
1142

848,396✔
1143
    /**
848,396✔
1144
     * Sets WHERE condition in the query builder.
848,396✔
1145
     * If you had previously WHERE expression defined,
848,396✔
1146
     * calling this function will override previously set WHERE conditions.
848,396✔
1147
     * Additionally you can add parameters used in where expression.
848,396✔
1148
     */
848,396✔
1149
    where(
848,396✔
1150
        where:
457,786✔
1151
            | Brackets
457,786✔
1152
            | string
457,786✔
1153
            | ((qb: this) => string)
457,786✔
1154
            | ObjectLiteral
457,786✔
1155
            | ObjectLiteral[],
457,786✔
1156
        parameters?: ObjectLiteral,
457,786✔
1157
    ): this {
457,786✔
1158
        this.expressionMap.wheres = [] // don't move this block below since computeWhereParameter can add where expressions
457,786✔
1159
        const condition = this.getWhereCondition(where)
457,786✔
1160
        if (condition) {
457,786✔
1161
            this.expressionMap.wheres = [
457,606✔
1162
                { type: "simple", condition: condition },
457,606✔
1163
            ]
457,606✔
1164
        }
457,606✔
1165
        if (parameters) this.setParameters(parameters)
457,786✔
1166
        return this
457,578✔
1167
    }
457,578✔
1168

848,396✔
1169
    /**
848,396✔
1170
     * Adds new AND WHERE condition in the query builder.
848,396✔
1171
     * Additionally you can add parameters used in where expression.
848,396✔
1172
     */
848,396✔
1173
    andWhere(
848,396✔
1174
        where:
67,112✔
1175
            | string
67,112✔
1176
            | Brackets
67,112✔
1177
            | ((qb: this) => string)
67,112✔
1178
            | ObjectLiteral
67,112✔
1179
            | ObjectLiteral[],
67,112✔
1180
        parameters?: ObjectLiteral,
67,112✔
1181
    ): this {
67,112✔
1182
        this.expressionMap.wheres.push({
67,112✔
1183
            type: "and",
67,112✔
1184
            condition: this.getWhereCondition(where),
67,112✔
1185
        })
67,112✔
1186
        if (parameters) this.setParameters(parameters)
67,112✔
1187
        return this
67,112✔
1188
    }
67,112✔
1189

848,396✔
1190
    /**
848,396✔
1191
     * Adds new OR WHERE condition in the query builder.
848,396✔
1192
     * Additionally you can add parameters used in where expression.
848,396✔
1193
     */
848,396✔
1194
    orWhere(
848,396✔
1195
        where:
19,705✔
1196
            | Brackets
19,705✔
1197
            | string
19,705✔
1198
            | ((qb: this) => string)
19,705✔
1199
            | ObjectLiteral
19,705✔
1200
            | ObjectLiteral[],
19,705✔
1201
        parameters?: ObjectLiteral,
19,705✔
1202
    ): this {
19,705✔
1203
        this.expressionMap.wheres.push({
19,705✔
1204
            type: "or",
19,705✔
1205
            condition: this.getWhereCondition(where),
19,705✔
1206
        })
19,705✔
1207
        if (parameters) this.setParameters(parameters)
19,705✔
1208
        return this
19,705✔
1209
    }
19,705✔
1210

848,396✔
1211
    /**
848,396✔
1212
     * Sets a new where EXISTS clause
848,396✔
1213
     */
848,396✔
1214
    whereExists(subQuery: SelectQueryBuilder<any>): this {
848,396✔
1215
        return this.where(...this.getExistsCondition(subQuery))
196✔
1216
    }
196✔
1217

848,396✔
1218
    /**
848,396✔
1219
     * Adds a new AND where EXISTS clause
848,396✔
1220
     */
848,396✔
1221
    andWhereExists(subQuery: SelectQueryBuilder<any>): this {
848,396✔
1222
        return this.andWhere(...this.getExistsCondition(subQuery))
×
1223
    }
×
1224

848,396✔
1225
    /**
848,396✔
1226
     * Adds a new OR where EXISTS clause
848,396✔
1227
     */
848,396✔
1228
    orWhereExists(subQuery: SelectQueryBuilder<any>): this {
848,396✔
1229
        return this.orWhere(...this.getExistsCondition(subQuery))
×
1230
    }
×
1231

848,396✔
1232
    /**
848,396✔
1233
     * Adds new AND WHERE with conditions for the given ids.
848,396✔
1234
     *
848,396✔
1235
     * Ids are mixed.
848,396✔
1236
     * It means if you have single primary key you can pass a simple id values, for example [1, 2, 3].
848,396✔
1237
     * If you have multiple primary keys you need to pass object with property names and values specified,
848,396✔
1238
     * for example [{ firstId: 1, secondId: 2 }, { firstId: 2, secondId: 3 }, ...]
848,396✔
1239
     */
848,396✔
1240
    whereInIds(ids: any | any[]): this {
848,396✔
1241
        return this.where(this.getWhereInIdsCondition(ids))
122,435✔
1242
    }
122,435✔
1243

848,396✔
1244
    /**
848,396✔
1245
     * Adds new AND WHERE with conditions for the given ids.
848,396✔
1246
     *
848,396✔
1247
     * Ids are mixed.
848,396✔
1248
     * It means if you have single primary key you can pass a simple id values, for example [1, 2, 3].
848,396✔
1249
     * If you have multiple primary keys you need to pass object with property names and values specified,
848,396✔
1250
     * for example [{ firstId: 1, secondId: 2 }, { firstId: 2, secondId: 3 }, ...]
848,396✔
1251
     */
848,396✔
1252
    andWhereInIds(ids: any | any[]): this {
848,396✔
1253
        return this.andWhere(this.getWhereInIdsCondition(ids))
204✔
1254
    }
204✔
1255

848,396✔
1256
    /**
848,396✔
1257
     * Adds new OR WHERE with conditions for the given ids.
848,396✔
1258
     *
848,396✔
1259
     * Ids are mixed.
848,396✔
1260
     * It means if you have single primary key you can pass a simple id values, for example [1, 2, 3].
848,396✔
1261
     * If you have multiple primary keys you need to pass object with property names and values specified,
848,396✔
1262
     * for example [{ firstId: 1, secondId: 2 }, { firstId: 2, secondId: 3 }, ...]
848,396✔
1263
     */
848,396✔
1264
    orWhereInIds(ids: any | any[]): this {
848,396✔
1265
        return this.orWhere(this.getWhereInIdsCondition(ids))
56✔
1266
    }
56✔
1267

848,396✔
1268
    /**
848,396✔
1269
     * Sets HAVING condition in the query builder.
848,396✔
1270
     * If you had previously HAVING expression defined,
848,396✔
1271
     * calling this function will override previously set HAVING conditions.
848,396✔
1272
     * Additionally you can add parameters used in where expression.
848,396✔
1273
     */
848,396✔
1274
    having(having: string, parameters?: ObjectLiteral): this {
848,396✔
1275
        this.expressionMap.havings.push({ type: "simple", condition: having })
4✔
1276
        if (parameters) this.setParameters(parameters)
4!
1277
        return this
4✔
1278
    }
4✔
1279

848,396✔
1280
    /**
848,396✔
1281
     * Adds new AND HAVING condition in the query builder.
848,396✔
1282
     * Additionally you can add parameters used in where expression.
848,396✔
1283
     */
848,396✔
1284
    andHaving(having: string, parameters?: ObjectLiteral): this {
848,396✔
1285
        this.expressionMap.havings.push({ type: "and", condition: having })
×
1286
        if (parameters) this.setParameters(parameters)
×
1287
        return this
×
1288
    }
×
1289

848,396✔
1290
    /**
848,396✔
1291
     * Adds new OR HAVING condition in the query builder.
848,396✔
1292
     * Additionally you can add parameters used in where expression.
848,396✔
1293
     */
848,396✔
1294
    orHaving(having: string, parameters?: ObjectLiteral): this {
848,396✔
1295
        this.expressionMap.havings.push({ type: "or", condition: having })
4✔
1296
        if (parameters) this.setParameters(parameters)
4!
1297
        return this
4✔
1298
    }
4✔
1299

848,396✔
1300
    /**
848,396✔
1301
     * Sets GROUP BY condition in the query builder.
848,396✔
1302
     * If you had previously GROUP BY expression defined,
848,396✔
1303
     * calling this function will override previously set GROUP BY conditions.
848,396✔
1304
     */
848,396✔
1305
    groupBy(): this
848,396✔
1306

848,396✔
1307
    /**
848,396✔
1308
     * Sets GROUP BY condition in the query builder.
848,396✔
1309
     * If you had previously GROUP BY expression defined,
848,396✔
1310
     * calling this function will override previously set GROUP BY conditions.
848,396✔
1311
     */
848,396✔
1312
    groupBy(groupBy: string): this
848,396✔
1313

848,396✔
1314
    /**
848,396✔
1315
     * Sets GROUP BY condition in the query builder.
848,396✔
1316
     * If you had previously GROUP BY expression defined,
848,396✔
1317
     * calling this function will override previously set GROUP BY conditions.
848,396✔
1318
     */
848,396✔
1319
    groupBy(groupBy?: string): this {
848,396✔
1320
        if (groupBy) {
1,305✔
1321
            this.expressionMap.groupBys = [groupBy]
93✔
1322
        } else {
1,305✔
1323
            this.expressionMap.groupBys = []
1,212✔
1324
        }
1,212✔
1325
        return this
1,305✔
1326
    }
1,305✔
1327

848,396✔
1328
    /**
848,396✔
1329
     * Adds GROUP BY condition in the query builder.
848,396✔
1330
     */
848,396✔
1331
    addGroupBy(groupBy: string): this {
848,396✔
1332
        this.expressionMap.groupBys.push(groupBy)
3,136✔
1333
        return this
3,136✔
1334
    }
3,136✔
1335

848,396✔
1336
    /**
848,396✔
1337
     * Enables time travelling for the current query (only supported by cockroach currently)
848,396✔
1338
     */
848,396✔
1339
    timeTravelQuery(timeTravelFn?: string | boolean): this {
848,396✔
1340
        if (this.connection.driver.options.type === "cockroachdb") {
14,803!
1341
            if (timeTravelFn === undefined) {
535✔
1342
                this.expressionMap.timeTravel = "follower_read_timestamp()"
1✔
1343
            } else {
535✔
1344
                this.expressionMap.timeTravel = timeTravelFn
534✔
1345
            }
534✔
1346
        }
535✔
1347

14,803✔
1348
        return this
14,803✔
1349
    }
14,803✔
1350

848,396✔
1351
    /**
848,396✔
1352
     * Sets ORDER BY condition in the query builder.
848,396✔
1353
     * If you had previously ORDER BY expression defined,
848,396✔
1354
     * calling this function will override previously set ORDER BY conditions.
848,396✔
1355
     *
848,396✔
1356
     * Calling order by without order set will remove all previously set order bys.
848,396✔
1357
     */
848,396✔
1358
    orderBy(): this
848,396✔
1359

848,396✔
1360
    /**
848,396✔
1361
     * Sets ORDER BY condition in the query builder.
848,396✔
1362
     * If you had previously ORDER BY expression defined,
848,396✔
1363
     * calling this function will override previously set ORDER BY conditions.
848,396✔
1364
     */
848,396✔
1365
    orderBy(
848,396✔
1366
        sort: string,
848,396✔
1367
        order?: "ASC" | "DESC",
848,396✔
1368
        nulls?: "NULLS FIRST" | "NULLS LAST",
848,396✔
1369
    ): this
848,396✔
1370

848,396✔
1371
    /**
848,396✔
1372
     * Sets ORDER BY condition in the query builder.
848,396✔
1373
     * If you had previously ORDER BY expression defined,
848,396✔
1374
     * calling this function will override previously set ORDER BY conditions.
848,396✔
1375
     */
848,396✔
1376
    orderBy(order: OrderByCondition): this
848,396✔
1377

848,396✔
1378
    /**
848,396✔
1379
     * Sets ORDER BY condition in the query builder.
848,396✔
1380
     * If you had previously ORDER BY expression defined,
848,396✔
1381
     * calling this function will override previously set ORDER BY conditions.
848,396✔
1382
     */
848,396✔
1383
    orderBy(
848,396✔
1384
        sort?: string | OrderByCondition,
23,480✔
1385
        order: "ASC" | "DESC" = "ASC",
23,480✔
1386
        nulls?: "NULLS FIRST" | "NULLS LAST",
23,480✔
1387
    ): this {
23,480✔
1388
        if (order !== undefined && order !== "ASC" && order !== "DESC")
23,480✔
1389
            throw new TypeORMError(
23,480✔
1390
                `SelectQueryBuilder.addOrderBy "order" can accept only "ASC" and "DESC" values.`,
28✔
1391
            )
28✔
1392
        if (
23,452✔
1393
            nulls !== undefined &&
23,452✔
1394
            nulls !== "NULLS FIRST" &&
23,480✔
1395
            nulls !== "NULLS LAST"
28✔
1396
        )
23,480✔
1397
            throw new TypeORMError(
23,480✔
1398
                `SelectQueryBuilder.addOrderBy "nulls" can accept only "NULLS FIRST" and "NULLS LAST" values.`,
28✔
1399
            )
28✔
1400

23,424✔
1401
        if (sort) {
23,480✔
1402
            if (typeof sort === "object") {
14,813✔
1403
                this.expressionMap.orderBys = sort as OrderByCondition
7,432✔
1404
            } else {
14,813✔
1405
                if (nulls) {
7,381!
1406
                    this.expressionMap.orderBys = {
×
1407
                        [sort as string]: { order, nulls },
×
1408
                    }
×
1409
                } else {
7,381✔
1410
                    this.expressionMap.orderBys = { [sort as string]: order }
7,381✔
1411
                }
7,381✔
1412
            }
7,381✔
1413
        } else {
23,480✔
1414
            this.expressionMap.orderBys = {}
8,611✔
1415
        }
8,611✔
1416
        return this
23,424✔
1417
    }
23,424✔
1418

848,396✔
1419
    /**
848,396✔
1420
     * Adds ORDER BY condition in the query builder.
848,396✔
1421
     */
848,396✔
1422
    addOrderBy(
848,396✔
1423
        sort: string,
17,729✔
1424
        order: "ASC" | "DESC" = "ASC",
17,729✔
1425
        nulls?: "NULLS FIRST" | "NULLS LAST",
17,729✔
1426
    ): this {
17,729✔
1427
        if (order !== undefined && order !== "ASC" && order !== "DESC")
17,729✔
1428
            throw new TypeORMError(
17,729!
1429
                `SelectQueryBuilder.addOrderBy "order" can accept only "ASC" and "DESC" values.`,
×
1430
            )
×
1431
        if (
17,729✔
1432
            nulls !== undefined &&
17,729!
1433
            nulls !== "NULLS FIRST" &&
17,729!
1434
            nulls !== "NULLS LAST"
28✔
1435
        )
17,729✔
1436
            throw new TypeORMError(
17,729!
1437
                `SelectQueryBuilder.addOrderBy "nulls" can accept only "NULLS FIRST" and "NULLS LAST" values.`,
×
1438
            )
×
1439

17,729✔
1440
        if (nulls) {
17,729!
1441
            this.expressionMap.orderBys[sort] = { order, nulls }
52✔
1442
        } else {
17,729✔
1443
            this.expressionMap.orderBys[sort] = order
17,677✔
1444
        }
17,677✔
1445
        return this
17,729✔
1446
    }
17,729✔
1447

848,396✔
1448
    /**
848,396✔
1449
     * Sets LIMIT - maximum number of rows to be selected.
848,396✔
1450
     * NOTE that it may not work as you expect if you are using joins.
848,396✔
1451
     * If you want to implement pagination, and you are having join in your query,
848,396✔
1452
     * then use the take method instead.
848,396✔
1453
     */
848,396✔
1454
    limit(limit?: number): this {
848,396✔
1455
        this.expressionMap.limit = this.normalizeNumber(limit)
9,191✔
1456
        if (
9,191✔
1457
            this.expressionMap.limit !== undefined &&
9,191✔
1458
            isNaN(this.expressionMap.limit)
7,951✔
1459
        )
9,191✔
1460
            throw new TypeORMError(
9,191!
1461
                `Provided "limit" value is not a number. Please provide a numeric value.`,
×
1462
            )
×
1463

9,191✔
1464
        return this
9,191✔
1465
    }
9,191✔
1466

848,396✔
1467
    /**
848,396✔
1468
     * Sets OFFSET - selection offset.
848,396✔
1469
     * NOTE that it may not work as you expect if you are using joins.
848,396✔
1470
     * If you want to implement pagination, and you are having join in your query,
848,396✔
1471
     * then use the skip method instead.
848,396✔
1472
     */
848,396✔
1473
    offset(offset?: number): this {
848,396✔
1474
        this.expressionMap.offset = this.normalizeNumber(offset)
8,877✔
1475
        if (
8,877✔
1476
            this.expressionMap.offset !== undefined &&
8,877✔
1477
            isNaN(this.expressionMap.offset)
388✔
1478
        )
8,877✔
1479
            throw new TypeORMError(
8,877!
1480
                `Provided "offset" value is not a number. Please provide a numeric value.`,
×
1481
            )
×
1482

8,877✔
1483
        return this
8,877✔
1484
    }
8,877✔
1485

848,396✔
1486
    /**
848,396✔
1487
     * Sets maximal number of entities to take.
848,396✔
1488
     */
848,396✔
1489
    take(take?: number): this {
848,396✔
1490
        this.expressionMap.take = this.normalizeNumber(take)
18,528✔
1491
        if (
18,528✔
1492
            this.expressionMap.take !== undefined &&
18,528✔
1493
            isNaN(this.expressionMap.take)
17,316✔
1494
        )
18,528✔
1495
            throw new TypeORMError(
18,528✔
1496
                `Provided "take" value is not a number. Please provide a numeric value.`,
56✔
1497
            )
56✔
1498

18,472✔
1499
        return this
18,472✔
1500
    }
18,472✔
1501

848,396✔
1502
    /**
848,396✔
1503
     * Sets number of entities to skip.
848,396✔
1504
     */
848,396✔
1505
    skip(skip?: number): this {
848,396✔
1506
        this.expressionMap.skip = this.normalizeNumber(skip)
2,103✔
1507
        if (
2,103✔
1508
            this.expressionMap.skip !== undefined &&
2,103✔
1509
            isNaN(this.expressionMap.skip)
891✔
1510
        )
2,103✔
1511
            throw new TypeORMError(
2,103✔
1512
                `Provided "skip" value is not a number. Please provide a numeric value.`,
56✔
1513
            )
56✔
1514

2,047✔
1515
        return this
2,047✔
1516
    }
2,047✔
1517

848,396✔
1518
    /**
848,396✔
1519
     * Set certain index to be used by the query.
848,396✔
1520
     *
848,396✔
1521
     * @param index Name of index to be used.
848,396✔
1522
     */
848,396✔
1523
    useIndex(index: string): this {
848,396✔
1524
        this.expressionMap.useIndex = index
8✔
1525

8✔
1526
        return this
8✔
1527
    }
8✔
1528

848,396✔
1529
    /**
848,396✔
1530
     * Sets locking mode.
848,396✔
1531
     */
848,396✔
1532
    setLock(lockMode: "optimistic", lockVersion: number | Date): this
848,396✔
1533

848,396✔
1534
    /**
848,396✔
1535
     * Sets locking mode.
848,396✔
1536
     */
848,396✔
1537
    setLock(
848,396✔
1538
        lockMode:
848,396✔
1539
            | "pessimistic_read"
848,396✔
1540
            | "pessimistic_write"
848,396✔
1541
            | "dirty_read"
848,396✔
1542
            /*
848,396✔
1543
                "pessimistic_partial_write" and "pessimistic_write_or_fail" are deprecated and
848,396✔
1544
                will be removed in a future version.
848,396✔
1545

848,396✔
1546
                Use setOnLocked instead.
848,396✔
1547
             */
848,396✔
1548
            | "pessimistic_partial_write"
848,396✔
1549
            | "pessimistic_write_or_fail"
848,396✔
1550
            | "for_no_key_update"
848,396✔
1551
            | "for_key_share",
848,396✔
1552
        lockVersion?: undefined,
848,396✔
1553
        lockTables?: string[],
848,396✔
1554
    ): this
848,396✔
1555

848,396✔
1556
    /**
848,396✔
1557
     * Sets locking mode.
848,396✔
1558
     */
848,396✔
1559
    setLock(
848,396✔
1560
        lockMode:
976✔
1561
            | "optimistic"
976✔
1562
            | "pessimistic_read"
976✔
1563
            | "pessimistic_write"
976✔
1564
            | "dirty_read"
976✔
1565
            /*
976✔
1566
                "pessimistic_partial_write" and "pessimistic_write_or_fail" are deprecated and
976✔
1567
                will be removed in a future version.
976✔
1568

976✔
1569
                Use setOnLocked instead.
976✔
1570
             */
976✔
1571
            | "pessimistic_partial_write"
976✔
1572
            | "pessimistic_write_or_fail"
976✔
1573
            | "for_no_key_update"
976✔
1574
            | "for_key_share",
976✔
1575
        lockVersion?: number | Date,
976✔
1576
        lockTables?: string[],
976✔
1577
    ): this {
976✔
1578
        this.expressionMap.lockMode = lockMode
976✔
1579
        this.expressionMap.lockVersion = lockVersion
976✔
1580
        this.expressionMap.lockTables = lockTables
976✔
1581
        return this
976✔
1582
    }
976✔
1583

848,396✔
1584
    /**
848,396✔
1585
     * Sets lock handling by adding NO WAIT or SKIP LOCKED.
848,396✔
1586
     */
848,396✔
1587
    setOnLocked(onLocked: "nowait" | "skip_locked"): this {
848,396✔
1588
        this.expressionMap.onLocked = onLocked
64✔
1589
        return this
64✔
1590
    }
64✔
1591

848,396✔
1592
    /**
848,396✔
1593
     * Disables the global condition of "non-deleted" for the entity with delete date columns.
848,396✔
1594
     */
848,396✔
1595
    withDeleted(): this {
848,396✔
1596
        this.expressionMap.withDeleted = true
118,754✔
1597
        return this
118,754✔
1598
    }
118,754✔
1599

848,396✔
1600
    /**
848,396✔
1601
     * Gets first raw result returned by execution of generated query builder sql.
848,396✔
1602
     */
848,396✔
1603
    async getRawOne<T = any>(): Promise<T | undefined> {
848,396✔
1604
        return (await this.getRawMany())[0]
7,405✔
1605
    }
7,377✔
1606

848,396✔
1607
    /**
848,396✔
1608
     * Gets all raw results returned by execution of generated query builder sql.
848,396✔
1609
     */
848,396✔
1610
    async getRawMany<T = any>(): Promise<T[]> {
848,396✔
1611
        if (this.expressionMap.lockMode === "optimistic")
26,736✔
1612
            throw new OptimisticLockCanNotBeUsedError()
26,736✔
1613

26,680✔
1614
        this.expressionMap.queryEntity = false
26,680✔
1615
        const queryRunner = this.obtainQueryRunner()
26,680✔
1616
        let transactionStartedByUs: boolean = false
26,680✔
1617
        try {
26,680✔
1618
            // start transaction if it was enabled
26,680✔
1619
            if (
26,680✔
1620
                this.expressionMap.useTransaction === true &&
26,680!
1621
                queryRunner.isTransactionActive === false
×
1622
            ) {
26,736!
1623
                await queryRunner.startTransaction()
×
1624
                transactionStartedByUs = true
×
1625
            }
×
1626

26,680✔
1627
            const results = await this.loadRawResults(queryRunner)
26,680✔
1628

26,665✔
1629
            // close transaction if we started it
26,665✔
1630
            if (transactionStartedByUs) {
26,736!
1631
                await queryRunner.commitTransaction()
×
1632
            }
×
1633

26,665✔
1634
            return results
26,665✔
1635
        } catch (error) {
26,736!
1636
            // rollback transaction if we started it
15✔
1637
            if (transactionStartedByUs) {
15!
1638
                try {
×
1639
                    await queryRunner.rollbackTransaction()
×
1640
                } catch (rollbackError) {}
×
1641
            }
×
1642
            throw error
15✔
1643
        } finally {
14,979!
1644
            if (queryRunner !== this.queryRunner) {
26,680✔
1645
                // means we created our own query runner
873✔
1646
                await queryRunner.release()
873✔
1647
            }
873✔
1648
        }
26,680✔
1649
    }
26,736✔
1650

848,396✔
1651
    /**
848,396✔
1652
     * Executes sql generated by query builder and returns object with raw results and entities created from them.
848,396✔
1653
     */
848,396✔
1654
    async getRawAndEntities<T = any>(): Promise<{
848,396✔
1655
        entities: Entity[]
172,369✔
1656
        raw: T[]
172,369✔
1657
    }> {
172,369✔
1658
        const queryRunner = this.obtainQueryRunner()
172,369✔
1659
        let transactionStartedByUs: boolean = false
172,369✔
1660
        try {
172,369✔
1661
            // start transaction if it was enabled
172,369✔
1662
            if (
172,369✔
1663
                this.expressionMap.useTransaction === true &&
172,369✔
1664
                queryRunner.isTransactionActive === false
28✔
1665
            ) {
172,369✔
1666
                await queryRunner.startTransaction()
28✔
1667
                transactionStartedByUs = true
28✔
1668
            }
28✔
1669

172,369✔
1670
            this.expressionMap.queryEntity = true
172,369✔
1671
            const results = await this.executeEntitiesAndRawResults(queryRunner)
172,369✔
1672

172,121✔
1673
            // close transaction if we started it
172,121✔
1674
            if (transactionStartedByUs) {
172,369✔
1675
                await queryRunner.commitTransaction()
28✔
1676
            }
28✔
1677

172,121✔
1678
            return results
172,121✔
1679
        } catch (error) {
172,369✔
1680
            // rollback transaction if we started it
248✔
1681
            if (transactionStartedByUs) {
248!
1682
                try {
×
1683
                    await queryRunner.rollbackTransaction()
×
1684
                } catch (rollbackError) {}
×
1685
            }
×
1686
            throw error
248✔
1687
        } finally {
172,369!
1688
            if (queryRunner !== this.queryRunner)
172,369✔
1689
                // means we created our own query runner
172,369✔
1690
                await queryRunner.release()
172,369✔
1691
        }
172,369✔
1692
    }
172,369✔
1693

848,396✔
1694
    /**
848,396✔
1695
     * Gets single entity returned by execution of generated query builder sql.
848,396✔
1696
     */
848,396✔
1697
    async getOne(): Promise<Entity | null> {
848,396✔
1698
        const results = await this.getRawAndEntities()
23,712✔
1699
        const result = results.entities[0] as any
23,468✔
1700

23,468✔
1701
        if (
23,468✔
1702
            result &&
23,468✔
1703
            this.expressionMap.lockMode === "optimistic" &&
23,712✔
1704
            this.expressionMap.lockVersion
160✔
1705
        ) {
23,712✔
1706
            const metadata = this.expressionMap.mainAlias!.metadata
160✔
1707

160✔
1708
            if (this.expressionMap.lockVersion instanceof Date) {
160!
1709
                const actualVersion =
78✔
1710
                    metadata.updateDateColumn!.getEntityValue(result) // what if columns arent set?
78✔
1711
                if (
78✔
1712
                    actualVersion.getTime() !==
78✔
1713
                    this.expressionMap.lockVersion.getTime()
78✔
1714
                )
78✔
1715
                    throw new OptimisticLockVersionMismatchError(
78✔
1716
                        metadata.name,
26✔
1717
                        this.expressionMap.lockVersion,
26✔
1718
                        actualVersion,
26✔
1719
                    )
26✔
1720
            } else {
82✔
1721
                const actualVersion =
82✔
1722
                    metadata.versionColumn!.getEntityValue(result) // what if columns arent set?
82✔
1723
                if (actualVersion !== this.expressionMap.lockVersion)
82✔
1724
                    throw new OptimisticLockVersionMismatchError(
82✔
1725
                        metadata.name,
28✔
1726
                        this.expressionMap.lockVersion,
28✔
1727
                        actualVersion,
28✔
1728
                    )
28✔
1729
            }
82✔
1730
        }
160✔
1731

23,414✔
1732
        if (result === undefined) {
23,712✔
1733
            return null
1,476✔
1734
        }
1,476✔
1735
        return result
21,938✔
1736
    }
21,938✔
1737

848,396✔
1738
    /**
848,396✔
1739
     * Gets the first entity returned by execution of generated query builder sql or rejects the returned promise on error.
848,396✔
1740
     */
848,396✔
1741
    async getOneOrFail(): Promise<Entity> {
848,396✔
1742
        const entity = await this.getOne()
18✔
1743

18✔
1744
        if (!entity) {
18!
1745
            throw new EntityNotFoundError(
3✔
1746
                this.expressionMap.mainAlias!.target,
3✔
1747
                this.expressionMap.parameters,
3✔
1748
            )
3✔
1749
        }
3✔
1750

15✔
1751
        return entity
15✔
1752
    }
15✔
1753

848,396✔
1754
    /**
848,396✔
1755
     * Gets entities returned by execution of generated query builder sql.
848,396✔
1756
     */
848,396✔
1757
    async getMany(): Promise<Entity[]> {
848,396✔
1758
        if (this.expressionMap.lockMode === "optimistic")
146,061✔
1759
            throw new OptimisticLockCanNotBeUsedError()
146,061✔
1760

146,005✔
1761
        const results = await this.getRawAndEntities()
146,005✔
1762
        return results.entities
146,001✔
1763
    }
146,001✔
1764

848,396✔
1765
    /**
848,396✔
1766
     * Gets count - number of entities selected by sql generated by this query builder.
848,396✔
1767
     * Count excludes all limitations set by offset, limit, skip, and take.
848,396✔
1768
     */
848,396✔
1769
    async getCount(): Promise<number> {
848,396✔
1770
        if (this.expressionMap.lockMode === "optimistic")
844✔
1771
            throw new OptimisticLockCanNotBeUsedError()
844✔
1772

816✔
1773
        const queryRunner = this.obtainQueryRunner()
816✔
1774
        let transactionStartedByUs: boolean = false
816✔
1775
        try {
816✔
1776
            // start transaction if it was enabled
816✔
1777
            if (
816✔
1778
                this.expressionMap.useTransaction === true &&
816!
1779
                queryRunner.isTransactionActive === false
×
1780
            ) {
844!
1781
                await queryRunner.startTransaction()
×
1782
                transactionStartedByUs = true
×
1783
            }
×
1784

816✔
1785
            this.expressionMap.queryEntity = false
816✔
1786
            const results = await this.executeCountQuery(queryRunner)
816✔
1787

816✔
1788
            // close transaction if we started it
816✔
1789
            if (transactionStartedByUs) {
844!
1790
                await queryRunner.commitTransaction()
×
1791
            }
×
1792

816✔
1793
            return results
816✔
1794
        } catch (error) {
844!
1795
            // rollback transaction if we started it
×
1796
            if (transactionStartedByUs) {
×
1797
                try {
×
1798
                    await queryRunner.rollbackTransaction()
×
1799
                } catch (rollbackError) {}
×
1800
            }
×
1801
            throw error
×
1802
        } finally {
✔
1803
            if (queryRunner !== this.queryRunner)
816✔
1804
                // means we created our own query runner
816✔
1805
                await queryRunner.release()
816✔
1806
        }
816✔
1807
    }
844✔
1808

848,396✔
1809
    /**
848,396✔
1810
     * Gets exists
848,396✔
1811
     * Returns whether any rows exists matching current query.
848,396✔
1812
     */
848,396✔
1813
    async getExists(): Promise<boolean> {
848,396✔
1814
        if (this.expressionMap.lockMode === "optimistic")
196✔
1815
            throw new OptimisticLockCanNotBeUsedError()
196!
1816

196✔
1817
        const queryRunner = this.obtainQueryRunner()
196✔
1818
        let transactionStartedByUs: boolean = false
196✔
1819
        try {
196✔
1820
            // start transaction if it was enabled
196✔
1821
            if (
196✔
1822
                this.expressionMap.useTransaction === true &&
196!
1823
                queryRunner.isTransactionActive === false
×
1824
            ) {
196!
1825
                await queryRunner.startTransaction()
×
1826
                transactionStartedByUs = true
×
1827
            }
×
1828

196✔
1829
            this.expressionMap.queryEntity = false
196✔
1830
            const results = await this.executeExistsQuery(queryRunner)
196✔
1831

196✔
1832
            // close transaction if we started it
196✔
1833
            if (transactionStartedByUs) {
196!
1834
                await queryRunner.commitTransaction()
×
1835
            }
×
1836

196✔
1837
            return results
196✔
1838
        } catch (error) {
196!
1839
            // rollback transaction if we started it
×
1840
            if (transactionStartedByUs) {
×
1841
                try {
×
1842
                    await queryRunner.rollbackTransaction()
×
1843
                } catch (rollbackError) {}
×
1844
            }
×
1845
            throw error
×
1846
        } finally {
×
1847
            if (queryRunner !== this.queryRunner)
196✔
1848
                // means we created our own query runner
196✔
1849
                await queryRunner.release()
196✔
1850
        }
196✔
1851
    }
196✔
1852

848,396✔
1853
    /**
848,396✔
1854
     * Executes built SQL query and returns entities and overall entities count (without limitation).
848,396✔
1855
     * This method is useful to build pagination.
848,396✔
1856
     */
848,396✔
1857
    async getManyAndCount(): Promise<[Entity[], number]> {
848,396✔
1858
        if (this.expressionMap.lockMode === "optimistic")
900✔
1859
            throw new OptimisticLockCanNotBeUsedError()
900✔
1860

872✔
1861
        const queryRunner = this.obtainQueryRunner()
872✔
1862
        let transactionStartedByUs: boolean = false
872✔
1863
        try {
872✔
1864
            // start transaction if it was enabled
872✔
1865
            if (
872✔
1866
                this.expressionMap.useTransaction === true &&
872!
1867
                queryRunner.isTransactionActive === false
×
1868
            ) {
900!
1869
                await queryRunner.startTransaction()
×
1870
                transactionStartedByUs = true
×
1871
            }
×
1872

872✔
1873
            this.expressionMap.queryEntity = true
872✔
1874
            const entitiesAndRaw = await this.executeEntitiesAndRawResults(
872✔
1875
                queryRunner,
872✔
1876
            )
872✔
1877
            this.expressionMap.queryEntity = false
862✔
1878

862✔
1879
            let count: number | undefined = this.lazyCount(entitiesAndRaw)
862✔
1880
            if (count === undefined) {
900✔
1881
                const cacheId = this.expressionMap.cacheId
200✔
1882
                // Creates a new cacheId for the count query, or it will retrieve the above query results
200✔
1883
                // and count will return 0.
200✔
1884
                if (cacheId) {
200!
1885
                    this.expressionMap.cacheId = `${cacheId}-count`
×
1886
                }
×
1887
                count = await this.executeCountQuery(queryRunner)
200✔
1888
            }
200✔
1889
            const results: [Entity[], number] = [entitiesAndRaw.entities, count]
862✔
1890

862✔
1891
            // close transaction if we started it
862✔
1892
            if (transactionStartedByUs) {
900!
1893
                await queryRunner.commitTransaction()
×
1894
            }
×
1895

862✔
1896
            return results
862✔
1897
        } catch (error) {
900!
1898
            // rollback transaction if we started it
10✔
1899
            if (transactionStartedByUs) {
10!
1900
                try {
×
1901
                    await queryRunner.rollbackTransaction()
×
1902
                } catch (rollbackError) {}
×
1903
            }
×
1904
            throw error
10✔
1905
        } finally {
320!
1906
            if (queryRunner !== this.queryRunner)
872✔
1907
                // means we created our own query runner
872✔
1908
                await queryRunner.release()
872✔
1909
        }
872✔
1910
    }
900✔
1911

848,396✔
1912
    private lazyCount(entitiesAndRaw: {
848,396✔
1913
        entities: Entity[]
862✔
1914
        raw: any[]
862✔
1915
    }): number | undefined {
862✔
1916
        const hasLimit =
862✔
1917
            this.expressionMap.limit !== undefined &&
862✔
1918
            this.expressionMap.limit !== null
140✔
1919
        if (this.expressionMap.joinAttributes.length > 0 && hasLimit) {
862✔
1920
            return undefined
56✔
1921
        }
56✔
1922

806✔
1923
        const hasTake =
806✔
1924
            this.expressionMap.take !== undefined &&
806✔
1925
            this.expressionMap.take !== null
228✔
1926

862✔
1927
        // limit overrides take when no join is defined
862✔
1928
        const maxResults = hasLimit
862✔
1929
            ? this.expressionMap.limit
862✔
1930
            : hasTake
862✔
1931
            ? this.expressionMap.take
722✔
1932
            : undefined
722✔
1933

862✔
1934
        if (
862✔
1935
            maxResults !== undefined &&
862✔
1936
            entitiesAndRaw.entities.length === maxResults
312✔
1937
        ) {
862✔
1938
            // stop here when the result set contains the max number of rows; we need to execute a full count
88✔
1939
            return undefined
88✔
1940
        }
88✔
1941

718✔
1942
        const hasSkip =
718✔
1943
            this.expressionMap.skip !== undefined &&
718✔
1944
            this.expressionMap.skip !== null &&
862✔
1945
            this.expressionMap.skip > 0
102✔
1946
        const hasOffset =
862✔
1947
            this.expressionMap.offset !== undefined &&
862✔
1948
            this.expressionMap.offset !== null &&
862✔
1949
            this.expressionMap.offset > 0
56✔
1950

862✔
1951
        if (entitiesAndRaw.entities.length === 0 && (hasSkip || hasOffset)) {
862✔
1952
            // when skip or offset were used and no results found, we need to execute a full count
56✔
1953
            // (the given offset may have exceeded the actual number of rows)
56✔
1954
            return undefined
56✔
1955
        }
56✔
1956

662✔
1957
        // offset overrides skip when no join is defined
662✔
1958
        const previousResults: number = hasOffset
662✔
1959
            ? this.expressionMap.offset!
862✔
1960
            : hasSkip
862✔
1961
            ? this.expressionMap.skip!
634✔
1962
            : 0
634✔
1963

862✔
1964
        return entitiesAndRaw.entities.length + previousResults
862✔
1965
    }
862✔
1966

848,396✔
1967
    /**
848,396✔
1968
     * Executes built SQL query and returns raw data stream.
848,396✔
1969
     */
848,396✔
1970
    async stream(): Promise<ReadStream> {
848,396✔
1971
        this.expressionMap.queryEntity = false
13✔
1972
        const [sql, parameters] = this.getQueryAndParameters()
13✔
1973
        const queryRunner = this.obtainQueryRunner()
13✔
1974
        let transactionStartedByUs: boolean = false
13✔
1975
        try {
13✔
1976
            // start transaction if it was enabled
13✔
1977
            if (
13✔
1978
                this.expressionMap.useTransaction === true &&
13!
1979
                queryRunner.isTransactionActive === false
×
1980
            ) {
13!
1981
                await queryRunner.startTransaction()
×
1982
                transactionStartedByUs = true
×
1983
            }
×
1984

13✔
1985
            const releaseFn = () => {
13✔
1986
                if (queryRunner !== this.queryRunner)
13✔
1987
                    // means we created our own query runner
13✔
1988
                    return queryRunner.release()
13✔
1989
                return
×
1990
            }
×
1991
            const results = queryRunner.stream(
13✔
1992
                sql,
13✔
1993
                parameters,
13✔
1994
                releaseFn,
13✔
1995
                releaseFn,
13✔
1996
            )
13✔
1997

13✔
1998
            // close transaction if we started it
13✔
1999
            if (transactionStartedByUs) {
13!
2000
                await queryRunner.commitTransaction()
×
2001
            }
×
2002

13✔
2003
            return results
13✔
2004
        } catch (error) {
13!
2005
            // rollback transaction if we started it
×
2006
            if (transactionStartedByUs) {
×
2007
                try {
×
2008
                    await queryRunner.rollbackTransaction()
×
2009
                } catch (rollbackError) {}
×
2010
            }
×
2011
            throw error
×
2012
        }
×
2013
    }
13✔
2014

848,396✔
2015
    /**
848,396✔
2016
     * Enables or disables query result caching.
848,396✔
2017
     */
848,396✔
2018
    cache(enabled: boolean): this
848,396✔
2019

848,396✔
2020
    /**
848,396✔
2021
     * Enables query result caching and sets in milliseconds in which cache will expire.
848,396✔
2022
     * If not set then global caching time will be used.
848,396✔
2023
     */
848,396✔
2024
    cache(milliseconds: number): this
848,396✔
2025

848,396✔
2026
    /**
848,396✔
2027
     * Enables query result caching and sets cache id and milliseconds in which cache will expire.
848,396✔
2028
     */
848,396✔
2029
    cache(id: any, milliseconds?: number): this
848,396✔
2030

848,396✔
2031
    /**
848,396✔
2032
     * Enables or disables query result caching.
848,396✔
2033
     */
848,396✔
2034
    cache(
848,396✔
2035
        enabledOrMillisecondsOrId: boolean | number | string,
9,223✔
2036
        maybeMilliseconds?: number,
9,223✔
2037
    ): this {
9,223✔
2038
        if (typeof enabledOrMillisecondsOrId === "boolean") {
9,223✔
2039
            this.expressionMap.cache = enabledOrMillisecondsOrId
1,348✔
2040
        } else if (typeof enabledOrMillisecondsOrId === "number") {
9,223✔
2041
            this.expressionMap.cache = true
112✔
2042
            this.expressionMap.cacheDuration = enabledOrMillisecondsOrId
112✔
2043
        } else if (
7,875✔
2044
            typeof enabledOrMillisecondsOrId === "string" ||
7,763✔
2045
            typeof enabledOrMillisecondsOrId === "number"
7,315✔
2046
        ) {
7,763✔
2047
            this.expressionMap.cache = true
448✔
2048
            this.expressionMap.cacheId = enabledOrMillisecondsOrId
448✔
2049
        }
448✔
2050

9,223✔
2051
        if (maybeMilliseconds) {
9,223✔
2052
            this.expressionMap.cacheDuration = maybeMilliseconds
448✔
2053
        }
448✔
2054

9,223✔
2055
        return this
9,223✔
2056
    }
9,223✔
2057

848,396✔
2058
    /**
848,396✔
2059
     * Sets extra options that can be used to configure how query builder works.
848,396✔
2060
     */
848,396✔
2061
    setOption(option: SelectQueryBuilderOption): this {
848,396✔
2062
        this.expressionMap.options.push(option)
9,765✔
2063
        return this
9,765✔
2064
    }
9,765✔
2065

848,396✔
2066
    // -------------------------------------------------------------------------
848,396✔
2067
    // Protected Methods
848,396✔
2068
    // -------------------------------------------------------------------------
848,396✔
2069

848,396✔
2070
    protected join(
848,396✔
2071
        direction: "INNER" | "LEFT",
2,354,232✔
2072
        entityOrProperty:
2,354,232✔
2073
            | Function
2,354,232✔
2074
            | string
2,354,232✔
2075
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
2,354,232✔
2076
        aliasName: string,
2,354,232✔
2077
        condition?: string,
2,354,232✔
2078
        parameters?: ObjectLiteral,
2,354,232✔
2079
        mapToProperty?: string,
2,354,232✔
2080
        isMappingMany?: boolean,
2,354,232✔
2081
        mapAsEntity?: Function | string,
2,354,232✔
2082
    ): void {
2,354,232✔
2083
        if (parameters) {
2,354,232!
2084
            this.setParameters(parameters)
×
2085
        }
×
2086

2,354,232✔
2087
        const joinAttribute = new JoinAttribute(
2,354,232✔
2088
            this.connection,
2,354,232✔
2089
            this.expressionMap,
2,354,232✔
2090
        )
2,354,232✔
2091
        joinAttribute.direction = direction
2,354,232✔
2092
        joinAttribute.mapAsEntity = mapAsEntity
2,354,232✔
2093
        joinAttribute.mapToProperty = mapToProperty
2,354,232✔
2094
        joinAttribute.isMappingMany = isMappingMany
2,354,232✔
2095
        joinAttribute.entityOrProperty = entityOrProperty // relationName
2,354,232✔
2096
        joinAttribute.condition = condition // joinInverseSideCondition
2,354,232✔
2097
        // joinAttribute.junctionAlias = joinAttribute.relation.isOwning ? parentAlias + "_" + destinationTableAlias : destinationTableAlias + "_" + parentAlias;
2,354,232✔
2098
        this.expressionMap.joinAttributes.push(joinAttribute)
2,354,232✔
2099

2,354,232✔
2100
        const joinAttributeMetadata = joinAttribute.metadata
2,354,232✔
2101
        if (joinAttributeMetadata) {
2,354,232✔
2102
            if (
2,354,129✔
2103
                joinAttributeMetadata.deleteDateColumn &&
2,354,129✔
2104
                !this.expressionMap.withDeleted
204✔
2105
            ) {
2,354,129✔
2106
                const conditionDeleteColumn = `${aliasName}.${joinAttributeMetadata.deleteDateColumn.propertyName} IS NULL`
148✔
2107
                joinAttribute.condition = joinAttribute.condition
148✔
2108
                    ? ` ${joinAttribute.condition} AND ${conditionDeleteColumn}`
148!
2109
                    : `${conditionDeleteColumn}`
148✔
2110
            }
148✔
2111
            // todo: find and set metadata right there?
2,354,129✔
2112
            joinAttribute.alias = this.expressionMap.createAlias({
2,354,129✔
2113
                type: "join",
2,354,129✔
2114
                name: aliasName,
2,354,129✔
2115
                metadata: joinAttributeMetadata,
2,354,129✔
2116
            })
2,354,129✔
2117
            if (
2,354,129✔
2118
                joinAttribute.relation &&
2,354,129✔
2119
                joinAttribute.relation.junctionEntityMetadata
2,341,207✔
2120
            ) {
2,354,129✔
2121
                this.expressionMap.createAlias({
1,966,546✔
2122
                    type: "join",
1,966,546✔
2123
                    name: joinAttribute.junctionAlias,
1,966,546✔
2124
                    metadata: joinAttribute.relation.junctionEntityMetadata,
1,966,546✔
2125
                })
1,966,546✔
2126
            }
1,966,546✔
2127
        } else {
2,354,232✔
2128
            let subQuery: string = ""
103✔
2129
            if (typeof entityOrProperty === "function") {
103✔
2130
                const subQueryBuilder: SelectQueryBuilder<any> = (
45✔
2131
                    entityOrProperty as any
45✔
2132
                )((this as any as SelectQueryBuilder<any>).subQuery())
45✔
2133
                this.setParameters(subQueryBuilder.getParameters())
45✔
2134
                subQuery = subQueryBuilder.getQuery()
45✔
2135
            } else {
77✔
2136
                subQuery = entityOrProperty
58✔
2137
            }
58✔
2138
            const isSubQuery =
103✔
2139
                typeof entityOrProperty === "function" ||
103✔
2140
                (entityOrProperty.substr(0, 1) === "(" &&
58✔
2141
                    entityOrProperty.substr(-1) === ")")
58✔
2142
            joinAttribute.alias = this.expressionMap.createAlias({
103✔
2143
                type: "join",
103✔
2144
                name: aliasName,
103✔
2145
                tablePath:
103✔
2146
                    isSubQuery === false
103✔
2147
                        ? (entityOrProperty as string)
103✔
2148
                        : undefined,
103✔
2149
                subQuery: isSubQuery === true ? subQuery : undefined,
103✔
2150
            })
103✔
2151
        }
103✔
2152
    }
2,354,232✔
2153

848,396✔
2154
    /**
848,396✔
2155
     * Creates "SELECT FROM" part of SQL query.
848,396✔
2156
     */
848,396✔
2157
    protected createSelectExpression() {
848,396✔
2158
        if (!this.expressionMap.mainAlias)
534,613✔
2159
            throw new TypeORMError(
534,613!
2160
                "Cannot build query because main alias is not set (call qb#from method)",
×
2161
            )
×
2162

534,613✔
2163
        // todo throw exception if selects or from is missing
534,613✔
2164

534,613✔
2165
        const allSelects: SelectQuery[] = []
534,613✔
2166
        const excludedSelects: SelectQuery[] = []
534,613✔
2167

534,613✔
2168
        if (this.expressionMap.mainAlias.hasMetadata) {
534,613✔
2169
            const metadata = this.expressionMap.mainAlias.metadata
524,076✔
2170
            allSelects.push(
524,076✔
2171
                ...this.buildEscapedEntityColumnSelects(
524,076✔
2172
                    this.expressionMap.mainAlias.name,
524,076✔
2173
                    metadata,
524,076✔
2174
                ),
524,076✔
2175
            )
524,076✔
2176
            excludedSelects.push(
524,076✔
2177
                ...this.findEntityColumnSelects(
524,076✔
2178
                    this.expressionMap.mainAlias.name,
524,076✔
2179
                    metadata,
524,076✔
2180
                ),
524,076✔
2181
            )
524,076✔
2182
        }
524,076✔
2183

534,613✔
2184
        // add selects from joins
534,613✔
2185
        this.expressionMap.joinAttributes.forEach((join) => {
534,613✔
2186
            if (join.metadata) {
2,363,345✔
2187
                allSelects.push(
2,363,242✔
2188
                    ...this.buildEscapedEntityColumnSelects(
2,363,242✔
2189
                        join.alias.name!,
2,363,242✔
2190
                        join.metadata,
2,363,242✔
2191
                    ),
2,363,242✔
2192
                )
2,363,242✔
2193
                excludedSelects.push(
2,363,242✔
2194
                    ...this.findEntityColumnSelects(
2,363,242✔
2195
                        join.alias.name!,
2,363,242✔
2196
                        join.metadata,
2,363,242✔
2197
                    ),
2,363,242✔
2198
                )
2,363,242✔
2199
            } else {
2,363,345✔
2200
                const hasMainAlias = this.expressionMap.selects.some(
103✔
2201
                    (select) => select.selection === join.alias.name,
103✔
2202
                )
103✔
2203
                if (hasMainAlias) {
103!
2204
                    allSelects.push({
17✔
2205
                        selection: this.escape(join.alias.name!) + ".*",
17✔
2206
                    })
17✔
2207
                    const excludedSelect = this.expressionMap.selects.find(
17✔
2208
                        (select) => select.selection === join.alias.name,
17✔
2209
                    )
17✔
2210
                    excludedSelects.push(excludedSelect!)
17✔
2211
                }
17✔
2212
            }
103✔
2213
        })
534,613✔
2214

534,613✔
2215
        // add all other selects
534,613✔
2216
        this.expressionMap.selects
534,613✔
2217
            .filter((select) => excludedSelects.indexOf(select) === -1)
534,613✔
2218
            .forEach((select) =>
534,613✔
2219
                allSelects.push({
14,581✔
2220
                    selection: this.replacePropertyNames(select.selection),
14,581✔
2221
                    aliasName: select.aliasName,
14,581✔
2222
                }),
534,613✔
2223
            )
534,613✔
2224

534,613✔
2225
        // if still selection is empty, then simply set it to all (*)
534,613✔
2226
        if (allSelects.length === 0) allSelects.push({ selection: "*" })
534,613✔
2227

534,613✔
2228
        // Use certain index
534,613✔
2229
        let useIndex: string = ""
534,613✔
2230
        if (this.expressionMap.useIndex) {
534,613!
2231
            if (DriverUtils.isMySQLFamily(this.connection.driver)) {
×
2232
                useIndex = ` USE INDEX (${this.expressionMap.useIndex})`
×
2233
            }
×
2234
        }
×
2235

534,613✔
2236
        // create a selection query
534,613✔
2237
        const froms = this.expressionMap.aliases
534,613✔
2238
            .filter(
534,613✔
2239
                (alias) =>
534,613✔
2240
                    alias.type === "from" &&
4,886,662✔
2241
                    (alias.tablePath || alias.subQuery),
534,613✔
2242
            )
534,613✔
2243
            .map((alias) => {
534,613✔
2244
                if (alias.subQuery)
534,725✔
2245
                    return alias.subQuery + " " + this.escape(alias.name)
534,725✔
2246

526,842✔
2247
                return (
526,842✔
2248
                    this.getTableName(alias.tablePath!) +
526,842✔
2249
                    " " +
526,842✔
2250
                    this.escape(alias.name)
526,842✔
2251
                )
526,842✔
2252
            })
534,613✔
2253

534,613✔
2254
        const select = this.createSelectDistinctExpression()
534,613✔
2255
        const selection = allSelects
534,613✔
2256
            .map(
534,613✔
2257
                (select) =>
534,613✔
2258
                    select.selection +
9,276,000✔
2259
                    (select.aliasName
9,276,000✔
2260
                        ? " AS " + this.escape(select.aliasName)
9,276,000✔
2261
                        : ""),
534,613✔
2262
            )
534,613✔
2263
            .join(", ")
534,613✔
2264

534,613✔
2265
        return (
534,613✔
2266
            select +
534,613✔
2267
            selection +
534,613✔
2268
            " FROM " +
534,613✔
2269
            froms.join(", ") +
534,613✔
2270
            this.createTableLockExpression() +
534,613✔
2271
            useIndex
534,613✔
2272
        )
534,613✔
2273
    }
534,613✔
2274

848,396✔
2275
    /**
848,396✔
2276
     * Creates select | select distinct part of SQL query.
848,396✔
2277
     */
848,396✔
2278
    protected createSelectDistinctExpression(): string {
848,396✔
2279
        const { selectDistinct, selectDistinctOn, maxExecutionTime } =
534,613✔
2280
            this.expressionMap
534,613✔
2281
        const { driver } = this.connection
534,613✔
2282

534,613✔
2283
        let select = "SELECT "
534,613✔
2284

534,613✔
2285
        if (maxExecutionTime > 0) {
534,613!
2286
            if (DriverUtils.isMySQLFamily(driver)) {
×
2287
                select += `/*+ MAX_EXECUTION_TIME(${this.expressionMap.maxExecutionTime}) */ `
×
2288
            }
×
2289
        }
×
2290

534,613✔
2291
        if (
534,613✔
2292
            DriverUtils.isPostgresFamily(driver) &&
534,613!
2293
            selectDistinctOn.length > 0
129,518✔
2294
        ) {
534,613!
2295
            const selectDistinctOnMap = selectDistinctOn
12✔
2296
                .map((on) => this.replacePropertyNames(on))
12✔
2297
                .join(", ")
12✔
2298

12✔
2299
            select = `SELECT DISTINCT ON (${selectDistinctOnMap}) `
12✔
2300
        } else if (selectDistinct) {
534,613✔
2301
            select = "SELECT DISTINCT "
59✔
2302
        }
59✔
2303

534,613✔
2304
        return select
534,613✔
2305
    }
534,613✔
2306

848,396✔
2307
    /**
848,396✔
2308
     * Creates "JOIN" part of SQL query.
848,396✔
2309
     */
848,396✔
2310
    protected createJoinExpression(): string {
848,396✔
2311
        // examples:
534,613✔
2312
        // select from owning side
534,613✔
2313
        // qb.select("post")
534,613✔
2314
        //     .leftJoinAndSelect("post.category", "category");
534,613✔
2315
        // select from non-owning side
534,613✔
2316
        // qb.select("category")
534,613✔
2317
        //     .leftJoinAndSelect("category.post", "post");
534,613✔
2318

534,613✔
2319
        const joins = this.expressionMap.joinAttributes.map((joinAttr) => {
534,613✔
2320
            const relation = joinAttr.relation
2,363,345✔
2321
            const destinationTableName = joinAttr.tablePath
2,363,345✔
2322
            const destinationTableAlias = joinAttr.alias.name
2,363,345✔
2323
            let appendedCondition = joinAttr.condition
2,363,345✔
2324
                ? " AND (" + joinAttr.condition + ")"
2,363,345✔
2325
                : ""
2,363,345✔
2326
            const parentAlias = joinAttr.parentAlias
2,363,345✔
2327

2,363,345✔
2328
            // if join was build without relation (e.g. without "post.category") then it means that we have direct
2,363,345✔
2329
            // table to join, without junction table involved. This means we simply join direct table.
2,363,345✔
2330
            if (!parentAlias || !relation) {
2,363,345✔
2331
                const destinationJoin = joinAttr.alias.subQuery
13,025✔
2332
                    ? joinAttr.alias.subQuery
13,025✔
2333
                    : this.getTableName(destinationTableName)
13,025✔
2334
                return (
13,025✔
2335
                    " " +
13,025✔
2336
                    joinAttr.direction +
13,025✔
2337
                    " JOIN " +
13,025✔
2338
                    destinationJoin +
13,025✔
2339
                    " " +
13,025✔
2340
                    this.escape(destinationTableAlias) +
13,025✔
2341
                    this.createTableLockExpression() +
13,025✔
2342
                    (joinAttr.condition
13,025✔
2343
                        ? " ON " + this.replacePropertyNames(joinAttr.condition)
13,025✔
2344
                        : "")
13,025!
2345
                )
13,025✔
2346
            }
13,025✔
2347

2,350,320✔
2348
            // if real entity relation is involved
2,350,320✔
2349
            if (relation.isManyToOne || relation.isOneToOneOwner) {
2,363,345✔
2350
                // JOIN `category` `category` ON `category`.`id` = `post`.`categoryId`
15,256✔
2351
                const condition = relation.joinColumns
15,256✔
2352
                    .map((joinColumn) => {
15,256✔
2353
                        return (
16,356✔
2354
                            destinationTableAlias +
16,356✔
2355
                            "." +
16,356✔
2356
                            joinColumn.referencedColumn!.propertyPath +
16,356✔
2357
                            "=" +
16,356✔
2358
                            parentAlias +
16,356✔
2359
                            "." +
16,356✔
2360
                            relation.propertyPath +
16,356✔
2361
                            "." +
16,356✔
2362
                            joinColumn.referencedColumn!.propertyPath
16,356✔
2363
                        )
16,356✔
2364
                    })
15,256✔
2365
                    .join(" AND ")
15,256✔
2366

15,256✔
2367
                return (
15,256✔
2368
                    " " +
15,256✔
2369
                    joinAttr.direction +
15,256✔
2370
                    " JOIN " +
15,256✔
2371
                    this.getTableName(destinationTableName) +
15,256✔
2372
                    " " +
15,256✔
2373
                    this.escape(destinationTableAlias) +
15,256✔
2374
                    this.createTableLockExpression() +
15,256✔
2375
                    " ON " +
15,256✔
2376
                    this.replacePropertyNames(condition + appendedCondition)
15,256✔
2377
                )
15,256✔
2378
            } else if (relation.isOneToMany || relation.isOneToOneNotOwner) {
2,363,345✔
2379
                // JOIN `post` `post` ON `post`.`categoryId` = `category`.`id`
366,152✔
2380
                const condition = relation
366,152✔
2381
                    .inverseRelation!.joinColumns.map((joinColumn) => {
366,152✔
2382
                        if (
367,104✔
2383
                            relation.inverseEntityMetadata.tableType ===
367,104✔
2384
                                "entity-child" &&
367,104✔
2385
                            relation.inverseEntityMetadata.discriminatorColumn
112✔
2386
                        ) {
367,104✔
2387
                            appendedCondition +=
112✔
2388
                                " AND " +
112✔
2389
                                destinationTableAlias +
112✔
2390
                                "." +
112✔
2391
                                relation.inverseEntityMetadata
112✔
2392
                                    .discriminatorColumn.databaseName +
112✔
2393
                                "='" +
112✔
2394
                                relation.inverseEntityMetadata
112✔
2395
                                    .discriminatorValue +
112✔
2396
                                "'"
112✔
2397
                        }
112✔
2398

367,104✔
2399
                        return (
367,104✔
2400
                            destinationTableAlias +
367,104✔
2401
                            "." +
367,104✔
2402
                            relation.inverseRelation!.propertyPath +
367,104✔
2403
                            "." +
367,104✔
2404
                            joinColumn.referencedColumn!.propertyPath +
367,104✔
2405
                            "=" +
367,104✔
2406
                            parentAlias +
367,104✔
2407
                            "." +
367,104✔
2408
                            joinColumn.referencedColumn!.propertyPath
367,104✔
2409
                        )
367,104✔
2410
                    })
366,152✔
2411
                    .join(" AND ")
366,152✔
2412

366,152✔
2413
                if (!condition)
366,152✔
2414
                    throw new TypeORMError(
366,152!
2415
                        `Relation ${relation.entityMetadata.name}.${relation.propertyName} does not have join columns.`,
×
2416
                    )
×
2417

366,152✔
2418
                return (
366,152✔
2419
                    " " +
366,152✔
2420
                    joinAttr.direction +
366,152✔
2421
                    " JOIN " +
366,152✔
2422
                    this.getTableName(destinationTableName) +
366,152✔
2423
                    " " +
366,152✔
2424
                    this.escape(destinationTableAlias) +
366,152✔
2425
                    this.createTableLockExpression() +
366,152✔
2426
                    " ON " +
366,152✔
2427
                    this.replacePropertyNames(condition + appendedCondition)
366,152✔
2428
                )
366,152✔
2429
            } else {
2,335,064✔
2430
                // means many-to-many
1,968,912✔
2431
                const junctionTableName =
1,968,912✔
2432
                    relation.junctionEntityMetadata!.tablePath
1,968,912✔
2433

1,968,912✔
2434
                const junctionAlias = joinAttr.junctionAlias
1,968,912✔
2435
                let junctionCondition = "",
1,968,912✔
2436
                    destinationCondition = ""
1,968,912✔
2437

1,968,912✔
2438
                if (relation.isOwning) {
1,968,912✔
2439
                    junctionCondition = relation.joinColumns
1,967,956✔
2440
                        .map((joinColumn) => {
1,967,956✔
2441
                            // `post_category`.`postId` = `post`.`id`
1,968,628✔
2442
                            return (
1,968,628✔
2443
                                junctionAlias +
1,968,628✔
2444
                                "." +
1,968,628✔
2445
                                joinColumn.propertyPath +
1,968,628✔
2446
                                "=" +
1,968,628✔
2447
                                parentAlias +
1,968,628✔
2448
                                "." +
1,968,628✔
2449
                                joinColumn.referencedColumn!.propertyPath
1,968,628✔
2450
                            )
1,968,628✔
2451
                        })
1,967,956✔
2452
                        .join(" AND ")
1,967,956✔
2453

1,967,956✔
2454
                    destinationCondition = relation.inverseJoinColumns
1,967,956✔
2455
                        .map((joinColumn) => {
1,967,956✔
2456
                            // `category`.`id` = `post_category`.`categoryId`
1,968,656✔
2457
                            return (
1,968,656✔
2458
                                destinationTableAlias +
1,968,656✔
2459
                                "." +
1,968,656✔
2460
                                joinColumn.referencedColumn!.propertyPath +
1,968,656✔
2461
                                "=" +
1,968,656✔
2462
                                junctionAlias +
1,968,656✔
2463
                                "." +
1,968,656✔
2464
                                joinColumn.propertyPath
1,968,656✔
2465
                            )
1,968,656✔
2466
                        })
1,967,956✔
2467
                        .join(" AND ")
1,967,956✔
2468
                } else {
1,968,912✔
2469
                    junctionCondition = relation
956✔
2470
                        .inverseRelation!.inverseJoinColumns.map(
956✔
2471
                            (joinColumn) => {
956✔
2472
                                // `post_category`.`categoryId` = `category`.`id`
1,572✔
2473
                                return (
1,572✔
2474
                                    junctionAlias +
1,572✔
2475
                                    "." +
1,572✔
2476
                                    joinColumn.propertyPath +
1,572✔
2477
                                    "=" +
1,572✔
2478
                                    parentAlias +
1,572✔
2479
                                    "." +
1,572✔
2480
                                    joinColumn.referencedColumn!.propertyPath
1,572✔
2481
                                )
1,572✔
2482
                            },
956✔
2483
                        )
956✔
2484
                        .join(" AND ")
956✔
2485

956✔
2486
                    destinationCondition = relation
956✔
2487
                        .inverseRelation!.joinColumns.map((joinColumn) => {
956✔
2488
                            // `post`.`id` = `post_category`.`postId`
1,516✔
2489
                            return (
1,516✔
2490
                                destinationTableAlias +
1,516✔
2491
                                "." +
1,516✔
2492
                                joinColumn.referencedColumn!.propertyPath +
1,516✔
2493
                                "=" +
1,516✔
2494
                                junctionAlias +
1,516✔
2495
                                "." +
1,516✔
2496
                                joinColumn.propertyPath
1,516✔
2497
                            )
1,516✔
2498
                        })
956✔
2499
                        .join(" AND ")
956✔
2500
                }
956✔
2501

1,968,912✔
2502
                return (
1,968,912✔
2503
                    " " +
1,968,912✔
2504
                    joinAttr.direction +
1,968,912✔
2505
                    " JOIN " +
1,968,912✔
2506
                    this.getTableName(junctionTableName) +
1,968,912✔
2507
                    " " +
1,968,912✔
2508
                    this.escape(junctionAlias) +
1,968,912✔
2509
                    this.createTableLockExpression() +
1,968,912✔
2510
                    " ON " +
1,968,912✔
2511
                    this.replacePropertyNames(junctionCondition) +
1,968,912✔
2512
                    " " +
1,968,912✔
2513
                    joinAttr.direction +
1,968,912✔
2514
                    " JOIN " +
1,968,912✔
2515
                    this.getTableName(destinationTableName) +
1,968,912✔
2516
                    " " +
1,968,912✔
2517
                    this.escape(destinationTableAlias) +
1,968,912✔
2518
                    this.createTableLockExpression() +
1,968,912✔
2519
                    " ON " +
1,968,912✔
2520
                    this.replacePropertyNames(
1,968,912✔
2521
                        destinationCondition + appendedCondition,
1,968,912✔
2522
                    )
1,968,912✔
2523
                )
1,968,912✔
2524
            }
1,968,912✔
2525
        })
534,613✔
2526

534,613✔
2527
        return joins.join(" ")
534,613✔
2528
    }
534,613✔
2529

848,396✔
2530
    /**
848,396✔
2531
     * Creates "GROUP BY" part of SQL query.
848,396✔
2532
     */
848,396✔
2533
    protected createGroupByExpression() {
848,396✔
2534
        if (!this.expressionMap.groupBys || !this.expressionMap.groupBys.length)
534,613✔
2535
            return ""
534,613✔
2536
        return (
3,229✔
2537
            " GROUP BY " +
3,229✔
2538
            this.replacePropertyNames(this.expressionMap.groupBys.join(", "))
3,229✔
2539
        )
3,229✔
2540
    }
3,229✔
2541

848,396✔
2542
    /**
848,396✔
2543
     * Creates "ORDER BY" part of SQL query.
848,396✔
2544
     */
848,396✔
2545
    protected createOrderByExpression() {
848,396✔
2546
        const orderBys = this.expressionMap.allOrderBys
534,613✔
2547
        if (Object.keys(orderBys).length === 0) return ""
534,613✔
2548

24,298✔
2549
        return (
24,298✔
2550
            " ORDER BY " +
24,298✔
2551
            Object.keys(orderBys)
24,298✔
2552
                .map((columnName) => {
24,298✔
2553
                    const orderValue =
32,972✔
2554
                        typeof orderBys[columnName] === "string"
32,972✔
2555
                            ? orderBys[columnName]
32,972✔
2556
                            : (orderBys[columnName] as any).order +
32,972!
2557
                              " " +
57✔
2558
                              (orderBys[columnName] as any).nulls
57✔
2559
                    const selection = this.expressionMap.selects.find(
32,972✔
2560
                        (s) => s.selection === columnName,
32,972✔
2561
                    )
32,972✔
2562
                    if (
32,972✔
2563
                        selection &&
32,972✔
2564
                        !selection.aliasName &&
32,972✔
2565
                        columnName.indexOf(".") !== -1
856✔
2566
                    ) {
32,972✔
2567
                        const criteriaParts = columnName.split(".")
628✔
2568
                        const aliasName = criteriaParts[0]
628✔
2569
                        const propertyPath = criteriaParts.slice(1).join(".")
628✔
2570
                        const alias = this.expressionMap.aliases.find(
628✔
2571
                            (alias) => alias.name === aliasName,
628✔
2572
                        )
628✔
2573
                        if (alias) {
628✔
2574
                            const column =
340✔
2575
                                alias.metadata.findColumnWithPropertyPath(
340✔
2576
                                    propertyPath,
340✔
2577
                                )
340✔
2578
                            if (column) {
340✔
2579
                                const orderAlias = DriverUtils.buildAlias(
340✔
2580
                                    this.connection.driver,
340✔
2581
                                    undefined,
340✔
2582
                                    aliasName,
340✔
2583
                                    column.databaseName,
340✔
2584
                                )
340✔
2585
                                return (
340✔
2586
                                    this.escape(orderAlias) + " " + orderValue
340✔
2587
                                )
340✔
2588
                            }
340✔
2589
                        }
340✔
2590
                    }
628✔
2591

32,632✔
2592
                    return (
32,632✔
2593
                        this.replacePropertyNames(columnName) + " " + orderValue
32,632✔
2594
                    )
32,632✔
2595
                })
24,298✔
2596
                .join(", ")
24,298✔
2597
        )
24,298✔
2598
    }
24,298✔
2599

848,396✔
2600
    /**
848,396✔
2601
     * Creates "LIMIT" and "OFFSET" parts of SQL query.
848,396✔
2602
     */
848,396✔
2603
    protected createLimitOffsetExpression(): string {
848,396✔
2604
        // in the case if nothing is joined in the query builder we don't need to make two requests to get paginated results
534,613✔
2605
        // we can use regular limit / offset, that's why we add offset and limit construction here based on skip and take values
534,613✔
2606
        let offset: number | undefined = this.expressionMap.offset,
534,613✔
2607
            limit: number | undefined = this.expressionMap.limit
534,613✔
2608
        if (
534,613✔
2609
            offset === undefined &&
534,613✔
2610
            limit === undefined &&
534,613✔
2611
            this.expressionMap.joinAttributes.length === 0
526,634✔
2612
        ) {
534,613✔
2613
            offset = this.expressionMap.skip
170,713✔
2614
            limit = this.expressionMap.take
170,713✔
2615
        }
170,713✔
2616

534,613✔
2617
        // Helper functions to check if values are set (including 0)
534,613✔
2618
        const hasLimit = limit !== undefined && limit !== null
534,613✔
2619
        const hasOffset = offset !== undefined && offset !== null
534,613✔
2620

534,613✔
2621
        if (this.connection.driver.options.type === "mssql") {
534,613!
2622
            // Due to a limitation in SQL Server's parser implementation it does not support using
34,928✔
2623
            // OFFSET or FETCH NEXT without an ORDER BY clause being provided. In cases where the
34,928✔
2624
            // user does not request one we insert a dummy ORDER BY that does nothing and should
34,928✔
2625
            // have no effect on the query planner or on the order of the results returned.
34,928✔
2626
            // https://dba.stackexchange.com/a/193799
34,928✔
2627
            let prefix = ""
34,928✔
2628
            if (
34,928✔
2629
                (hasLimit || hasOffset) &&
34,928✔
2630
                Object.keys(this.expressionMap.allOrderBys).length <= 0
1,194✔
2631
            ) {
34,928✔
2632
                prefix = " ORDER BY (SELECT NULL)"
594✔
2633
            }
594✔
2634

34,928✔
2635
            if (hasLimit && hasOffset)
34,928✔
2636
                return (
34,928✔
2637
                    prefix +
70✔
2638
                    " OFFSET " +
70✔
2639
                    offset +
70✔
2640
                    " ROWS FETCH NEXT " +
70✔
2641
                    limit +
70✔
2642
                    " ROWS ONLY"
70✔
2643
                )
70✔
2644
            if (hasLimit)
34,858✔
2645
                return (
34,928✔
2646
                    prefix + " OFFSET 0 ROWS FETCH NEXT " + limit + " ROWS ONLY"
1,122✔
2647
                )
1,122✔
2648
            if (hasOffset) return prefix + " OFFSET " + offset + " ROWS"
34,928✔
2649
        } else if (
534,613!
2650
            DriverUtils.isMySQLFamily(this.connection.driver) ||
499,685!
2651
            this.connection.driver.options.type === "aurora-mysql" ||
499,685!
2652
            this.connection.driver.options.type === "sap" ||
499,685!
2653
            this.connection.driver.options.type === "spanner"
322,027✔
2654
        ) {
499,685!
2655
            if (hasLimit && hasOffset)
177,658✔
2656
                return " LIMIT " + limit + " OFFSET " + offset
177,658✔
2657
            if (hasLimit) return " LIMIT " + limit
177,658✔
2658
            if (hasOffset) throw new OffsetWithoutLimitNotSupportedError()
177,658✔
2659
        } else if (DriverUtils.isSQLiteFamily(this.connection.driver)) {
499,685!
2660
            if (hasLimit && hasOffset)
158,445✔
2661
                return " LIMIT " + limit + " OFFSET " + offset
158,445✔
2662
            if (hasLimit) return " LIMIT " + limit
158,445✔
2663
            if (hasOffset) return " LIMIT -1 OFFSET " + offset
158,445✔
2664
        } else if (this.connection.driver.options.type === "oracle") {
322,027!
2665
            if (hasLimit && hasOffset)
34,064✔
2666
                return (
34,064✔
2667
                    " OFFSET " +
70✔
2668
                    offset +
70✔
2669
                    " ROWS FETCH NEXT " +
70✔
2670
                    limit +
70✔
2671
                    " ROWS ONLY"
70✔
2672
                )
70✔
2673
            if (hasLimit) return " FETCH NEXT " + limit + " ROWS ONLY"
34,064✔
2674
            if (hasOffset) return " OFFSET " + offset + " ROWS"
34,064✔
2675
        } else {
163,582!
2676
            if (hasLimit && hasOffset)
129,518✔
2677
                return " LIMIT " + limit + " OFFSET " + offset
129,518✔
2678
            if (hasLimit) return " LIMIT " + limit
129,518✔
2679
            if (hasOffset) return " OFFSET " + offset
129,518✔
2680
        }
129,518✔
2681

516,867✔
2682
        return ""
516,867✔
2683
    }
516,867✔
2684

848,396✔
2685
    /**
848,396✔
2686
     * Creates "LOCK" part of SELECT Query after table Clause
848,396✔
2687
     * ex.
848,396✔
2688
     *  SELECT 1
848,396✔
2689
     *  FROM USER U WITH (NOLOCK)
848,396✔
2690
     *  JOIN ORDER O WITH (NOLOCK)
848,396✔
2691
     *      ON U.ID=O.OrderID
848,396✔
2692
     */
848,396✔
2693
    private createTableLockExpression(): string {
848,396✔
2694
        if (this.connection.driver.options.type === "mssql") {
4,866,870!
2695
            switch (this.expressionMap.lockMode) {
318,642✔
2696
                case "pessimistic_read":
318,642✔
2697
                    return " WITH (HOLDLOCK, ROWLOCK)"
10✔
2698
                case "pessimistic_write":
318,642✔
2699
                    return " WITH (UPDLOCK, ROWLOCK)"
14✔
2700
                case "dirty_read":
318,642✔
2701
                    return " WITH (NOLOCK)"
22✔
2702
            }
318,642✔
2703
        }
318,642✔
2704

4,866,824✔
2705
        return ""
4,866,824✔
2706
    }
4,866,824✔
2707

848,396✔
2708
    /**
848,396✔
2709
     * Creates "LOCK" part of SQL query.
848,396✔
2710
     */
848,396✔
2711
    protected createLockExpression(): string {
848,396✔
2712
        const driver = this.connection.driver
534,603✔
2713

534,603✔
2714
        let lockTablesClause = ""
534,603✔
2715

534,603✔
2716
        if (this.expressionMap.lockTables) {
534,603!
2717
            if (
89✔
2718
                !(
89✔
2719
                    DriverUtils.isPostgresFamily(driver) ||
89!
2720
                    driver.options.type === "cockroachdb"
×
2721
                )
89✔
2722
            ) {
89!
2723
                throw new TypeORMError(
×
2724
                    "Lock tables not supported in selected driver",
×
2725
                )
×
2726
            }
×
2727
            if (this.expressionMap.lockTables.length < 1) {
89✔
2728
                throw new TypeORMError("lockTables cannot be an empty array")
10✔
2729
            }
10✔
2730
            lockTablesClause = " OF " + this.expressionMap.lockTables.join(", ")
79✔
2731
        }
79✔
2732

534,593✔
2733
        let onLockExpression = ""
534,593✔
2734
        if (this.expressionMap.onLocked === "nowait") {
534,603!
2735
            onLockExpression = " NOWAIT"
18✔
2736
        } else if (this.expressionMap.onLocked === "skip_locked") {
534,603!
2737
            onLockExpression = " SKIP LOCKED"
46✔
2738
        }
46✔
2739
        switch (this.expressionMap.lockMode) {
534,593✔
2740
            case "pessimistic_read":
534,603!
2741
                if (
122✔
2742
                    driver.options.type === "mysql" ||
122✔
2743
                    driver.options.type === "aurora-mysql"
96✔
2744
                ) {
122!
2745
                    if (
26✔
2746
                        DriverUtils.isReleaseVersionOrGreater(driver, "8.0.0")
26✔
2747
                    ) {
26!
2748
                        return (
16✔
2749
                            " FOR SHARE" + lockTablesClause + onLockExpression
16✔
2750
                        )
16✔
2751
                    } else {
26!
2752
                        return " LOCK IN SHARE MODE"
10✔
2753
                    }
10✔
2754
                } else if (driver.options.type === "mariadb") {
122!
2755
                    return " LOCK IN SHARE MODE"
16✔
2756
                } else if (DriverUtils.isPostgresFamily(driver)) {
96!
2757
                    return " FOR SHARE" + lockTablesClause + onLockExpression
40✔
2758
                } else if (driver.options.type === "oracle") {
80!
2759
                    return " FOR UPDATE"
8✔
2760
                } else if (driver.options.type === "mssql") {
40!
2761
                    return ""
10✔
2762
                } else {
32!
2763
                    throw new LockNotSupportedOnGivenDriverError()
22✔
2764
                }
22✔
2765
            case "pessimistic_write":
534,603✔
2766
                if (
157✔
2767
                    DriverUtils.isMySQLFamily(driver) ||
157!
2768
                    driver.options.type === "aurora-mysql" ||
157!
2769
                    driver.options.type === "oracle"
119✔
2770
                ) {
157!
2771
                    return " FOR UPDATE" + onLockExpression
46✔
2772
                } else if (
157!
2773
                    DriverUtils.isPostgresFamily(driver) ||
111!
2774
                    driver.options.type === "cockroachdb"
34✔
2775
                ) {
111!
2776
                    return " FOR UPDATE" + lockTablesClause + onLockExpression
77✔
2777
                } else if (driver.options.type === "mssql") {
111!
2778
                    return ""
12✔
2779
                } else {
34!
2780
                    throw new LockNotSupportedOnGivenDriverError()
22✔
2781
                }
22✔
2782
            case "pessimistic_partial_write":
534,603!
2783
                if (DriverUtils.isPostgresFamily(driver)) {
38!
2784
                    return " FOR UPDATE" + lockTablesClause + " SKIP LOCKED"
20✔
2785
                } else if (DriverUtils.isMySQLFamily(driver)) {
38!
2786
                    return " FOR UPDATE SKIP LOCKED"
18✔
2787
                } else {
18!
2788
                    throw new LockNotSupportedOnGivenDriverError()
×
2789
                }
×
2790
            case "pessimistic_write_or_fail":
534,603!
2791
                if (
44✔
2792
                    DriverUtils.isPostgresFamily(driver) ||
44!
2793
                    driver.options.type === "cockroachdb"
22✔
2794
                ) {
44!
2795
                    return " FOR UPDATE" + lockTablesClause + " NOWAIT"
22✔
2796
                } else if (DriverUtils.isMySQLFamily(driver)) {
44!
2797
                    return " FOR UPDATE NOWAIT"
22✔
2798
                } else {
22!
2799
                    throw new LockNotSupportedOnGivenDriverError()
×
2800
                }
×
2801
            case "for_no_key_update":
534,603✔
2802
                if (
45✔
2803
                    DriverUtils.isPostgresFamily(driver) ||
45!
2804
                    driver.options.type === "cockroachdb"
23✔
2805
                ) {
45!
2806
                    return (
22✔
2807
                        " FOR NO KEY UPDATE" +
22✔
2808
                        lockTablesClause +
22✔
2809
                        onLockExpression
22✔
2810
                    )
22✔
2811
                } else {
45!
2812
                    throw new LockNotSupportedOnGivenDriverError()
23✔
2813
                }
23✔
2814
            case "for_key_share":
534,603!
2815
                if (DriverUtils.isPostgresFamily(driver)) {
43!
2816
                    return (
20✔
2817
                        " FOR KEY SHARE" + lockTablesClause + onLockExpression
20✔
2818
                    )
20✔
2819
                } else {
43!
2820
                    throw new LockNotSupportedOnGivenDriverError()
23✔
2821
                }
23✔
2822
            default:
534,603✔
2823
                return ""
534,144✔
2824
        }
534,603✔
2825
    }
534,603✔
2826

848,396✔
2827
    /**
848,396✔
2828
     * Creates "HAVING" part of SQL query.
848,396✔
2829
     */
848,396✔
2830
    protected createHavingExpression() {
848,396✔
2831
        if (!this.expressionMap.havings || !this.expressionMap.havings.length)
534,613✔
2832
            return ""
534,613✔
2833
        const conditions = this.expressionMap.havings
4!
2834
            .map((having, index) => {
4✔
2835
                switch (having.type) {
8✔
2836
                    case "and":
8!
2837
                        return (
×
2838
                            (index > 0 ? "AND " : "") +
×
2839
                            this.replacePropertyNames(having.condition)
×
2840
                        )
×
2841
                    case "or":
8✔
2842
                        return (
4✔
2843
                            (index > 0 ? "OR " : "") +
4!
2844
                            this.replacePropertyNames(having.condition)
4✔
2845
                        )
4✔
2846
                    default:
8✔
2847
                        return this.replacePropertyNames(having.condition)
4✔
2848
                }
8✔
2849
            })
4✔
2850
            .join(" ")
4✔
2851

4✔
2852
        if (!conditions.length) return ""
142,666!
2853
        return " HAVING " + conditions
4✔
2854
    }
4✔
2855

848,396✔
2856
    protected buildEscapedEntityColumnSelects(
848,396✔
2857
        aliasName: string,
2,887,318✔
2858
        metadata: EntityMetadata,
2,887,318✔
2859
    ): SelectQuery[] {
2,887,318✔
2860
        const hasMainAlias = this.expressionMap.selects.some(
2,887,318✔
2861
            (select) => select.selection === aliasName,
2,887,318✔
2862
        )
2,887,318✔
2863

2,887,318✔
2864
        const columns: ColumnMetadata[] = []
2,887,318✔
2865
        if (hasMainAlias) {
2,887,318✔
2866
            columns.push(
2,841,360✔
2867
                ...metadata.columns.filter(
2,841,360✔
2868
                    (column) => column.isSelect === true,
2,841,360✔
2869
                ),
2,841,360✔
2870
            )
2,841,360✔
2871
        }
2,841,360✔
2872
        columns.push(
2,887,318✔
2873
            ...metadata.columns.filter((column) => {
2,887,318✔
2874
                return this.expressionMap.selects.some(
9,368,654✔
2875
                    (select) =>
9,368,654✔
2876
                        select.selection ===
77,142,469✔
2877
                        aliasName + "." + column.propertyPath,
9,368,654✔
2878
                )
9,368,654✔
2879
            }),
2,887,318✔
2880
        )
2,887,318✔
2881

2,887,318✔
2882
        // if user used partial selection and did not select some primary columns which are required to be selected
2,887,318✔
2883
        // we select those primary columns and mark them as "virtual". Later virtual column values will be removed from final entity
2,887,318✔
2884
        // to make entity contain exactly what user selected
2,887,318✔
2885
        if (columns.length === 0)
2,887,318✔
2886
            // however not in the case when nothing (even partial) was selected from this target (for example joins without selection)
2,887,318✔
2887
            return []
2,887,318✔
2888

2,872,355✔
2889
        const nonSelectedPrimaryColumns = this.expressionMap.queryEntity
2,872,355✔
2890
            ? metadata.primaryColumns.filter(
2,887,318✔
2891
                  (primaryColumn) => columns.indexOf(primaryColumn) === -1,
177,390✔
2892
              )
2,887,318✔
2893
            : []
2,887,318✔
2894
        const allColumns = [...columns, ...nonSelectedPrimaryColumns]
2,887,318✔
2895
        const finalSelects: SelectQuery[] = []
2,887,318✔
2896

2,887,318✔
2897
        const escapedAliasName = this.escape(aliasName)
2,887,318✔
2898
        allColumns.forEach((column) => {
2,887,318✔
2899
            let selectionPath =
9,258,774✔
2900
                escapedAliasName + "." + this.escape(column.databaseName)
9,258,774✔
2901

9,258,774✔
2902
            if (column.isVirtualProperty && column.query) {
9,258,774✔
2903
                selectionPath = `(${column.query(escapedAliasName)})`
538✔
2904
            }
538✔
2905

9,258,774✔
2906
            if (
9,258,774✔
2907
                this.connection.driver.spatialTypes.indexOf(column.type) !== -1
9,258,774✔
2908
            ) {
9,258,774!
2909
                if (
272✔
2910
                    DriverUtils.isMySQLFamily(this.connection.driver) ||
272!
2911
                    this.connection.driver.options.type === "aurora-mysql"
196✔
2912
                ) {
272!
2913
                    const useLegacy = (
76✔
2914
                        this.connection.driver as
76✔
2915
                            | MysqlDriver
76✔
2916
                            | AuroraMysqlDriver
76✔
2917
                    ).options.legacySpatialSupport
76✔
2918
                    const asText = useLegacy ? "AsText" : "ST_AsText"
76✔
2919
                    selectionPath = `${asText}(${selectionPath})`
76✔
2920
                }
76✔
2921

272✔
2922
                if (DriverUtils.isPostgresFamily(this.connection.driver))
272✔
2923
                    if (column.precision) {
272!
2924
                        // cast to JSON to trigger parsing in the driver
×
2925
                        selectionPath = `ST_AsGeoJSON(${selectionPath}, ${column.precision})::json`
×
2926
                    } else {
168✔
2927
                        selectionPath = `ST_AsGeoJSON(${selectionPath})::json`
168✔
2928
                    }
168✔
2929
                if (this.connection.driver.options.type === "mssql")
272✔
2930
                    selectionPath = `${selectionPath}.ToString()`
272!
2931
            }
272✔
2932

9,258,774✔
2933
            const selections = this.expressionMap.selects.filter(
9,258,774✔
2934
                (select) =>
9,258,774✔
2935
                    select.selection === aliasName + "." + column.propertyPath,
9,258,774✔
2936
            )
9,258,774✔
2937
            if (selections.length) {
9,258,774✔
2938
                selections.forEach((selection) => {
57,253✔
2939
                    finalSelects.push({
57,253✔
2940
                        selection: selectionPath,
57,253✔
2941
                        aliasName: selection.aliasName
57,253✔
2942
                            ? selection.aliasName
57,253✔
2943
                            : DriverUtils.buildAlias(
57,253✔
2944
                                  this.connection.driver,
22,496✔
2945
                                  undefined,
22,496✔
2946
                                  aliasName,
22,496✔
2947
                                  column.databaseName,
22,496✔
2948
                              ),
57,253✔
2949
                        // todo: need to keep in mind that custom selection.aliasName breaks hydrator. fix it later!
57,253✔
2950
                        virtual: selection.virtual,
57,253✔
2951
                    })
57,253✔
2952
                })
57,253✔
2953
            } else {
9,258,774✔
2954
                finalSelects.push({
9,201,521✔
2955
                    selection: selectionPath,
9,201,521✔
2956
                    aliasName: DriverUtils.buildAlias(
9,201,521✔
2957
                        this.connection.driver,
9,201,521✔
2958
                        undefined,
9,201,521✔
2959
                        aliasName,
9,201,521✔
2960
                        column.databaseName,
9,201,521✔
2961
                    ),
9,201,521✔
2962
                    // todo: need to keep in mind that custom selection.aliasName breaks hydrator. fix it later!
9,201,521✔
2963
                    virtual: hasMainAlias,
9,201,521✔
2964
                })
9,201,521✔
2965
            }
9,201,521✔
2966
        })
2,887,318✔
2967
        return finalSelects
2,887,318✔
2968
    }
2,887,318✔
2969

848,396✔
2970
    protected findEntityColumnSelects(
848,396✔
2971
        aliasName: string,
2,887,318✔
2972
        metadata: EntityMetadata,
2,887,318✔
2973
    ): SelectQuery[] {
2,887,318✔
2974
        return this.expressionMap.selects.filter(
2,887,318✔
2975
            (select) =>
2,887,318✔
2976
                select.selection === aliasName ||
22,301,307✔
2977
                metadata.columns.some(
19,459,947✔
2978
                    (column) =>
19,459,947✔
2979
                        select.selection ===
67,891,652✔
2980
                        aliasName + "." + column.propertyPath,
19,459,947✔
2981
                ),
2,887,318✔
2982
        )
2,887,318✔
2983
    }
2,887,318✔
2984

848,396✔
2985
    private computeCountExpression() {
848,396✔
2986
        const mainAlias = this.expressionMap.mainAlias!.name // todo: will this work with "fromTableName"?
1,016✔
2987
        const metadata = this.expressionMap.mainAlias!.metadata
1,016✔
2988

1,016✔
2989
        const primaryColumns = metadata.primaryColumns
1,016✔
2990
        const distinctAlias = this.escape(mainAlias)
1,016✔
2991

1,016✔
2992
        // If we aren't doing anything that will create a join, we can use a simpler `COUNT` instead
1,016✔
2993
        // so we prevent poor query patterns in the most likely cases
1,016✔
2994
        if (
1,016✔
2995
            this.expressionMap.joinAttributes.length === 0 &&
1,016✔
2996
            this.expressionMap.relationIdAttributes.length === 0 &&
1,016✔
2997
            this.expressionMap.relationCountAttributes.length === 0
876✔
2998
        ) {
1,016✔
2999
            return "COUNT(1)"
876✔
3000
        }
876✔
3001

140✔
3002
        // For everything else, we'll need to do some hackery to get the correct count values.
140✔
3003

140✔
3004
        if (
140✔
3005
            this.connection.driver.options.type === "cockroachdb" ||
140!
3006
            DriverUtils.isPostgresFamily(this.connection.driver)
135✔
3007
        ) {
1,016!
3008
            // Postgres and CockroachDB can pass multiple parameters to the `DISTINCT` function
25✔
3009
            // https://www.postgresql.org/docs/9.5/sql-select.html#SQL-DISTINCT
25✔
3010
            return (
25✔
3011
                "COUNT(DISTINCT(" +
25✔
3012
                primaryColumns
25✔
3013
                    .map(
25✔
3014
                        (c) =>
25✔
3015
                            `${distinctAlias}.${this.escape(c.databaseName)}`,
25✔
3016
                    )
25✔
3017
                    .join(", ") +
25✔
3018
                "))"
25✔
3019
            )
25✔
3020
        }
25✔
3021

115!
3022
        if (DriverUtils.isMySQLFamily(this.connection.driver)) {
580!
3023
            // MySQL & MariaDB can pass multiple parameters to the `DISTINCT` language construct
40✔
3024
            // https://mariadb.com/kb/en/count-distinct/
40✔
3025
            return (
40✔
3026
                "COUNT(DISTINCT " +
40✔
3027
                primaryColumns
40✔
3028
                    .map(
40✔
3029
                        (c) =>
40✔
3030
                            `${distinctAlias}.${this.escape(c.databaseName)}`,
40✔
3031
                    )
40✔
3032
                    .join(", ") +
40✔
3033
                ")"
40✔
3034
            )
40✔
3035
        }
40✔
3036

75!
3037
        if (this.connection.driver.options.type === "mssql") {
478!
3038
            // SQL Server has gotta be different from everyone else.  They don't support
10✔
3039
            // distinct counting multiple columns & they don't have the same operator
10✔
3040
            // characteristic for concatenating, so we gotta use the `CONCAT` function.
10✔
3041
            // However, If it's exactly 1 column we can omit the `CONCAT` for better performance.
10✔
3042

10✔
3043
            const columnsExpression = primaryColumns
10✔
3044
                .map(
10✔
3045
                    (primaryColumn) =>
10✔
3046
                        `${distinctAlias}.${this.escape(
16✔
3047
                            primaryColumn.databaseName,
16✔
3048
                        )}`,
10✔
3049
                )
10✔
3050
                .join(", '|;|', ")
10✔
3051

10✔
3052
            if (primaryColumns.length === 1) {
10✔
3053
                return `COUNT(DISTINCT(${columnsExpression}))`
6✔
3054
            }
6✔
3055

4✔
3056
            return `COUNT(DISTINCT(CONCAT(${columnsExpression})))`
4✔
3057
        }
4✔
3058

65✔
3059
        if (this.connection.driver.options.type === "spanner") {
468!
3060
            // spanner also has gotta be different from everyone else.
×
3061
            // they do not support concatenation of different column types without casting them to string
×
3062

×
3063
            if (primaryColumns.length === 1) {
×
3064
                return `COUNT(DISTINCT(${distinctAlias}.${this.escape(
×
3065
                    primaryColumns[0].databaseName,
×
3066
                )}))`
×
3067
            }
×
3068

×
3069
            const columnsExpression = primaryColumns
×
3070
                .map(
×
3071
                    (primaryColumn) =>
×
3072
                        `CAST(${distinctAlias}.${this.escape(
×
3073
                            primaryColumn.databaseName,
×
3074
                        )} AS STRING)`,
×
3075
                )
×
3076
                .join(", '|;|', ")
×
3077
            return `COUNT(DISTINCT(CONCAT(${columnsExpression})))`
×
3078
        }
×
3079

65✔
3080
        // If all else fails, fall back to a `COUNT` and `DISTINCT` across all the primary columns concatenated.
65✔
3081
        // Per the SQL spec, this is the canonical string concatenation mechanism which is most
65✔
3082
        // likely to work across servers implementing the SQL standard.
65✔
3083

65✔
3084
        // Please note, if there is only one primary column that the concatenation does not occur in this
65✔
3085
        // query and the query is a standard `COUNT DISTINCT` in that case.
65✔
3086

65✔
3087
        return (
65✔
3088
            `COUNT(DISTINCT(` +
65✔
3089
            primaryColumns
65✔
3090
                .map((c) => `${distinctAlias}.${this.escape(c.databaseName)}`)
65✔
3091
                .join(" || '|;|' || ") +
65✔
3092
            "))"
65✔
3093
        )
65✔
3094
    }
65✔
3095

848,396✔
3096
    protected async executeCountQuery(
848,396✔
3097
        queryRunner: QueryRunner,
1,016✔
3098
    ): Promise<number> {
1,016✔
3099
        const countSql = this.computeCountExpression()
1,016✔
3100

1,016✔
3101
        const results = await this.clone()
1,016✔
3102
            .orderBy()
1,016✔
3103
            .groupBy()
1,016✔
3104
            .offset(undefined)
1,016✔
3105
            .limit(undefined)
1,016✔
3106
            .skip(undefined)
1,016✔
3107
            .take(undefined)
1,016✔
3108
            .select(countSql, "cnt")
1,016✔
3109
            .setOption("disable-global-order")
1,016✔
3110
            .loadRawResults(queryRunner)
1,016✔
3111

1,016✔
3112
        if (!results || !results[0] || !results[0]["cnt"]) return 0
1,016!
3113

986✔
3114
        return parseInt(results[0]["cnt"])
986✔
3115
    }
986✔
3116

848,396✔
3117
    protected async executeExistsQuery(
848,396✔
3118
        queryRunner: QueryRunner,
196✔
3119
    ): Promise<boolean> {
196✔
3120
        const results = await this.connection
196✔
3121
            .createQueryBuilder()
196✔
3122
            .fromDummy()
196✔
3123
            .select("1", "row_exists")
196✔
3124
            .whereExists(this)
196✔
3125
            .limit(1)
196✔
3126
            .loadRawResults(queryRunner)
196✔
3127

196✔
3128
        return results.length > 0
196✔
3129
    }
196✔
3130

848,396✔
3131
    protected applyFindOptions() {
848,396✔
3132
        // todo: convert relations: string[] to object map to simplify code
183,772✔
3133
        // todo: same with selects
183,772✔
3134

183,772✔
3135
        if (this.expressionMap.mainAlias!.metadata) {
183,772✔
3136
            if (this.findOptions.relationLoadStrategy) {
183,772!
3137
                this.expressionMap.relationLoadStrategy =
24✔
3138
                    this.findOptions.relationLoadStrategy
24✔
3139
            }
24✔
3140

183,772✔
3141
            if (this.findOptions.comment) {
183,772✔
3142
                this.comment(this.findOptions.comment)
28✔
3143
            }
28✔
3144

183,772✔
3145
            if (this.findOptions.withDeleted) {
183,772✔
3146
                this.withDeleted()
118,057✔
3147
            }
118,057✔
3148

183,772✔
3149
            if (this.findOptions.select) {
183,772✔
3150
                const select = Array.isArray(this.findOptions.select)
723✔
3151
                    ? OrmUtils.propertyPathsToTruthyObject(
723!
3152
                          this.findOptions.select as string[],
×
3153
                      )
723✔
3154
                    : this.findOptions.select
723✔
3155

723✔
3156
                this.buildSelect(
723✔
3157
                    select,
723✔
3158
                    this.expressionMap.mainAlias!.metadata,
723✔
3159
                    this.expressionMap.mainAlias!.name,
723✔
3160
                )
723✔
3161
            }
723✔
3162

183,744✔
3163
            if (this.selects.length) {
183,772✔
3164
                this.select(this.selects)
639✔
3165
            }
639✔
3166

183,744✔
3167
            this.selects = []
183,744✔
3168

183,744✔
3169
            if (this.findOptions.relations) {
183,772✔
3170
                const relations = Array.isArray(this.findOptions.relations)
47,258✔
3171
                    ? OrmUtils.propertyPathsToTruthyObject(
47,258✔
3172
                          this.findOptions.relations,
140✔
3173
                      )
47,258✔
3174
                    : this.findOptions.relations
47,258✔
3175

47,258✔
3176
                this.buildRelations(
47,258✔
3177
                    relations,
47,258✔
3178
                    typeof this.findOptions.select === "object"
47,258✔
3179
                        ? (this.findOptions.select as FindOptionsSelect<any>)
47,258✔
3180
                        : undefined,
47,258✔
3181
                    this.expressionMap.mainAlias!.metadata,
47,258✔
3182
                    this.expressionMap.mainAlias!.name,
47,258✔
3183
                )
47,258✔
3184
                if (
47,258✔
3185
                    this.findOptions.loadEagerRelations !== false &&
47,258✔
3186
                    this.expressionMap.relationLoadStrategy === "join"
47,090✔
3187
                ) {
47,258✔
3188
                    this.buildEagerRelations(
47,066✔
3189
                        relations,
47,066✔
3190
                        typeof this.findOptions.select === "object"
47,066✔
3191
                            ? (this.findOptions
47,066✔
3192
                                  .select as FindOptionsSelect<any>)
280✔
3193
                            : undefined,
47,066✔
3194
                        this.expressionMap.mainAlias!.metadata,
47,066✔
3195
                        this.expressionMap.mainAlias!.name,
47,066✔
3196
                    )
47,066✔
3197
                }
47,066✔
3198
            }
47,258✔
3199
            if (this.selects.length) {
183,772✔
3200
                this.addSelect(this.selects)
224✔
3201
            }
224✔
3202

183,576✔
3203
            if (this.findOptions.where) {
183,772✔
3204
                this.conditions = this.buildWhere(
60,342✔
3205
                    this.findOptions.where,
60,342✔
3206
                    this.expressionMap.mainAlias!.metadata,
60,342✔
3207
                    this.expressionMap.mainAlias!.name,
60,342✔
3208
                )
60,342✔
3209

60,342✔
3210
                if (this.conditions.length)
60,342✔
3211
                    this.andWhere(
60,342✔
3212
                        this.conditions.substr(0, 1) !== "("
59,285✔
3213
                            ? "(" + this.conditions + ")"
59,285!
3214
                            : this.conditions,
59,285✔
3215
                    ) // temporary and where and braces
60,342✔
3216
            }
60,342✔
3217

183,296✔
3218
            if (this.findOptions.order) {
183,772✔
3219
                this.buildOrder(
2,586✔
3220
                    this.findOptions.order,
2,586✔
3221
                    this.expressionMap.mainAlias!.metadata,
2,586✔
3222
                    this.expressionMap.mainAlias!.name,
2,586✔
3223
                )
2,586✔
3224
            }
2,586✔
3225

183,268✔
3226
            // apply joins
183,268✔
3227
            if (this.joins.length) {
183,772✔
3228
                this.joins.forEach((join) => {
47,658✔
3229
                    if (join.select && !join.selection) {
369,700✔
3230
                        // if (join.selection) {
368,600✔
3231
                        //
368,600✔
3232
                        // } else {
368,600✔
3233
                        if (join.type === "inner") {
368,600!
3234
                            this.innerJoinAndSelect(
×
3235
                                `${join.parentAlias}.${join.relationMetadata.propertyPath}`,
×
3236
                                join.alias,
×
3237
                            )
×
3238
                        } else {
368,600✔
3239
                            this.leftJoinAndSelect(
368,600✔
3240
                                `${join.parentAlias}.${join.relationMetadata.propertyPath}`,
368,600✔
3241
                                join.alias,
368,600✔
3242
                            )
368,600✔
3243
                        }
368,600✔
3244
                        // }
368,600✔
3245
                    } else {
369,700✔
3246
                        if (join.type === "inner") {
1,100!
3247
                            this.innerJoin(
×
3248
                                `${join.parentAlias}.${join.relationMetadata.propertyPath}`,
×
3249
                                join.alias,
×
3250
                            )
×
3251
                        } else {
1,100✔
3252
                            this.leftJoin(
1,100✔
3253
                                `${join.parentAlias}.${join.relationMetadata.propertyPath}`,
1,100✔
3254
                                join.alias,
1,100✔
3255
                            )
1,100✔
3256
                        }
1,100✔
3257
                    }
1,100✔
3258

369,700✔
3259
                    // if (join.select) {
369,700✔
3260
                    //     if (this.findOptions.loadEagerRelations !== false) {
369,700✔
3261
                    //         FindOptionsUtils.joinEagerRelations(
369,700✔
3262
                    //             this,
369,700✔
3263
                    //             join.alias,
369,700✔
3264
                    //             join.relationMetadata.inverseEntityMetadata
369,700✔
3265
                    //         );
369,700✔
3266
                    //     }
369,700✔
3267
                    // }
369,700✔
3268
                })
47,658✔
3269
            }
47,658✔
3270

183,268✔
3271
            // if (this.conditions.length) {
183,268✔
3272
            //     this.where(this.conditions.join(" AND "));
183,268✔
3273
            // }
183,268✔
3274

183,268✔
3275
            // apply offset
183,268✔
3276
            if (this.findOptions.skip !== undefined) {
183,772✔
3277
                // if (this.findOptions.options && this.findOptions.options.pagination === false) {
172✔
3278
                //     this.offset(this.findOptions.skip);
172✔
3279
                // } else {
172✔
3280
                this.skip(this.findOptions.skip)
172✔
3281
                // }
172✔
3282
            }
172✔
3283

183,240✔
3284
            // apply limit
183,240✔
3285
            if (this.findOptions.take !== undefined) {
183,772✔
3286
                // if (this.findOptions.options && this.findOptions.options.pagination === false) {
16,377✔
3287
                //     this.limit(this.findOptions.take);
16,377✔
3288
                // } else {
16,377✔
3289
                this.take(this.findOptions.take)
16,377✔
3290
                // }
16,377✔
3291
            }
16,377✔
3292

183,212✔
3293
            // apply caching options
183,212✔
3294
            if (typeof this.findOptions.cache === "number") {
183,772✔
3295
                this.cache(this.findOptions.cache)
56✔
3296
            } else if (typeof this.findOptions.cache === "boolean") {
183,772✔
3297
                this.cache(this.findOptions.cache)
84✔
3298
            } else if (typeof this.findOptions.cache === "object") {
183,156✔
3299
                this.cache(
140✔
3300
                    this.findOptions.cache.id,
140✔
3301
                    this.findOptions.cache.milliseconds,
140✔
3302
                )
140✔
3303
            }
140✔
3304

183,212✔
3305
            if (this.findOptions.join) {
183,772✔
3306
                if (this.findOptions.join.leftJoin)
649✔
3307
                    Object.keys(this.findOptions.join.leftJoin).forEach(
649!
3308
                        (key) => {
×
3309
                            this.leftJoin(
×
3310
                                this.findOptions.join!.leftJoin![key],
×
3311
                                key,
×
3312
                            )
×
3313
                        },
×
3314
                    )
×
3315

649✔
3316
                if (this.findOptions.join.innerJoin)
649✔
3317
                    Object.keys(this.findOptions.join.innerJoin).forEach(
649!
3318
                        (key) => {
×
3319
                            this.innerJoin(
×
3320
                                this.findOptions.join!.innerJoin![key],
×
3321
                                key,
×
3322
                            )
×
3323
                        },
×
3324
                    )
×
3325

649✔
3326
                if (this.findOptions.join.leftJoinAndSelect)
649✔
3327
                    Object.keys(
649✔
3328
                        this.findOptions.join.leftJoinAndSelect,
392✔
3329
                    ).forEach((key) => {
392✔
3330
                        this.leftJoinAndSelect(
588✔
3331
                            this.findOptions.join!.leftJoinAndSelect![key],
588✔
3332
                            key,
588✔
3333
                        )
588✔
3334
                    })
392✔
3335

649✔
3336
                if (this.findOptions.join.innerJoinAndSelect)
649✔
3337
                    Object.keys(
649✔
3338
                        this.findOptions.join.innerJoinAndSelect,
257✔
3339
                    ).forEach((key) => {
257✔
3340
                        this.innerJoinAndSelect(
262✔
3341
                            this.findOptions.join!.innerJoinAndSelect![key],
262✔
3342
                            key,
262✔
3343
                        )
262✔
3344
                    })
257✔
3345
            }
649✔
3346

183,212✔
3347
            if (this.findOptions.lock) {
183,772✔
3348
                if (this.findOptions.lock.mode === "optimistic") {
440✔
3349
                    this.setLock(
244✔
3350
                        this.findOptions.lock.mode,
244✔
3351
                        this.findOptions.lock.version,
244✔
3352
                    )
244✔
3353
                } else if (
440✔
3354
                    this.findOptions.lock.mode === "pessimistic_read" ||
196✔
3355
                    this.findOptions.lock.mode === "pessimistic_write" ||
196!
3356
                    this.findOptions.lock.mode === "dirty_read" ||
196!
3357
                    this.findOptions.lock.mode ===
24✔
3358
                        "pessimistic_partial_write" ||
196!
3359
                    this.findOptions.lock.mode ===
20✔
3360
                        "pessimistic_write_or_fail" ||
196!
3361
                    this.findOptions.lock.mode === "for_no_key_update" ||
196!
3362
                    this.findOptions.lock.mode === "for_key_share"
8✔
3363
                ) {
196✔
3364
                    const tableNames = this.findOptions.lock.tables
196✔
3365
                        ? this.findOptions.lock.tables.map((table) => {
196!
3366
                              const tableAlias =
39✔
3367
                                  this.expressionMap.aliases.find((alias) => {
39✔
3368
                                      return (
59✔
3369
                                          alias.metadata
59✔
3370
                                              .tableNameWithoutPrefix === table
59✔
3371
                                      )
59✔
3372
                                  })
39✔
3373
                              if (!tableAlias) {
39✔
3374
                                  throw new TypeORMError(
5✔
3375
                                      `"${table}" is not part of this query`,
5✔
3376
                                  )
5✔
3377
                              }
5✔
3378
                              return this.escape(tableAlias.name)
34✔
3379
                          })
44✔
3380
                        : undefined
196✔
3381
                    this.setLock(
196✔
3382
                        this.findOptions.lock.mode,
196✔
3383
                        undefined,
196✔
3384
                        tableNames,
196✔
3385
                    )
196✔
3386

196✔
3387
                    if (this.findOptions.lock.onLocked) {
196!
3388
                        this.setOnLocked(this.findOptions.lock.onLocked)
16✔
3389
                    }
16✔
3390
                }
196✔
3391
            }
440✔
3392

183,207✔
3393
            if (this.findOptions.loadRelationIds === true) {
183,772✔
3394
                this.loadAllRelationIds()
28✔
3395
            } else if (typeof this.findOptions.loadRelationIds === "object") {
183,772✔
3396
                this.loadAllRelationIds(this.findOptions.loadRelationIds as any)
117,685✔
3397
            }
117,685✔
3398

183,207✔
3399
            if (this.findOptions.loadEagerRelations !== false) {
183,772✔
3400
                FindOptionsUtils.joinEagerRelations(
65,466✔
3401
                    this,
65,466✔
3402
                    this.expressionMap.mainAlias!.name,
65,466✔
3403
                    this.expressionMap.mainAlias!.metadata,
65,466✔
3404
                )
65,466✔
3405
            }
65,466✔
3406

183,207✔
3407
            if (this.findOptions.transaction === true) {
183,772✔
3408
                this.expressionMap.useTransaction = true
28✔
3409
            }
28✔
3410

183,772✔
3411
            // if (this.orderBys.length) {
183,772✔
3412
            //     this.orderBys.forEach(orderBy => {
183,772✔
3413
            //         this.addOrderBy(orderBy.alias, orderBy.direction, orderBy.nulls);
183,772✔
3414
            //     });
183,772✔
3415
            // }
183,772✔
3416

183,772✔
3417
            // todo
183,772✔
3418
            // if (this.options.options && this.options.options.eagerRelations) {
183,772✔
3419
            //     this.queryBuilder
183,772✔
3420
            // }
183,772✔
3421

183,772✔
3422
            // todo
183,772✔
3423
            // if (this.findOptions.options && this.findOptions.listeners === false) {
183,772✔
3424
            //     this.callListeners(false);
183,772✔
3425
            // }
183,772✔
3426
        }
183,772✔
3427
    }
183,772✔
3428

848,396✔
3429
    public concatRelationMetadata(relationMetadata: RelationMetadata) {
848,396✔
3430
        this.relationMetadatas.push(relationMetadata)
20✔
3431
    }
20✔
3432

848,396✔
3433
    /**
848,396✔
3434
     * Executes sql generated by query builder and returns object with raw results and entities created from them.
848,396✔
3435
     */
848,396✔
3436
    protected async executeEntitiesAndRawResults(
848,396✔
3437
        queryRunner: QueryRunner,
173,241✔
3438
    ): Promise<{ entities: Entity[]; raw: any[] }> {
173,241✔
3439
        if (!this.expressionMap.mainAlias)
173,241✔
3440
            throw new TypeORMError(
173,241!
3441
                `Alias is not set. Use "from" method to set an alias.`,
×
3442
            )
×
3443

173,241✔
3444
        if (
173,241✔
3445
            (this.expressionMap.lockMode === "pessimistic_read" ||
173,241✔
3446
                this.expressionMap.lockMode === "pessimistic_write" ||
173,241✔
3447
                this.expressionMap.lockMode === "pessimistic_partial_write" ||
173,241✔
3448
                this.expressionMap.lockMode === "pessimistic_write_or_fail" ||
173,241✔
3449
                this.expressionMap.lockMode === "for_no_key_update" ||
173,241✔
3450
                this.expressionMap.lockMode === "for_key_share") &&
173,241✔
3451
            !queryRunner.isTransactionActive
431✔
3452
        )
173,241✔
3453
            throw new PessimisticLockTransactionRequiredError()
173,241!
3454

173,148✔
3455
        if (this.expressionMap.lockMode === "optimistic") {
173,241✔
3456
            const metadata = this.expressionMap.mainAlias.metadata
244✔
3457
            if (!metadata.versionColumn && !metadata.updateDateColumn)
244✔
3458
                throw new NoVersionOrUpdateDateColumnError(metadata.name)
244✔
3459
        }
244✔
3460

173,120✔
3461
        const relationIdLoader = new RelationIdLoader(
173,120✔
3462
            this.connection,
173,120✔
3463
            queryRunner,
173,120✔
3464
            this.expressionMap.relationIdAttributes,
173,120✔
3465
        )
173,120✔
3466
        const relationCountLoader = new RelationCountLoader(
173,120✔
3467
            this.connection,
173,120✔
3468
            queryRunner,
173,120✔
3469
            this.expressionMap.relationCountAttributes,
173,120✔
3470
        )
173,120✔
3471
        const relationIdMetadataTransformer =
173,120✔
3472
            new RelationIdMetadataToAttributeTransformer(this.expressionMap)
173,120✔
3473
        relationIdMetadataTransformer.transform()
173,120✔
3474
        const relationCountMetadataTransformer =
173,120✔
3475
            new RelationCountMetadataToAttributeTransformer(this.expressionMap)
173,120✔
3476
        relationCountMetadataTransformer.transform()
173,120✔
3477

173,120✔
3478
        let rawResults: any[] = [],
173,120✔
3479
            entities: any[] = []
173,120✔
3480

173,120✔
3481
        // for pagination enabled (e.g. skip and take) its much more complicated - its a special process
173,120✔
3482
        // where we make two queries to find the data we need
173,120✔
3483
        // first query find ids in skip and take range
173,120✔
3484
        // and second query loads the actual data in given ids range
173,120✔
3485
        if (
173,120✔
3486
            (this.expressionMap.skip || this.expressionMap.take) &&
173,241✔
3487
            this.expressionMap.joinAttributes.length > 0
17,157✔
3488
        ) {
173,241✔
3489
            // we are skipping order by here because its not working in subqueries anyway
7,399✔
3490
            // to make order by working we need to apply it on a distinct query
7,399✔
3491
            const [selects, orderBys] =
7,399✔
3492
                this.createOrderByCombinedWithSelectExpression("distinctAlias")
7,399✔
3493
            const metadata = this.expressionMap.mainAlias.metadata
7,399✔
3494
            const mainAliasName = this.expressionMap.mainAlias.name
7,399✔
3495

7,399✔
3496
            const querySelects = metadata.primaryColumns.map(
7,399✔
3497
                (primaryColumn) => {
7,399✔
3498
                    const distinctAlias = this.escape("distinctAlias")
7,487✔
3499
                    const columnAlias = this.escape(
7,487✔
3500
                        DriverUtils.buildAlias(
7,487✔
3501
                            this.connection.driver,
7,487✔
3502
                            undefined,
7,487✔
3503
                            mainAliasName,
7,487✔
3504
                            primaryColumn.databaseName,
7,487✔
3505
                        ),
7,487✔
3506
                    )
7,487✔
3507
                    if (!orderBys[columnAlias])
7,487✔
3508
                        // make sure we aren't overriding user-defined order in inverse direction
7,487✔
3509
                        orderBys[columnAlias] = "ASC"
7,487✔
3510

7,487✔
3511
                    const alias = DriverUtils.buildAlias(
7,487✔
3512
                        this.connection.driver,
7,487✔
3513
                        undefined,
7,487✔
3514
                        "ids_" + mainAliasName,
7,487✔
3515
                        primaryColumn.databaseName,
7,487✔
3516
                    )
7,487✔
3517

7,487✔
3518
                    return `${distinctAlias}.${columnAlias} AS ${this.escape(
7,487✔
3519
                        alias,
7,487✔
3520
                    )}`
7,487✔
3521
                },
7,399✔
3522
            )
7,399✔
3523

7,399✔
3524
            const originalQuery = this.clone()
7,399✔
3525

7,399✔
3526
            // preserve original timeTravel value since we set it to "false" in subquery
7,399✔
3527
            const originalQueryTimeTravel =
7,399✔
3528
                originalQuery.expressionMap.timeTravel
7,399✔
3529

7,399✔
3530
            rawResults = await new SelectQueryBuilder(
7,399✔
3531
                this.connection,
7,399✔
3532
                queryRunner,
7,399✔
3533
            )
7,399✔
3534
                .select(`DISTINCT ${querySelects.join(", ")}`)
7,399✔
3535
                .addSelect(selects)
7,399✔
3536
                .from(
7,399✔
3537
                    `(${originalQuery
7,399✔
3538
                        .orderBy()
7,399✔
3539
                        .timeTravelQuery(false) // set it to "false" since time travel clause must appear at the very end and applies to the entire SELECT clause.
7,399✔
3540
                        .getQuery()})`,
7,399✔
3541
                    "distinctAlias",
7,399✔
3542
                )
7,399✔
3543
                .timeTravelQuery(originalQueryTimeTravel)
7,399✔
3544
                .offset(this.expressionMap.skip)
7,399✔
3545
                .limit(this.expressionMap.take)
7,399✔
3546
                .orderBy(orderBys)
7,399✔
3547
                .cache(
7,399✔
3548
                    this.expressionMap.cache && this.expressionMap.cacheId
7,399✔
3549
                        ? `${this.expressionMap.cacheId}-pagination`
7,399✔
3550
                        : this.expressionMap.cache,
7,399✔
3551
                    this.expressionMap.cacheDuration,
7,399✔
3552
                )
7,399✔
3553
                .setParameters(this.getParameters())
7,399✔
3554
                .setNativeParameters(this.expressionMap.nativeParameters)
7,399✔
3555
                .getRawMany()
7,399✔
3556

7,384✔
3557
            if (rawResults.length > 0) {
7,399✔
3558
                let condition = ""
7,234✔
3559
                const parameters: ObjectLiteral = {}
7,234✔
3560
                if (metadata.hasMultiplePrimaryKeys) {
7,234✔
3561
                    condition = rawResults
88✔
3562
                        .map((result, index) => {
88✔
3563
                            return metadata.primaryColumns
452✔
3564
                                .map((primaryColumn) => {
452✔
3565
                                    const paramKey = `orm_distinct_ids_${index}_${primaryColumn.databaseName}`
904✔
3566
                                    const paramKeyResult =
904✔
3567
                                        DriverUtils.buildAlias(
904✔
3568
                                            this.connection.driver,
904✔
3569
                                            undefined,
904✔
3570
                                            "ids_" + mainAliasName,
904✔
3571
                                            primaryColumn.databaseName,
904✔
3572
                                        )
904✔
3573
                                    parameters[paramKey] =
904✔
3574
                                        result[paramKeyResult]
904✔
3575
                                    return `${mainAliasName}.${primaryColumn.propertyPath}=:${paramKey}`
904✔
3576
                                })
452✔
3577
                                .join(" AND ")
452✔
3578
                        })
88✔
3579
                        .join(" OR ")
88✔
3580
                } else {
7,234✔
3581
                    const alias = DriverUtils.buildAlias(
7,146✔
3582
                        this.connection.driver,
7,146✔
3583
                        undefined,
7,146✔
3584
                        "ids_" + mainAliasName,
7,146✔
3585
                        metadata.primaryColumns[0].databaseName,
7,146✔
3586
                    )
7,146✔
3587

7,146✔
3588
                    const ids = rawResults.map((result) => result[alias])
7,146✔
3589
                    const areAllNumbers = ids.every(
7,146✔
3590
                        (id: any) => typeof id === "number",
7,146✔
3591
                    )
7,146✔
3592
                    if (areAllNumbers) {
7,146!
3593
                        // fixes #190. if all numbers then its safe to perform query without parameter
6,806✔
3594
                        condition = `${mainAliasName}.${
6,806✔
3595
                            metadata.primaryColumns[0].propertyPath
6,806✔
3596
                        } IN (${ids.join(", ")})`
6,806✔
3597
                    } else {
7,146✔
3598
                        parameters["orm_distinct_ids"] = ids
340✔
3599
                        condition =
340✔
3600
                            mainAliasName +
340✔
3601
                            "." +
340✔
3602
                            metadata.primaryColumns[0].propertyPath +
340✔
3603
                            " IN (:...orm_distinct_ids)"
340✔
3604
                    }
340✔
3605
                }
7,146✔
3606
                rawResults = await this.clone()
7,234✔
3607
                    .mergeExpressionMap({
7,234✔
3608
                        extraAppendedAndWhereCondition: condition,
7,234✔
3609
                    })
7,234✔
3610
                    .setParameters(parameters)
7,234✔
3611
                    .loadRawResults(queryRunner)
7,234✔
3612
            }
7,234✔
3613
        } else {
173,241✔
3614
            rawResults = await this.loadRawResults(queryRunner)
165,721✔
3615
        }
165,607✔
3616

172,991✔
3617
        if (rawResults.length > 0) {
173,241✔
3618
            // transform raw results into entities
60,309✔
3619
            const rawRelationIdResults = await relationIdLoader.load(rawResults)
60,309✔
3620
            const rawRelationCountResults = await relationCountLoader.load(
60,309✔
3621
                rawResults,
60,309✔
3622
            )
60,309✔
3623
            const transformer = new RawSqlResultsToEntityTransformer(
60,309✔
3624
                this.expressionMap,
60,309✔
3625
                this.connection.driver,
60,309✔
3626
                rawRelationIdResults,
60,309✔
3627
                rawRelationCountResults,
60,309✔
3628
                this.queryRunner,
60,309✔
3629
            )
60,309✔
3630
            entities = transformer.transform(
60,309✔
3631
                rawResults,
60,309✔
3632
                this.expressionMap.mainAlias!,
60,309✔
3633
            )
60,309✔
3634

60,309✔
3635
            // broadcast all "after load" events
60,309✔
3636
            if (
60,309✔
3637
                this.expressionMap.callListeners === true &&
60,309✔
3638
                this.expressionMap.mainAlias.hasMetadata
60,301✔
3639
            ) {
60,309✔
3640
                await queryRunner.broadcaster.broadcast(
60,301✔
3641
                    "Load",
60,301✔
3642
                    this.expressionMap.mainAlias.metadata,
60,301✔
3643
                    entities,
60,301✔
3644
                )
60,301✔
3645
            }
60,301✔
3646
        }
60,309✔
3647

172,983✔
3648
        if (this.expressionMap.relationLoadStrategy === "query") {
173,241!
3649
            const queryStrategyRelationIdLoader =
72✔
3650
                new QueryStrategyRelationIdLoader(this.connection, queryRunner)
72✔
3651

72✔
3652
            await Promise.all(
72✔
3653
                this.relationMetadatas.map(async (relation) => {
72✔
3654
                    const relationTarget = relation.inverseEntityMetadata.target
20✔
3655
                    const relationAlias =
20✔
3656
                        relation.inverseEntityMetadata.targetName
20✔
3657

20✔
3658
                    const select = Array.isArray(this.findOptions.select)
20✔
3659
                        ? OrmUtils.propertyPathsToTruthyObject(
20!
3660
                              this.findOptions.select as string[],
×
3661
                          )
20✔
3662
                        : this.findOptions.select
20✔
3663
                    const relations = Array.isArray(this.findOptions.relations)
20✔
3664
                        ? OrmUtils.propertyPathsToTruthyObject(
20!
3665
                              this.findOptions.relations,
×
3666
                          )
20✔
3667
                        : this.findOptions.relations
20✔
3668

20✔
3669
                    const queryBuilder = this.createQueryBuilder(queryRunner)
20✔
3670
                        .select(relationAlias)
20✔
3671
                        .from(relationTarget, relationAlias)
20✔
3672
                        .setFindOptions({
20✔
3673
                            select: select
20✔
3674
                                ? OrmUtils.deepValue(
20!
3675
                                      select,
×
3676
                                      relation.propertyPath,
×
3677
                                  )
20✔
3678
                                : undefined,
20✔
3679
                            order: this.findOptions.order
20✔
3680
                                ? OrmUtils.deepValue(
20!
3681
                                      this.findOptions.order,
×
3682
                                      relation.propertyPath,
×
3683
                                  )
20✔
3684
                                : undefined,
20✔
3685
                            relations: relations
20✔
3686
                                ? OrmUtils.deepValue(
20!
3687
                                      relations,
12✔
3688
                                      relation.propertyPath,
12✔
3689
                                  )
20✔
3690
                                : undefined,
20!
3691
                            withDeleted: this.findOptions.withDeleted,
20✔
3692
                            relationLoadStrategy:
20✔
3693
                                this.findOptions.relationLoadStrategy,
20✔
3694
                        })
20✔
3695
                    if (entities.length > 0) {
20✔
3696
                        const relatedEntityGroups: any[] =
20✔
3697
                            await queryStrategyRelationIdLoader.loadManyToManyRelationIdsAndGroup(
20✔
3698
                                relation,
20✔
3699
                                entities,
20✔
3700
                                undefined,
20✔
3701
                                queryBuilder,
20✔
3702
                            )
20✔
3703
                        entities.forEach((entity) => {
20✔
3704
                            const relatedEntityGroup = relatedEntityGroups.find(
28✔
3705
                                (group) => group.entity === entity,
28✔
3706
                            )
28✔
3707
                            if (relatedEntityGroup) {
28✔
3708
                                const value =
28✔
3709
                                    relatedEntityGroup.related === undefined
28✔
3710
                                        ? null
28!
3711
                                        : relatedEntityGroup.related
28✔
3712
                                relation.setEntityValue(entity, value)
28✔
3713
                            }
28✔
3714
                        })
20✔
3715
                    }
20✔
3716
                }),
72✔
3717
            )
72✔
3718
        }
72✔
3719

172,983✔
3720
        return {
172,983✔
3721
            raw: rawResults,
172,983✔
3722
            entities: entities,
172,983✔
3723
        }
172,983✔
3724
    }
172,983✔
3725

848,396✔
3726
    protected createOrderByCombinedWithSelectExpression(
848,396✔
3727
        parentAlias: string,
7,399✔
3728
    ): [string, OrderByCondition] {
7,399✔
3729
        // if table has a default order then apply it
7,399✔
3730
        const orderBys = this.expressionMap.allOrderBys
7,399✔
3731
        const selectString = Object.keys(orderBys)
7,399✔
3732
            .map((orderCriteria) => {
7,399✔
3733
                if (orderCriteria.indexOf(".") !== -1) {
352✔
3734
                    const criteriaParts = orderCriteria.split(".")
336✔
3735
                    const aliasName = criteriaParts[0]
336✔
3736
                    const propertyPath = criteriaParts.slice(1).join(".")
336✔
3737
                    const alias = this.expressionMap.findAliasByName(aliasName)
336✔
3738
                    const column =
336✔
3739
                        alias.metadata.findColumnWithPropertyPath(propertyPath)
336✔
3740
                    return (
336✔
3741
                        this.escape(parentAlias) +
336✔
3742
                        "." +
336✔
3743
                        this.escape(
336✔
3744
                            DriverUtils.buildAlias(
336✔
3745
                                this.connection.driver,
336✔
3746
                                undefined,
336✔
3747
                                aliasName,
336✔
3748
                                column!.databaseName,
336✔
3749
                            ),
336✔
3750
                        )
336✔
3751
                    )
336✔
3752
                } else {
352!
3753
                    if (
16✔
3754
                        this.expressionMap.selects.find(
16✔
3755
                            (select) =>
16✔
3756
                                select.selection === orderCriteria ||
32✔
3757
                                select.aliasName === orderCriteria,
16✔
3758
                        )
16✔
3759
                    )
16✔
3760
                        return (
16!
3761
                            this.escape(parentAlias) +
8✔
3762
                            "." +
8✔
3763
                            this.escape(orderCriteria)
8✔
3764
                        )
8✔
3765

8!
3766
                    return ""
8✔
3767
                }
8✔
3768
            })
7,399✔
3769
            .join(", ")
7,399✔
3770

7,399✔
3771
        const orderByObject: OrderByCondition = {}
7,399✔
3772
        Object.keys(orderBys).forEach((orderCriteria) => {
7,399✔
3773
            if (orderCriteria.indexOf(".") !== -1) {
352✔
3774
                const criteriaParts = orderCriteria.split(".")
336✔
3775
                const aliasName = criteriaParts[0]
336✔
3776
                const propertyPath = criteriaParts.slice(1).join(".")
336✔
3777
                const alias = this.expressionMap.findAliasByName(aliasName)
336✔
3778
                const column =
336✔
3779
                    alias.metadata.findColumnWithPropertyPath(propertyPath)
336✔
3780
                orderByObject[
336✔
3781
                    this.escape(parentAlias) +
336✔
3782
                        "." +
336✔
3783
                        this.escape(
336✔
3784
                            DriverUtils.buildAlias(
336✔
3785
                                this.connection.driver,
336✔
3786
                                undefined,
336✔
3787
                                aliasName,
336✔
3788
                                column!.databaseName,
336✔
3789
                            ),
336✔
3790
                        )
336✔
3791
                ] = orderBys[orderCriteria]
336✔
3792
            } else {
352!
3793
                if (
16✔
3794
                    this.expressionMap.selects.find(
16✔
3795
                        (select) =>
16✔
3796
                            select.selection === orderCriteria ||
32✔
3797
                            select.aliasName === orderCriteria,
16✔
3798
                    )
16✔
3799
                ) {
16!
3800
                    orderByObject[
8✔
3801
                        this.escape(parentAlias) +
8✔
3802
                            "." +
8✔
3803
                            this.escape(orderCriteria)
8✔
3804
                    ] = orderBys[orderCriteria]
8✔
3805
                } else {
16!
3806
                    orderByObject[orderCriteria] = orderBys[orderCriteria]
8✔
3807
                }
8✔
3808
            }
16✔
3809
        })
7,399✔
3810

7,399✔
3811
        return [selectString, orderByObject]
7,399✔
3812
    }
7,399✔
3813

848,396✔
3814
    /**
848,396✔
3815
     * Loads raw results from the database.
848,396✔
3816
     */
848,396✔
3817
    protected async loadRawResults(queryRunner: QueryRunner) {
848,396✔
3818
        const [sql, parameters] = this.getQueryAndParameters()
200,847✔
3819
        const queryId =
200,847✔
3820
            sql +
200,847✔
3821
            " -- PARAMETERS: " +
200,847✔
3822
            JSON.stringify(parameters, (_, value) =>
200,847✔
3823
                typeof value === "bigint" ? value.toString() : value,
200,847!
3824
            )
200,847✔
3825
        const cacheOptions =
200,847✔
3826
            typeof this.connection.options.cache === "object"
200,847✔
3827
                ? this.connection.options.cache
200,847✔
3828
                : {}
200,847✔
3829
        let savedQueryResultCacheOptions: QueryResultCacheOptions | undefined =
200,847✔
3830
            undefined
200,847✔
3831
        const isCachingEnabled =
200,847✔
3832
            // Caching is enabled globally and isn't disabled locally.
200,847✔
3833
            (cacheOptions.alwaysEnabled &&
200,847✔
3834
                this.expressionMap.cache !== false) ||
200,847✔
3835
            // ...or it's enabled locally explicitly.
200,681✔
3836
            this.expressionMap.cache === true
200,681✔
3837
        let cacheError = false
200,847✔
3838
        if (this.connection.queryResultCache && isCachingEnabled) {
200,847✔
3839
            try {
1,164✔
3840
                savedQueryResultCacheOptions =
1,164✔
3841
                    await this.connection.queryResultCache.getFromCache(
1,164✔
3842
                        {
1,164✔
3843
                            identifier: this.expressionMap.cacheId,
1,164✔
3844
                            query: queryId,
1,164✔
3845
                            duration:
1,164✔
3846
                                this.expressionMap.cacheDuration ||
1,164✔
3847
                                cacheOptions.duration ||
1,164✔
3848
                                1000,
1,164✔
3849
                        },
1,164✔
3850
                        queryRunner,
1,164✔
3851
                    )
1,164✔
3852
                if (
1,164✔
3853
                    savedQueryResultCacheOptions &&
1,164✔
3854
                    !this.connection.queryResultCache.isExpired(
708✔
3855
                        savedQueryResultCacheOptions,
708✔
3856
                    )
1,164✔
3857
                ) {
1,164✔
3858
                    return JSON.parse(savedQueryResultCacheOptions.result)
456✔
3859
                }
456✔
3860
            } catch (error) {
1,164!
3861
                if (!cacheOptions.ignoreErrors) {
×
3862
                    throw error
×
3863
                }
×
3864
                cacheError = true
×
3865
            }
×
3866
        }
1,164✔
3867

200,281✔
3868
        const results = await queryRunner.query(sql, parameters, true)
200,281✔
3869

200,262✔
3870
        if (
200,262✔
3871
            !cacheError &&
200,262✔
3872
            this.connection.queryResultCache &&
200,847✔
3873
            isCachingEnabled
2,264✔
3874
        ) {
200,847✔
3875
            try {
708✔
3876
                await this.connection.queryResultCache.storeInCache(
708✔
3877
                    {
708✔
3878
                        identifier: this.expressionMap.cacheId,
708✔
3879
                        query: queryId,
708✔
3880
                        time: Date.now(),
708✔
3881
                        duration:
708✔
3882
                            this.expressionMap.cacheDuration ||
708✔
3883
                            cacheOptions.duration ||
708✔
3884
                            1000,
708✔
3885
                        result: JSON.stringify(results.records),
708✔
3886
                    },
708✔
3887
                    savedQueryResultCacheOptions,
708✔
3888
                    queryRunner,
708✔
3889
                )
708✔
3890
            } catch (error) {
708!
3891
                if (!cacheOptions.ignoreErrors) {
×
3892
                    throw error
×
3893
                }
×
3894
            }
×
3895
        }
708✔
3896

200,262✔
3897
        return results.records
200,262✔
3898
    }
200,262✔
3899

848,396✔
3900
    /**
848,396✔
3901
     * Merges into expression map given expression map properties.
848,396✔
3902
     */
848,396✔
3903
    protected mergeExpressionMap(
848,396✔
3904
        expressionMap: Partial<QueryExpressionMap>,
7,234✔
3905
    ): this {
7,234✔
3906
        ObjectUtils.assign(this.expressionMap, expressionMap)
7,234✔
3907
        return this
7,234✔
3908
    }
7,234✔
3909

848,396✔
3910
    /**
848,396✔
3911
     * Normalizes a give number - converts to int if possible.
848,396✔
3912
     */
848,396✔
3913
    protected normalizeNumber(num: any) {
848,396✔
3914
        if (typeof num === "number" || num === undefined || num === null)
38,699✔
3915
            return num
38,699✔
3916

112✔
3917
        return Number(num)
112✔
3918
    }
112✔
3919

848,396✔
3920
    /**
848,396✔
3921
     * Creates a query builder used to execute sql queries inside this query builder.
848,396✔
3922
     */
848,396✔
3923
    protected obtainQueryRunner() {
848,396✔
3924
        return (
200,986✔
3925
            this.queryRunner ||
200,986✔
3926
            this.connection.createQueryRunner(
48,269✔
3927
                this.connection.defaultReplicationModeForReads(),
48,269✔
3928
            )
200,986✔
3929
        )
200,986✔
3930
    }
200,986✔
3931

848,396✔
3932
    protected buildSelect(
848,396✔
3933
        select: FindOptionsSelect<any>,
1,105✔
3934
        metadata: EntityMetadata,
1,105✔
3935
        alias: string,
1,105✔
3936
        embedPrefix?: string,
1,105✔
3937
    ) {
1,105✔
3938
        for (const key in select) {
1,105✔
3939
            if (select[key] === undefined || select[key] === false) continue
1,996✔
3940

1,912✔
3941
            const propertyPath = embedPrefix ? embedPrefix + "." + key : key
1,996✔
3942
            const column =
1,996✔
3943
                metadata.findColumnWithPropertyPathStrict(propertyPath)
1,996✔
3944
            const embed = metadata.findEmbeddedWithPropertyPath(propertyPath)
1,996✔
3945
            const relation = metadata.findRelationWithPropertyPath(propertyPath)
1,996✔
3946

1,996✔
3947
            if (!embed && !column && !relation)
1,996✔
3948
                throw new EntityPropertyNotFoundError(propertyPath, metadata)
1,996✔
3949

1,884✔
3950
            if (column) {
1,996✔
3951
                this.selects.push(alias + "." + propertyPath)
1,446✔
3952
                // this.addSelect(alias + "." + propertyPath);
1,446✔
3953
            } else if (embed) {
1,996✔
3954
                this.buildSelect(
74✔
3955
                    select[key] as FindOptionsSelect<any>,
74✔
3956
                    metadata,
74✔
3957
                    alias,
74✔
3958
                    propertyPath,
74✔
3959
                )
74✔
3960

74✔
3961
                // } else if (relation) {
74✔
3962
                //     const joinAlias = alias + "_" + relation.propertyName;
74✔
3963
                //     const existJoin = this.joins.find(join => join.alias === joinAlias);
74✔
3964
                //     if (!existJoin) {
74✔
3965
                //         this.joins.push({
74✔
3966
                //             type: "left",
74✔
3967
                //             select: false,
74✔
3968
                //             alias: joinAlias,
74✔
3969
                //             parentAlias: alias,
74✔
3970
                //             relationMetadata: relation
74✔
3971
                //         });
74✔
3972
                //     }
74✔
3973
                //     this.buildOrder(select[key] as FindOptionsOrder<any>, relation.inverseEntityMetadata, joinAlias);
74✔
3974
            }
74✔
3975
        }
1,996✔
3976
    }
1,077✔
3977

848,396✔
3978
    protected buildRelations(
848,396✔
3979
        relations: FindOptionsRelations<any>,
48,366✔
3980
        selection: FindOptionsSelect<any> | undefined,
48,366✔
3981
        metadata: EntityMetadata,
48,366✔
3982
        alias: string,
48,366✔
3983
        embedPrefix?: string,
48,366✔
3984
    ) {
48,366✔
3985
        if (!relations) return
48,366!
3986

48,366✔
3987
        Object.keys(relations).forEach((relationName) => {
48,366✔
3988
            const relationValue = (relations as any)[relationName]
369,056✔
3989
            const propertyPath = embedPrefix
369,056✔
3990
                ? embedPrefix + "." + relationName
369,056✔
3991
                : relationName
369,056✔
3992
            const embed = metadata.findEmbeddedWithPropertyPath(propertyPath)
369,056✔
3993
            const relation = metadata.findRelationWithPropertyPath(propertyPath)
369,056✔
3994
            if (!embed && !relation)
369,056✔
3995
                throw new EntityPropertyNotFoundError(propertyPath, metadata)
369,056✔
3996

368,888✔
3997
            if (embed) {
369,056✔
3998
                this.buildRelations(
140✔
3999
                    relationValue,
140✔
4000
                    typeof selection === "object"
140✔
4001
                        ? OrmUtils.deepValue(selection, embed.propertyPath)
140!
4002
                        : undefined,
140✔
4003
                    metadata,
140✔
4004
                    alias,
140✔
4005
                    propertyPath,
140✔
4006
                )
140✔
4007
            } else if (relation) {
369,056✔
4008
                let joinAlias = alias + "_" + propertyPath.replace(".", "_")
368,748✔
4009
                joinAlias = DriverUtils.buildAlias(
368,748✔
4010
                    this.connection.driver,
368,748✔
4011
                    { joiner: "__" },
368,748✔
4012
                    alias,
368,748✔
4013
                    joinAlias,
368,748✔
4014
                )
368,748✔
4015
                if (
368,748✔
4016
                    relationValue === true ||
368,748✔
4017
                    typeof relationValue === "object"
968✔
4018
                ) {
368,748✔
4019
                    if (this.expressionMap.relationLoadStrategy === "query") {
368,748!
4020
                        this.concatRelationMetadata(relation)
12✔
4021
                    } else {
368,748✔
4022
                        // join
368,736✔
4023
                        this.joins.push({
368,736✔
4024
                            type: "left",
368,736✔
4025
                            select: true,
368,736✔
4026
                            selection:
368,736✔
4027
                                selection &&
368,736✔
4028
                                typeof selection[relationName] === "object"
448✔
4029
                                    ? (selection[
368,736✔
4030
                                          relationName
308✔
4031
                                      ] as FindOptionsSelect<any>)
368,736✔
4032
                                    : undefined,
368,736✔
4033
                            alias: joinAlias,
368,736✔
4034
                            parentAlias: alias,
368,736✔
4035
                            relationMetadata: relation,
368,736✔
4036
                        })
368,736✔
4037

368,736✔
4038
                        if (
368,736✔
4039
                            selection &&
368,736✔
4040
                            typeof selection[relationName] === "object"
448✔
4041
                        ) {
368,736✔
4042
                            this.buildSelect(
308✔
4043
                                selection[
308✔
4044
                                    relationName
308✔
4045
                                ] as FindOptionsSelect<any>,
308✔
4046
                                relation.inverseEntityMetadata,
308✔
4047
                                joinAlias,
308✔
4048
                            )
308✔
4049
                        }
308✔
4050
                    }
368,736✔
4051
                }
368,748✔
4052

368,748✔
4053
                if (
368,748✔
4054
                    typeof relationValue === "object" &&
368,748✔
4055
                    this.expressionMap.relationLoadStrategy === "join"
968✔
4056
                ) {
368,748✔
4057
                    this.buildRelations(
968✔
4058
                        relationValue,
968✔
4059
                        typeof selection === "object"
968✔
4060
                            ? OrmUtils.deepValue(
968✔
4061
                                  selection,
168✔
4062
                                  relation.propertyPath,
168✔
4063
                              )
968✔
4064
                            : undefined,
968✔
4065
                        relation.inverseEntityMetadata,
968✔
4066
                        joinAlias,
968✔
4067
                        undefined,
968✔
4068
                    )
968✔
4069
                }
968✔
4070
            }
368,748✔
4071
        })
48,366✔
4072
    }
48,366✔
4073

848,396✔
4074
    protected buildEagerRelations(
848,396✔
4075
        relations: FindOptionsRelations<any>,
48,090✔
4076
        selection: FindOptionsSelect<any> | undefined,
48,090✔
4077
        metadata: EntityMetadata,
48,090✔
4078
        alias: string,
48,090✔
4079
        embedPrefix?: string,
48,090✔
4080
    ) {
48,090✔
4081
        if (!relations) return
48,090!
4082

48,090✔
4083
        Object.keys(relations).forEach((relationName) => {
48,090✔
4084
            const relationValue = (relations as any)[relationName]
368,736✔
4085
            const propertyPath = embedPrefix
368,736✔
4086
                ? embedPrefix + "." + relationName
368,736✔
4087
                : relationName
368,736✔
4088
            const embed = metadata.findEmbeddedWithPropertyPath(propertyPath)
368,736✔
4089
            const relation = metadata.findRelationWithPropertyPath(propertyPath)
368,736✔
4090
            if (!embed && !relation)
368,736✔
4091
                throw new EntityPropertyNotFoundError(propertyPath, metadata)
368,736!
4092

368,736✔
4093
            if (embed) {
368,736✔
4094
                this.buildEagerRelations(
112✔
4095
                    relationValue,
112✔
4096
                    typeof selection === "object"
112✔
4097
                        ? OrmUtils.deepValue(selection, embed.propertyPath)
112!
4098
                        : undefined,
112✔
4099
                    metadata,
112✔
4100
                    alias,
112✔
4101
                    propertyPath,
112✔
4102
                )
112✔
4103
            } else if (relation) {
368,736✔
4104
                let joinAlias = alias + "_" + propertyPath.replace(".", "_")
368,624✔
4105
                joinAlias = DriverUtils.buildAlias(
368,624✔
4106
                    this.connection.driver,
368,624✔
4107
                    { joiner: "__" },
368,624✔
4108
                    alias,
368,624✔
4109
                    joinAlias,
368,624✔
4110
                )
368,624✔
4111

368,624✔
4112
                if (
368,624✔
4113
                    relationValue === true ||
368,624✔
4114
                    typeof relationValue === "object"
912✔
4115
                ) {
368,624✔
4116
                    relation.inverseEntityMetadata.eagerRelations.forEach(
368,624✔
4117
                        (eagerRelation) => {
368,624✔
4118
                            let eagerRelationJoinAlias =
424✔
4119
                                joinAlias +
424✔
4120
                                "_" +
424✔
4121
                                eagerRelation.propertyPath.replace(".", "_")
424✔
4122
                            eagerRelationJoinAlias = DriverUtils.buildAlias(
424✔
4123
                                this.connection.driver,
424✔
4124
                                { joiner: "__" },
424✔
4125
                                joinAlias,
424✔
4126
                                eagerRelationJoinAlias,
424✔
4127
                            )
424✔
4128

424✔
4129
                            const existJoin = this.joins.find(
424✔
4130
                                (join) => join.alias === eagerRelationJoinAlias,
424✔
4131
                            )
424✔
4132
                            if (!existJoin) {
424✔
4133
                                this.joins.push({
284✔
4134
                                    type: "left",
284✔
4135
                                    select: true,
284✔
4136
                                    alias: eagerRelationJoinAlias,
284✔
4137
                                    parentAlias: joinAlias,
284✔
4138
                                    selection: undefined,
284✔
4139
                                    relationMetadata: eagerRelation,
284✔
4140
                                })
284✔
4141
                            }
284✔
4142

424✔
4143
                            if (
424✔
4144
                                selection &&
424!
4145
                                typeof selection[relationName] === "object"
×
4146
                            ) {
424!
4147
                                this.buildSelect(
×
4148
                                    selection[
×
4149
                                        relationName
×
4150
                                    ] as FindOptionsSelect<any>,
×
4151
                                    relation.inverseEntityMetadata,
×
4152
                                    joinAlias,
×
4153
                                )
×
4154
                            }
×
4155
                        },
368,624✔
4156
                    )
368,624✔
4157
                }
368,624✔
4158

368,624✔
4159
                if (typeof relationValue === "object") {
368,624✔
4160
                    this.buildEagerRelations(
912✔
4161
                        relationValue,
912✔
4162
                        typeof selection === "object"
912✔
4163
                            ? OrmUtils.deepValue(
912✔
4164
                                  selection,
168✔
4165
                                  relation.propertyPath,
168✔
4166
                              )
912✔
4167
                            : undefined,
912✔
4168
                        relation.inverseEntityMetadata,
912✔
4169
                        joinAlias,
912✔
4170
                        undefined,
912✔
4171
                    )
912✔
4172
                }
912✔
4173
            }
368,624✔
4174
        })
48,090✔
4175
    }
48,090✔
4176

848,396✔
4177
    protected buildOrder(
848,396✔
4178
        order: FindOptionsOrder<any>,
3,230✔
4179
        metadata: EntityMetadata,
3,230✔
4180
        alias: string,
3,230✔
4181
        embedPrefix?: string,
3,230✔
4182
    ) {
3,230✔
4183
        for (const key in order) {
3,230✔
4184
            if (order[key] === undefined) continue
3,594!
4185

3,594✔
4186
            const propertyPath = embedPrefix ? embedPrefix + "." + key : key
3,594✔
4187
            const column =
3,594✔
4188
                metadata.findColumnWithPropertyPathStrict(propertyPath)
3,594✔
4189
            const embed = metadata.findEmbeddedWithPropertyPath(propertyPath)
3,594✔
4190
            const relation = metadata.findRelationWithPropertyPath(propertyPath)
3,594✔
4191

3,594✔
4192
            if (!embed && !column && !relation)
3,594✔
4193
                throw new EntityPropertyNotFoundError(propertyPath, metadata)
3,594✔
4194

3,566✔
4195
            if (column) {
3,594✔
4196
                let direction =
2,922✔
4197
                    typeof order[key] === "object"
2,922✔
4198
                        ? (order[key] as any).direction
2,922✔
4199
                        : order[key]
2,922✔
4200
                direction =
2,922✔
4201
                    direction === "DESC" ||
2,922✔
4202
                    direction === "desc" ||
2,922✔
4203
                    direction === -1
2,508✔
4204
                        ? "DESC"
2,922✔
4205
                        : "ASC"
2,922✔
4206
                let nulls =
2,922✔
4207
                    typeof order[key] === "object"
2,922✔
4208
                        ? (order[key] as any).nulls
2,922✔
4209
                        : undefined
2,922✔
4210
                nulls =
2,922✔
4211
                    nulls?.toLowerCase() === "first"
2,922!
4212
                        ? "NULLS FIRST"
2,922!
4213
                        : nulls?.toLowerCase() === "last"
2,922!
4214
                        ? "NULLS LAST"
2,902!
4215
                        : undefined
2,902✔
4216

2,922✔
4217
                const aliasPath = `${alias}.${propertyPath}`
2,922✔
4218
                // const selection = this.expressionMap.selects.find(
2,922✔
4219
                //     (s) => s.selection === aliasPath,
2,922✔
4220
                // )
2,922✔
4221
                // if (selection) {
2,922✔
4222
                //     // this is not building correctly now???
2,922✔
4223
                //     aliasPath = this.escape(
2,922✔
4224
                //         DriverUtils.buildAlias(
2,922✔
4225
                //             this.connection.driver,
2,922✔
4226
                //             undefined,
2,922✔
4227
                //             alias,
2,922✔
4228
                //             column.databaseName,
2,922✔
4229
                //         ),
2,922✔
4230
                //     )
2,922✔
4231
                //     // selection.aliasName = aliasPath
2,922✔
4232
                // } else {
2,922✔
4233
                //     if (column.isVirtualProperty && column.query) {
2,922✔
4234
                //         aliasPath = `(${column.query(alias)})`
2,922✔
4235
                //     }
2,922✔
4236
                // }
2,922✔
4237

2,922✔
4238
                // console.log("add sort", selection, aliasPath, direction, nulls)
2,922✔
4239
                this.addOrderBy(aliasPath, direction, nulls)
2,922✔
4240
                // this.orderBys.push({ alias: alias + "." + propertyPath, direction, nulls });
2,922✔
4241
            } else if (embed) {
3,594✔
4242
                this.buildOrder(
84✔
4243
                    order[key] as FindOptionsOrder<any>,
84✔
4244
                    metadata,
84✔
4245
                    alias,
84✔
4246
                    propertyPath,
84✔
4247
                )
84✔
4248
            } else if (relation) {
644✔
4249
                let joinAlias = alias + "_" + propertyPath.replace(".", "_")
560✔
4250
                joinAlias = DriverUtils.buildAlias(
560✔
4251
                    this.connection.driver,
560✔
4252
                    { joiner: "__" },
560✔
4253
                    alias,
560✔
4254
                    joinAlias,
560✔
4255
                )
560✔
4256
                // console.log("joinAlias", joinAlias, joinAlias.length, this.connection.driver.maxAliasLength)
560✔
4257
                // todo: use expressionMap.joinAttributes, and create a new one using
560✔
4258
                //  const joinAttribute = new JoinAttribute(this.connection, this.expressionMap);
560✔
4259

560✔
4260
                const existJoin = this.joins.find(
560✔
4261
                    (join) => join.alias === joinAlias,
560✔
4262
                )
560✔
4263
                if (!existJoin) {
560✔
4264
                    this.joins.push({
196✔
4265
                        type: "left",
196✔
4266
                        select: false,
196✔
4267
                        alias: joinAlias,
196✔
4268
                        parentAlias: alias,
196✔
4269
                        selection: undefined,
196✔
4270
                        relationMetadata: relation,
196✔
4271
                    })
196✔
4272
                }
196✔
4273
                this.buildOrder(
560✔
4274
                    order[key] as FindOptionsOrder<any>,
560✔
4275
                    relation.inverseEntityMetadata,
560✔
4276
                    joinAlias,
560✔
4277
                )
560✔
4278
            }
560✔
4279
        }
3,594✔
4280
    }
3,202✔
4281

848,396✔
4282
    protected buildWhere(
848,396✔
4283
        where: FindOptionsWhere<any>[] | FindOptionsWhere<any>,
62,086✔
4284
        metadata: EntityMetadata,
62,086✔
4285
        alias: string,
62,086✔
4286
        embedPrefix?: string,
62,086✔
4287
    ) {
62,086✔
4288
        let condition: string = ""
62,086✔
4289
        // let parameterIndex = Object.keys(this.expressionMap.nativeParameters).length;
62,086✔
4290
        if (Array.isArray(where)) {
62,086✔
4291
            if (where.length) {
200✔
4292
                condition = where
196✔
4293
                    .map((whereItem) => {
196✔
4294
                        return this.buildWhere(
392✔
4295
                            whereItem,
392✔
4296
                            metadata,
392✔
4297
                            alias,
392✔
4298
                            embedPrefix,
392✔
4299
                        )
392✔
4300
                    })
196✔
4301
                    .filter((condition) => !!condition)
196✔
4302
                    .map((condition) => "(" + condition + ")")
196✔
4303
                    .join(" OR ")
196✔
4304
            }
196✔
4305
        } else {
62,086✔
4306
            const andConditions: string[] = []
61,886✔
4307
            for (const key in where) {
61,886✔
4308
                let parameterValue = where[key]
63,017✔
4309

63,017✔
4310
                const propertyPath = embedPrefix ? embedPrefix + "." + key : key
63,017✔
4311
                const column =
63,017✔
4312
                    metadata.findColumnWithPropertyPathStrict(propertyPath)
63,017✔
4313
                const embed =
63,017✔
4314
                    metadata.findEmbeddedWithPropertyPath(propertyPath)
63,017✔
4315
                const relation =
63,017✔
4316
                    metadata.findRelationWithPropertyPath(propertyPath)
63,017✔
4317

63,017✔
4318
                if (!embed && !column && !relation) {
63,017✔
4319
                    throw new EntityPropertyNotFoundError(
56✔
4320
                        propertyPath,
56✔
4321
                        metadata,
56✔
4322
                    )
56✔
4323
                }
56✔
4324

62,961✔
4325
                if (parameterValue === undefined) {
63,017✔
4326
                    const undefinedBehavior =
253✔
4327
                        this.connection.options.invalidWhereValuesBehavior
253✔
4328
                            ?.undefined || "ignore"
253✔
4329
                    if (undefinedBehavior === "throw") {
253✔
4330
                        throw new TypeORMError(
112✔
4331
                            `Undefined value encountered in property '${alias}.${key}' of a where condition. ` +
112✔
4332
                                `Set 'invalidWhereValuesBehavior.undefined' to 'ignore' in connection options to skip properties with undefined values.`,
112✔
4333
                        )
112✔
4334
                    }
112✔
4335
                    continue
141✔
4336
                }
141✔
4337

62,708✔
4338
                if (parameterValue === null) {
63,017✔
4339
                    const nullBehavior =
476✔
4340
                        this.connection.options.invalidWhereValuesBehavior
476✔
4341
                            ?.null || "ignore"
476✔
4342
                    if (nullBehavior === "ignore") {
476✔
4343
                        continue
168✔
4344
                    } else if (nullBehavior === "throw") {
476✔
4345
                        throw new TypeORMError(
112✔
4346
                            `Null value encountered in property '${alias}.${key}' of a where condition. ` +
112✔
4347
                                `To match with SQL NULL, the IsNull() operator must be used. ` +
112✔
4348
                                `Set 'invalidWhereValuesBehavior.null' to 'ignore' or 'sql-null' in connection options to skip or handle null values.`,
112✔
4349
                        )
112✔
4350
                    }
112✔
4351
                    // 'sql-null' behavior continues to the next logic
476✔
4352
                }
476✔
4353

62,428✔
4354
                if (column) {
63,017✔
4355
                    let aliasPath = `${alias}.${propertyPath}`
60,348✔
4356
                    if (column.isVirtualProperty && column.query) {
60,348✔
4357
                        aliasPath = `(${column.query(this.escape(alias))})`
112✔
4358
                    }
112✔
4359

60,348✔
4360
                    if (parameterValue === null) {
60,348✔
4361
                        andConditions.push(`${aliasPath} IS NULL`)
112✔
4362
                        continue
112✔
4363
                    }
112✔
4364

60,236✔
4365
                    // const parameterName = alias + "_" + propertyPath.split(".").join("_") + "_" + parameterIndex;
60,236✔
4366

60,236✔
4367
                    // todo: we need to handle other operators as well?
60,236✔
4368
                    if (InstanceChecker.isEqualOperator(where[key])) {
60,348✔
4369
                        parameterValue = where[key].value
58✔
4370
                    }
58✔
4371

60,236✔
4372
                    if (column.transformer) {
60,348✔
4373
                        if (parameterValue instanceof FindOperator) {
126✔
4374
                            parameterValue.transformValue(column.transformer)
44✔
4375
                        } else {
126✔
4376
                            parameterValue = ApplyValueTransformers.transformTo(
82✔
4377
                                column.transformer,
82✔
4378
                                parameterValue,
82✔
4379
                            )
82✔
4380
                        }
82✔
4381
                    }
126✔
4382

60,236✔
4383
                    // MSSQL requires parameters to carry extra type information
60,236✔
4384
                    if (this.connection.driver.options.type === "mssql") {
60,340!
4385
                        parameterValue = (
1,376✔
4386
                            this.connection.driver as SqlServerDriver
1,376✔
4387
                        ).parametrizeValues(column, parameterValue)
1,376✔
4388
                    }
1,376✔
4389

60,236✔
4390
                    andConditions.push(
60,236✔
4391
                        this.createWhereConditionExpression(
60,236✔
4392
                            this.getWherePredicateCondition(
60,236✔
4393
                                aliasPath,
60,236✔
4394
                                parameterValue,
60,236✔
4395
                            ),
60,236✔
4396
                        ),
60,236✔
4397
                        // parameterValue.toSql(this.connection, aliasPath, parameters));
60,236✔
4398
                    )
60,236✔
4399

60,236✔
4400
                    // this.conditions.push(`${alias}.${propertyPath} = :${paramName}`);
60,236✔
4401
                    // this.expressionMap.parameters[paramName] = where[key]; // todo: handle functions and other edge cases
60,236✔
4402
                } else if (embed) {
63,017✔
4403
                    const condition = this.buildWhere(
560✔
4404
                        where[key],
560✔
4405
                        metadata,
560✔
4406
                        alias,
560✔
4407
                        propertyPath,
560✔
4408
                    )
560✔
4409
                    if (condition) andConditions.push(condition)
560✔
4410
                } else if (relation) {
2,080✔
4411
                    if (where[key] === null) {
1,520✔
4412
                        const nullBehavior =
84✔
4413
                            this.connection.options.invalidWhereValuesBehavior
84✔
4414
                                ?.null || "ignore"
84!
4415
                        if (nullBehavior === "sql-null") {
84✔
4416
                            andConditions.push(
84✔
4417
                                `${alias}.${propertyPath} IS NULL`,
84✔
4418
                            )
84✔
4419
                        } else if (nullBehavior === "throw") {
84!
4420
                            throw new TypeORMError(
×
4421
                                `Null value encountered in property '${alias}.${key}' of a where condition. ` +
×
4422
                                    `Set 'invalidWhereValuesBehavior.null' to 'ignore' or 'sql-null' in connection options to skip or handle null values.`,
×
4423
                            )
×
4424
                        }
×
4425
                        // 'ignore' behavior falls through to continue
84✔
4426
                        continue
84✔
4427
                    }
84✔
4428

1,436✔
4429
                    // if all properties of where are undefined we don't need to join anything
1,436✔
4430
                    // this can happen when user defines map with conditional queries inside
1,436✔
4431
                    if (typeof where[key] === "object") {
1,520✔
4432
                        const allAllUndefined = Object.keys(where[key]).every(
1,408✔
4433
                            (k) => where[key][k] === undefined,
1,408✔
4434
                        )
1,408✔
4435
                        if (allAllUndefined) {
1,408✔
4436
                            continue
28✔
4437
                        }
28✔
4438
                    }
1,408✔
4439

1,408✔
4440
                    if (InstanceChecker.isFindOperator(where[key])) {
1,520✔
4441
                        if (
616✔
4442
                            where[key].type === "moreThan" ||
616✔
4443
                            where[key].type === "lessThan" ||
616✔
4444
                            where[key].type === "moreThanOrEqual" ||
616✔
4445
                            where[key].type === "lessThanOrEqual"
252✔
4446
                        ) {
616✔
4447
                            let sqlOperator = ""
392✔
4448
                            if (where[key].type === "moreThan") {
392✔
4449
                                sqlOperator = ">"
168✔
4450
                            } else if (where[key].type === "lessThan") {
392✔
4451
                                sqlOperator = "<"
28✔
4452
                            } else if (where[key].type === "moreThanOrEqual") {
224✔
4453
                                sqlOperator = ">="
168✔
4454
                            } else if (where[key].type === "lessThanOrEqual") {
196✔
4455
                                sqlOperator = "<="
28✔
4456
                            }
28✔
4457
                            // basically relation count functionality
392✔
4458
                            const qb: QueryBuilder<any> = this.subQuery()
392✔
4459
                            if (relation.isManyToManyOwner) {
392✔
4460
                                qb.select("COUNT(*)")
168✔
4461
                                    .from(
168✔
4462
                                        relation.joinTableName,
168✔
4463
                                        relation.joinTableName,
168✔
4464
                                    )
168✔
4465
                                    .where(
168✔
4466
                                        relation.joinColumns
168✔
4467
                                            .map((column) => {
168✔
4468
                                                return `${
168✔
4469
                                                    relation.joinTableName
168✔
4470
                                                }.${
168✔
4471
                                                    column.propertyName
168✔
4472
                                                } = ${alias}.${
168✔
4473
                                                    column.referencedColumn!
168✔
4474
                                                        .propertyName
168✔
4475
                                                }`
168✔
4476
                                            })
168✔
4477
                                            .join(" AND "),
168✔
4478
                                    )
168✔
4479
                            } else if (relation.isManyToManyNotOwner) {
392✔
4480
                                qb.select("COUNT(*)")
112✔
4481
                                    .from(
112✔
4482
                                        relation.inverseRelation!.joinTableName,
112✔
4483
                                        relation.inverseRelation!.joinTableName,
112✔
4484
                                    )
112✔
4485
                                    .where(
112✔
4486
                                        relation
112✔
4487
                                            .inverseRelation!.inverseJoinColumns.map(
112✔
4488
                                                (column) => {
112✔
4489
                                                    return `${
112✔
4490
                                                        relation.inverseRelation!
112✔
4491
                                                            .joinTableName
112✔
4492
                                                    }.${
112✔
4493
                                                        column.propertyName
112✔
4494
                                                    } = ${alias}.${
112✔
4495
                                                        column.referencedColumn!
112✔
4496
                                                            .propertyName
112✔
4497
                                                    }`
112✔
4498
                                                },
112✔
4499
                                            )
112✔
4500
                                            .join(" AND "),
112✔
4501
                                    )
112✔
4502
                            } else if (relation.isOneToMany) {
112✔
4503
                                qb.select("COUNT(*)")
112✔
4504
                                    .from(
112✔
4505
                                        relation.inverseEntityMetadata.target,
112✔
4506
                                        relation.inverseEntityMetadata
112✔
4507
                                            .tableName,
112✔
4508
                                    )
112✔
4509
                                    .where(
112✔
4510
                                        relation
112✔
4511
                                            .inverseRelation!.joinColumns.map(
112✔
4512
                                                (column) => {
112✔
4513
                                                    return `${
112✔
4514
                                                        relation
112✔
4515
                                                            .inverseEntityMetadata
112✔
4516
                                                            .tableName
112✔
4517
                                                    }.${
112✔
4518
                                                        column.propertyName
112✔
4519
                                                    } = ${alias}.${
112✔
4520
                                                        column.referencedColumn!
112✔
4521
                                                            .propertyName
112✔
4522
                                                    }`
112✔
4523
                                                },
112✔
4524
                                            )
112✔
4525
                                            .join(" AND "),
112✔
4526
                                    )
112✔
4527
                            } else {
112!
4528
                                throw new Error(
×
4529
                                    `This relation isn't supported by given find operator`,
×
4530
                                )
×
4531
                            }
×
4532
                            // this
392✔
4533
                            //     .addSelect(qb.getSql(), relation.propertyAliasName + "_cnt")
392✔
4534
                            //     .andWhere(this.escape(relation.propertyAliasName + "_cnt") + " " + sqlOperator + " " + parseInt(where[key].value));
392✔
4535
                            this.andWhere(
392✔
4536
                                qb.getSql() +
392✔
4537
                                    " " +
392✔
4538
                                    sqlOperator +
392✔
4539
                                    " " +
392✔
4540
                                    parseInt(where[key].value),
392✔
4541
                            )
392✔
4542
                        } else {
616✔
4543
                            if (
224✔
4544
                                relation.isManyToOne ||
224✔
4545
                                (relation.isOneToOne &&
112✔
4546
                                    relation.isOneToOneOwner)
112✔
4547
                            ) {
224✔
4548
                                const aliasPath = `${alias}.${propertyPath}`
224✔
4549

224✔
4550
                                andConditions.push(
224✔
4551
                                    this.createWhereConditionExpression(
224✔
4552
                                        this.getWherePredicateCondition(
224✔
4553
                                            aliasPath,
224✔
4554
                                            where[key],
224✔
4555
                                        ),
224✔
4556
                                    ),
224✔
4557
                                )
224✔
4558
                            } else {
224!
4559
                                throw new Error(
×
4560
                                    `This relation isn't supported by given find operator`,
×
4561
                                )
×
4562
                            }
×
4563
                        }
224✔
4564
                    } else {
1,520✔
4565
                        // const joinAlias = alias + "_" + relation.propertyName;
792✔
4566
                        let joinAlias =
792✔
4567
                            alias +
792✔
4568
                            "_" +
792✔
4569
                            relation.propertyPath.replace(".", "_")
792✔
4570
                        joinAlias = DriverUtils.buildAlias(
792✔
4571
                            this.connection.driver,
792✔
4572
                            { joiner: "__" },
792✔
4573
                            alias,
792✔
4574
                            joinAlias,
792✔
4575
                        )
792✔
4576

792✔
4577
                        const existJoin = this.joins.find(
792✔
4578
                            (join) => join.alias === joinAlias,
792✔
4579
                        )
792✔
4580
                        if (!existJoin) {
792✔
4581
                            this.joins.push({
596✔
4582
                                type: "left",
596✔
4583
                                select: false,
596✔
4584
                                selection: undefined,
596✔
4585
                                alias: joinAlias,
596✔
4586
                                parentAlias: alias,
596✔
4587
                                relationMetadata: relation,
596✔
4588
                            })
596✔
4589
                        }
596✔
4590

792✔
4591
                        const condition = this.buildWhere(
792✔
4592
                            where[key],
792✔
4593
                            relation.inverseEntityMetadata,
792✔
4594
                            joinAlias,
792✔
4595
                        )
792✔
4596
                        if (condition) {
792✔
4597
                            andConditions.push(condition)
708✔
4598
                            // parameterIndex = Object.keys(this.expressionMap.nativeParameters).length;
708✔
4599
                        }
708✔
4600
                    }
792✔
4601
                }
1,520✔
4602
            }
63,017✔
4603
            condition = andConditions.length
61,606✔
4604
                ? "(" + andConditions.join(") AND (") + ")"
61,886✔
4605
                : andConditions.join(" AND ")
61,886✔
4606
        }
61,886✔
4607
        return condition.length ? "(" + condition + ")" : condition
62,086✔
4608
    }
62,086✔
4609
}
848,396✔
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