@mikro-orm/sql 7.0.0-dev.97 → 7.0.0-dev.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/AbstractSqlConnection.d.ts +57 -0
  2. package/AbstractSqlConnection.js +239 -0
  3. package/AbstractSqlDriver.d.ts +94 -0
  4. package/AbstractSqlDriver.js +1387 -0
  5. package/AbstractSqlPlatform.d.ts +38 -0
  6. package/AbstractSqlPlatform.js +104 -0
  7. package/LICENSE +21 -0
  8. package/PivotCollectionPersister.d.ts +22 -0
  9. package/PivotCollectionPersister.js +159 -0
  10. package/README.md +390 -0
  11. package/SqlEntityManager.d.ts +33 -0
  12. package/SqlEntityManager.js +44 -0
  13. package/SqlEntityRepository.d.ts +19 -0
  14. package/SqlEntityRepository.js +26 -0
  15. package/dialects/index.d.ts +4 -0
  16. package/dialects/index.js +4 -0
  17. package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +14 -0
  18. package/dialects/mssql/MsSqlNativeQueryBuilder.js +200 -0
  19. package/dialects/mssql/index.d.ts +1 -0
  20. package/dialects/mssql/index.js +1 -0
  21. package/dialects/mysql/MySqlExceptionConverter.d.ts +9 -0
  22. package/dialects/mysql/MySqlExceptionConverter.js +80 -0
  23. package/dialects/mysql/MySqlNativeQueryBuilder.d.ts +7 -0
  24. package/dialects/mysql/MySqlNativeQueryBuilder.js +77 -0
  25. package/dialects/mysql/MySqlPlatform.d.ts +45 -0
  26. package/dialects/mysql/MySqlPlatform.js +116 -0
  27. package/dialects/mysql/MySqlSchemaHelper.d.ts +36 -0
  28. package/dialects/mysql/MySqlSchemaHelper.js +269 -0
  29. package/dialects/mysql/index.d.ts +4 -0
  30. package/dialects/mysql/index.js +4 -0
  31. package/dialects/postgresql/PostgreSqlNativeQueryBuilder.d.ts +5 -0
  32. package/dialects/postgresql/PostgreSqlNativeQueryBuilder.js +8 -0
  33. package/dialects/postgresql/PostgreSqlTableCompiler.d.ts +1 -0
  34. package/dialects/postgresql/PostgreSqlTableCompiler.js +1 -0
  35. package/dialects/postgresql/index.d.ts +1 -0
  36. package/dialects/postgresql/index.js +1 -0
  37. package/dialects/sqlite/BaseSqliteConnection.d.ts +6 -0
  38. package/dialects/sqlite/BaseSqliteConnection.js +8 -0
  39. package/dialects/sqlite/BaseSqlitePlatform.d.ts +70 -0
  40. package/dialects/sqlite/BaseSqlitePlatform.js +104 -0
  41. package/dialects/sqlite/SqliteExceptionConverter.d.ts +9 -0
  42. package/dialects/sqlite/SqliteExceptionConverter.js +54 -0
  43. package/dialects/sqlite/SqliteNativeQueryBuilder.d.ts +6 -0
  44. package/dialects/sqlite/SqliteNativeQueryBuilder.js +11 -0
  45. package/dialects/sqlite/SqliteSchemaHelper.d.ts +38 -0
  46. package/dialects/sqlite/SqliteSchemaHelper.js +379 -0
  47. package/dialects/sqlite/index.d.ts +5 -0
  48. package/dialects/sqlite/index.js +5 -0
  49. package/index.d.ts +19 -0
  50. package/index.js +19 -0
  51. package/package.json +3 -3
  52. package/plugin/index.d.ts +53 -0
  53. package/plugin/index.js +42 -0
  54. package/plugin/transformer.d.ts +115 -0
  55. package/plugin/transformer.js +883 -0
  56. package/query/ArrayCriteriaNode.d.ts +11 -0
  57. package/query/ArrayCriteriaNode.js +24 -0
  58. package/query/CriteriaNode.d.ts +29 -0
  59. package/query/CriteriaNode.js +121 -0
  60. package/query/CriteriaNodeFactory.d.ts +12 -0
  61. package/query/CriteriaNodeFactory.js +90 -0
  62. package/query/NativeQueryBuilder.d.ts +108 -0
  63. package/query/NativeQueryBuilder.js +425 -0
  64. package/query/ObjectCriteriaNode.d.ts +19 -0
  65. package/query/ObjectCriteriaNode.js +249 -0
  66. package/query/QueryBuilder.d.ts +389 -0
  67. package/query/QueryBuilder.js +1558 -0
  68. package/query/QueryBuilderHelper.d.ts +73 -0
  69. package/query/QueryBuilderHelper.js +756 -0
  70. package/query/ScalarCriteriaNode.d.ts +10 -0
  71. package/query/ScalarCriteriaNode.js +49 -0
  72. package/query/enums.d.ts +18 -0
  73. package/query/enums.js +20 -0
  74. package/query/index.d.ts +10 -0
  75. package/query/index.js +10 -0
  76. package/query/raw.d.ts +59 -0
  77. package/query/raw.js +68 -0
  78. package/schema/DatabaseSchema.d.ts +45 -0
  79. package/schema/DatabaseSchema.js +185 -0
  80. package/schema/DatabaseTable.d.ts +68 -0
  81. package/schema/DatabaseTable.js +793 -0
  82. package/schema/SchemaComparator.d.ts +58 -0
  83. package/schema/SchemaComparator.js +577 -0
  84. package/schema/SchemaHelper.d.ts +76 -0
  85. package/schema/SchemaHelper.js +545 -0
  86. package/schema/SqlSchemaGenerator.d.ts +65 -0
  87. package/schema/SqlSchemaGenerator.js +375 -0
  88. package/schema/index.d.ts +5 -0
  89. package/schema/index.js +5 -0
  90. package/typings.d.ts +272 -0
  91. package/typings.js +1 -0
