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

typeorm / typeorm / 20153290793

12 Dec 2025 01:29AM UTC coverage: 80.807% (+0.04%) from 80.764%
20153290793

push

github

alumni
refactor(mysql)!: drop support for mysql package and default to mysql2 (#11766)

Co-authored-by: Lucian Mocanu <alumni@users.noreply.github.com>

26912 of 32666 branches covered (82.39%)

Branch coverage included in aggregate %.

13 of 15 new or added lines in 2 files covered. (86.67%)

694 existing lines in 23 files now uncovered.

91350 of 113685 relevant lines covered (80.35%)

68942.63 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>
610,247✔
54
    extends QueryBuilder<Entity>
610,247✔
55
    implements WhereExpressionBuilder
610,247✔
56
{
610,247✔
57
    readonly "@instanceof" = Symbol.for("SelectQueryBuilder")
610,247✔
58

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

610,247✔
77
    // -------------------------------------------------------------------------
610,247✔
78
    // Public Implemented Methods
610,247✔
79
    // -------------------------------------------------------------------------
610,247✔
80

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

610,247✔
100
    // -------------------------------------------------------------------------
610,247✔
101
    // Public Methods
610,247✔
102
    // -------------------------------------------------------------------------
610,247✔
103

610,247✔
104
    setFindOptions(findOptions: FindManyOptions<Entity>) {
610,247✔
105
        this.findOptions = findOptions
184,228✔
106
        this.applyFindOptions()
184,228✔
107
        return this
184,228✔
108
    }
184,228✔
109

610,247✔
110
    /**
610,247✔
111
     * Creates a subquery - query that can be used inside other queries.
610,247✔
112
     */
610,247✔
113
    subQuery(): SelectQueryBuilder<any> {
610,247✔
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

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

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

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

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

610,247✔
147
    /**
610,247✔
148
     * Creates SELECT query and selects given data.
610,247✔
149
     * Replaces all previous selections if they exist.
610,247✔
150
     */
610,247✔
151
    select(
610,247✔
152
        selection?:
284,632✔
153
            | string
284,632✔
154
            | string[]
284,632✔
155
            | ((qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>),
284,632✔
156
        selectionAliasName?: string,
284,632✔
157
    ): SelectQueryBuilder<Entity> {
284,632✔
158
        this.expressionMap.queryType = "select"
284,632✔
159
        if (Array.isArray(selection)) {
284,632✔
160
            this.expressionMap.selects = selection.map((selection) => ({
9,348✔
161
                selection: selection,
10,169✔
162
            }))
9,348✔
163
        } else if (typeof selection === "function") {
284,632!
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) {
275,284✔
171
            this.expressionMap.selects = [
272,640✔
172
                { selection: selection, aliasName: selectionAliasName },
272,640✔
173
            ]
272,640✔
174
        }
272,640✔
175

284,632✔
176
        return this
284,632✔
177
    }
284,632✔
178

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

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

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

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

696,430✔
209
        if (Array.isArray(selection)) {
703,569✔
210
            this.expressionMap.selects = this.expressionMap.selects.concat(
8,822✔
211
                selection.map((selection) => ({ selection: selection })),
8,822✔
212
            )
8,822✔
213
        } else if (typeof selection === "function") {
703,569✔
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) {
687,608✔
221
            this.expressionMap.selects.push({
687,580✔
222
                selection: selection,
687,580✔
223
                aliasName: selectionAliasName,
687,580✔
224
            })
687,580✔
225
        }
687,580✔
226

696,430✔
227
        return this
696,430✔
228
    }
696,430✔
229

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

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

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

610,247✔
255
    fromDummy(): SelectQueryBuilder<any> {
610,247✔
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

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

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

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

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

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

610,247✔
317
    /**
610,247✔
318
     * Specifies FROM which entity's table select/update/delete will be executed.
610,247✔
319
     * Also sets a main string alias of the selection data.
610,247✔
320
     */
610,247✔
321
    addFrom<T extends ObjectLiteral>(
610,247✔
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

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

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

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

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

610,247✔
385
    /**
610,247✔
386
     * INNER JOINs (without selection).
610,247✔
387
     * You also need to specify an alias of the joined data.
610,247✔
388
     * Optionally, you can add condition and parameters used in condition.
610,247✔
389
     */
610,247✔
390
    innerJoin(
610,247✔
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

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

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

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

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

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

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

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

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

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

610,247✔
523
    /**
610,247✔
524
     * INNER JOINs and adds all selection properties to SELECT.
610,247✔
525
     * You also need to specify an alias of the joined data.
610,247✔
526
     * Optionally, you can add condition and parameters used in condition.
610,247✔
527
     */
610,247✔
528
    innerJoinAndSelect(
610,247✔
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

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

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

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

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

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

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

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

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

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

610,247✔
676
    /**
610,247✔
677
     * INNER JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property.
610,247✔
678
     * This is extremely useful when you want to select some data and map it to some virtual property.
610,247✔
679
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
610,247✔
680
     * You also need to specify an alias of the joined data.
610,247✔
681
     * Optionally, you can add condition and parameters used in condition.
610,247✔
682
     */
610,247✔
683
    innerJoinAndMapMany(
610,247✔
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

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

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

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

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

610,247✔
771
    /**
610,247✔
772
     * INNER JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property.
610,247✔
773
     * This is extremely useful when you want to select some data and map it to some virtual property.
610,247✔
774
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
610,247✔
775
     * You also need to specify an alias of the joined data.
610,247✔
776
     * Optionally, you can add condition and parameters used in condition.
610,247✔
777
     */
610,247✔
778
    innerJoinAndMapOne(
610,247✔
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

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

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

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

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

610,247✔
867
    /**
610,247✔
868
     * LEFT JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property.
610,247✔
869
     * This is extremely useful when you want to select some data and map it to some virtual property.
610,247✔
870
     * It will assume that there are multiple rows of selecting data, and mapped result will be an array.
610,247✔
871
     * You also need to specify an alias of the joined data.
610,247✔
872
     * Optionally, you can add condition and parameters used in condition.
610,247✔
873
     */
610,247✔
874
    leftJoinAndMapMany(
610,247✔
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

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

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

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

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

610,247✔
962
    /**
610,247✔
963
     * LEFT JOINs, SELECTs the data returned by a join and MAPs all that data to some entity's property.
610,247✔
964
     * This is extremely useful when you want to select some data and map it to some virtual property.
610,247✔
965
     * It will assume that there is a single row of selecting data, and mapped result will be a single selected value.
610,247✔
966
     * You also need to specify an alias of the joined data.
610,247✔
967
     * Optionally, you can add condition and parameters used in condition.
610,247✔
968
     */
610,247✔
969
    leftJoinAndMapOne(
610,247✔
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

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

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

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

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

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

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

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

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

33,366✔
1066
        if (relationIdAttribute.relation.junctionEntityMetadata) {
33,366✔
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,366✔
1074
    }
33,366✔
1075

610,247✔
1076
    /**
610,247✔
1077
     * Counts number of entities of entity's relation and maps the value into some entity's property.
610,247✔
1078
     * Optionally, you can add condition and parameters used in condition.
610,247✔
1079
     */
610,247✔
1080
    loadRelationCountAndMap(
610,247✔
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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

610,247✔
1314
    /**
610,247✔
1315
     * Sets GROUP BY condition in the query builder.
610,247✔
1316
     * If you had previously GROUP BY expression defined,
610,247✔
1317
     * calling this function will override previously set GROUP BY conditions.
610,247✔
1318
     */
610,247✔
1319
    groupBy(groupBy?: string): this {
610,247✔
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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

610,247✔
1502
    /**
610,247✔
1503
     * Sets number of entities to skip.
610,247✔
1504
     */
610,247✔
1505
    skip(skip?: number): this {
610,247✔
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

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

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

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

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

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

610,247✔
1556
    /**
610,247✔
1557
     * Sets locking mode.
610,247✔
1558
     */
610,247✔
1559
    setLock(
610,247✔
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

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

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

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

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

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

27,018✔
1627
            const results = await this.loadRawResults(queryRunner)
27,018✔
1628

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

27,003✔
1634
            return results
27,003✔
1635
        } catch (error) {
27,074!
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 {
15,159!
1644
            if (queryRunner !== this.queryRunner) {
27,018✔
1645
                // means we created our own query runner
1,153✔
1646
                await queryRunner.release()
1,153✔
1647
            }
1,153✔
1648
        }
27,018✔
1649
    }
27,074✔
1650

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

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

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

172,342✔
1678
            return results
172,342✔
1679
        } catch (error) {
172,590✔
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,590!
1688
            if (queryRunner !== this.queryRunner)
172,590✔
1689
                // means we created our own query runner
172,590✔
1690
                await queryRunner.release()
172,590✔
1691
        }
172,590✔
1692
    }
172,590✔
1693

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

23,556✔
1701
        if (
23,556✔
1702
            result &&
23,556✔
1703
            this.expressionMap.lockMode === "optimistic" &&
23,800✔
1704
            this.expressionMap.lockVersion
160✔
1705
        ) {
23,800✔
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,502✔
1732
        if (result === undefined) {
23,800✔
1733
            return null
1,476✔
1734
        }
1,476✔
1735
        return result
22,026✔
1736
    }
22,026✔
1737

610,247✔
1738
    /**
610,247✔
1739
     * Gets the first entity returned by execution of generated query builder sql or rejects the returned promise on error.
610,247✔
1740
     */
610,247✔
1741
    async getOneOrFail(): Promise<Entity> {
610,247✔
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

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

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

610,247✔
1765
    /**
610,247✔
1766
     * Gets count - number of entities selected by sql generated by this query builder.
610,247✔
1767
     * Count excludes all limitations set by offset, limit, skip, and take.
610,247✔
1768
     */
610,247✔
1769
    async getCount(): Promise<number> {
610,247✔
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

610,247✔
1809
    /**
610,247✔
1810
     * Gets exists
610,247✔
1811
     * Returns whether any rows exists matching current query.
610,247✔
1812
     */
610,247✔
1813
    async getExists(): Promise<boolean> {
610,247✔
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

610,247✔
1853
    /**
610,247✔
1854
     * Executes built SQL query and returns entities and overall entities count (without limitation).
610,247✔
1855
     * This method is useful to build pagination.
610,247✔
1856
     */
610,247✔
1857
    async getManyAndCount(): Promise<[Entity[], number]> {
610,247✔
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 =
872✔
1875
                await this.executeEntitiesAndRawResults(queryRunner)
872✔
1876
            this.expressionMap.queryEntity = false
862✔
1877

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

610,247✔
2014
    /**
610,247✔
2015
     * Enables or disables query result caching.
610,247✔
2016
     */
610,247✔
2017
    cache(enabled: boolean): this
610,247✔
2018

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

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

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

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

9,279✔
2054
        return this
9,279✔
2055
    }
9,279✔
2056

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

610,247✔
2065
    // -------------------------------------------------------------------------
610,247✔
2066
    // Protected Methods
610,247✔
2067
    // -------------------------------------------------------------------------
610,247✔
2068

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

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

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

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

295,228✔
2162
        // todo throw exception if selects or from is missing
295,228✔
2163

295,228✔
2164
        const allSelects: SelectQuery[] = []
295,228✔
2165
        const excludedSelects: SelectQuery[] = []
295,228✔
2166

295,228✔
2167
        if (this.expressionMap.mainAlias.hasMetadata) {
295,228✔
2168
            const metadata = this.expressionMap.mainAlias.metadata
284,633✔
2169
            allSelects.push(
284,633✔
2170
                ...this.buildEscapedEntityColumnSelects(
284,633✔
2171
                    this.expressionMap.mainAlias.name,
284,633✔
2172
                    metadata,
284,633✔
2173
                ),
284,633✔
2174
            )
284,633✔
2175
            excludedSelects.push(
284,633✔
2176
                ...this.findEntityColumnSelects(
284,633✔
2177
                    this.expressionMap.mainAlias.name,
284,633✔
2178
                    metadata,
284,633✔
2179
                ),
284,633✔
2180
            )
284,633✔
2181
        }
284,633✔
2182

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

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

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

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

295,228✔
2235
        // create a selection query
295,228✔
2236
        const froms = this.expressionMap.aliases
295,228✔
2237
            .filter(
295,228✔
2238
                (alias) =>
295,228✔
2239
                    alias.type === "from" &&
1,287,921✔
2240
                    (alias.tablePath || alias.subQuery),
295,228✔
2241
            )
295,228✔
2242
            .map((alias) => {
295,228✔
2243
                if (alias.subQuery)
295,340✔
2244
                    return alias.subQuery + " " + this.escape(alias.name)
295,340✔
2245

287,401✔
2246
                return (
287,401✔
2247
                    this.getTableName(alias.tablePath!) +
287,401✔
2248
                    " " +
287,401✔
2249
                    this.escape(alias.name)
287,401✔
2250
                )
287,401✔
2251
            })
295,228✔
2252

295,228✔
2253
        const select = this.createSelectDistinctExpression()
295,228✔
2254
        const selection = allSelects
295,228✔
2255
            .map(
295,228✔
2256
                (select) =>
295,228✔
2257
                    select.selection +
5,438,672✔
2258
                    (select.aliasName
5,438,672✔
2259
                        ? " AS " + this.escape(select.aliasName)
5,438,672✔
2260
                        : ""),
295,228✔
2261
            )
295,228✔
2262
            .join(", ")
295,228✔
2263

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

610,247✔
2274
    /**
610,247✔
2275
     * Creates select | select distinct part of SQL query.
610,247✔
2276
     */
610,247✔
2277
    protected createSelectDistinctExpression(): string {
610,247✔
2278
        const { selectDistinct, selectDistinctOn, maxExecutionTime } =
295,228✔
2279
            this.expressionMap
295,228✔
2280
        const { driver } = this.connection
295,228✔
2281

295,228✔
2282
        let select = "SELECT "
295,228✔
2283

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

295,228✔
2290
        if (
295,228✔
2291
            DriverUtils.isPostgresFamily(driver) &&
295,228!
2292
            selectDistinctOn.length > 0
119,618✔
2293
        ) {
295,228!
2294
            const selectDistinctOnMap = selectDistinctOn
12✔
2295
                .map((on) => this.replacePropertyNames(on))
12✔
2296
                .join(", ")
12✔
2297

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

295,228✔
2303
        return select
295,228✔
2304
    }
295,228✔
2305

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

295,228✔
2318
        const joins = this.expressionMap.joinAttributes.map((joinAttr) => {
295,228✔
2319
            const relation = joinAttr.relation
683,989✔
2320
            const destinationTableName = joinAttr.tablePath
683,989✔
2321
            const destinationTableAlias = joinAttr.alias.name
683,989✔
2322
            let appendedCondition = joinAttr.condition
683,989✔
2323
                ? " AND (" + joinAttr.condition + ")"
683,989✔
2324
                : ""
683,989✔
2325
            const parentAlias = joinAttr.parentAlias
683,989✔
2326

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

670,964✔
2347
            // if real entity relation is involved
670,964✔
2348
            if (relation.isManyToOne || relation.isOneToOneOwner) {
683,989✔
2349
                // JOIN `category` `category` ON `category`.`id` = `post`.`categoryId`
15,900✔
2350
                const condition = relation.joinColumns
15,900✔
2351
                    .map((joinColumn) => {
15,900✔
2352
                        return (
17,000✔
2353
                            destinationTableAlias +
17,000✔
2354
                            "." +
17,000✔
2355
                            joinColumn.referencedColumn!.propertyPath +
17,000✔
2356
                            "=" +
17,000✔
2357
                            parentAlias +
17,000✔
2358
                            "." +
17,000✔
2359
                            relation.propertyPath +
17,000✔
2360
                            "." +
17,000✔
2361
                            joinColumn.referencedColumn!.propertyPath
17,000✔
2362
                        )
17,000✔
2363
                    })
15,900✔
2364
                    .join(" AND ")
15,900✔
2365

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

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

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

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

288,912✔
2433
                const junctionAlias = joinAttr.junctionAlias
288,912✔
2434
                let junctionCondition = "",
288,912✔
2435
                    destinationCondition = ""
288,912✔
2436

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

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

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

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

295,228✔
2526
        return joins.join(" ")
295,228✔
2527
    }
295,228✔
2528

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

610,247✔
2541
    /**
610,247✔
2542
     * Creates "ORDER BY" part of SQL query.
610,247✔
2543
     */
610,247✔
2544
    protected createOrderByExpression() {
610,247✔
2545
        const orderBys = this.expressionMap.allOrderBys
295,228✔
2546
        if (Object.keys(orderBys).length === 0) return ""
295,228✔
2547

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

32,746✔
2591
                    return (
32,746✔
2592
                        this.replacePropertyNames(columnName) + " " + orderValue
32,746✔
2593
                    )
32,746✔
2594
                })
24,384✔
2595
                .join(", ")
24,384✔
2596
        )
24,384✔
2597
    }
24,384✔
2598

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

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

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

14,968✔
2634
            if (hasLimit && hasOffset)
14,968✔
2635
                return (
14,968✔
2636
                    prefix +
70✔
2637
                    " OFFSET " +
70✔
2638
                    offset +
70✔
2639
                    " ROWS FETCH NEXT " +
70✔
2640
                    limit +
70✔
2641
                    " ROWS ONLY"
70✔
2642
                )
70✔
2643
            if (hasLimit)
14,898✔
2644
                return (
14,968✔
2645
                    prefix + " OFFSET 0 ROWS FETCH NEXT " + limit + " ROWS ONLY"
1,128✔
2646
                )
1,128✔
2647
            if (hasOffset) return prefix + " OFFSET " + offset + " ROWS"
14,968✔
2648
        } else if (
295,228!
2649
            DriverUtils.isMySQLFamily(this.connection.driver) ||
280,260!
2650
            this.connection.driver.options.type === "aurora-mysql" ||
280,260!
2651
            this.connection.driver.options.type === "sap" ||
280,260!
2652
            this.connection.driver.options.type === "spanner"
202,376✔
2653
        ) {
280,260!
2654
            if (hasLimit && hasOffset)
77,884✔
2655
                return " LIMIT " + limit + " OFFSET " + offset
77,884✔
2656
            if (hasLimit) return " LIMIT " + limit
77,884✔
2657
            if (hasOffset) throw new OffsetWithoutLimitNotSupportedError()
77,884✔
2658
        } else if (DriverUtils.isSQLiteFamily(this.connection.driver)) {
280,260!
2659
            if (hasLimit && hasOffset)
68,652✔
2660
                return " LIMIT " + limit + " OFFSET " + offset
68,652✔
2661
            if (hasLimit) return " LIMIT " + limit
68,652✔
2662
            if (hasOffset) return " LIMIT -1 OFFSET " + offset
68,652✔
2663
        } else if (this.connection.driver.options.type === "oracle") {
202,376!
2664
            if (hasLimit && hasOffset)
14,106✔
2665
                return (
14,106✔
2666
                    " OFFSET " +
70✔
2667
                    offset +
70✔
2668
                    " ROWS FETCH NEXT " +
70✔
2669
                    limit +
70✔
2670
                    " ROWS ONLY"
70✔
2671
                )
70✔
2672
            if (hasLimit) return " FETCH NEXT " + limit + " ROWS ONLY"
14,106✔
2673
            if (hasOffset) return " OFFSET " + offset + " ROWS"
14,106✔
2674
        } else {
133,724!
2675
            if (hasLimit && hasOffset)
119,618✔
2676
                return " LIMIT " + limit + " OFFSET " + offset
119,618✔
2677
            if (hasLimit) return " LIMIT " + limit
119,618✔
2678
            if (hasOffset) return " OFFSET " + offset
119,618✔
2679
        }
119,618✔
2680

277,394✔
2681
        return ""
277,394✔
2682
    }
277,394✔
2683

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

1,268,083✔
2704
        return ""
1,268,083✔
2705
    }
1,268,083✔
2706

610,247✔
2707
    /**
610,247✔
2708
     * Creates "LOCK" part of SQL query.
610,247✔
2709
     */
610,247✔
2710
    protected createLockExpression(): string {
610,247✔
2711
        const driver = this.connection.driver
295,218✔
2712

295,218✔
2713
        let lockTablesClause = ""
295,218✔
2714

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

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

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

4✔
2851
        if (!conditions.length) return ""
62,846!
2852
        return " HAVING " + conditions
4✔
2853
    }
4✔
2854

610,247✔
2855
    protected buildEscapedEntityColumnSelects(
610,247✔
2856
        aliasName: string,
968,519✔
2857
        metadata: EntityMetadata,
968,519✔
2858
    ): SelectQuery[] {
968,519✔
2859
        const hasMainAlias = this.expressionMap.selects.some(
968,519✔
2860
            (select) => select.selection === aliasName,
968,519✔
2861
        )
968,519✔
2862

968,519✔
2863
        const columns: ColumnMetadata[] = []
968,519✔
2864
        if (hasMainAlias) {
968,519✔
2865
            columns.push(
921,928✔
2866
                ...metadata.columns.filter(
921,928✔
2867
                    (column) => column.isSelect === true,
921,928✔
2868
                ),
921,928✔
2869
            )
921,928✔
2870
        }
921,928✔
2871
        columns.push(
968,519✔
2872
            ...metadata.columns.filter((column) => {
968,519✔
2873
                return this.expressionMap.selects.some(
5,532,904✔
2874
                    (select) =>
5,532,904✔
2875
                        select.selection ===
46,434,560✔
2876
                        aliasName + "." + column.propertyPath,
5,532,904✔
2877
                )
5,532,904✔
2878
            }),
968,519✔
2879
        )
968,519✔
2880

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

952,968✔
2888
        const nonSelectedPrimaryColumns = this.expressionMap.queryEntity
952,968✔
2889
            ? metadata.primaryColumns.filter(
968,519✔
2890
                  (primaryColumn) => columns.indexOf(primaryColumn) === -1,
177,555✔
2891
              )
968,519✔
2892
            : []
968,519✔
2893
        const allColumns = [...columns, ...nonSelectedPrimaryColumns]
968,519✔
2894
        const finalSelects: SelectQuery[] = []
968,519✔
2895

968,519✔
2896
        const escapedAliasName = this.escape(aliasName)
968,519✔
2897
        allColumns.forEach((column) => {
968,519✔
2898
            let selectionPath =
5,421,108✔
2899
                escapedAliasName + "." + this.escape(column.databaseName)
5,421,108✔
2900

5,421,108✔
2901
            if (column.isVirtualProperty && column.query) {
5,421,108✔
2902
                selectionPath = `(${column.query(escapedAliasName)})`
538✔
2903
            }
538✔
2904

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

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

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

610,247✔
2969
    protected findEntityColumnSelects(
610,247✔
2970
        aliasName: string,
968,519✔
2971
        metadata: EntityMetadata,
968,519✔
2972
    ): SelectQuery[] {
968,519✔
2973
        return this.expressionMap.selects.filter(
968,519✔
2974
            (select) =>
968,519✔
2975
                select.selection === aliasName ||
6,944,345✔
2976
                metadata.columns.some(
6,022,417✔
2977
                    (column) =>
6,022,417✔
2978
                        select.selection ===
41,021,229✔
2979
                        aliasName + "." + column.propertyPath,
6,022,417✔
2980
                ),
968,519✔
2981
        )
968,519✔
2982
    }
968,519✔
2983

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

610,247✔
3130
    protected applyFindOptions() {
610,247✔
3131
        // todo: convert relations: string[] to object map to simplify code
184,228✔
3132
        // todo: same with selects
184,228✔
3133

184,228✔
3134
        if (this.expressionMap.mainAlias!.metadata) {
184,228✔
3135
            if (this.findOptions.relationLoadStrategy) {
184,228!
3136
                this.expressionMap.relationLoadStrategy =
24✔
3137
                    this.findOptions.relationLoadStrategy
24✔
3138
            }
24✔
3139

184,228✔
3140
            if (this.findOptions.comment) {
184,228✔
3141
                this.comment(this.findOptions.comment)
28✔
3142
            }
28✔
3143

184,228✔
3144
            if (this.findOptions.withDeleted) {
184,228✔
3145
                this.withDeleted()
118,117✔
3146
            }
118,117✔
3147

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

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

184,200✔
3162
            if (this.selects.length) {
184,228✔
3163
                this.select(this.selects)
639✔
3164
            }
639✔
3165

184,200✔
3166
            this.selects = []
184,200✔
3167

184,200✔
3168
            if (this.findOptions.relations) {
184,228✔
3169
                const relations = Array.isArray(this.findOptions.relations)
47,286✔
3170
                    ? OrmUtils.propertyPathsToTruthyObject(
47,286✔
3171
                          this.findOptions.relations,
140✔
3172
                      )
47,286✔
3173
                    : this.findOptions.relations
47,286✔
3174

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

184,032✔
3202
            if (this.findOptions.where) {
184,228✔
3203
                this.conditions = this.buildWhere(
60,738✔
3204
                    this.findOptions.where,
60,738✔
3205
                    this.expressionMap.mainAlias!.metadata,
60,738✔
3206
                    this.expressionMap.mainAlias!.name,
60,738✔
3207
                )
60,738✔
3208

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

183,752✔
3217
            if (this.findOptions.order) {
184,228✔
3218
                this.buildOrder(
2,614✔
3219
                    this.findOptions.order,
2,614✔
3220
                    this.expressionMap.mainAlias!.metadata,
2,614✔
3221
                    this.expressionMap.mainAlias!.name,
2,614✔
3222
                )
2,614✔
3223
            }
2,614✔
3224

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

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

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

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

183,696✔
3283
            // apply limit
183,696✔
3284
            if (this.findOptions.take !== undefined) {
184,228✔
3285
                // if (this.findOptions.options && this.findOptions.options.pagination === false) {
16,465✔
3286
                //     this.limit(this.findOptions.take);
16,465✔
3287
                // } else {
16,465✔
3288
                this.take(this.findOptions.take)
16,465✔
3289
                // }
16,465✔
3290
            }
16,465✔
3291

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

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

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

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

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

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

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

183,663✔
3392
            if (this.findOptions.loadRelationIds === true) {
184,228✔
3393
                this.loadAllRelationIds()
28✔
3394
            } else if (typeof this.findOptions.loadRelationIds === "object") {
184,228✔
3395
                this.loadAllRelationIds(this.findOptions.loadRelationIds as any)
117,745✔
3396
            }
117,745✔
3397

183,663✔
3398
            if (this.findOptions.loadEagerRelations !== false) {
184,228✔
3399
                FindOptionsUtils.joinEagerRelations(
65,862✔
3400
                    this,
65,862✔
3401
                    this.expressionMap.mainAlias!.name,
65,862✔
3402
                    this.expressionMap.mainAlias!.metadata,
65,862✔
3403
                )
65,862✔
3404
            }
65,862✔
3405

183,663✔
3406
            if (this.findOptions.transaction === true) {
184,228✔
3407
                this.expressionMap.useTransaction = true
28✔
3408
            }
28✔
3409

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

184,228✔
3416
            // todo
184,228✔
3417
            // if (this.options.options && this.options.options.eagerRelations) {
184,228✔
3418
            //     this.queryBuilder
184,228✔
3419
            // }
184,228✔
3420

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

610,247✔
3428
    public concatRelationMetadata(relationMetadata: RelationMetadata) {
610,247✔
3429
        this.relationMetadatas.push(relationMetadata)
20✔
3430
    }
20✔
3431

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

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

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

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

173,341✔
3477
        let rawResults: any[] = [],
173,341✔
3478
            entities: any[] = []
173,341✔
3479

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

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

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

7,571✔
3517
                    return `${distinctAlias}.${columnAlias} AS ${this.escape(
7,571✔
3518
                        alias,
7,571✔
3519
                    )}`
7,571✔
3520
                },
7,455✔
3521
            )
7,455✔
3522

7,455✔
3523
            const originalQuery = this.clone()
7,455✔
3524

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

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

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

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

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

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

173,204✔
3646
        if (this.expressionMap.relationLoadStrategy === "query") {
173,462!
3647
            const queryStrategyRelationIdLoader =
72✔
3648
                new QueryStrategyRelationIdLoader(this.connection, queryRunner)
72✔
3649

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

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

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

173,204✔
3718
        return {
173,204✔
3719
            raw: rawResults,
173,204✔
3720
            entities: entities,
173,204✔
3721
        }
173,204✔
3722
    }
173,204✔
3723

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

8!
3764
                    return ""
8✔
3765
                }
8✔
3766
            })
7,455✔
3767
            .join(", ")
7,455✔
3768

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

7,455✔
3809
        return [selectString, orderByObject]
7,455✔
3810
    }
7,455✔
3811

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

200,840✔
3866
        const results = await queryRunner.query(sql, parameters, true)
200,840✔
3867

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

200,821✔
3895
        return results.records
200,821✔
3896
    }
200,821✔
3897

610,247✔
3898
    /**
610,247✔
3899
     * Merges into expression map given expression map properties.
610,247✔
3900
     */
610,247✔
3901
    protected mergeExpressionMap(
610,247✔
3902
        expressionMap: Partial<QueryExpressionMap>,
7,290✔
3903
    ): this {
7,290✔
3904
        ObjectUtils.assign(this.expressionMap, expressionMap)
7,290✔
3905
        return this
7,290✔
3906
    }
7,290✔
3907

610,247✔
3908
    /**
610,247✔
3909
     * Normalizes a give number - converts to int if possible.
610,247✔
3910
     */
610,247✔
3911
    protected normalizeNumber(num: any) {
610,247✔
3912
        if (typeof num === "number" || num === undefined || num === null)
38,899✔
3913
            return num
38,899✔
3914

112✔
3915
        return Number(num)
112✔
3916
    }
112✔
3917

610,247✔
3918
    /**
610,247✔
3919
     * Creates a query builder used to execute sql queries inside this query builder.
610,247✔
3920
     */
610,247✔
3921
    protected obtainQueryRunner() {
610,247✔
3922
        return (
201,545✔
3923
            this.queryRunner ||
201,545✔
3924
            this.connection.createQueryRunner(
48,665✔
3925
                this.connection.defaultReplicationModeForReads(),
48,665✔
3926
            )
201,545✔
3927
        )
201,545✔
3928
    }
201,545✔
3929

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

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

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

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

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

610,247✔
3976
    protected buildRelations(
610,247✔
3977
        relations: FindOptionsRelations<any>,
48,422✔
3978
        selection: FindOptionsSelect<any> | undefined,
48,422✔
3979
        metadata: EntityMetadata,
48,422✔
3980
        alias: string,
48,422✔
3981
        embedPrefix?: string,
48,422✔
3982
    ) {
48,422✔
3983
        if (!relations) return
48,422!
3984

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

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

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

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

610,247✔
4072
    protected buildEagerRelations(
610,247✔
4073
        relations: FindOptionsRelations<any>,
48,146✔
4074
        selection: FindOptionsSelect<any> | undefined,
48,146✔
4075
        metadata: EntityMetadata,
48,146✔
4076
        alias: string,
48,146✔
4077
        embedPrefix?: string,
48,146✔
4078
    ) {
48,146✔
4079
        if (!relations) return
48,146!
4080

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

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

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

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

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

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

610,247✔
4175
    protected buildOrder(
610,247✔
4176
        order: FindOptionsOrder<any>,
3,258✔
4177
        metadata: EntityMetadata,
3,258✔
4178
        alias: string,
3,258✔
4179
        embedPrefix?: string,
3,258✔
4180
    ) {
3,258✔
4181
        for (const key in order) {
3,258✔
4182
            if (order[key] === undefined) continue
3,622!
4183

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

3,622✔
4190
            if (!embed && !column && !relation)
3,622✔
4191
                throw new EntityPropertyNotFoundError(propertyPath, metadata)
3,622✔
4192

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

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

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

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

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

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

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

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

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

63,160✔
4352
                if (column) {
63,749✔
4353
                    let aliasPath = `${alias}.${propertyPath}`
60,772✔
4354
                    if (column.isVirtualProperty && column.query) {
60,772✔
4355
                        aliasPath = `(${column.query(this.escape(alias))})`
112✔
4356
                    }
112✔
4357

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

60,660✔
4363
                    // const parameterName = alias + "_" + propertyPath.split(".").join("_") + "_" + parameterIndex;
60,660✔
4364

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

60,660✔
4370
                    if (column.transformer) {
60,772✔
4371
                        if (parameterValue instanceof FindOperator) {
126✔
4372
                            parameterValue.transformValue(column.transformer)
44✔
4373
                        } else {
126✔
4374
                            parameterValue = ApplyValueTransformers.transformTo(
82✔
4375
                                column.transformer,
82✔
4376
                                parameterValue,
82✔
4377
                            )
82✔
4378
                        }
82✔
4379
                    }
126✔
4380

60,660✔
4381
                    // MSSQL requires parameters to carry extra type information
60,660✔
4382
                    if (this.connection.driver.options.type === "mssql") {
60,764!
4383
                        parameterValue = (
1,406✔
4384
                            this.connection.driver as SqlServerDriver
1,406✔
4385
                        ).parametrizeValues(column, parameterValue)
1,406✔
4386
                    }
1,406✔
4387

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

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

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

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

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

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

1,100✔
4590
                        const condition = this.buildWhere(
1,100✔
4591
                            where[key],
1,100✔
4592
                            relation.inverseEntityMetadata,
1,100✔
4593
                            joinAlias,
1,100✔
4594
                        )
1,100✔
4595
                        if (condition) {
1,100✔
4596
                            andConditions.push(condition)
1,016✔
4597
                            // parameterIndex = Object.keys(this.expressionMap.nativeParameters).length;
1,016✔
4598
                        }
1,016✔
4599
                    }
1,100✔
4600
                }
1,828✔
4601
            }
63,749✔
4602
            condition = andConditions.length
62,310✔
4603
                ? "(" + andConditions.join(") AND (") + ")"
62,590✔
4604
                : andConditions.join(" AND ")
62,590✔
4605
        }
62,590✔
4606
        return condition.length ? "(" + condition + ")" : condition
62,790✔
4607
    }
62,790✔
4608
}
610,247✔
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