@@ -0,0 +1,1558 @@
1
+ import { helper, isRaw, LoadStrategy, LockMode, PopulateHint, QueryFlag, QueryHelper, raw, RawQueryFragment, Reference, ReferenceKind, serialize, Utils, ValidationError, inspect, } from '@mikro-orm/core';
2
+ import { JoinType, QueryType } from './enums.js';
3
+ import { QueryBuilderHelper } from './QueryBuilderHelper.js';
4
+ import { CriteriaNodeFactory } from './CriteriaNodeFactory.js';
5
+ import { NativeQueryBuilder } from './NativeQueryBuilder.js';
6
+ /**
7
+ * SQL query builder with fluent interface.
8
+ *
9
+ * ```ts
10
+ * const qb = orm.em.createQueryBuilder(Publisher);
11
+ * qb.select('*')
12
+ * .where({
13
+ * name: 'test 123',
14
+ * type: PublisherType.GLOBAL,
15
+ * })
16
+ * .orderBy({
17
+ * name: QueryOrder.DESC,
18
+ * type: QueryOrder.ASC,
19
+ * })
20
+ * .limit(2, 1);
21
+ *
22
+ * const publisher = await qb.getSingleResult();
23
+ * ```
24
+ */
25
+ export class QueryBuilder {
26
+ metadata;
27
+ driver;
28
+ context;
29
+ connectionType;
30
+ em;
31
+ loggerContext;
32
+ get mainAlias() {
33
+ this.ensureFromClause();
34
+ return this._mainAlias;
35
+ }
36
+ get alias() {
37
+ return this.mainAlias.aliasName;
38
+ }
39
+ get helper() {
40
+ this.ensureFromClause();
41
+ return this._helper;
42
+ }
43
+ get type() {
44
+ return this._type ?? QueryType.SELECT;
45
+ }
46
+ /** @internal */
47
+ _populate = [];
48
+ /** @internal */
49
+ _populateMap = {};
50
+ /** @internal */
51
+ rawFragments = new Set();
52
+ aliasCounter = 0;
53
+ flags = new Set([QueryFlag.CONVERT_CUSTOM_TYPES]);
54
+ finalized = false;
55
+ populateHintFinalized = false;
56
+ _joins = {};
57
+ _explicitAlias = false;
58
+ _schema;
59
+ _cond = {};
60
+ _data;
61
+ _orderBy = [];
62
+ _groupBy = [];
63
+ _having = {};
64
+ _returning;
65
+ _onConflict;
66
+ _limit;
67
+ _offset;
68
+ _distinctOn;
69
+ _joinedProps = new Map();
70
+ _cache;
71
+ _indexHint;
72
+ _comments = [];
73
+ _hintComments = [];
74
+ flushMode;
75
+ lockMode;
76
+ lockTables;
77
+ subQueries = {};
78
+ _mainAlias;
79
+ _aliases = {};
80
+ _helper;
81
+ _query;
82
+ platform;
83
+ /**
84
+ * @internal
85
+ */
86
+ constructor(entityName, metadata, driver, context, alias, connectionType, em, loggerContext) {
87
+ this.metadata = metadata;
88
+ this.driver = driver;
89
+ this.context = context;
90
+ this.connectionType = connectionType;
91
+ this.em = em;
92
+ this.loggerContext = loggerContext;
93
+ this.platform = this.driver.getPlatform();
94
+ if (alias) {
95
+ this.aliasCounter++;
96
+ this._explicitAlias = true;
97
+ }
98
+ // @ts-expect-error union type does not match the overloaded method signature
99
+ this.from(entityName, alias);
100
+ }
101
+ select(fields, distinct = false) {
102
+ this.ensureNotFinalized();
103
+ this._fields = Utils.asArray(fields);
104
+ if (distinct) {
105
+ this.flags.add(QueryFlag.DISTINCT);
106
+ }
107
+ return this.init(QueryType.SELECT);
108
+ }
109
+ addSelect(fields) {
110
+ this.ensureNotFinalized();
111
+ if (this._type && this._type !== QueryType.SELECT) {
112
+ return this;
113
+ }
114
+ return this.select([...Utils.asArray(this._fields), ...Utils.asArray(fields)]);
115
+ }
116
+ distinct() {
117
+ this.ensureNotFinalized();
118
+ return this.setFlag(QueryFlag.DISTINCT);
119
+ }
120
+ /** postgres only */
121
+ distinctOn(fields) {
122
+ this.ensureNotFinalized();
123
+ this._distinctOn = Utils.asArray(fields);
124
+ return this;
125
+ }
126
+ insert(data) {
127
+ return this.init(QueryType.INSERT, data);
128
+ }
129
+ update(data) {
130
+ return this.init(QueryType.UPDATE, data);
131
+ }
132
+ delete(cond) {
133
+ return this.init(QueryType.DELETE, undefined, cond);
134
+ }
135
+ truncate() {
136
+ return this.init(QueryType.TRUNCATE);
137
+ }
138
+ count(field, distinct = false) {
139
+ if (field) {
140
+ this._fields = Utils.asArray(field);
141
+ }
142
+ else if (distinct || this.hasToManyJoins()) {
143
+ this._fields = this.mainAlias.metadata.primaryKeys;
144
+ }
145
+ else {
146
+ this._fields = [raw('*')];
147
+ }
148
+ if (distinct) {
149
+ this.flags.add(QueryFlag.DISTINCT);
150
+ }
151
+ return this.init(QueryType.COUNT);
152
+ }
153
+ join(field, alias, cond = {}, type = JoinType.innerJoin, path, schema) {
154
+ this.joinReference(field, alias, cond, type, path, schema);
155
+ return this;
156
+ }
157
+ innerJoin(field, alias, cond = {}, schema) {
158
+ this.join(field, alias, cond, JoinType.innerJoin, undefined, schema);
159
+ return this;
160
+ }
161
+ innerJoinLateral(field, alias, cond, schema) {
162
+ this.join(field, alias, cond, JoinType.innerJoinLateral, undefined, schema);
163
+ return this;
164
+ }
165
+ leftJoin(field, alias, cond = {}, schema) {
166
+ return this.join(field, alias, cond, JoinType.leftJoin, undefined, schema);
167
+ }
168
+ leftJoinLateral(field, alias, cond, schema) {
169
+ return this.join(field, alias, cond, JoinType.leftJoinLateral, undefined, schema);
170
+ }
171
+ joinAndSelect(field, alias, cond = {}, type = JoinType.innerJoin, path, fields, schema) {
172
+ if (!this._type) {
173
+ this.select('*');
174
+ }
175
+ let subquery;
176
+ if (Array.isArray(field)) {
177
+ const rawFragment = field[1] instanceof QueryBuilder ? field[1].toRaw() : field[1];
178
+ subquery = this.platform.formatQuery(rawFragment.sql, rawFragment.params);
179
+ field = field[0];
180
+ }
181
+ const { prop, key } = this.joinReference(field, alias, cond, type, path, schema, subquery);
182
+ const [fromAlias] = this.helper.splitField(field);
183
+ if (subquery) {
184
+ this._joins[key].subquery = subquery;
185
+ }
186
+ const populate = this._joinedProps.get(fromAlias);
187
+ const item = { field: prop.name, strategy: LoadStrategy.JOINED, children: [] };
188
+ if (populate) {
189
+ populate.children.push(item);
190
+ }
191
+ else { // root entity
192
+ this._populate.push(item);
193
+ }
194
+ this._joinedProps.set(alias, item);
195
+ this.addSelect(this.getFieldsForJoinedLoad(prop, alias, fields));
196
+ return this;
197
+ }
198
+ leftJoinAndSelect(field, alias, cond = {}, fields, schema) {
199
+ return this.joinAndSelect(field, alias, cond, JoinType.leftJoin, undefined, fields, schema);
200
+ }
201
+ leftJoinLateralAndSelect(field, alias, cond = {}, fields, schema) {
202
+ return this.joinAndSelect(field, alias, cond, JoinType.leftJoinLateral, undefined, fields, schema);
203
+ }
204
+ innerJoinAndSelect(field, alias, cond = {}, fields, schema) {
205
+ return this.joinAndSelect(field, alias, cond, JoinType.innerJoin, undefined, fields, schema);
206
+ }
207
+ innerJoinLateralAndSelect(field, alias, cond = {}, fields, schema) {
208
+ return this.joinAndSelect(field, alias, cond, JoinType.innerJoinLateral, undefined, fields, schema);
209
+ }
210
+ getFieldsForJoinedLoad(prop, alias, explicitFields) {
211
+ const fields = [];
212
+ const populate = [];
213
+ const joinKey = Object.keys(this._joins).find(join => join.endsWith(`#${alias}`));
214
+ if (joinKey) {
215
+ const path = this._joins[joinKey].path.split('.').slice(1);
216
+ let children = this._populate;
217
+ for (let i = 0; i < path.length; i++) {
218
+ const child = children.filter(hint => {
219
+ const [propName] = hint.field.split(':', 2);
220
+ return propName === path[i];
221
+ });
222
+ children = child.flatMap(c => c.children);
223
+ }
224
+ populate.push(...children);
225
+ }
226
+ for (const p of prop.targetMeta.getPrimaryProps()) {
227
+ fields.push(...this.driver.mapPropToFieldNames(this, p, alias));
228
+ }
229
+ if (explicitFields) {
230
+ for (const field of explicitFields) {
231
+ const [a, f] = this.helper.splitField(field);
232
+ const p = prop.targetMeta.properties[f];
233
+ if (p) {
234
+ fields.push(...this.driver.mapPropToFieldNames(this, p, alias));
235
+ }
236
+ else {
237
+ fields.push(`${a}.${f} as ${a}__${f}`);
238
+ }
239
+ }
240
+ }
241
+ prop.targetMeta.props
242
+ .filter(prop => {
243
+ if (!explicitFields) {
244
+ return this.platform.shouldHaveColumn(prop, populate);
245
+ }
246
+ return prop.primary && !explicitFields.includes(prop.name) && !explicitFields.includes(`${alias}.${prop.name}`);
247
+ })
248
+ .forEach(prop => fields.push(...this.driver.mapPropToFieldNames(this, prop, alias)));
249
+ return fields;
250
+ }
251
+ /**
252
+ * Apply filters to the QB where condition.
253
+ */
254
+ async applyFilters(filterOptions = {}) {
255
+ /* v8 ignore next */
256
+ if (!this.em) {
257
+ throw new Error('Cannot apply filters, this QueryBuilder is not attached to an EntityManager');
258
+ }
259
+ const cond = await this.em.applyFilters(this.mainAlias.entityName, {}, filterOptions, 'read');
260
+ this.andWhere(cond);
261
+ }
262
+ autoJoinedPaths = [];
263
+ /**
264
+ * @internal
265
+ */
266
+ scheduleFilterCheck(path) {
267
+ this.autoJoinedPaths.push(path);
268
+ }
269
+ /**
270
+ * @internal
271
+ */
272
+ async applyJoinedFilters(em, filterOptions) {
273
+ for (const path of this.autoJoinedPaths) {
274
+ const join = this.getJoinForPath(path);
275
+ if (join.type === JoinType.pivotJoin) {
276
+ continue;
277
+ }
278
+ filterOptions = QueryHelper.mergePropertyFilters(join.prop.filters, filterOptions);
279
+ const cond = await em.applyFilters(join.prop.type, join.cond, filterOptions, 'read');
280
+ if (Utils.hasObjectKeys(cond)) {
281
+ // remove nested filters, we only care about scalars here, nesting would require another join branch
282
+ for (const key of Object.keys(cond)) {
283
+ if (Utils.isPlainObject(cond[key]) && Object.keys(cond[key]).every(k => !(Utils.isOperator(k) && !['$some', '$none', '$every'].includes(k)))) {
284
+ delete cond[key];
285
+ }
286
+ }
287
+ if (Utils.hasObjectKeys(join.cond)) {
288
+ /* v8 ignore next */
289
+ join.cond = { $and: [join.cond, cond] };
290
+ }
291
+ else {
292
+ join.cond = { ...cond };
293
+ }
294
+ }
295
+ }
296
+ }
297
+ withSubQuery(subQuery, alias) {
298
+ this.ensureNotFinalized();
299
+ if (subQuery instanceof RawQueryFragment) {
300
+ this.subQueries[alias] = this.platform.formatQuery(subQuery.sql, subQuery.params);
301
+ }
302
+ else {
303
+ this.subQueries[alias] = subQuery.toString();
304
+ }
305
+ return this;
306
+ }
307
+ where(cond, params, operator) {
308
+ this.ensureNotFinalized();
309
+ const rawField = RawQueryFragment.getKnownFragment(cond);
310
+ if (rawField) {
311
+ const sql = this.platform.formatQuery(rawField.sql, rawField.params);
312
+ cond = { [raw(`(${sql})`)]: Utils.asArray(params) };
313
+ operator ??= '$and';
314
+ }
315
+ else if (typeof cond === 'string') {
316
+ cond = { [raw(`(${cond})`, Utils.asArray(params))]: [] };
317
+ operator ??= '$and';
318
+ }
319
+ else {
320
+ cond = QueryHelper.processWhere({
321
+ where: cond,
322
+ entityName: this.mainAlias.entityName,
323
+ metadata: this.metadata,
324
+ platform: this.platform,
325
+ aliasMap: this.getAliasMap(),
326
+ aliased: [QueryType.SELECT, QueryType.COUNT].includes(this.type),
327
+ convertCustomTypes: this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES),
328
+ });
329
+ }
330
+ const op = operator || params;
331
+ const topLevel = !op || !Utils.hasObjectKeys(this._cond);
332
+ const criteriaNode = CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond);
333
+ const ignoreBranching = this.__populateWhere === 'infer';
334
+ if ([QueryType.UPDATE, QueryType.DELETE].includes(this.type) && criteriaNode.willAutoJoin(this, undefined, { ignoreBranching })) {
335
+ // use sub-query to support joining
336
+ this.setFlag(this.type === QueryType.UPDATE ? QueryFlag.UPDATE_SUB_QUERY : QueryFlag.DELETE_SUB_QUERY);
337
+ this.select(this.mainAlias.metadata.primaryKeys, true);
338
+ }
339
+ if (topLevel) {
340
+ this._cond = criteriaNode.process(this, { ignoreBranching });
341
+ }
342
+ else if (Array.isArray(this._cond[op])) {
343
+ this._cond[op].push(criteriaNode.process(this, { ignoreBranching }));
344
+ }
345
+ else {
346
+ const cond1 = [this._cond, criteriaNode.process(this, { ignoreBranching })];
347
+ this._cond = { [op]: cond1 };
348
+ }
349
+ if (this._onConflict) {
350
+ this._onConflict[this._onConflict.length - 1].where = this.helper.processOnConflictCondition(this._cond, this._schema);
351
+ this._cond = {};
352
+ }
353
+ return this;
354
+ }
355
+ andWhere(cond, params) {
356
+ return this.where(cond, params, '$and');
357
+ }
358
+ orWhere(cond, params) {
359
+ return this.where(cond, params, '$or');
360
+ }
361
+ orderBy(orderBy) {
362
+ return this.processOrderBy(orderBy, true);
363
+ }
364
+ andOrderBy(orderBy) {
365
+ return this.processOrderBy(orderBy, false);
366
+ }
367
+ processOrderBy(orderBy, reset = true) {
368
+ this.ensureNotFinalized();
369
+ if (reset) {
370
+ this._orderBy = [];
371
+ }
372
+ Utils.asArray(orderBy).forEach(o => {
373
+ const processed = QueryHelper.processWhere({
374
+ where: o,
375
+ entityName: this.mainAlias.entityName,
376
+ metadata: this.metadata,
377
+ platform: this.platform,
378
+ aliasMap: this.getAliasMap(),
379
+ aliased: [QueryType.SELECT, QueryType.COUNT].includes(this.type),
380
+ convertCustomTypes: false,
381
+ type: 'orderBy',
382
+ });
383
+ this._orderBy.push(CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, processed).process(this, { matchPopulateJoins: true, type: 'orderBy' }));
384
+ });
385
+ return this;
386
+ }
387
+ groupBy(fields) {
388
+ this.ensureNotFinalized();
389
+ this._groupBy = Utils.asArray(fields);
390
+ return this;
391
+ }
392
+ having(cond = {}, params, operator) {
393
+ this.ensureNotFinalized();
394
+ if (typeof cond === 'string') {
395
+ cond = { [raw(`(${cond})`, params)]: [] };
396
+ }
397
+ cond = CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond).process(this);
398
+ if (!this._having || !operator) {
399
+ this._having = cond;
400
+ }
401
+ else {
402
+ const cond1 = [this._having, cond];
403
+ this._having = { [operator]: cond1 };
404
+ }
405
+ return this;
406
+ }
407
+ andHaving(cond, params) {
408
+ return this.having(cond, params, '$and');
409
+ }
410
+ orHaving(cond, params) {
411
+ return this.having(cond, params, '$or');
412
+ }
413
+ onConflict(fields = []) {
414
+ const meta = this.mainAlias.metadata;
415
+ this.ensureNotFinalized();
416
+ this._onConflict ??= [];
417
+ this._onConflict.push({
418
+ fields: isRaw(fields)
419
+ ? fields
420
+ : Utils.asArray(fields).flatMap(f => {
421
+ const key = f.toString();
422
+ /* v8 ignore next */
423
+ return meta.properties[key]?.fieldNames ?? [key];
424
+ }),
425
+ });
426
+ return this;
427
+ }
428
+ ignore() {
429
+ if (!this._onConflict) {
430
+ throw new Error('You need to call `qb.onConflict()` first to use `qb.ignore()`');
431
+ }
432
+ this._onConflict[this._onConflict.length - 1].ignore = true;
433
+ return this;
434
+ }
435
+ merge(data) {
436
+ if (!this._onConflict) {
437
+ throw new Error('You need to call `qb.onConflict()` first to use `qb.merge()`');
438
+ }
439
+ if (Array.isArray(data) && data.length === 0) {
440
+ return this.ignore();
441
+ }
442
+ this._onConflict[this._onConflict.length - 1].merge = data;
443
+ return this;
444
+ }
445
+ returning(fields) {
446
+ this._returning = Utils.asArray(fields);
447
+ return this;
448
+ }
449
+ /**
450
+ * @internal
451
+ */
452
+ populate(populate, populateWhere, populateFilter) {
453
+ this.ensureNotFinalized();
454
+ this._populate = populate;
455
+ this._populateWhere = populateWhere;
456
+ this._populateFilter = populateFilter;
457
+ return this;
458
+ }
459
+ limit(limit, offset = 0) {
460
+ this.ensureNotFinalized();
461
+ this._limit = limit;
462
+ if (offset) {
463
+ this.offset(offset);
464
+ }
465
+ return this;
466
+ }
467
+ offset(offset) {
468
+ this.ensureNotFinalized();
469
+ this._offset = offset;
470
+ return this;
471
+ }
472
+ withSchema(schema) {
473
+ this.ensureNotFinalized();
474
+ this._schema = schema;
475
+ return this;
476
+ }
477
+ setLockMode(mode, tables) {
478
+ this.ensureNotFinalized();
479
+ if (mode != null && ![LockMode.OPTIMISTIC, LockMode.NONE].includes(mode) && !this.context) {
480
+ throw ValidationError.transactionRequired();
481
+ }
482
+ this.lockMode = mode;
483
+ this.lockTables = tables;
484
+ return this;
485
+ }
486
+ setFlushMode(flushMode) {
487
+ this.ensureNotFinalized();
488
+ this.flushMode = flushMode;
489
+ return this;
490
+ }
491
+ setFlag(flag) {
492
+ this.ensureNotFinalized();
493
+ this.flags.add(flag);
494
+ return this;
495
+ }
496
+ unsetFlag(flag) {
497
+ this.ensureNotFinalized();
498
+ this.flags.delete(flag);
499
+ return this;
500
+ }
501
+ hasFlag(flag) {
502
+ return this.flags.has(flag);
503
+ }
504
+ cache(config = true) {
505
+ this.ensureNotFinalized();
506
+ this._cache = config;
507
+ return this;
508
+ }
509
+ /**
510
+ * Adds index hint to the FROM clause.
511
+ */
512
+ indexHint(sql) {
513
+ this.ensureNotFinalized();
514
+ this._indexHint = sql;
515
+ return this;
516
+ }
517
+ /**
518
+ * Prepend comment to the sql query using the syntax `/* ... *&#8205;/`. Some characters are forbidden such as `/*, *&#8205;/` and `?`.
519
+ */
520
+ comment(comment) {
521
+ this.ensureNotFinalized();
522
+ this._comments.push(...Utils.asArray(comment));
523
+ return this;
524
+ }
525
+ /**
526
+ * Add hints to the query using comment-like syntax `/*+ ... *&#8205;/`. MySQL and Oracle use this syntax for optimizer hints.
527
+ * Also various DB proxies and routers use this syntax to pass hints to alter their behavior. In other dialects the hints
528
+ * are ignored as simple comments.
529
+ */
530
+ hintComment(comment) {
531
+ this.ensureNotFinalized();
532
+ this._hintComments.push(...Utils.asArray(comment));
533
+ return this;
534
+ }
535
+ from(target, aliasName) {
536
+ this.ensureNotFinalized();
537
+ if (target instanceof QueryBuilder) {
538
+ this.fromSubQuery(target, aliasName);
539
+ }
540
+ else {
541
+ const entityName = Utils.className(target);
542
+ if (aliasName && this._mainAlias && entityName !== this._mainAlias.aliasName) {
543
+ throw new Error(`Cannot override the alias to '${aliasName}' since a query already contains references to '${this._mainAlias.aliasName}'`);
544
+ }
545
+ this.fromEntityName(entityName, aliasName);
546
+ }
547
+ return this;
548
+ }
549
+ getNativeQuery(processVirtualEntity = true) {
550
+ if (this._query?.qb) {
551
+ return this._query.qb;
552
+ }
553
+ this._query = {};
554
+ this.finalize();
555
+ const qb = this.getQueryBase(processVirtualEntity);
556
+ Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._cond, qb), this._cond && !this._onConflict);
557
+ Utils.runIfNotEmpty(() => qb.groupBy(this.prepareFields(this._groupBy, 'groupBy')), this._groupBy);
558
+ Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._having, qb, undefined, 'having'), this._having);
559
+ Utils.runIfNotEmpty(() => {
560
+ const queryOrder = this.helper.getQueryOrder(this.type, this._orderBy, this._populateMap);
561
+ if (queryOrder.length > 0) {
562
+ const sql = Utils.unique(queryOrder).join(', ');
563
+ qb.orderBy(sql);
564
+ return;
565
+ }
566
+ }, this._orderBy);
567
+ Utils.runIfNotEmpty(() => qb.limit(this._limit), this._limit != null);
568
+ Utils.runIfNotEmpty(() => qb.offset(this._offset), this._offset);
569
+ Utils.runIfNotEmpty(() => qb.comment(this._comments), this._comments);
570
+ Utils.runIfNotEmpty(() => qb.hintComment(this._hintComments), this._hintComments);
571
+ Utils.runIfNotEmpty(() => this.helper.appendOnConflictClause(QueryType.UPSERT, this._onConflict, qb), this._onConflict);
572
+ if (this.lockMode) {
573
+ this.helper.getLockSQL(qb, this.lockMode, this.lockTables, this._joins);
574
+ }
575
+ this.helper.finalize(this.type, qb, this.mainAlias.metadata, this._data, this._returning);
576
+ this.clearRawFragmentsCache();
577
+ return this._query.qb = qb;
578
+ }
579
+ /**
580
+ * @internal
581
+ */
582
+ clearRawFragmentsCache() {
583
+ this.rawFragments.forEach(key => RawQueryFragment.remove(key));
584
+ this.rawFragments.clear();
585
+ }
586
+ /**
587
+ * Returns the query with parameters as wildcards.
588
+ */
589
+ getQuery() {
590
+ return this.toQuery().sql;
591
+ }
592
+ /**
593
+ * Returns raw fragment representation of this QueryBuilder.
594
+ */
595
+ toRaw() {
596
+ const { sql, params } = this.toQuery();
597
+ return raw(sql, params);
598
+ }
599
+ toQuery() {
600
+ if (this._query?.sql) {
601
+ return { sql: this._query.sql, params: this._query.params };
602
+ }
603
+ const query = this.getNativeQuery().compile();
604
+ this._query.sql = query.sql;
605
+ this._query.params = query.params;
606
+ return { sql: this._query.sql, params: this._query.params };
607
+ }
608
+ /**
609
+ * Returns the list of all parameters for this query.
610
+ */
611
+ getParams() {
612
+ return this.toQuery().params;
613
+ }
614
+ /**
615
+ * Returns raw interpolated query string with all the parameters inlined.
616
+ */
617
+ getFormattedQuery() {
618
+ const query = this.toQuery();
619
+ return this.platform.formatQuery(query.sql, query.params);
620
+ }
621
+ /**
622
+ * @internal
623
+ */
624
+ getAliasForJoinPath(path, options) {
625
+ if (!path || path === this.mainAlias.entityName) {
626
+ return this.mainAlias.aliasName;
627
+ }
628
+ const join = typeof path === 'string' ? this.getJoinForPath(path, options) : path;
629
+ if (join?.path?.endsWith('[pivot]')) {
630
+ return join.alias;
631
+ }
632
+ return join?.inverseAlias || join?.alias;
633
+ }
634
+ /**
635
+ * @internal
636
+ */
637
+ getJoinForPath(path, options) {
638
+ const joins = Object.values(this._joins);
639
+ if (joins.length === 0) {
640
+ return undefined;
641
+ }
642
+ let join = joins.find(j => j.path === path);
643
+ if (options?.preferNoBranch) {
644
+ join = joins.find(j => {
645
+ return j.path?.replace(/\[\d+]|\[populate]/g, '') === path.replace(/\[\d+]|\[populate]/g, '');
646
+ });
647
+ }
648
+ if (!join && options?.ignoreBranching) {
649
+ join = joins.find(j => {
650
+ return j.path?.replace(/\[\d+]/g, '') === path.replace(/\[\d+]/g, '');
651
+ });
652
+ }
653
+ if (!join && options?.matchPopulateJoins && options?.ignoreBranching) {
654
+ join = joins.find(j => {
655
+ return j.path?.replace(/\[\d+]|\[populate]/g, '') === path.replace(/\[\d+]|\[populate]/g, '');
656
+ });
657
+ }
658
+ if (!join && options?.matchPopulateJoins) {
659
+ join = joins.find(j => {
660
+ return j.path?.replace(/\[populate]/g, '') === path.replace(/\[populate]/g, '');
661
+ });
662
+ }
663
+ return join;
664
+ }
665
+ /**
666
+ * @internal
667
+ */
668
+ getNextAlias(entityName = 'e') {
669
+ return this.driver.config.getNamingStrategy().aliasName(entityName, this.aliasCounter++);
670
+ }
671
+ /**
672
+ * @internal
673
+ */
674
+ getAliasMap() {
675
+ return Object.fromEntries(Object.entries(this._aliases).map(([key, value]) => [key, value.entityName]));
676
+ }
677
+ /**
678
+ * Executes this QB and returns the raw results, mapped to the property names (unless disabled via last parameter).
679
+ * Use `method` to specify what kind of result you want to get (array/single/meta).
680
+ */
681
+ async execute(method, options) {
682
+ options = typeof options === 'boolean' ? { mapResults: options } : (options ?? {});
683
+ options.mergeResults ??= true;
684
+ options.mapResults ??= true;
685
+ const isRunType = [QueryType.INSERT, QueryType.UPDATE, QueryType.DELETE, QueryType.TRUNCATE].includes(this.type);
686
+ method ??= isRunType ? 'run' : 'all';
687
+ if (!this.connectionType && (isRunType || this.context)) {
688
+ this.connectionType = 'write';
689
+ }
690
+ if (!this.finalized && method === 'get' && this.type === QueryType.SELECT) {
691
+ this.limit(1);
692
+ }
693
+ const query = this.toQuery();
694
+ const cached = await this.em?.tryCache(this.mainAlias.entityName, this._cache, ['qb.execute', query.sql, query.params, method]);
695
+ if (cached?.data !== undefined) {
696
+ return cached.data;
697
+ }
698
+ const loggerContext = { id: this.em?.id, ...this.loggerContext };
699
+ const res = await this.getConnection().execute(query.sql, query.params, method, this.context, loggerContext);
700
+ const meta = this.mainAlias.metadata;
701
+ if (!options.mapResults || !meta) {
702
+ await this.em?.storeCache(this._cache, cached, res);
703
+ return res;
704
+ }
705
+ if (method === 'run') {
706
+ return res;
707
+ }
708
+ const joinedProps = this.driver.joinedProps(meta, this._populate);
709
+ let mapped;
710
+ if (Array.isArray(res)) {
711
+ const map = {};
712
+ mapped = res.map(r => this.driver.mapResult(r, meta, this._populate, this, map));
713
+ if (options.mergeResults && joinedProps.length > 0) {
714
+ mapped = this.driver.mergeJoinedResult(mapped, this.mainAlias.metadata, joinedProps);
715
+ }
716
+ }
717
+ else {
718
+ mapped = [this.driver.mapResult(res, meta, joinedProps, this)];
719
+ }
720
+ if (method === 'get') {
721
+ await this.em?.storeCache(this._cache, cached, mapped[0]);
722
+ return mapped[0];
723
+ }
724
+ await this.em?.storeCache(this._cache, cached, mapped);
725
+ return mapped;
726
+ }
727
+ getConnection() {
728
+ const write = !this.platform.getConfig().get('preferReadReplicas');
729
+ const type = this.connectionType || (write ? 'write' : 'read');
730
+ return this.driver.getConnection(type);
731
+ }
732
+ /**
733
+ * Executes the query and returns an async iterable (async generator) that yields results one by one.
734
+ * By default, the results are merged and mapped to entity instances, without adding them to the identity map.
735
+ * You can disable merging and mapping by passing the options `{ mergeResults: false, mapResults: false }`.
736
+ * This is useful for processing large datasets without loading everything into memory at once.
737
+ *
738
+ * ```ts
739
+ * const qb = em.createQueryBuilder(Book, 'b');
740
+ * qb.select('*').where({ title: '1984' }).leftJoinAndSelect('b.author', 'a');
741
+ *
742
+ * for await (const book of qb.stream()) {
743
+ * // book is an instance of Book entity
744
+ * console.log(book.title, book.author.name);
745
+ * }
746
+ * ```
747
+ */
748
+ async *stream(options) {
749
+ options ??= {};
750
+ options.mergeResults ??= true;
751
+ options.mapResults ??= true;
752
+ const query = this.toQuery();
753
+ const loggerContext = { id: this.em?.id, ...this.loggerContext };
754
+ const res = this.getConnection().stream(query.sql, query.params, this.context, loggerContext);
755
+ const meta = this.mainAlias.metadata;
756
+ if (options.rawResults || !meta) {
757
+ yield* res;
758
+ return;
759
+ }
760
+ const joinedProps = this.driver.joinedProps(meta, this._populate);
761
+ const stack = [];
762
+ const hash = (data) => {
763
+ return Utils.getPrimaryKeyHash(meta.primaryKeys.map(pk => data[pk]));
764
+ };
765
+ for await (const row of res) {
766
+ const mapped = this.driver.mapResult(row, meta, this._populate, this);
767
+ if (!options.mergeResults || joinedProps.length === 0) {
768
+ yield this.mapResult(mapped, options.mapResults);
769
+ continue;
770
+ }
771
+ if (stack.length > 0 && hash(stack[stack.length - 1]) !== hash(mapped)) {
772
+ const res = this.driver.mergeJoinedResult(stack, this.mainAlias.metadata, joinedProps);
773
+ for (const row of res) {
774
+ yield this.mapResult(row, options.mapResults);
775
+ }
776
+ stack.length = 0;
777
+ }
778
+ stack.push(mapped);
779
+ }
780
+ if (stack.length > 0) {
781
+ const merged = this.driver.mergeJoinedResult(stack, this.mainAlias.metadata, joinedProps);
782
+ yield this.mapResult(merged[0], options.mapResults);
783
+ }
784
+ }
785
+ /**
786
+ * Alias for `qb.getResultList()`
787
+ */
788
+ async getResult() {
789
+ return this.getResultList();
790
+ }
791
+ /**
792
+ * Executes the query, returning array of results mapped to entity instances.
793
+ */
794
+ async getResultList(limit) {
795
+ await this.em.tryFlush(this.mainAlias.entityName, { flushMode: this.flushMode });
796
+ const res = await this.execute('all', true);
797
+ return this.mapResults(res, limit);
798
+ }
799
+ propagatePopulateHint(entity, hint) {
800
+ helper(entity).__serializationContext.populate = hint.concat(helper(entity).__serializationContext.populate ?? []);
801
+ hint.forEach(hint => {
802
+ const [propName] = hint.field.split(':', 2);
803
+ const value = Reference.unwrapReference(entity[propName]);
804
+ if (Utils.isEntity(value)) {
805
+ this.propagatePopulateHint(value, hint.children ?? []);
806
+ }
807
+ else if (Utils.isCollection(value)) {
808
+ value.populated();
809
+ value.getItems(false).forEach(item => this.propagatePopulateHint(item, hint.children ?? []));
810
+ }
811
+ });
812
+ }
813
+ mapResult(row, map = true) {
814
+ if (!map) {
815
+ return row;
816
+ }
817
+ const entity = this.em.map(this.mainAlias.entityName, row, { schema: this._schema });
818
+ this.propagatePopulateHint(entity, this._populate);
819
+ return entity;
820
+ }
821
+ mapResults(res, limit) {
822
+ const entities = [];
823
+ for (const row of res) {
824
+ const entity = this.mapResult(row);
825
+ this.propagatePopulateHint(entity, this._populate);
826
+ entities.push(entity);
827
+ if (limit != null && --limit === 0) {
828
+ break;
829
+ }
830
+ }
831
+ return Utils.unique(entities);
832
+ }
833
+ /**
834
+ * Executes the query, returning the first result or null
835
+ */
836
+ async getSingleResult() {
837
+ if (!this.finalized) {
838
+ this.limit(1);
839
+ }
840
+ const [res] = await this.getResultList(1);
841
+ return res || null;
842
+ }
843
+ /**
844
+ * Executes count query (without offset and limit), returning total count of results
845
+ */
846
+ async getCount(field, distinct) {
847
+ let res;
848
+ if (this.type === QueryType.COUNT) {
849
+ res = await this.execute('get', false);
850
+ }
851
+ else {
852
+ const qb = this._type === undefined ? this : this.clone();
853
+ qb.processPopulateHint(); // needs to happen sooner so `qb.hasToManyJoins()` reports correctly
854
+ qb.count(field, distinct ?? qb.hasToManyJoins()).limit(undefined).offset(undefined).orderBy([]);
855
+ res = await qb.execute('get', false);
856
+ }
857
+ return res ? +res.count : 0;
858
+ }
859
+ /**
860
+ * Executes the query, returning both array of results and total count query (without offset and limit).
861
+ */
862
+ async getResultAndCount() {
863
+ return [
864
+ await this.clone().getResultList(),
865
+ await this.clone().getCount(),
866
+ ];
867
+ }
868
+ /**
869
+ * Returns native query builder instance with sub-query aliased with given alias.
870
+ * You can provide `EntityName.propName` as alias, then the field name will be used based on the metadata
871
+ */
872
+ as(alias) {
873
+ const qb = this.getNativeQuery();
874
+ if (alias.includes('.')) {
875
+ const [a, f] = alias.split('.');
876
+ const meta = this.metadata.find(a);
877
+ /* v8 ignore next */
878
+ alias = meta?.properties[f]?.fieldNames[0] ?? alias;
879
+ }
880
+ qb.as(alias);
881
+ // tag the instance, so it is possible to detect it easily
882
+ Object.defineProperty(qb, '__as', { enumerable: false, value: alias });
883
+ return qb;
884
+ }
885
+ clone(reset) {
886
+ const qb = new QueryBuilder(this.mainAlias.entityName, this.metadata, this.driver, this.context, this.mainAlias.aliasName, this.connectionType, this.em);
887
+ if (reset === true) {
888
+ return qb;
889
+ }
890
+ reset = reset || [];
891
+ // clone array/object properties
892
+ const properties = [
893
+ 'flags', '_populate', '_populateWhere', '_populateFilter', '__populateWhere', '_populateMap', '_joins', '_joinedProps', '_cond', '_data', '_orderBy',
894
+ '_schema', '_indexHint', '_cache', 'subQueries', 'lockMode', 'lockTables', '_groupBy', '_having', '_returning',
895
+ '_comments', '_hintComments', 'rawFragments', 'aliasCounter',
896
+ ];
897
+ RawQueryFragment.cloneRegistry = this.rawFragments;
898
+ for (const prop of Object.keys(this)) {
899
+ if (reset.includes(prop) || ['_helper', '_query'].includes(prop)) {
900
+ continue;
901
+ }
902
+ qb[prop] = properties.includes(prop) ? Utils.copy(this[prop]) : this[prop];
903
+ }
904
+ delete RawQueryFragment.cloneRegistry;
905
+ /* v8 ignore next */
906
+ if (this._fields && !reset.includes('_fields')) {
907
+ qb._fields = [...this._fields];
908
+ }
909
+ qb._aliases = { ...this._aliases };
910
+ qb._helper.aliasMap = qb._aliases;
911
+ qb.finalized = false;
912
+ return qb;
913
+ }
914
+ /**
915
+ * Sets logger context for this query builder.
916
+ */
917
+ setLoggerContext(context) {
918
+ this.loggerContext = context;
919
+ }
920
+ /**
921
+ * Gets logger context for this query builder.
922
+ */
923
+ getLoggerContext() {
924
+ this.loggerContext ??= {};
925
+ return this.loggerContext;
926
+ }
927
+ fromVirtual(meta) {
928
+ if (typeof meta.expression === 'string') {
929
+ return `(${meta.expression}) as ${this.platform.quoteIdentifier(this.alias)}`;
930
+ }
931
+ const res = meta.expression(this.em, this._cond, {});
932
+ if (typeof res === 'string') {
933
+ return `(${res}) as ${this.platform.quoteIdentifier(this.alias)}`;
934
+ }
935
+ if (res instanceof QueryBuilder) {
936
+ return `(${res.getFormattedQuery()}) as ${this.platform.quoteIdentifier(this.alias)}`;
937
+ }
938
+ if (res instanceof RawQueryFragment) {
939
+ const query = this.platform.formatQuery(res.sql, res.params);
940
+ return `(${query}) as ${this.platform.quoteIdentifier(this.alias)}`;
941
+ }
942
+ /* v8 ignore next */
943
+ return res;
944
+ }
945
+ joinReference(field, alias, cond, type, path, schema, subquery) {
946
+ this.ensureNotFinalized();
947
+ if (typeof field === 'object') {
948
+ const prop = {
949
+ name: '__subquery__',
950
+ kind: ReferenceKind.MANY_TO_ONE,
951
+ };
952
+ if (field instanceof QueryBuilder) {
953
+ prop.type = field.mainAlias.entityName;
954
+ prop.targetMeta = field.mainAlias.metadata;
955
+ field = field.getNativeQuery();
956
+ }
957
+ if (field instanceof RawQueryFragment) {
958
+ field = this.platform.formatQuery(field.sql, field.params);
959
+ }
960
+ const key = `${this.alias}.${prop.name}#${alias}`;
961
+ this._joins[key] = {
962
+ prop,
963
+ alias,
964
+ type,
965
+ cond,
966
+ schema,
967
+ subquery: field.toString(),
968
+ ownerAlias: this.alias,
969
+ };
970
+ return { prop, key };
971
+ }
972
+ if (!subquery && type.includes('lateral')) {
973
+ throw new Error(`Lateral join can be used only with a sub-query.`);
974
+ }
975
+ const [fromAlias, fromField] = this.helper.splitField(field);
976
+ const q = (str) => `'${str}'`;
977
+ if (!this._aliases[fromAlias]) {
978
+ throw new Error(`Trying to join ${q(fromField)} with alias ${q(fromAlias)}, but ${q(fromAlias)} is not a known alias. Available aliases are: ${Object.keys(this._aliases).map(q).join(', ')}.`);
979
+ }
980
+ const entityName = this._aliases[fromAlias].entityName;
981
+ const meta = this.metadata.get(entityName);
982
+ const prop = meta.properties[fromField];
983
+ if (!prop) {
984
+ throw new Error(`Trying to join ${q(field)}, but ${q(fromField)} is not a defined relation on ${meta.className}.`);
985
+ }
986
+ this.createAlias(prop.type, alias);
987
+ cond = QueryHelper.processWhere({
988
+ where: cond,
989
+ entityName: this.mainAlias.entityName,
990
+ metadata: this.metadata,
991
+ platform: this.platform,
992
+ aliasMap: this.getAliasMap(),
993
+ aliased: [QueryType.SELECT, QueryType.COUNT].includes(this.type),
994
+ });
995
+ const criteriaNode = CriteriaNodeFactory.createNode(this.metadata, prop.targetMeta.className, cond);
996
+ cond = criteriaNode.process(this, { ignoreBranching: true, alias });
997
+ let aliasedName = `${fromAlias}.${prop.name}#${alias}`;
998
+ path ??= `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? entityName)}.${prop.name}`;
999
+ if (prop.kind === ReferenceKind.ONE_TO_MANY) {
1000
+ this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond, schema);
1001
+ this._joins[aliasedName].path ??= path;
1002
+ }
1003
+ else if (prop.kind === ReferenceKind.MANY_TO_MANY) {
1004
+ let pivotAlias = alias;
1005
+ if (type !== JoinType.pivotJoin) {
1006
+ const oldPivotAlias = this.getAliasForJoinPath(path + '[pivot]');
1007
+ pivotAlias = oldPivotAlias ?? this.getNextAlias(prop.pivotEntity);
1008
+ aliasedName = `${fromAlias}.${prop.name}#${pivotAlias}`;
1009
+ }
1010
+ const joins = this.helper.joinManyToManyReference(prop, fromAlias, alias, pivotAlias, type, cond, path, schema);
1011
+ Object.assign(this._joins, joins);
1012
+ this.createAlias(prop.pivotEntity, pivotAlias);
1013
+ this._joins[aliasedName].path ??= path;
1014
+ aliasedName = Object.keys(joins)[1];
1015
+ }
1016
+ else if (prop.kind === ReferenceKind.ONE_TO_ONE) {
1017
+ this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond, schema);
1018
+ this._joins[aliasedName].path ??= path;
1019
+ }
1020
+ else { // MANY_TO_ONE
1021
+ this._joins[aliasedName] = this.helper.joinManyToOneReference(prop, fromAlias, alias, type, cond, schema);
1022
+ this._joins[aliasedName].path ??= path;
1023
+ }
1024
+ return { prop, key: aliasedName };
1025
+ }
1026
+ prepareFields(fields, type = 'where') {
1027
+ const ret = [];
1028
+ const getFieldName = (name) => {
1029
+ return this.helper.mapper(name, this.type, undefined, type === 'groupBy' ? null : undefined);
1030
+ };
1031
+ fields.forEach(field => {
1032
+ const rawField = RawQueryFragment.getKnownFragment(field, false);
1033
+ if (rawField) {
1034
+ ret.push(rawField);
1035
+ return;
1036
+ }
1037
+ if (typeof field !== 'string') {
1038
+ ret.push(field);
1039
+ return;
1040
+ }
1041
+ const join = Object.keys(this._joins).find(k => field === k.substring(0, k.indexOf('#')));
1042
+ if (join && type === 'where') {
1043
+ ret.push(...this.helper.mapJoinColumns(this.type, this._joins[join]));
1044
+ return;
1045
+ }
1046
+ const [a, f] = this.helper.splitField(field);
1047
+ const prop = this.helper.getProperty(f, a);
1048
+ /* v8 ignore next */
1049
+ if (prop && [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
1050
+ return;
1051
+ }
1052
+ if (prop?.persist === false && !prop.embedded && !prop.formula && type === 'where') {
1053
+ return;
1054
+ }
1055
+ if (prop?.embedded || (prop?.kind === ReferenceKind.EMBEDDED && prop.object)) {
1056
+ const name = prop.embeddedPath?.join('.') ?? prop.fieldNames[0];
1057
+ const aliased = this._aliases[a] ? `${a}.${name}` : name;
1058
+ ret.push(getFieldName(aliased));
1059
+ return;
1060
+ }
1061
+ if (prop?.kind === ReferenceKind.EMBEDDED) {
1062
+ const nest = (prop) => {
1063
+ for (const childProp of Object.values(prop.embeddedProps)) {
1064
+ if (childProp.fieldNames && (childProp.kind !== ReferenceKind.EMBEDDED || childProp.object) && childProp.persist !== false) {
1065
+ ret.push(getFieldName(childProp.fieldNames[0]));
1066
+ }
1067
+ else {
1068
+ nest(childProp);
1069
+ }
1070
+ }
1071
+ };
1072
+ nest(prop);
1073
+ return;
1074
+ }
1075
+ if (prop && prop.fieldNames.length > 1) {
1076
+ ret.push(...prop.fieldNames.map(f => getFieldName(f)));
1077
+ return;
1078
+ }
1079
+ ret.push(getFieldName(field));
1080
+ });
1081
+ const meta = this.mainAlias.metadata;
1082
+ /* v8 ignore next */
1083
+ const requiresSQLConversion = meta?.props.filter(p => p.hasConvertToJSValueSQL && p.persist !== false) ?? [];
1084
+ if (this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES) && (fields.includes('*') || fields.includes(`${this.mainAlias.aliasName}.*`)) && requiresSQLConversion.length > 0) {
1085
+ for (const p of requiresSQLConversion) {
1086
+ ret.push(this.helper.mapper(p.name, this.type));
1087
+ }
1088
+ }
1089
+ for (const f of Object.keys(this._populateMap)) {
1090
+ if (type === 'where' && this._joins[f]) {
1091
+ const cols = this.helper.mapJoinColumns(this.type, this._joins[f]);
1092
+ for (const col of cols) {
1093
+ ret.push(col);
1094
+ }
1095
+ }
1096
+ }
1097
+ return Utils.unique(ret);
1098
+ }
1099
+ init(type, data, cond) {
1100
+ this.ensureNotFinalized();
1101
+ this._type = type;
1102
+ if ([QueryType.UPDATE, QueryType.DELETE].includes(type) && Utils.hasObjectKeys(this._cond)) {
1103
+ throw new Error(`You are trying to call \`qb.where().${type.toLowerCase()}()\`. Calling \`qb.${type.toLowerCase()}()\` before \`qb.where()\` is required.`);
1104
+ }
1105
+ if (!this.helper.isTableNameAliasRequired(type)) {
1106
+ delete this._fields;
1107
+ }
1108
+ if (data) {
1109
+ if (Utils.isEntity(data)) {
1110
+ data = this.em?.getComparator().prepareEntity(data) ?? serialize(data);
1111
+ }
1112
+ this._data = this.helper.processData(data, this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES), false);
1113
+ }
1114
+ if (cond) {
1115
+ this.where(cond);
1116
+ }
1117
+ return this;
1118
+ }
1119
+ getQueryBase(processVirtualEntity) {
1120
+ const qb = this.platform.createNativeQueryBuilder().setFlags(this.flags);
1121
+ const { subQuery, aliasName, entityName, metadata } = this.mainAlias;
1122
+ const requiresAlias = this.finalized && (this._explicitAlias || this.helper.isTableNameAliasRequired(this.type));
1123
+ const alias = requiresAlias ? aliasName : undefined;
1124
+ const schema = this.getSchema(this.mainAlias);
1125
+ const tableName = subQuery ? subQuery.as(aliasName) : this.helper.getTableName(entityName);
1126
+ const joinSchema = this._schema ?? this.em?.schema ?? schema;
1127
+ if (metadata?.virtual && processVirtualEntity) {
1128
+ qb.from(raw(this.fromVirtual(metadata)), { indexHint: this._indexHint });
1129
+ }
1130
+ else {
1131
+ qb.from(tableName, {
1132
+ schema,
1133
+ alias,
1134
+ indexHint: this._indexHint,
1135
+ });
1136
+ }
1137
+ switch (this.type) {
1138
+ case QueryType.SELECT:
1139
+ qb.select(this.prepareFields(this._fields));
1140
+ if (this._distinctOn) {
1141
+ qb.distinctOn(this.prepareFields(this._distinctOn));
1142
+ }
1143
+ else if (this.flags.has(QueryFlag.DISTINCT)) {
1144
+ qb.distinct();
1145
+ }
1146
+ this.helper.processJoins(qb, this._joins, joinSchema);
1147
+ break;
1148
+ case QueryType.COUNT: {
1149
+ const fields = this._fields.map(f => this.helper.mapper(f, this.type));
1150
+ qb.count(fields, this.flags.has(QueryFlag.DISTINCT));
1151
+ this.helper.processJoins(qb, this._joins, joinSchema);
1152
+ break;
1153
+ }
1154
+ case QueryType.INSERT:
1155
+ qb.insert(this._data);
1156
+ break;
1157
+ case QueryType.UPDATE:
1158
+ qb.update(this._data);
1159
+ this.helper.processJoins(qb, this._joins, joinSchema);
1160
+ this.helper.updateVersionProperty(qb, this._data);
1161
+ break;
1162
+ case QueryType.DELETE:
1163
+ qb.delete();
1164
+ break;
1165
+ case QueryType.TRUNCATE:
1166
+ qb.truncate();
1167
+ break;
1168
+ }
1169
+ return qb;
1170
+ }
1171
+ applyDiscriminatorCondition() {
1172
+ const meta = this.mainAlias.metadata;
1173
+ if (!meta?.discriminatorValue) {
1174
+ return;
1175
+ }
1176
+ const types = Object.values(meta.root.discriminatorMap).map(cls => this.metadata.find(cls));
1177
+ const children = [];
1178
+ const lookUpChildren = (ret, type) => {
1179
+ const children = types.filter(meta2 => meta2.extends === type);
1180
+ children.forEach(m => lookUpChildren(ret, m.className));
1181
+ ret.push(...children.filter(c => c.discriminatorValue));
1182
+ return children;
1183
+ };
1184
+ lookUpChildren(children, meta.className);
1185
+ this.andWhere({
1186
+ [meta.root.discriminatorColumn]: children.length > 0 ? { $in: [meta.discriminatorValue, ...children.map(c => c.discriminatorValue)] } : meta.discriminatorValue,
1187
+ });
1188
+ }
1189
+ finalize() {
1190
+ if (this.finalized) {
1191
+ return;
1192
+ }
1193
+ if (!this._type) {
1194
+ this.select('*');
1195
+ }
1196
+ const meta = this.mainAlias.metadata;
1197
+ this.applyDiscriminatorCondition();
1198
+ this.processPopulateHint();
1199
+ this.processNestedJoins();
1200
+ if (meta && (this._fields?.includes('*') || this._fields?.includes(`${this.mainAlias.aliasName}.*`))) {
1201
+ meta.props
1202
+ .filter(prop => prop.formula && (!prop.lazy || this.flags.has(QueryFlag.INCLUDE_LAZY_FORMULAS)))
1203
+ .map(prop => {
1204
+ const alias = this.platform.quoteIdentifier(this.mainAlias.aliasName);
1205
+ const aliased = this.platform.quoteIdentifier(prop.fieldNames[0]);
1206
+ return `${prop.formula(alias)} as ${aliased}`;
1207
+ })
1208
+ .filter(field => !this._fields.some(f => {
1209
+ if (f instanceof RawQueryFragment) {
1210
+ return f.sql === field && f.params.length === 0;
1211
+ }
1212
+ return f === field;
1213
+ }))
1214
+ .forEach(field => this._fields.push(raw(field)));
1215
+ }
1216
+ QueryHelper.processObjectParams(this._data);
1217
+ QueryHelper.processObjectParams(this._cond);
1218
+ QueryHelper.processObjectParams(this._having);
1219
+ // automatically enable paginate flag when we detect to-many joins, but only if there is no `group by` clause
1220
+ if (!this.flags.has(QueryFlag.DISABLE_PAGINATE) && this._groupBy.length === 0 && this.hasToManyJoins()) {
1221
+ this.flags.add(QueryFlag.PAGINATE);
1222
+ }
1223
+ if (meta && this.flags.has(QueryFlag.PAGINATE) && !this.flags.has(QueryFlag.DISABLE_PAGINATE) && (this._limit > 0 || this._offset > 0)) {
1224
+ this.wrapPaginateSubQuery(meta);
1225
+ }
1226
+ if (meta && (this.flags.has(QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(QueryFlag.DELETE_SUB_QUERY))) {
1227
+ this.wrapModifySubQuery(meta);
1228
+ }
1229
+ this.finalized = true;
1230
+ }
1231
+ /** @internal */
1232
+ processPopulateHint() {
1233
+ if (this.populateHintFinalized) {
1234
+ return;
1235
+ }
1236
+ const meta = this.mainAlias.metadata;
1237
+ if (meta && this.flags.has(QueryFlag.AUTO_JOIN_ONE_TO_ONE_OWNER)) {
1238
+ const relationsToPopulate = this._populate.map(({ field }) => field);
1239
+ meta.relations
1240
+ .filter(prop => prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner && !relationsToPopulate.includes(prop.name) && !relationsToPopulate.includes(`${prop.name}:ref`))
1241
+ .map(prop => ({ field: `${prop.name}:ref` }))
1242
+ .forEach(item => this._populate.push(item));
1243
+ }
1244
+ this._populate.forEach(({ field }) => {
1245
+ const [fromAlias, fromField] = this.helper.splitField(field);
1246
+ const aliasedField = `${fromAlias}.${fromField}`;
1247
+ const join = Object.keys(this._joins).find(k => `${aliasedField}#${this._joins[k].alias}` === k);
1248
+ if (join && this._joins[join] && this.helper.isOneToOneInverse(fromField)) {
1249
+ this._populateMap[join] = this._joins[join].alias;
1250
+ return;
1251
+ }
1252
+ if (meta && this.helper.isOneToOneInverse(fromField)) {
1253
+ const prop = meta.properties[fromField];
1254
+ const alias = this.getNextAlias(prop.pivotEntity ?? prop.type);
1255
+ const aliasedName = `${fromAlias}.${prop.name}#${alias}`;
1256
+ this._joins[aliasedName] = this.helper.joinOneToReference(prop, this.mainAlias.aliasName, alias, JoinType.leftJoin);
1257
+ this._joins[aliasedName].path = `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? meta.className)}.${prop.name}`;
1258
+ this._populateMap[aliasedName] = this._joins[aliasedName].alias;
1259
+ this.createAlias(prop.type, alias);
1260
+ }
1261
+ });
1262
+ this.processPopulateWhere(false);
1263
+ this.processPopulateWhere(true);
1264
+ this.populateHintFinalized = true;
1265
+ }
1266
+ processPopulateWhere(filter) {
1267
+ const key = filter ? '_populateFilter' : '_populateWhere';
1268
+ if (this[key] == null || this[key] === PopulateHint.ALL) {
1269
+ return;
1270
+ }
1271
+ let joins = Object.values(this._joins);
1272
+ for (const join of joins) {
1273
+ join.cond_ ??= join.cond;
1274
+ join.cond = { ...join.cond };
1275
+ }
1276
+ if (typeof this[key] === 'object') {
1277
+ const cond = CriteriaNodeFactory
1278
+ .createNode(this.metadata, this.mainAlias.entityName, this[key])
1279
+ .process(this, { matchPopulateJoins: true, ignoreBranching: true, preferNoBranch: true, filter });
1280
+ // there might be new joins created by processing the `populateWhere` object
1281
+ joins = Object.values(this._joins);
1282
+ this.mergeOnConditions(joins, cond, filter);
1283
+ }
1284
+ }
1285
+ mergeOnConditions(joins, cond, filter, op) {
1286
+ for (const k of Object.keys(cond)) {
1287
+ if (Utils.isOperator(k)) {
1288
+ if (Array.isArray(cond[k])) {
1289
+ cond[k].forEach((c) => this.mergeOnConditions(joins, c, filter, k));
1290
+ }
1291
+ /* v8 ignore next */
1292
+ this.mergeOnConditions(joins, cond[k], filter, k);
1293
+ }
1294
+ const [alias] = this.helper.splitField(k);
1295
+ const join = joins.find(j => j.alias === alias);
1296
+ if (join) {
1297
+ const parentJoin = joins.find(j => j.alias === join.ownerAlias);
1298
+ // https://stackoverflow.com/a/56815807/3665878
1299
+ if (parentJoin && !filter) {
1300
+ const nested = (parentJoin.nested ??= new Set());
1301
+ join.type = join.type === JoinType.innerJoin || ([ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(parentJoin.prop.kind))
1302
+ ? JoinType.nestedInnerJoin
1303
+ : JoinType.nestedLeftJoin;
1304
+ nested.add(join);
1305
+ }
1306
+ if (join.cond[k]) {
1307
+ /* v8 ignore next */
1308
+ join.cond = { [op ?? '$and']: [join.cond, { [k]: cond[k] }] };
1309
+ }
1310
+ else if (op === '$or') {
1311
+ join.cond.$or ??= [];
1312
+ join.cond.$or.push({ [k]: cond[k] });
1313
+ }
1314
+ else {
1315
+ join.cond = { ...join.cond, [k]: cond[k] };
1316
+ }
1317
+ }
1318
+ }
1319
+ }
1320
+ /**
1321
+ * When adding an inner join on a left joined relation, we need to nest them,
1322
+ * otherwise the inner join could discard rows of the root table.
1323
+ */
1324
+ processNestedJoins() {
1325
+ if (this.flags.has(QueryFlag.DISABLE_NESTED_INNER_JOIN)) {
1326
+ return;
1327
+ }
1328
+ const joins = Object.values(this._joins);
1329
+ const lookupParentGroup = (j) => {
1330
+ return j.nested ?? (j.parent ? lookupParentGroup(j.parent) : undefined);
1331
+ };
1332
+ for (const join of joins) {
1333
+ if (join.type === JoinType.innerJoin) {
1334
+ join.parent = joins.find(j => j.alias === join.ownerAlias);
1335
+ // https://stackoverflow.com/a/56815807/3665878
1336
+ if (join.parent?.type === JoinType.leftJoin || join.parent?.type === JoinType.nestedLeftJoin) {
1337
+ const nested = ((join.parent).nested ??= new Set());
1338
+ join.type = join.type === JoinType.innerJoin
1339
+ ? JoinType.nestedInnerJoin
1340
+ : JoinType.nestedLeftJoin;
1341
+ nested.add(join);
1342
+ }
1343
+ else if (join.parent?.type === JoinType.nestedInnerJoin) {
1344
+ const group = lookupParentGroup(join.parent);
1345
+ const nested = group ?? ((join.parent).nested ??= new Set());
1346
+ join.type = join.type === JoinType.innerJoin
1347
+ ? JoinType.nestedInnerJoin
1348
+ : JoinType.nestedLeftJoin;
1349
+ nested.add(join);
1350
+ }
1351
+ }
1352
+ }
1353
+ }
1354
+ hasToManyJoins() {
1355
+ return Object.values(this._joins).some(join => {
1356
+ return [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(join.prop.kind);
1357
+ });
1358
+ }
1359
+ wrapPaginateSubQuery(meta) {
1360
+ const pks = this.prepareFields(meta.primaryKeys, 'sub-query');
1361
+ const subQuery = this.clone(['_orderBy', '_fields', 'lockMode', 'lockTableAliases']).select(pks).groupBy(pks).limit(this._limit);
1362
+ // revert the on conditions added via populateWhere, we want to apply those only once
1363
+ for (const join of Object.values(subQuery._joins)) {
1364
+ if (join.cond_) {
1365
+ join.cond = join.cond_;
1366
+ }
1367
+ }
1368
+ if (this._offset) {
1369
+ subQuery.offset(this._offset);
1370
+ }
1371
+ const addToSelect = [];
1372
+ if (this._orderBy.length > 0) {
1373
+ const orderBy = [];
1374
+ for (const orderMap of this._orderBy) {
1375
+ for (const [field, direction] of Object.entries(orderMap)) {
1376
+ if (RawQueryFragment.isKnownFragment(field)) {
1377
+ const rawField = RawQueryFragment.getKnownFragment(field, false);
1378
+ this.rawFragments.add(field);
1379
+ orderBy.push({ [rawField.clone()]: direction });
1380
+ continue;
1381
+ }
1382
+ const [a, f] = this.helper.splitField(field);
1383
+ const prop = this.helper.getProperty(f, a);
1384
+ const type = this.platform.castColumn(prop);
1385
+ const fieldName = this.helper.mapper(field, this.type, undefined, null);
1386
+ if (!prop?.persist && !prop?.formula && !prop?.hasConvertToJSValueSQL && !pks.includes(fieldName)) {
1387
+ addToSelect.push(fieldName);
1388
+ }
1389
+ const quoted = this.platform.quoteIdentifier(fieldName);
1390
+ const key = raw(`min(${quoted}${type})`);
1391
+ orderBy.push({ [key]: direction });
1392
+ }
1393
+ }
1394
+ subQuery.orderBy(orderBy);
1395
+ }
1396
+ subQuery.finalized = true;
1397
+ const innerQuery = subQuery.as(this.mainAlias.aliasName).clear('select').select(pks);
1398
+ if (addToSelect.length > 0) {
1399
+ addToSelect.forEach(prop => {
1400
+ const field = this._fields.find(field => {
1401
+ if (typeof field === 'object' && field && '__as' in field) {
1402
+ return field.__as === prop;
1403
+ }
1404
+ if (field instanceof RawQueryFragment) {
1405
+ // not perfect, but should work most of the time, ideally we should check only the alias (`... as alias`)
1406
+ return field.sql.includes(prop);
1407
+ }
1408
+ return false;
1409
+ });
1410
+ /* v8 ignore next */
1411
+ if (field instanceof RawQueryFragment) {
1412
+ innerQuery.select(field);
1413
+ }
1414
+ else if (field instanceof NativeQueryBuilder) {
1415
+ innerQuery.select(field.toRaw());
1416
+ }
1417
+ else if (field) {
1418
+ innerQuery.select(field);
1419
+ }
1420
+ });
1421
+ }
1422
+ // multiple sub-queries are needed to get around mysql limitations with order by + limit + where in + group by (o.O)
1423
+ // https://stackoverflow.com/questions/17892762/mysql-this-version-of-mysql-doesnt-yet-support-limit-in-all-any-some-subqu
1424
+ const subSubQuery = this.platform.createNativeQueryBuilder();
1425
+ subSubQuery.select(pks).from(innerQuery);
1426
+ this._limit = undefined;
1427
+ this._offset = undefined;
1428
+ if (!this._fields.some(f => RawQueryFragment.isKnownFragment(f))) {
1429
+ this.pruneExtraJoins(meta);
1430
+ }
1431
+ const { sql, params } = subSubQuery.compile();
1432
+ this.select(this._fields).where({ [Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: raw(sql, params) } });
1433
+ }
1434
+ pruneExtraJoins(meta) {
1435
+ // remove joins that are not used for population or ordering to improve performance
1436
+ const populate = new Set();
1437
+ const orderByAliases = this._orderBy
1438
+ .flatMap(hint => Object.keys(hint))
1439
+ .map(k => k.split('.')[0]);
1440
+ function addPath(hints, prefix = '') {
1441
+ for (const hint of hints) {
1442
+ const field = hint.field.split(':')[0];
1443
+ populate.add((prefix ? prefix + '.' : '') + field);
1444
+ if (hint.children) {
1445
+ addPath(hint.children, (prefix ? prefix + '.' : '') + field);
1446
+ }
1447
+ }
1448
+ }
1449
+ addPath(this._populate);
1450
+ const joins = Object.entries(this._joins);
1451
+ const rootAlias = this.alias;
1452
+ function addParentAlias(alias) {
1453
+ const join = joins.find(j => j[1].alias === alias);
1454
+ if (join && join[1].ownerAlias !== rootAlias) {
1455
+ orderByAliases.push(join[1].ownerAlias);
1456
+ addParentAlias(join[1].ownerAlias);
1457
+ }
1458
+ }
1459
+ for (const orderByAlias of orderByAliases) {
1460
+ addParentAlias(orderByAlias);
1461
+ }
1462
+ for (const [key, join] of joins) {
1463
+ const path = join.path?.replace(/\[populate]|\[pivot]|:ref/g, '').replace(new RegExp(`^${meta.className}.`), '');
1464
+ if (!populate.has(path ?? '') && !orderByAliases.includes(join.alias)) {
1465
+ delete this._joins[key];
1466
+ }
1467
+ }
1468
+ }
1469
+ wrapModifySubQuery(meta) {
1470
+ const subQuery = this.clone();
1471
+ subQuery.finalized = true;
1472
+ // wrap one more time to get around MySQL limitations
1473
+ // https://stackoverflow.com/questions/45494/mysql-error-1093-cant-specify-target-table-for-update-in-from-clause
1474
+ const subSubQuery = this.platform.createNativeQueryBuilder();
1475
+ const method = this.flags.has(QueryFlag.UPDATE_SUB_QUERY) ? 'update' : 'delete';
1476
+ const pks = this.prepareFields(meta.primaryKeys, 'sub-query');
1477
+ this._cond = {}; // otherwise we would trigger validation error
1478
+ this._joins = {}; // included in the subquery
1479
+ subSubQuery.select(pks).from(subQuery.as(this.mainAlias.aliasName));
1480
+ const { sql, params } = subSubQuery.compile();
1481
+ this[method](this._data).where({
1482
+ [Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: raw(sql, params) },
1483
+ });
1484
+ }
1485
+ getSchema(alias) {
1486
+ const { metadata } = alias;
1487
+ const metaSchema = metadata?.schema && metadata.schema !== '*' ? metadata.schema : undefined;
1488
+ const schema = this._schema ?? metaSchema ?? this.em?.schema ?? this.em?.config.getSchema(true);
1489
+ if (schema === this.platform.getDefaultSchemaName()) {
1490
+ return undefined;
1491
+ }
1492
+ return schema;
1493
+ }
1494
+ createAlias(entityName, aliasName, subQuery) {
1495
+ const metadata = this.metadata.find(entityName);
1496
+ const alias = { aliasName, entityName, metadata, subQuery };
1497
+ this._aliases[aliasName] = alias;
1498
+ return alias;
1499
+ }
1500
+ createMainAlias(entityName, aliasName, subQuery) {
1501
+ this._mainAlias = this.createAlias(entityName, aliasName, subQuery);
1502
+ this._helper = this.createQueryBuilderHelper();
1503
+ return this._mainAlias;
1504
+ }
1505
+ fromSubQuery(target, aliasName) {
1506
+ const subQuery = target.getNativeQuery();
1507
+ const { entityName } = target.mainAlias;
1508
+ aliasName ??= this.getNextAlias(entityName);
1509
+ this.createMainAlias(entityName, aliasName, subQuery);
1510
+ }
1511
+ fromEntityName(entityName, aliasName) {
1512
+ aliasName ??= this._mainAlias?.aliasName ?? this.getNextAlias(entityName);
1513
+ this.createMainAlias(entityName, aliasName);
1514
+ }
1515
+ createQueryBuilderHelper() {
1516
+ return new QueryBuilderHelper(this.mainAlias.entityName, this.mainAlias.aliasName, this._aliases, this.subQueries, this.driver);
1517
+ }
1518
+ ensureFromClause() {
1519
+ /* v8 ignore next */
1520
+ if (!this._mainAlias) {
1521
+ throw new Error(`Cannot proceed to build a query because the main alias is not set.`);
1522
+ }
1523
+ }
1524
+ ensureNotFinalized() {
1525
+ if (this.finalized) {
1526
+ throw new Error('This QueryBuilder instance is already finalized, clone it first if you want to modify it.');
1527
+ }
1528
+ }
1529
+ /** @ignore */
1530
+ /* v8 ignore next */
1531
+ [Symbol.for('nodejs.util.inspect.custom')](depth = 2) {
1532
+ const object = { ...this };
1533
+ const hidden = ['metadata', 'driver', 'context', 'platform', 'type'];
1534
+ Object.keys(object).filter(k => k.startsWith('_')).forEach(k => delete object[k]);
1535
+ Object.keys(object).filter(k => object[k] == null).forEach(k => delete object[k]);
1536
+ hidden.forEach(k => delete object[k]);
1537
+ let prefix = this.type ? this.type.substring(0, 1) + this.type.toLowerCase().substring(1) : '';
1538
+ if (this._data) {
1539
+ object.data = this._data;
1540
+ }
1541
+ if (this._schema) {
1542
+ object.schema = this._schema;
1543
+ }
1544
+ if (!Utils.isEmpty(this._cond)) {
1545
+ object.where = this._cond;
1546
+ }
1547
+ if (this._onConflict?.[0]) {
1548
+ prefix = 'Upsert';
1549
+ object.onConflict = this._onConflict[0];
1550
+ }
1551
+ if (!Utils.isEmpty(this._orderBy)) {
1552
+ object.orderBy = this._orderBy;
1553
+ }
1554
+ const name = this._mainAlias ? `${prefix}QueryBuilder<${this._mainAlias?.entityName}>` : 'QueryBuilder';
1555
+ const ret = inspect(object, { depth });
1556
+ return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
1557
+ }
1558
+ }