@mikro-orm/sql 7.0.0-rc.2 → 7.0.0

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 (66) hide show
  1. package/AbstractSqlConnection.d.ts +5 -4
  2. package/AbstractSqlConnection.js +20 -6
  3. package/AbstractSqlDriver.d.ts +19 -13
  4. package/AbstractSqlDriver.js +225 -47
  5. package/AbstractSqlPlatform.d.ts +35 -0
  6. package/AbstractSqlPlatform.js +51 -5
  7. package/PivotCollectionPersister.d.ts +2 -11
  8. package/PivotCollectionPersister.js +59 -59
  9. package/README.md +5 -4
  10. package/SqlEntityManager.d.ts +2 -2
  11. package/SqlEntityManager.js +5 -5
  12. package/dialects/index.d.ts +1 -0
  13. package/dialects/index.js +1 -0
  14. package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +2 -0
  15. package/dialects/mssql/MsSqlNativeQueryBuilder.js +8 -4
  16. package/dialects/mysql/BaseMySqlPlatform.d.ts +6 -0
  17. package/dialects/mysql/BaseMySqlPlatform.js +18 -2
  18. package/dialects/mysql/MySqlSchemaHelper.d.ts +1 -1
  19. package/dialects/mysql/MySqlSchemaHelper.js +25 -14
  20. package/dialects/oracledb/OracleDialect.d.ts +78 -0
  21. package/dialects/oracledb/OracleDialect.js +166 -0
  22. package/dialects/oracledb/OracleNativeQueryBuilder.d.ts +19 -0
  23. package/dialects/oracledb/OracleNativeQueryBuilder.js +249 -0
  24. package/dialects/oracledb/index.d.ts +2 -0
  25. package/dialects/oracledb/index.js +2 -0
  26. package/dialects/postgresql/BasePostgreSqlPlatform.d.ts +6 -0
  27. package/dialects/postgresql/BasePostgreSqlPlatform.js +49 -37
  28. package/dialects/postgresql/PostgreSqlSchemaHelper.js +75 -59
  29. package/dialects/sqlite/BaseSqliteConnection.js +2 -2
  30. package/dialects/sqlite/NodeSqliteDialect.js +3 -1
  31. package/dialects/sqlite/SqlitePlatform.d.ts +1 -0
  32. package/dialects/sqlite/SqlitePlatform.js +7 -1
  33. package/dialects/sqlite/SqliteSchemaHelper.js +23 -17
  34. package/index.d.ts +1 -1
  35. package/index.js +0 -1
  36. package/package.json +30 -30
  37. package/plugin/index.d.ts +1 -14
  38. package/plugin/index.js +13 -13
  39. package/plugin/transformer.d.ts +6 -22
  40. package/plugin/transformer.js +91 -82
  41. package/query/ArrayCriteriaNode.d.ts +1 -1
  42. package/query/CriteriaNode.js +28 -10
  43. package/query/CriteriaNodeFactory.js +20 -4
  44. package/query/NativeQueryBuilder.d.ts +28 -3
  45. package/query/NativeQueryBuilder.js +65 -3
  46. package/query/ObjectCriteriaNode.js +75 -31
  47. package/query/QueryBuilder.d.ts +199 -100
  48. package/query/QueryBuilder.js +544 -358
  49. package/query/QueryBuilderHelper.d.ts +18 -14
  50. package/query/QueryBuilderHelper.js +364 -147
  51. package/query/ScalarCriteriaNode.js +17 -8
  52. package/query/enums.d.ts +2 -0
  53. package/query/enums.js +2 -0
  54. package/query/raw.js +1 -1
  55. package/schema/DatabaseSchema.d.ts +7 -5
  56. package/schema/DatabaseSchema.js +68 -45
  57. package/schema/DatabaseTable.d.ts +8 -6
  58. package/schema/DatabaseTable.js +191 -107
  59. package/schema/SchemaComparator.d.ts +1 -3
  60. package/schema/SchemaComparator.js +76 -50
  61. package/schema/SchemaHelper.d.ts +2 -13
  62. package/schema/SchemaHelper.js +30 -9
  63. package/schema/SqlSchemaGenerator.d.ts +4 -14
  64. package/schema/SqlSchemaGenerator.js +26 -12
  65. package/typings.d.ts +10 -5
  66. package/tsconfig.build.tsbuildinfo +0 -1
@@ -1,4 +1,5 @@
1
- import { helper, inspect, isRaw, LoadStrategy, LockMode, PopulateHint, QueryFlag, QueryHelper, raw, RawQueryFragment, Reference, ReferenceKind, serialize, Utils, ValidationError, } from '@mikro-orm/core';
1
+ var _a;
2
+ import { EntityMetadata, helper, inspect, isRaw, LoadStrategy, LockMode, PopulateHint, QueryFlag, QueryHelper, raw, RawQueryFragment, Reference, ReferenceKind, serialize, Utils, ValidationError, } from '@mikro-orm/core';
2
3
  import { JoinType, QueryType } from './enums.js';
3
4
  import { QueryBuilderHelper } from './QueryBuilderHelper.js';
4
5
  import { CriteriaNodeFactory } from './CriteriaNodeFactory.js';
@@ -31,59 +32,54 @@ export class QueryBuilder {
31
32
  connectionType;
32
33
  em;
33
34
  loggerContext;
35
+ #state = _a.createDefaultState();
36
+ #helper;
37
+ #query;
38
+ /** @internal */
39
+ static createDefaultState() {
40
+ return {
41
+ aliasCounter: 0,
42
+ explicitAlias: false,
43
+ populateHintFinalized: false,
44
+ joins: {},
45
+ cond: {},
46
+ orderBy: [],
47
+ groupBy: [],
48
+ having: {},
49
+ comments: [],
50
+ hintComments: [],
51
+ subQueries: {},
52
+ aliases: {},
53
+ tptAlias: {},
54
+ ctes: [],
55
+ tptJoinsApplied: false,
56
+ autoJoinedPaths: [],
57
+ populate: [],
58
+ populateMap: {},
59
+ flags: new Set([QueryFlag.CONVERT_CUSTOM_TYPES]),
60
+ finalized: false,
61
+ joinedProps: new Map(),
62
+ };
63
+ }
34
64
  get mainAlias() {
35
65
  this.ensureFromClause();
36
- return this._mainAlias;
66
+ return this.#state.mainAlias;
37
67
  }
38
68
  get alias() {
39
69
  return this.mainAlias.aliasName;
40
70
  }
41
71
  get helper() {
42
72
  this.ensureFromClause();
43
- return this._helper;
73
+ return this.#helper;
44
74
  }
45
75
  get type() {
46
- return this._type ?? QueryType.SELECT;
76
+ return this.#state.type ?? QueryType.SELECT;
47
77
  }
48
78
  /** @internal */
49
- _populate = [];
50
- /** @internal */
51
- _populateMap = {};
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
- _collation;
73
- _comments = [];
74
- _hintComments = [];
75
- flushMode;
76
- lockMode;
77
- lockTables;
78
- subQueries = {};
79
- _mainAlias;
80
- _aliases = {};
81
- _tptAlias = {}; // maps entity className to alias for TPT parent tables
82
- _helper;
83
- _query;
79
+ get state() {
80
+ return this.#state;
81
+ }
84
82
  platform;
85
- tptJoinsApplied = false;
86
- autoJoinedPaths = [];
87
83
  /**
88
84
  * @internal
89
85
  */
@@ -96,15 +92,15 @@ export class QueryBuilder {
96
92
  this.loggerContext = loggerContext;
97
93
  this.platform = this.driver.getPlatform();
98
94
  if (alias) {
99
- this.aliasCounter++;
100
- this._explicitAlias = true;
95
+ this.#state.aliasCounter++;
96
+ this.#state.explicitAlias = true;
101
97
  }
102
98
  // @ts-expect-error union type does not match the overloaded method signature
103
99
  this.from(entityName, alias);
104
100
  }
105
101
  select(fields, distinct = false) {
106
102
  this.ensureNotFinalized();
107
- this._fields = Utils.asArray(fields).flatMap(f => {
103
+ this.#state.fields = Utils.asArray(fields).flatMap(f => {
108
104
  if (typeof f !== 'string') {
109
105
  // Normalize sql.ref('prop') and sql.ref('prop').as('alias') to string form
110
106
  if (isRaw(f) && f.sql === '??' && f.params.length === 1) {
@@ -115,14 +111,14 @@ export class QueryBuilder {
115
111
  }
116
112
  return f;
117
113
  }
118
- const asMatch = f.match(FIELD_ALIAS_RE);
114
+ const asMatch = FIELD_ALIAS_RE.exec(f);
119
115
  if (asMatch) {
120
116
  return `${this.resolveNestedPath(asMatch[1].trim())} as ${asMatch[2]}`;
121
117
  }
122
118
  return this.resolveNestedPath(f);
123
119
  });
124
120
  if (distinct) {
125
- this.flags.add(QueryFlag.DISTINCT);
121
+ this.#state.flags.add(QueryFlag.DISTINCT);
126
122
  }
127
123
  return this.init(QueryType.SELECT);
128
124
  }
@@ -131,10 +127,10 @@ export class QueryBuilder {
131
127
  */
132
128
  addSelect(fields) {
133
129
  this.ensureNotFinalized();
134
- if (this._type && this._type !== QueryType.SELECT) {
130
+ if (this.#state.type && this.#state.type !== QueryType.SELECT) {
135
131
  return this;
136
132
  }
137
- return this.select([...Utils.asArray(this._fields), ...Utils.asArray(fields)]);
133
+ return this.select([...Utils.asArray(this.#state.fields), ...Utils.asArray(fields)]);
138
134
  }
139
135
  distinct() {
140
136
  this.ensureNotFinalized();
@@ -142,7 +138,7 @@ export class QueryBuilder {
142
138
  }
143
139
  distinctOn(fields) {
144
140
  this.ensureNotFinalized();
145
- this._distinctOn = Utils.asArray(fields);
141
+ this.#state.distinctOn = Utils.asArray(fields);
146
142
  return this;
147
143
  }
148
144
  /**
@@ -217,16 +213,16 @@ export class QueryBuilder {
217
213
  */
218
214
  count(field, distinct = false) {
219
215
  if (field) {
220
- this._fields = Utils.asArray(field);
216
+ this.#state.fields = Utils.asArray(field);
221
217
  }
222
218
  else if (distinct || this.hasToManyJoins()) {
223
- this._fields = this.mainAlias.meta.primaryKeys;
219
+ this.#state.fields = this.mainAlias.meta.primaryKeys;
224
220
  }
225
221
  else {
226
- this._fields = [raw('*')];
222
+ this.#state.fields = [raw('*')];
227
223
  }
228
224
  if (distinct) {
229
- this.flags.add(QueryFlag.DISTINCT);
225
+ this.#state.flags.add(QueryFlag.DISTINCT);
230
226
  }
231
227
  return this.init(QueryType.COUNT);
232
228
  }
@@ -260,29 +256,30 @@ export class QueryBuilder {
260
256
  * ```
261
257
  */
262
258
  joinAndSelect(field, alias, cond = {}, type = JoinType.innerJoin, path, fields, schema) {
263
- if (!this._type) {
259
+ if (!this.#state.type) {
264
260
  this.select('*');
265
261
  }
266
262
  let subquery;
267
263
  if (Array.isArray(field)) {
268
- const rawFragment = field[1] instanceof QueryBuilder ? field[1].toRaw() : field[1];
264
+ const rawFragment = field[1] instanceof _a ? field[1].toRaw() : field[1];
269
265
  subquery = this.platform.formatQuery(rawFragment.sql, rawFragment.params);
270
266
  field = field[0];
271
267
  }
272
268
  const { prop, key } = this.joinReference(field, alias, cond, type, path, schema, subquery);
273
269
  const [fromAlias] = this.helper.splitField(field);
274
270
  if (subquery) {
275
- this._joins[key].subquery = subquery;
271
+ this.#state.joins[key].subquery = subquery;
276
272
  }
277
- const populate = this._joinedProps.get(fromAlias);
273
+ const populate = this.#state.joinedProps.get(fromAlias);
278
274
  const item = { field: prop.name, strategy: LoadStrategy.JOINED, children: [] };
279
275
  if (populate) {
280
276
  populate.children.push(item);
281
277
  }
282
- else { // root entity
283
- this._populate.push(item);
278
+ else {
279
+ // root entity
280
+ this.#state.populate.push(item);
284
281
  }
285
- this._joinedProps.set(alias, item);
282
+ this.#state.joinedProps.set(alias, item);
286
283
  this.addSelect(this.getFieldsForJoinedLoad(prop, alias, fields));
287
284
  return this;
288
285
  }
@@ -303,12 +300,12 @@ export class QueryBuilder {
303
300
  getFieldsForJoinedLoad(prop, alias, explicitFields) {
304
301
  const fields = [];
305
302
  const populate = [];
306
- const joinKey = Object.keys(this._joins).find(join => join.endsWith(`#${alias}`));
303
+ const joinKey = Object.keys(this.#state.joins).find(join => join.endsWith(`#${alias}`));
307
304
  const targetMeta = prop.targetMeta;
308
- const schema = this._schema ?? (targetMeta.schema !== '*' ? targetMeta.schema : undefined);
305
+ const schema = this.#state.schema ?? (targetMeta.schema !== '*' ? targetMeta.schema : undefined);
309
306
  if (joinKey) {
310
- const path = this._joins[joinKey].path.split('.').slice(1);
311
- let children = this._populate;
307
+ const path = this.#state.joins[joinKey].path.split('.').slice(1);
308
+ let children = this.#state.populate;
312
309
  for (let i = 0; i < path.length; i++) {
313
310
  const child = children.filter(hint => {
314
311
  const [propName] = hint.field.split(':', 2);
@@ -358,13 +355,13 @@ export class QueryBuilder {
358
355
  * @internal
359
356
  */
360
357
  scheduleFilterCheck(path) {
361
- this.autoJoinedPaths.push(path);
358
+ this.#state.autoJoinedPaths.push(path);
362
359
  }
363
360
  /**
364
361
  * @internal
365
362
  */
366
363
  async applyJoinedFilters(em, filterOptions) {
367
- for (const path of this.autoJoinedPaths) {
364
+ for (const path of this.#state.autoJoinedPaths) {
368
365
  const join = this.getJoinForPath(path);
369
366
  if (join.type === JoinType.pivotJoin) {
370
367
  continue;
@@ -382,7 +379,8 @@ export class QueryBuilder {
382
379
  if (Utils.hasObjectKeys(cond) || RawQueryFragment.hasObjectFragments(cond)) {
383
380
  // remove nested filters, we only care about scalars here, nesting would require another join branch
384
381
  for (const key of Object.keys(cond)) {
385
- if (Utils.isPlainObject(cond[key]) && Object.keys(cond[key]).every(k => !(Utils.isOperator(k) && !['$some', '$none', '$every', '$size'].includes(k)))) {
382
+ if (Utils.isPlainObject(cond[key]) &&
383
+ Object.keys(cond[key]).every(k => !(Utils.isOperator(k) && !['$some', '$none', '$every', '$size'].includes(k)))) {
386
384
  delete cond[key];
387
385
  }
388
386
  }
@@ -399,10 +397,10 @@ export class QueryBuilder {
399
397
  withSubQuery(subQuery, alias) {
400
398
  this.ensureNotFinalized();
401
399
  if (isRaw(subQuery)) {
402
- this.subQueries[alias] = this.platform.formatQuery(subQuery.sql, subQuery.params);
400
+ this.#state.subQueries[alias] = this.platform.formatQuery(subQuery.sql, subQuery.params);
403
401
  }
404
402
  else {
405
- this.subQueries[alias] = subQuery.toString();
403
+ this.#state.subQueries[alias] = subQuery.toString();
406
404
  }
407
405
  return this;
408
406
  }
@@ -426,31 +424,32 @@ export class QueryBuilder {
426
424
  platform: this.platform,
427
425
  aliasMap: this.getAliasMap(),
428
426
  aliased: [QueryType.SELECT, QueryType.COUNT].includes(this.type),
429
- convertCustomTypes: this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES),
427
+ convertCustomTypes: this.#state.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES),
430
428
  });
431
429
  }
432
430
  const op = operator || params;
433
- const topLevel = !op || !(Utils.hasObjectKeys(this._cond) || RawQueryFragment.hasObjectFragments(this._cond));
431
+ const topLevel = !op || !(Utils.hasObjectKeys(this.#state.cond) || RawQueryFragment.hasObjectFragments(this.#state.cond));
434
432
  const criteriaNode = CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, processedCond);
435
- const ignoreBranching = this.__populateWhere === 'infer';
436
- if ([QueryType.UPDATE, QueryType.DELETE].includes(this.type) && criteriaNode.willAutoJoin(this, undefined, { ignoreBranching })) {
433
+ const ignoreBranching = this.#state.resolvedPopulateWhere === 'infer';
434
+ if ([QueryType.UPDATE, QueryType.DELETE].includes(this.type) &&
435
+ criteriaNode.willAutoJoin(this, undefined, { ignoreBranching })) {
437
436
  // use sub-query to support joining
438
437
  this.setFlag(this.type === QueryType.UPDATE ? QueryFlag.UPDATE_SUB_QUERY : QueryFlag.DELETE_SUB_QUERY);
439
438
  this.select(this.mainAlias.meta.primaryKeys, true);
440
439
  }
441
440
  if (topLevel) {
442
- this._cond = criteriaNode.process(this, { ignoreBranching });
441
+ this.#state.cond = criteriaNode.process(this, { ignoreBranching });
443
442
  }
444
- else if (Array.isArray(this._cond[op])) {
445
- this._cond[op].push(criteriaNode.process(this, { ignoreBranching }));
443
+ else if (Array.isArray(this.#state.cond[op])) {
444
+ this.#state.cond[op].push(criteriaNode.process(this, { ignoreBranching }));
446
445
  }
447
446
  else {
448
- const cond1 = [this._cond, criteriaNode.process(this, { ignoreBranching })];
449
- this._cond = { [op]: cond1 };
447
+ const cond1 = [this.#state.cond, criteriaNode.process(this, { ignoreBranching })];
448
+ this.#state.cond = { [op]: cond1 };
450
449
  }
451
- if (this._onConflict) {
452
- this._onConflict[this._onConflict.length - 1].where = this.helper.processOnConflictCondition(this._cond, this._schema);
453
- this._cond = {};
450
+ if (this.#state.onConflict) {
451
+ this.#state.onConflict[this.#state.onConflict.length - 1].where = this.helper.processOnConflictCondition(this.#state.cond, this.#state.schema);
452
+ this.#state.cond = {};
454
453
  }
455
454
  return this;
456
455
  }
@@ -469,7 +468,7 @@ export class QueryBuilder {
469
468
  processOrderBy(orderBy, reset = true) {
470
469
  this.ensureNotFinalized();
471
470
  if (reset) {
472
- this._orderBy = [];
471
+ this.#state.orderBy = [];
473
472
  }
474
473
  const selectAliases = this.getSelectAliases();
475
474
  Utils.asArray(orderBy).forEach(orig => {
@@ -494,7 +493,7 @@ export class QueryBuilder {
494
493
  convertCustomTypes: false,
495
494
  type: 'orderBy',
496
495
  });
497
- this._orderBy.push(CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, processed).process(this, {
496
+ this.#state.orderBy.push(CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, processed).process(this, {
498
497
  matchPopulateJoins: true,
499
498
  type: 'orderBy',
500
499
  }));
@@ -504,9 +503,9 @@ export class QueryBuilder {
504
503
  /** Collect custom aliases from select fields (stored as 'resolved as alias' strings by select()). */
505
504
  getSelectAliases() {
506
505
  const aliases = new Set();
507
- for (const field of this._fields ?? []) {
506
+ for (const field of this.#state.fields ?? []) {
508
507
  if (typeof field === 'string') {
509
- const m = field.match(FIELD_ALIAS_RE);
508
+ const m = FIELD_ALIAS_RE.exec(field);
510
509
  if (m) {
511
510
  aliases.add(m[2]);
512
511
  }
@@ -516,7 +515,7 @@ export class QueryBuilder {
516
515
  }
517
516
  groupBy(fields) {
518
517
  this.ensureNotFinalized();
519
- this._groupBy = Utils.asArray(fields).flatMap(f => {
518
+ this.#state.groupBy = Utils.asArray(fields).flatMap(f => {
520
519
  if (typeof f !== 'string') {
521
520
  // Normalize sql.ref('prop') to string for proper formula resolution
522
521
  if (isRaw(f) && f.sql === '??' && f.params.length === 1) {
@@ -544,12 +543,12 @@ export class QueryBuilder {
544
543
  cond = { [raw(`(${cond})`, params)]: [] };
545
544
  }
546
545
  const processed = CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond, undefined, undefined, false).process(this, { type: 'having' });
547
- if (!this._having || !operator) {
548
- this._having = processed;
546
+ if (!this.#state.having || !operator) {
547
+ this.#state.having = processed;
549
548
  }
550
549
  else {
551
- const cond1 = [this._having, processed];
552
- this._having = { [operator]: cond1 };
550
+ const cond1 = [this.#state.having, processed];
551
+ this.#state.having = { [operator]: cond1 };
553
552
  }
554
553
  return this;
555
554
  }
@@ -562,8 +561,8 @@ export class QueryBuilder {
562
561
  onConflict(fields = []) {
563
562
  const meta = this.mainAlias.meta;
564
563
  this.ensureNotFinalized();
565
- this._onConflict ??= [];
566
- this._onConflict.push({
564
+ this.#state.onConflict ??= [];
565
+ this.#state.onConflict.push({
567
566
  fields: isRaw(fields)
568
567
  ? fields
569
568
  : Utils.asArray(fields).flatMap(f => {
@@ -575,24 +574,24 @@ export class QueryBuilder {
575
574
  return this;
576
575
  }
577
576
  ignore() {
578
- if (!this._onConflict) {
577
+ if (!this.#state.onConflict) {
579
578
  throw new Error('You need to call `qb.onConflict()` first to use `qb.ignore()`');
580
579
  }
581
- this._onConflict[this._onConflict.length - 1].ignore = true;
580
+ this.#state.onConflict[this.#state.onConflict.length - 1].ignore = true;
582
581
  return this;
583
582
  }
584
583
  merge(data) {
585
- if (!this._onConflict) {
584
+ if (!this.#state.onConflict) {
586
585
  throw new Error('You need to call `qb.onConflict()` first to use `qb.merge()`');
587
586
  }
588
587
  if (Array.isArray(data) && data.length === 0) {
589
588
  return this.ignore();
590
589
  }
591
- this._onConflict[this._onConflict.length - 1].merge = data;
590
+ this.#state.onConflict[this.#state.onConflict.length - 1].merge = data;
592
591
  return this;
593
592
  }
594
593
  returning(fields) {
595
- this._returning = Utils.asArray(fields);
594
+ this.#state.returning = Utils.asArray(fields);
596
595
  return this;
597
596
  }
598
597
  /**
@@ -600,9 +599,9 @@ export class QueryBuilder {
600
599
  */
601
600
  populate(populate, populateWhere, populateFilter) {
602
601
  this.ensureNotFinalized();
603
- this._populate = populate;
604
- this._populateWhere = populateWhere;
605
- this._populateFilter = populateFilter;
602
+ this.#state.populate = populate;
603
+ this.#state.populateWhere = populateWhere;
604
+ this.#state.populateFilter = populateFilter;
606
605
  return this;
607
606
  }
608
607
  /**
@@ -616,7 +615,7 @@ export class QueryBuilder {
616
615
  */
617
616
  limit(limit, offset = 0) {
618
617
  this.ensureNotFinalized();
619
- this._limit = limit;
618
+ this.#state.limit = limit;
620
619
  if (offset) {
621
620
  this.offset(offset);
622
621
  }
@@ -632,12 +631,12 @@ export class QueryBuilder {
632
631
  */
633
632
  offset(offset) {
634
633
  this.ensureNotFinalized();
635
- this._offset = offset;
634
+ this.#state.offset = offset;
636
635
  return this;
637
636
  }
638
637
  withSchema(schema) {
639
638
  this.ensureNotFinalized();
640
- this._schema = schema;
639
+ this.#state.schema = schema;
641
640
  return this;
642
641
  }
643
642
  setLockMode(mode, tables) {
@@ -645,31 +644,31 @@ export class QueryBuilder {
645
644
  if (mode != null && ![LockMode.OPTIMISTIC, LockMode.NONE].includes(mode) && !this.context) {
646
645
  throw ValidationError.transactionRequired();
647
646
  }
648
- this.lockMode = mode;
649
- this.lockTables = tables;
647
+ this.#state.lockMode = mode;
648
+ this.#state.lockTables = tables;
650
649
  return this;
651
650
  }
652
651
  setFlushMode(flushMode) {
653
652
  this.ensureNotFinalized();
654
- this.flushMode = flushMode;
653
+ this.#state.flushMode = flushMode;
655
654
  return this;
656
655
  }
657
656
  setFlag(flag) {
658
657
  this.ensureNotFinalized();
659
- this.flags.add(flag);
658
+ this.#state.flags.add(flag);
660
659
  return this;
661
660
  }
662
661
  unsetFlag(flag) {
663
662
  this.ensureNotFinalized();
664
- this.flags.delete(flag);
663
+ this.#state.flags.delete(flag);
665
664
  return this;
666
665
  }
667
666
  hasFlag(flag) {
668
- return this.flags.has(flag);
667
+ return this.#state.flags.has(flag);
669
668
  }
670
669
  cache(config = true) {
671
670
  this.ensureNotFinalized();
672
- this._cache = config;
671
+ this.#state.cache = config;
673
672
  return this;
674
673
  }
675
674
  /**
@@ -677,7 +676,7 @@ export class QueryBuilder {
677
676
  */
678
677
  indexHint(sql) {
679
678
  this.ensureNotFinalized();
680
- this._indexHint = sql;
679
+ this.#state.indexHint = sql;
681
680
  return this;
682
681
  }
683
682
  /**
@@ -685,7 +684,7 @@ export class QueryBuilder {
685
684
  */
686
685
  collation(collation) {
687
686
  this.ensureNotFinalized();
688
- this._collation = collation;
687
+ this.#state.collation = collation;
689
688
  return this;
690
689
  }
691
690
  /**
@@ -693,7 +692,7 @@ export class QueryBuilder {
693
692
  */
694
693
  comment(comment) {
695
694
  this.ensureNotFinalized();
696
- this._comments.push(...Utils.asArray(comment));
695
+ this.#state.comments.push(...Utils.asArray(comment));
697
696
  return this;
698
697
  }
699
698
  /**
@@ -703,52 +702,110 @@ export class QueryBuilder {
703
702
  */
704
703
  hintComment(comment) {
705
704
  this.ensureNotFinalized();
706
- this._hintComments.push(...Utils.asArray(comment));
705
+ this.#state.hintComments.push(...Utils.asArray(comment));
707
706
  return this;
708
707
  }
709
708
  from(target, aliasName) {
710
709
  this.ensureNotFinalized();
711
- if (target instanceof QueryBuilder) {
710
+ if (target instanceof _a) {
712
711
  this.fromSubQuery(target, aliasName);
713
712
  }
713
+ else if (typeof target === 'string' && !this.metadata.find(target)) {
714
+ this.fromRawTable(target, aliasName);
715
+ }
714
716
  else {
715
- if (aliasName && this._mainAlias && Utils.className(target) !== this._mainAlias.aliasName) {
716
- throw new Error(`Cannot override the alias to '${aliasName}' since a query already contains references to '${this._mainAlias.aliasName}'`);
717
+ if (aliasName && this.#state.mainAlias && Utils.className(target) !== this.#state.mainAlias.aliasName) {
718
+ throw new Error(`Cannot override the alias to '${aliasName}' since a query already contains references to '${this.#state.mainAlias.aliasName}'`);
717
719
  }
718
720
  this.fromEntityName(target, aliasName);
719
721
  }
720
722
  return this;
721
723
  }
722
724
  getNativeQuery(processVirtualEntity = true) {
723
- if (this._query?.qb) {
724
- return this._query.qb;
725
+ if (this.#state.unionQuery) {
726
+ if (!this.#query?.qb) {
727
+ this.#query = {};
728
+ const nqb = this.platform.createNativeQueryBuilder();
729
+ nqb.select('*');
730
+ nqb.from(raw(`(${this.#state.unionQuery.sql})`, this.#state.unionQuery.params));
731
+ this.#query.qb = nqb;
732
+ }
733
+ return this.#query.qb;
725
734
  }
726
- this._query = {};
735
+ if (this.#query?.qb) {
736
+ return this.#query.qb;
737
+ }
738
+ this.#query = {};
727
739
  this.finalize();
728
740
  const qb = this.getQueryBase(processVirtualEntity);
741
+ for (const cte of this.#state.ctes) {
742
+ const query = cte.query;
743
+ const opts = { columns: cte.columns, materialized: cte.materialized };
744
+ if (cte.recursive) {
745
+ qb.withRecursive(cte.name, query, opts);
746
+ }
747
+ else {
748
+ qb.with(cte.name, query, opts);
749
+ }
750
+ }
729
751
  const schema = this.getSchema(this.mainAlias);
730
752
  const isNotEmptyObject = (obj) => Utils.hasObjectKeys(obj) || RawQueryFragment.hasObjectFragments(obj);
731
- Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._cond, qb), this._cond && !this._onConflict);
732
- Utils.runIfNotEmpty(() => qb.groupBy(this.prepareFields(this._groupBy, 'groupBy', schema)), isNotEmptyObject(this._groupBy));
733
- Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._having, qb, undefined, 'having'), isNotEmptyObject(this._having));
753
+ Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this.#state.cond, qb), this.#state.cond && !this.#state.onConflict);
754
+ Utils.runIfNotEmpty(() => qb.groupBy(this.prepareFields(this.#state.groupBy, 'groupBy', schema)), isNotEmptyObject(this.#state.groupBy));
755
+ Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this.#state.having, qb, undefined, 'having'), isNotEmptyObject(this.#state.having));
734
756
  Utils.runIfNotEmpty(() => {
735
- const queryOrder = this.helper.getQueryOrder(this.type, this._orderBy, this._populateMap, this._collation);
757
+ const queryOrder = this.helper.getQueryOrder(this.type, this.#state.orderBy, this.#state.populateMap, this.#state.collation);
736
758
  if (queryOrder.length > 0) {
737
759
  const sql = Utils.unique(queryOrder).join(', ');
738
760
  qb.orderBy(sql);
739
761
  return;
740
762
  }
741
- }, isNotEmptyObject(this._orderBy));
742
- Utils.runIfNotEmpty(() => qb.limit(this._limit), this._limit != null);
743
- Utils.runIfNotEmpty(() => qb.offset(this._offset), this._offset);
744
- Utils.runIfNotEmpty(() => qb.comment(this._comments), this._comments);
745
- Utils.runIfNotEmpty(() => qb.hintComment(this._hintComments), this._hintComments);
746
- Utils.runIfNotEmpty(() => this.helper.appendOnConflictClause(QueryType.UPSERT, this._onConflict, qb), this._onConflict);
747
- if (this.lockMode) {
748
- this.helper.getLockSQL(qb, this.lockMode, this.lockTables, this._joins);
749
- }
750
- this.helper.finalize(this.type, qb, this.mainAlias.meta, this._data, this._returning);
751
- return this._query.qb = qb;
763
+ }, isNotEmptyObject(this.#state.orderBy));
764
+ Utils.runIfNotEmpty(() => qb.limit(this.#state.limit), this.#state.limit != null);
765
+ Utils.runIfNotEmpty(() => qb.offset(this.#state.offset), this.#state.offset);
766
+ Utils.runIfNotEmpty(() => qb.comment(this.#state.comments), this.#state.comments);
767
+ Utils.runIfNotEmpty(() => qb.hintComment(this.#state.hintComments), this.#state.hintComments);
768
+ Utils.runIfNotEmpty(() => this.helper.appendOnConflictClause(QueryType.UPSERT, this.#state.onConflict, qb), this.#state.onConflict);
769
+ if (this.#state.lockMode) {
770
+ this.helper.getLockSQL(qb, this.#state.lockMode, this.#state.lockTables, this.#state.joins);
771
+ }
772
+ this.processReturningStatement(qb, this.mainAlias.meta, this.#state.data, this.#state.returning);
773
+ return (this.#query.qb = qb);
774
+ }
775
+ processReturningStatement(qb, meta, data, returning) {
776
+ const usesReturningStatement = this.platform.usesReturningStatement() || this.platform.usesOutputStatement();
777
+ if (!meta || !data || !usesReturningStatement) {
778
+ return;
779
+ }
780
+ // always respect explicit returning hint
781
+ if (returning && returning.length > 0) {
782
+ qb.returning(returning.map(field => this.helper.mapper(field, this.type)));
783
+ return;
784
+ }
785
+ if (this.type === QueryType.INSERT) {
786
+ const returningProps = meta.hydrateProps
787
+ .filter(prop => prop.returning || (prop.persist !== false && ((prop.primary && prop.autoincrement) || prop.defaultRaw)))
788
+ .filter(prop => !(prop.name in data));
789
+ if (returningProps.length > 0) {
790
+ qb.returning(Utils.flatten(returningProps.map(prop => prop.fieldNames)));
791
+ }
792
+ return;
793
+ }
794
+ if (this.type === QueryType.UPDATE) {
795
+ const returningProps = meta.hydrateProps.filter(prop => prop.fieldNames && isRaw(data[prop.fieldNames[0]]));
796
+ if (returningProps.length > 0) {
797
+ qb.returning(returningProps.flatMap((prop) => {
798
+ if (prop.hasConvertToJSValueSQL) {
799
+ const aliased = this.platform.quoteIdentifier(prop.fieldNames[0]);
800
+ const sql = prop.customType.convertToJSValueSQL(aliased, this.platform) +
801
+ ' as ' +
802
+ this.platform.quoteIdentifier(prop.fieldNames[0]);
803
+ return [raw(sql)];
804
+ }
805
+ return prop.fieldNames;
806
+ }));
807
+ }
808
+ }
752
809
  }
753
810
  /**
754
811
  * Returns the query with parameters as wildcards.
@@ -764,13 +821,16 @@ export class QueryBuilder {
764
821
  return raw(sql, params);
765
822
  }
766
823
  toQuery() {
767
- if (this._query?.sql) {
768
- return { sql: this._query.sql, params: this._query.params };
824
+ if (this.#state.unionQuery) {
825
+ return this.#state.unionQuery;
826
+ }
827
+ if (this.#query?.sql) {
828
+ return { sql: this.#query.sql, params: this.#query.params };
769
829
  }
770
830
  const query = this.getNativeQuery().compile();
771
- this._query.sql = query.sql;
772
- this._query.params = query.params;
773
- return { sql: this._query.sql, params: this._query.params };
831
+ this.#query.sql = query.sql;
832
+ this.#query.params = query.params;
833
+ return { sql: this.#query.sql, params: this.#query.params };
774
834
  }
775
835
  /**
776
836
  * Returns the list of all parameters for this query.
@@ -802,7 +862,7 @@ export class QueryBuilder {
802
862
  * @internal
803
863
  */
804
864
  getJoinForPath(path, options) {
805
- const joins = Object.values(this._joins);
865
+ const joins = Object.values(this.#state.joins);
806
866
  if (joins.length === 0) {
807
867
  return undefined;
808
868
  }
@@ -834,7 +894,7 @@ export class QueryBuilder {
834
894
  */
835
895
  getNextAlias(entityName = 'e') {
836
896
  entityName = Utils.className(entityName);
837
- return this.driver.config.getNamingStrategy().aliasName(entityName, this.aliasCounter++);
897
+ return this.driver.config.getNamingStrategy().aliasName(entityName, this.#state.aliasCounter++);
838
898
  }
839
899
  /**
840
900
  * Registers a join for a specific polymorphic target type.
@@ -847,15 +907,15 @@ export class QueryBuilder {
847
907
  const referencedColumnNames = targetMeta.getPrimaryProps().flatMap(pk => pk.fieldNames);
848
908
  const targetProp = { ...prop, targetMeta, referencedColumnNames };
849
909
  const aliasedName = `${ownerAlias}.${prop.name}[${targetMeta.className}]#${alias}`;
850
- this._joins[aliasedName] = this.helper.joinManyToOneReference(targetProp, ownerAlias, alias, type, {}, schema);
851
- this._joins[aliasedName].path = path;
910
+ this.#state.joins[aliasedName] = this.helper.joinManyToOneReference(targetProp, ownerAlias, alias, type, {}, schema);
911
+ this.#state.joins[aliasedName].path = path;
852
912
  this.createAlias(targetMeta.class, alias);
853
913
  }
854
914
  /**
855
915
  * @internal
856
916
  */
857
917
  getAliasMap() {
858
- return Object.fromEntries(Object.entries(this._aliases).map(([key, value]) => [key, value.entityName]));
918
+ return Object.fromEntries(Object.entries(this.#state.aliases).map(([key, value]) => [key, value.entityName]));
859
919
  }
860
920
  /**
861
921
  * Executes this QB and returns the raw results, mapped to the property names (unless disabled via last parameter).
@@ -870,11 +930,16 @@ export class QueryBuilder {
870
930
  if (!this.connectionType && (isRunType || this.context)) {
871
931
  this.connectionType = 'write';
872
932
  }
873
- if (!this.finalized && method === 'get' && this.type === QueryType.SELECT) {
933
+ if (!this.#state.finalized && method === 'get' && this.type === QueryType.SELECT) {
874
934
  this.limit(1);
875
935
  }
876
936
  const query = this.toQuery();
877
- const cached = await this.em?.tryCache(this.mainAlias.entityName, this._cache, ['qb.execute', query.sql, query.params, method]);
937
+ const cached = await this.em?.tryCache(this.mainAlias.entityName, this.#state.cache, [
938
+ 'qb.execute',
939
+ query.sql,
940
+ query.params,
941
+ method,
942
+ ]);
878
943
  if (cached?.data !== undefined) {
879
944
  return cached.data;
880
945
  }
@@ -882,17 +947,17 @@ export class QueryBuilder {
882
947
  const res = await this.getConnection().execute(query.sql, query.params, method, this.context, loggerContext);
883
948
  const meta = this.mainAlias.meta;
884
949
  if (!options.mapResults || !meta) {
885
- await this.em?.storeCache(this._cache, cached, res);
950
+ await this.em?.storeCache(this.#state.cache, cached, res);
886
951
  return res;
887
952
  }
888
953
  if (method === 'run') {
889
954
  return res;
890
955
  }
891
- const joinedProps = this.driver.joinedProps(meta, this._populate);
956
+ const joinedProps = this.driver.joinedProps(meta, this.#state.populate);
892
957
  let mapped;
893
958
  if (Array.isArray(res)) {
894
959
  const map = {};
895
- mapped = res.map(r => this.driver.mapResult(r, meta, this._populate, this, map));
960
+ mapped = res.map(r => this.driver.mapResult(r, meta, this.#state.populate, this, map));
896
961
  if (options.mergeResults && joinedProps.length > 0) {
897
962
  mapped = this.driver.mergeJoinedResult(mapped, this.mainAlias.meta, joinedProps);
898
963
  }
@@ -901,10 +966,10 @@ export class QueryBuilder {
901
966
  mapped = [this.driver.mapResult(res, meta, joinedProps, this)];
902
967
  }
903
968
  if (method === 'get') {
904
- await this.em?.storeCache(this._cache, cached, mapped[0]);
969
+ await this.em?.storeCache(this.#state.cache, cached, mapped[0]);
905
970
  return mapped[0];
906
971
  }
907
- await this.em?.storeCache(this._cache, cached, mapped);
972
+ await this.em?.storeCache(this.#state.cache, cached, mapped);
908
973
  return mapped;
909
974
  }
910
975
  getConnection() {
@@ -940,13 +1005,13 @@ export class QueryBuilder {
940
1005
  yield* res;
941
1006
  return;
942
1007
  }
943
- const joinedProps = this.driver.joinedProps(meta, this._populate);
1008
+ const joinedProps = this.driver.joinedProps(meta, this.#state.populate);
944
1009
  const stack = [];
945
1010
  const hash = (data) => {
946
1011
  return Utils.getPrimaryKeyHash(meta.primaryKeys.map(pk => data[pk]));
947
1012
  };
948
1013
  for await (const row of res) {
949
- const mapped = this.driver.mapResult(row, meta, this._populate, this);
1014
+ const mapped = this.driver.mapResult(row, meta, this.#state.populate, this);
950
1015
  if (!options.mergeResults || joinedProps.length === 0) {
951
1016
  yield this.mapResult(mapped, options.mapResults);
952
1017
  continue;
@@ -975,7 +1040,7 @@ export class QueryBuilder {
975
1040
  * Executes the query, returning array of results mapped to entity instances.
976
1041
  */
977
1042
  async getResultList(limit) {
978
- await this.em.tryFlush(this.mainAlias.entityName, { flushMode: this.flushMode });
1043
+ await this.em.tryFlush(this.mainAlias.entityName, { flushMode: this.#state.flushMode });
979
1044
  const res = await this.execute('all', true);
980
1045
  return this.mapResults(res, limit);
981
1046
  }
@@ -997,15 +1062,15 @@ export class QueryBuilder {
997
1062
  if (!map) {
998
1063
  return row;
999
1064
  }
1000
- const entity = this.em.map(this.mainAlias.entityName, row, { schema: this._schema });
1001
- this.propagatePopulateHint(entity, this._populate);
1065
+ const entity = this.em.map(this.mainAlias.entityName, row, { schema: this.#state.schema });
1066
+ this.propagatePopulateHint(entity, this.#state.populate);
1002
1067
  return entity;
1003
1068
  }
1004
1069
  mapResults(res, limit) {
1005
1070
  const entities = [];
1006
1071
  for (const row of res) {
1007
1072
  const entity = this.mapResult(row);
1008
- this.propagatePopulateHint(entity, this._populate);
1073
+ this.propagatePopulateHint(entity, this.#state.populate);
1009
1074
  entities.push(entity);
1010
1075
  if (limit != null && --limit === 0) {
1011
1076
  break;
@@ -1017,7 +1082,7 @@ export class QueryBuilder {
1017
1082
  * Executes the query, returning the first result or null
1018
1083
  */
1019
1084
  async getSingleResult() {
1020
- if (!this.finalized) {
1085
+ if (!this.#state.finalized) {
1021
1086
  this.limit(1);
1022
1087
  }
1023
1088
  const [res] = await this.getResultList(1);
@@ -1029,9 +1094,12 @@ export class QueryBuilder {
1029
1094
  res = await this.execute('get', false);
1030
1095
  }
1031
1096
  else {
1032
- const qb = (this._type === undefined ? this : this.clone());
1097
+ const qb = (this.#state.type === undefined ? this : this.clone());
1033
1098
  qb.processPopulateHint(); // needs to happen sooner so `qb.hasToManyJoins()` reports correctly
1034
- qb.count(field, distinct ?? qb.hasToManyJoins()).limit(undefined).offset(undefined).orderBy([]);
1099
+ qb.count(field, distinct ?? qb.hasToManyJoins())
1100
+ .limit(undefined)
1101
+ .offset(undefined)
1102
+ .orderBy([]);
1035
1103
  res = await qb.execute('get', false);
1036
1104
  }
1037
1105
  return res ? +res.count : 0;
@@ -1059,28 +1127,97 @@ export class QueryBuilder {
1059
1127
  Object.defineProperty(qb, '__as', { enumerable: false, value: finalAlias });
1060
1128
  return qb;
1061
1129
  }
1130
+ /**
1131
+ * Combines the current query with one or more other queries using `UNION ALL`.
1132
+ * All queries must select the same columns. Returns a `QueryBuilder` that
1133
+ * can be used with `$in`, passed to `qb.from()`, or converted via `.getQuery()`,
1134
+ * `.getParams()`, `.toQuery()`, `.toRaw()`, etc.
1135
+ *
1136
+ * ```ts
1137
+ * const qb1 = em.createQueryBuilder(Employee).select('id').where(condition1);
1138
+ * const qb2 = em.createQueryBuilder(Employee).select('id').where(condition2);
1139
+ * const qb3 = em.createQueryBuilder(Employee).select('id').where(condition3);
1140
+ * const subquery = qb1.unionAll(qb2, qb3);
1141
+ *
1142
+ * const results = await em.find(Employee, { id: { $in: subquery } });
1143
+ * ```
1144
+ */
1145
+ unionAll(...others) {
1146
+ return this.buildUnionQuery('union all', others);
1147
+ }
1148
+ /**
1149
+ * Combines the current query with one or more other queries using `UNION` (with deduplication).
1150
+ * All queries must select the same columns. Returns a `QueryBuilder` that
1151
+ * can be used with `$in`, passed to `qb.from()`, or converted via `.getQuery()`,
1152
+ * `.getParams()`, `.toQuery()`, `.toRaw()`, etc.
1153
+ *
1154
+ * ```ts
1155
+ * const qb1 = em.createQueryBuilder(Employee).select('id').where(condition1);
1156
+ * const qb2 = em.createQueryBuilder(Employee).select('id').where(condition2);
1157
+ * const subquery = qb1.union(qb2);
1158
+ *
1159
+ * const results = await em.find(Employee, { id: { $in: subquery } });
1160
+ * ```
1161
+ */
1162
+ union(...others) {
1163
+ return this.buildUnionQuery('union', others);
1164
+ }
1165
+ buildUnionQuery(separator, others) {
1166
+ const all = [this, ...others];
1167
+ const parts = [];
1168
+ const params = [];
1169
+ for (const qb of all) {
1170
+ const compiled = qb instanceof _a ? qb.toQuery() : qb.compile();
1171
+ parts.push(`(${compiled.sql})`);
1172
+ params.push(...compiled.params);
1173
+ }
1174
+ const result = this.clone(true);
1175
+ result.#state.unionQuery = { sql: parts.join(` ${separator} `), params };
1176
+ return result;
1177
+ }
1178
+ with(name, query, options) {
1179
+ return this.addCte(name, query, options);
1180
+ }
1181
+ withRecursive(name, query, options) {
1182
+ return this.addCte(name, query, options, true);
1183
+ }
1184
+ addCte(name, query, options, recursive) {
1185
+ this.ensureNotFinalized();
1186
+ if (this.#state.ctes.some(cte => cte.name === name)) {
1187
+ throw new Error(`CTE with name '${name}' already exists`);
1188
+ }
1189
+ // Eagerly compile QueryBuilder to RawQueryFragment — later mutations to the sub-query won't be reflected
1190
+ const compiled = query instanceof _a ? query.toRaw() : query;
1191
+ this.#state.ctes.push({
1192
+ name,
1193
+ query: compiled,
1194
+ recursive,
1195
+ columns: options?.columns,
1196
+ materialized: options?.materialized,
1197
+ });
1198
+ return this;
1199
+ }
1062
1200
  clone(reset, preserve) {
1063
- const qb = new QueryBuilder(this.mainAlias.entityName, this.metadata, this.driver, this.context, this.mainAlias.aliasName, this.connectionType, this.em);
1064
- reset = reset || [];
1065
- // clone array/object properties
1066
- const properties = [
1067
- 'flags', '_populate', '_populateWhere', '_populateFilter', '__populateWhere', '_populateMap', '_joins', '_joinedProps', '_cond', '_data', '_orderBy',
1068
- '_schema', '_indexHint', '_collation', '_cache', 'subQueries', 'lockMode', 'lockTables', '_groupBy', '_having', '_returning',
1069
- '_comments', '_hintComments', 'aliasCounter',
1070
- ];
1071
- for (const prop of Object.keys(this)) {
1072
- if (!preserve?.includes(prop) && (reset === true || reset.includes(prop) || ['_helper', '_query'].includes(prop))) {
1073
- continue;
1201
+ const qb = new _a(this.#state.mainAlias.entityName, this.metadata, this.driver, this.context, this.#state.mainAlias.aliasName, this.connectionType, this.em);
1202
+ if (reset !== true) {
1203
+ qb.#state = Utils.copy(this.#state);
1204
+ // CTEs contain NativeQueryBuilder instances that should not be deep-cloned
1205
+ qb.#state.ctes = this.#state.ctes.map(cte => ({ ...cte }));
1206
+ if (Array.isArray(reset)) {
1207
+ const fresh = _a.createDefaultState();
1208
+ for (const key of reset) {
1209
+ qb.#state[key] = fresh[key];
1210
+ }
1074
1211
  }
1075
- qb[prop] = properties.includes(prop) ? Utils.copy(this[prop]) : this[prop];
1076
1212
  }
1077
- /* v8 ignore next */
1078
- if (this._fields && reset !== true && !reset.includes('_fields')) {
1079
- qb._fields = [...this._fields];
1213
+ else if (preserve) {
1214
+ for (const key of preserve) {
1215
+ qb.#state[key] = Utils.copy(this.#state[key]);
1216
+ }
1080
1217
  }
1081
- qb._aliases = { ...this._aliases };
1082
- qb._helper.aliasMap = qb._aliases;
1083
- qb.finalized = false;
1218
+ qb.#state.finalized = false;
1219
+ qb.#query = undefined;
1220
+ qb.#helper = qb.createQueryBuilderHelper();
1084
1221
  return qb;
1085
1222
  }
1086
1223
  /**
@@ -1100,11 +1237,11 @@ export class QueryBuilder {
1100
1237
  if (typeof meta.expression === 'string') {
1101
1238
  return `(${meta.expression}) as ${this.platform.quoteIdentifier(this.alias)}`;
1102
1239
  }
1103
- const res = meta.expression(this.em, this._cond, {});
1240
+ const res = meta.expression(this.em, this.#state.cond, {});
1104
1241
  if (typeof res === 'string') {
1105
1242
  return `(${res}) as ${this.platform.quoteIdentifier(this.alias)}`;
1106
1243
  }
1107
- if (res instanceof QueryBuilder) {
1244
+ if (res instanceof _a) {
1108
1245
  return `(${res.getFormattedQuery()}) as ${this.platform.quoteIdentifier(this.alias)}`;
1109
1246
  }
1110
1247
  if (isRaw(res)) {
@@ -1123,10 +1260,11 @@ export class QueryBuilder {
1123
1260
  addPropertyJoin(prop, ownerAlias, alias, type, path, schema) {
1124
1261
  schema ??= prop.targetMeta?.schema === '*' ? '*' : this.driver.getSchemaName(prop.targetMeta);
1125
1262
  const key = `[tpt]${ownerAlias}#${alias}`;
1126
- this._joins[key] = prop.kind === ReferenceKind.MANY_TO_ONE
1127
- ? this.helper.joinManyToOneReference(prop, ownerAlias, alias, type, {}, schema)
1128
- : this.helper.joinOneToReference(prop, ownerAlias, alias, type, {}, schema);
1129
- this._joins[key].path = path;
1263
+ this.#state.joins[key] =
1264
+ prop.kind === ReferenceKind.MANY_TO_ONE
1265
+ ? this.helper.joinManyToOneReference(prop, ownerAlias, alias, type, {}, schema)
1266
+ : this.helper.joinOneToReference(prop, ownerAlias, alias, type, {}, schema);
1267
+ this.#state.joins[key].path = path;
1130
1268
  return key;
1131
1269
  }
1132
1270
  joinReference(field, alias, cond, type, path, schema, subquery) {
@@ -1136,7 +1274,7 @@ export class QueryBuilder {
1136
1274
  name: '__subquery__',
1137
1275
  kind: ReferenceKind.MANY_TO_ONE,
1138
1276
  };
1139
- if (field instanceof QueryBuilder) {
1277
+ if (field instanceof _a) {
1140
1278
  prop.type = Utils.className(field.mainAlias.entityName);
1141
1279
  prop.targetMeta = field.mainAlias.meta;
1142
1280
  field = field.getNativeQuery();
@@ -1145,7 +1283,7 @@ export class QueryBuilder {
1145
1283
  field = this.platform.formatQuery(field.sql, field.params);
1146
1284
  }
1147
1285
  const key = `${this.alias}.${prop.name}#${alias}`;
1148
- this._joins[key] = {
1286
+ this.#state.joins[key] = {
1149
1287
  prop,
1150
1288
  alias,
1151
1289
  type,
@@ -1161,10 +1299,10 @@ export class QueryBuilder {
1161
1299
  }
1162
1300
  const [fromAlias, fromField] = this.helper.splitField(field);
1163
1301
  const q = (str) => `'${str}'`;
1164
- if (!this._aliases[fromAlias]) {
1165
- 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(', ')}.`);
1302
+ if (!this.#state.aliases[fromAlias]) {
1303
+ 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.#state.aliases).map(q).join(', ')}.`);
1166
1304
  }
1167
- const entityName = this._aliases[fromAlias].entityName;
1305
+ const entityName = this.#state.aliases[fromAlias].entityName;
1168
1306
  const meta = this.metadata.get(entityName);
1169
1307
  const prop = meta.properties[fromField];
1170
1308
  if (!prop) {
@@ -1172,7 +1310,7 @@ export class QueryBuilder {
1172
1310
  }
1173
1311
  // For TPT inheritance, owning relations (M:1 and owning 1:1) may have FK columns in a parent table
1174
1312
  // Resolve the correct alias for the table that owns the FK column
1175
- const ownerAlias = (prop.kind === ReferenceKind.MANY_TO_ONE || (prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner))
1313
+ const ownerAlias = prop.kind === ReferenceKind.MANY_TO_ONE || (prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner)
1176
1314
  ? this.helper.getTPTAliasForProperty(fromField, fromAlias)
1177
1315
  : fromAlias;
1178
1316
  this.createAlias(prop.targetMeta.class, alias);
@@ -1187,10 +1325,10 @@ export class QueryBuilder {
1187
1325
  const criteriaNode = CriteriaNodeFactory.createNode(this.metadata, prop.targetMeta.class, cond);
1188
1326
  cond = criteriaNode.process(this, { ignoreBranching: true, alias });
1189
1327
  let aliasedName = `${fromAlias}.${prop.name}#${alias}`;
1190
- path ??= `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? Utils.className(entityName))}.${prop.name}`;
1328
+ path ??= `${Object.values(this.#state.joins).find(j => j.alias === fromAlias)?.path ?? Utils.className(entityName)}.${prop.name}`;
1191
1329
  if (prop.kind === ReferenceKind.ONE_TO_MANY) {
1192
- this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond, schema);
1193
- this._joins[aliasedName].path ??= path;
1330
+ this.#state.joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond, schema);
1331
+ this.#state.joins[aliasedName].path ??= path;
1194
1332
  }
1195
1333
  else if (prop.kind === ReferenceKind.MANY_TO_MANY) {
1196
1334
  let pivotAlias = alias;
@@ -1200,18 +1338,19 @@ export class QueryBuilder {
1200
1338
  aliasedName = `${fromAlias}.${prop.name}#${pivotAlias}`;
1201
1339
  }
1202
1340
  const joins = this.helper.joinManyToManyReference(prop, fromAlias, alias, pivotAlias, type, cond, path, schema);
1203
- Object.assign(this._joins, joins);
1341
+ Object.assign(this.#state.joins, joins);
1204
1342
  this.createAlias(prop.pivotEntity, pivotAlias);
1205
- this._joins[aliasedName].path ??= path;
1343
+ this.#state.joins[aliasedName].path ??= path;
1206
1344
  aliasedName = Object.keys(joins)[1];
1207
1345
  }
1208
1346
  else if (prop.kind === ReferenceKind.ONE_TO_ONE) {
1209
- this._joins[aliasedName] = this.helper.joinOneToReference(prop, ownerAlias, alias, type, cond, schema);
1210
- this._joins[aliasedName].path ??= path;
1347
+ this.#state.joins[aliasedName] = this.helper.joinOneToReference(prop, ownerAlias, alias, type, cond, schema);
1348
+ this.#state.joins[aliasedName].path ??= path;
1211
1349
  }
1212
- else { // MANY_TO_ONE
1213
- this._joins[aliasedName] = this.helper.joinManyToOneReference(prop, ownerAlias, alias, type, cond, schema);
1214
- this._joins[aliasedName].path ??= path;
1350
+ else {
1351
+ // MANY_TO_ONE
1352
+ this.#state.joins[aliasedName] = this.helper.joinManyToOneReference(prop, ownerAlias, alias, type, cond, schema);
1353
+ this.#state.joins[aliasedName].path ??= path;
1215
1354
  }
1216
1355
  return { prop, key: aliasedName };
1217
1356
  }
@@ -1229,14 +1368,14 @@ export class QueryBuilder {
1229
1368
  // Strip 'as alias' suffix if present — the alias is passed to mapper at the end
1230
1369
  let field = originalField;
1231
1370
  let customAlias;
1232
- const asMatch = originalField.match(FIELD_ALIAS_RE);
1371
+ const asMatch = FIELD_ALIAS_RE.exec(originalField);
1233
1372
  if (asMatch) {
1234
1373
  field = asMatch[1].trim();
1235
1374
  customAlias = asMatch[2];
1236
1375
  }
1237
- const join = Object.keys(this._joins).find(k => field === k.substring(0, k.indexOf('#')));
1376
+ const join = Object.keys(this.#state.joins).find(k => field === k.substring(0, k.indexOf('#')));
1238
1377
  if (join && type === 'where') {
1239
- ret.push(...this.helper.mapJoinColumns(this.type, this._joins[join]));
1378
+ ret.push(...this.helper.mapJoinColumns(this.type, this.#state.joins[join]));
1240
1379
  return;
1241
1380
  }
1242
1381
  const [a, f] = this.helper.splitField(field);
@@ -1250,7 +1389,7 @@ export class QueryBuilder {
1250
1389
  }
1251
1390
  if (prop?.embedded || (prop?.kind === ReferenceKind.EMBEDDED && prop.object)) {
1252
1391
  const name = prop.embeddedPath?.join('.') ?? prop.fieldNames[0];
1253
- const aliased = this._aliases[a] ? `${a}.${name}` : name;
1392
+ const aliased = this.#state.aliases[a] ? `${a}.${name}` : name;
1254
1393
  ret.push(getFieldName(aliased, customAlias));
1255
1394
  return;
1256
1395
  }
@@ -1260,7 +1399,9 @@ export class QueryBuilder {
1260
1399
  }
1261
1400
  const nest = (prop) => {
1262
1401
  for (const childProp of Object.values(prop.embeddedProps)) {
1263
- if (childProp.fieldNames && (childProp.kind !== ReferenceKind.EMBEDDED || childProp.object) && childProp.persist !== false) {
1402
+ if (childProp.fieldNames &&
1403
+ (childProp.kind !== ReferenceKind.EMBEDDED || childProp.object) &&
1404
+ childProp.persist !== false) {
1264
1405
  ret.push(getFieldName(childProp.fieldNames[0]));
1265
1406
  }
1266
1407
  else {
@@ -1281,16 +1422,16 @@ export class QueryBuilder {
1281
1422
  ret.push(getFieldName(field, customAlias));
1282
1423
  });
1283
1424
  const requiresSQLConversion = this.mainAlias.meta.props.filter(p => p.hasConvertToJSValueSQL && p.persist !== false);
1284
- if (this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES) &&
1425
+ if (this.#state.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES) &&
1285
1426
  (fields.includes('*') || fields.includes(`${this.mainAlias.aliasName}.*`)) &&
1286
1427
  requiresSQLConversion.length > 0) {
1287
1428
  for (const p of requiresSQLConversion) {
1288
1429
  ret.push(this.helper.mapper(p.name, this.type));
1289
1430
  }
1290
1431
  }
1291
- for (const f of Object.keys(this._populateMap)) {
1292
- if (type === 'where' && this._joins[f]) {
1293
- ret.push(...this.helper.mapJoinColumns(this.type, this._joins[f]));
1432
+ for (const f of Object.keys(this.#state.populateMap)) {
1433
+ if (type === 'where' && this.#state.joins[f]) {
1434
+ ret.push(...this.helper.mapJoinColumns(this.type, this.#state.joins[f]));
1294
1435
  }
1295
1436
  }
1296
1437
  return Utils.unique(ret);
@@ -1306,14 +1447,16 @@ export class QueryBuilder {
1306
1447
  }
1307
1448
  const parts = field.split('.');
1308
1449
  // Simple alias.property case - let prepareFields handle it
1309
- if (parts.length === 2 && this._aliases[parts[0]]) {
1450
+ if (parts.length === 2 && this.#state.aliases[parts[0]]) {
1310
1451
  return field;
1311
1452
  }
1312
1453
  // Start with root alias
1313
1454
  let currentAlias = parts[0];
1314
- let currentMeta = this._aliases[currentAlias] ? this.metadata.get(this._aliases[currentAlias].entityName) : this.mainAlias.meta;
1455
+ let currentMeta = this.#state.aliases[currentAlias]
1456
+ ? this.metadata.get(this.#state.aliases[currentAlias].entityName)
1457
+ : this.mainAlias.meta;
1315
1458
  // If first part is not an alias, it's a property of the main entity
1316
- if (!this._aliases[currentAlias]) {
1459
+ if (!this.#state.aliases[currentAlias]) {
1317
1460
  currentAlias = this.mainAlias.aliasName;
1318
1461
  parts.unshift(currentAlias);
1319
1462
  }
@@ -1351,14 +1494,14 @@ export class QueryBuilder {
1351
1494
  }
1352
1495
  // Find existing join or create new one
1353
1496
  const joinPath = parts.slice(0, i + 1).join('.');
1354
- const existingJoinKey = Object.keys(this._joins).find(k => {
1355
- const join = this._joins[k];
1497
+ const existingJoinKey = Object.keys(this.#state.joins).find(k => {
1498
+ const join = this.#state.joins[k];
1356
1499
  // Check by path or by key prefix (key format is `alias.field#joinAlias`)
1357
1500
  return join.path === joinPath || k.startsWith(`${currentAlias}.${propName}#`);
1358
1501
  });
1359
1502
  let joinAlias;
1360
1503
  if (existingJoinKey) {
1361
- joinAlias = this._joins[existingJoinKey].alias;
1504
+ joinAlias = this.#state.joins[existingJoinKey].alias;
1362
1505
  }
1363
1506
  else {
1364
1507
  joinAlias = this.getNextAlias(prop.targetMeta?.className ?? propName);
@@ -1375,18 +1518,18 @@ export class QueryBuilder {
1375
1518
  }
1376
1519
  init(type, data, cond) {
1377
1520
  this.ensureNotFinalized();
1378
- this._type = type;
1379
- if ([QueryType.UPDATE, QueryType.DELETE].includes(type) && Utils.hasObjectKeys(this._cond)) {
1521
+ this.#state.type = type;
1522
+ if ([QueryType.UPDATE, QueryType.DELETE].includes(type) && Utils.hasObjectKeys(this.#state.cond)) {
1380
1523
  throw new Error(`You are trying to call \`qb.where().${type.toLowerCase()}()\`. Calling \`qb.${type.toLowerCase()}()\` before \`qb.where()\` is required.`);
1381
1524
  }
1382
1525
  if (!this.helper.isTableNameAliasRequired(type)) {
1383
- delete this._fields;
1526
+ this.#state.fields = undefined;
1384
1527
  }
1385
1528
  if (data) {
1386
1529
  if (Utils.isEntity(data)) {
1387
1530
  data = this.em?.getComparator().prepareEntity(data) ?? serialize(data);
1388
1531
  }
1389
- this._data = this.helper.processData(data, this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES), false);
1532
+ this.#state.data = this.helper.processData(data, this.#state.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES), false);
1390
1533
  }
1391
1534
  if (cond) {
1392
1535
  this.where(cond);
@@ -1394,47 +1537,54 @@ export class QueryBuilder {
1394
1537
  return this;
1395
1538
  }
1396
1539
  getQueryBase(processVirtualEntity) {
1397
- const qb = this.platform.createNativeQueryBuilder().setFlags(this.flags);
1398
- const { subQuery, aliasName, entityName, meta } = this.mainAlias;
1399
- const requiresAlias = this.finalized && (this._explicitAlias || this.helper.isTableNameAliasRequired(this.type));
1540
+ const qb = this.platform.createNativeQueryBuilder().setFlags(this.#state.flags);
1541
+ const { subQuery, aliasName, entityName, meta, rawTableName } = this.mainAlias;
1542
+ const requiresAlias = this.#state.finalized && (this.#state.explicitAlias || this.helper.isTableNameAliasRequired(this.type));
1400
1543
  const alias = requiresAlias ? aliasName : undefined;
1401
1544
  const schema = this.getSchema(this.mainAlias);
1402
- const tableName = subQuery ? subQuery.as(aliasName) : this.helper.getTableName(entityName);
1403
- const joinSchema = this._schema ?? this.em?.schema ?? schema;
1545
+ const tableName = rawTableName
1546
+ ? rawTableName
1547
+ : subQuery instanceof NativeQueryBuilder
1548
+ ? subQuery.as(aliasName)
1549
+ : subQuery
1550
+ ? raw(`(${subQuery.sql}) as ${this.platform.quoteIdentifier(aliasName)}`, subQuery.params)
1551
+ : this.helper.getTableName(entityName);
1552
+ const joinSchema = this.#state.schema ?? this.em?.schema ?? schema;
1553
+ const schemaOverride = this.#state.schema ?? this.em?.schema;
1404
1554
  if (meta.virtual && processVirtualEntity) {
1405
- qb.from(raw(this.fromVirtual(meta)), { indexHint: this._indexHint });
1555
+ qb.from(raw(this.fromVirtual(meta)), { indexHint: this.#state.indexHint });
1406
1556
  }
1407
1557
  else {
1408
1558
  qb.from(tableName, {
1409
- schema,
1559
+ schema: rawTableName ? undefined : schema,
1410
1560
  alias,
1411
- indexHint: this._indexHint,
1561
+ indexHint: this.#state.indexHint,
1412
1562
  });
1413
1563
  }
1414
1564
  switch (this.type) {
1415
1565
  case QueryType.SELECT:
1416
- qb.select(this.prepareFields(this._fields, 'where', schema));
1417
- if (this._distinctOn) {
1418
- qb.distinctOn(this.prepareFields(this._distinctOn, 'where', schema));
1566
+ qb.select(this.prepareFields(this.#state.fields, 'where', schema));
1567
+ if (this.#state.distinctOn) {
1568
+ qb.distinctOn(this.prepareFields(this.#state.distinctOn, 'where', schema));
1419
1569
  }
1420
- else if (this.flags.has(QueryFlag.DISTINCT)) {
1570
+ else if (this.#state.flags.has(QueryFlag.DISTINCT)) {
1421
1571
  qb.distinct();
1422
1572
  }
1423
- this.helper.processJoins(qb, this._joins, joinSchema);
1573
+ this.helper.processJoins(qb, this.#state.joins, joinSchema, schemaOverride);
1424
1574
  break;
1425
1575
  case QueryType.COUNT: {
1426
- const fields = this._fields.map(f => this.helper.mapper(f, this.type, undefined, undefined, schema));
1427
- qb.count(fields, this.flags.has(QueryFlag.DISTINCT));
1428
- this.helper.processJoins(qb, this._joins, joinSchema);
1576
+ const fields = this.#state.fields.map(f => this.helper.mapper(f, this.type, undefined, undefined, schema));
1577
+ qb.count(fields, this.#state.flags.has(QueryFlag.DISTINCT));
1578
+ this.helper.processJoins(qb, this.#state.joins, joinSchema, schemaOverride);
1429
1579
  break;
1430
1580
  }
1431
1581
  case QueryType.INSERT:
1432
- qb.insert(this._data);
1582
+ qb.insert(this.#state.data);
1433
1583
  break;
1434
1584
  case QueryType.UPDATE:
1435
- qb.update(this._data);
1436
- this.helper.processJoins(qb, this._joins, joinSchema);
1437
- this.helper.updateVersionProperty(qb, this._data);
1585
+ qb.update(this.#state.data);
1586
+ this.helper.processJoins(qb, this.#state.joins, joinSchema, schemaOverride);
1587
+ this.helper.updateVersionProperty(qb, this.#state.data);
1438
1588
  break;
1439
1589
  case QueryType.DELETE:
1440
1590
  qb.delete();
@@ -1460,7 +1610,9 @@ export class QueryBuilder {
1460
1610
  };
1461
1611
  lookUpChildren(children, meta.class);
1462
1612
  this.andWhere({
1463
- [meta.root.discriminatorColumn]: children.length > 0 ? { $in: [meta.discriminatorValue, ...children.map(c => c.discriminatorValue)] } : meta.discriminatorValue,
1613
+ [meta.root.discriminatorColumn]: children.length > 0
1614
+ ? { $in: [meta.discriminatorValue, ...children.map(c => c.discriminatorValue)] }
1615
+ : meta.discriminatorValue,
1464
1616
  });
1465
1617
  }
1466
1618
  /**
@@ -1478,20 +1630,22 @@ export class QueryBuilder {
1478
1630
  */
1479
1631
  applyTPTJoins() {
1480
1632
  const meta = this.mainAlias.meta;
1481
- if (meta?.inheritanceType !== 'tpt' || !meta.tptParent || ![QueryType.SELECT, QueryType.COUNT].includes(this.type)) {
1633
+ if (meta?.inheritanceType !== 'tpt' ||
1634
+ !meta.tptParent ||
1635
+ ![QueryType.SELECT, QueryType.COUNT].includes(this.type)) {
1482
1636
  return;
1483
1637
  }
1484
- if (this.tptJoinsApplied) {
1638
+ if (this.#state.tptJoinsApplied) {
1485
1639
  return;
1486
1640
  }
1487
- this.tptJoinsApplied = true;
1641
+ this.#state.tptJoinsApplied = true;
1488
1642
  let childMeta = meta;
1489
1643
  let childAlias = this.mainAlias.aliasName;
1490
1644
  while (childMeta.tptParent) {
1491
1645
  const parentMeta = childMeta.tptParent;
1492
1646
  const parentAlias = this.getNextAlias(parentMeta.className);
1493
1647
  this.createAlias(parentMeta.class, parentAlias);
1494
- this._tptAlias[parentMeta.className] = parentAlias;
1648
+ this.#state.tptAlias[parentMeta.className] = parentAlias;
1495
1649
  this.addPropertyJoin(childMeta.tptParentProp, childAlias, parentAlias, JoinType.innerJoin, `[tpt]${childMeta.className}`);
1496
1650
  childMeta = parentMeta;
1497
1651
  childAlias = parentAlias;
@@ -1502,20 +1656,22 @@ export class QueryBuilder {
1502
1656
  */
1503
1657
  addTPTParentFields() {
1504
1658
  const meta = this.mainAlias.meta;
1505
- if (meta?.inheritanceType !== 'tpt' || !meta.tptParent || ![QueryType.SELECT, QueryType.COUNT].includes(this.type)) {
1659
+ if (meta?.inheritanceType !== 'tpt' ||
1660
+ !meta.tptParent ||
1661
+ ![QueryType.SELECT, QueryType.COUNT].includes(this.type)) {
1506
1662
  return;
1507
1663
  }
1508
- if (!this._fields?.includes('*') && !this._fields?.includes(`${this.mainAlias.aliasName}.*`)) {
1664
+ if (!this.#state.fields?.includes('*') && !this.#state.fields?.includes(`${this.mainAlias.aliasName}.*`)) {
1509
1665
  return;
1510
1666
  }
1511
1667
  let parentMeta = meta.tptParent;
1512
1668
  while (parentMeta) {
1513
- const parentAlias = this._tptAlias[parentMeta.className];
1669
+ const parentAlias = this.#state.tptAlias[parentMeta.className];
1514
1670
  if (parentAlias) {
1515
1671
  const schema = parentMeta.schema === '*' ? '*' : this.driver.getSchemaName(parentMeta);
1516
- parentMeta.ownProps
1517
- .filter(prop => this.platform.shouldHaveColumn(prop, []))
1518
- .forEach(prop => this._fields.push(...this.driver.mapPropToFieldNames(this, prop, parentAlias, parentMeta, schema)));
1672
+ parentMeta
1673
+ .ownProps.filter(prop => this.platform.shouldHaveColumn(prop, []))
1674
+ .forEach(prop => this.#state.fields.push(...this.driver.mapPropToFieldNames(this, prop, parentAlias, parentMeta, schema)));
1519
1675
  }
1520
1676
  parentMeta = parentMeta.tptParent;
1521
1677
  }
@@ -1530,32 +1686,32 @@ export class QueryBuilder {
1530
1686
  if (!descendants?.length || ![QueryType.SELECT, QueryType.COUNT].includes(this.type)) {
1531
1687
  return;
1532
1688
  }
1533
- if (!this._fields?.includes('*') && !this._fields?.includes(`${this.mainAlias.aliasName}.*`)) {
1689
+ if (!this.#state.fields?.includes('*') && !this.#state.fields?.includes(`${this.mainAlias.aliasName}.*`)) {
1534
1690
  return;
1535
1691
  }
1536
1692
  // LEFT JOIN each descendant table and add their fields
1537
1693
  for (const childMeta of descendants) {
1538
1694
  const childAlias = this.getNextAlias(childMeta.className);
1539
1695
  this.createAlias(childMeta.class, childAlias);
1540
- this._tptAlias[childMeta.className] = childAlias;
1696
+ this.#state.tptAlias[childMeta.className] = childAlias;
1541
1697
  this.addPropertyJoin(childMeta.tptInverseProp, this.mainAlias.aliasName, childAlias, JoinType.leftJoin, `[tpt]${meta.className}`);
1542
1698
  // Add child fields
1543
1699
  const schema = childMeta.schema === '*' ? '*' : this.driver.getSchemaName(childMeta);
1544
- childMeta.ownProps
1545
- .filter(prop => !prop.primary && this.platform.shouldHaveColumn(prop, []))
1546
- .forEach(prop => this._fields.push(...this.driver.mapPropToFieldNames(this, prop, childAlias, childMeta, schema)));
1700
+ childMeta
1701
+ .ownProps.filter(prop => !prop.primary && this.platform.shouldHaveColumn(prop, []))
1702
+ .forEach(prop => this.#state.fields.push(...this.driver.mapPropToFieldNames(this, prop, childAlias, childMeta, schema)));
1547
1703
  }
1548
1704
  // Add computed discriminator (CASE WHEN to determine concrete type)
1549
1705
  // descendants is pre-sorted by depth (deepest first) during discovery
1550
1706
  if (meta.tptDiscriminatorColumn) {
1551
- this._fields.push(this.driver.buildTPTDiscriminatorExpression(meta, descendants, this._tptAlias, this.mainAlias.aliasName));
1707
+ this.#state.fields.push(this.driver.buildTPTDiscriminatorExpression(meta, descendants, this.#state.tptAlias, this.mainAlias.aliasName));
1552
1708
  }
1553
1709
  }
1554
1710
  finalize() {
1555
- if (this.finalized) {
1711
+ if (this.#state.finalized) {
1556
1712
  return;
1557
1713
  }
1558
- if (!this._type) {
1714
+ if (!this.#state.type) {
1559
1715
  this.select('*');
1560
1716
  }
1561
1717
  const meta = this.mainAlias.meta;
@@ -1565,93 +1721,102 @@ export class QueryBuilder {
1565
1721
  this.applyTPTPolymorphicJoins();
1566
1722
  this.processPopulateHint();
1567
1723
  this.processNestedJoins();
1568
- if (meta && (this._fields?.includes('*') || this._fields?.includes(`${this.mainAlias.aliasName}.*`))) {
1724
+ if (meta && (this.#state.fields?.includes('*') || this.#state.fields?.includes(`${this.mainAlias.aliasName}.*`))) {
1569
1725
  const schema = this.getSchema(this.mainAlias);
1570
1726
  // Create a column mapping with unquoted aliases - quoting should be handled by the user via `quote` helper
1571
1727
  // For TPT, use helper to resolve correct alias per property (inherited props use parent alias)
1572
1728
  const quotedMainAlias = this.platform.quoteIdentifier(this.mainAlias.aliasName).toString();
1573
1729
  const columns = meta.createColumnMappingObject(prop => this.helper.getTPTAliasForProperty(prop.name, this.mainAlias.aliasName), quotedMainAlias);
1574
1730
  meta.props
1575
- .filter(prop => prop.formula && (!prop.lazy || this.flags.has(QueryFlag.INCLUDE_LAZY_FORMULAS)))
1731
+ .filter(prop => prop.formula && (!prop.lazy || this.#state.flags.has(QueryFlag.INCLUDE_LAZY_FORMULAS)))
1576
1732
  .map(prop => {
1577
1733
  const aliased = this.platform.quoteIdentifier(prop.fieldNames[0]);
1578
1734
  const table = this.helper.createFormulaTable(quotedMainAlias, meta, schema);
1579
1735
  return `${this.driver.evaluateFormula(prop.formula, columns, table)} as ${aliased}`;
1580
1736
  })
1581
- .filter(field => !this._fields.some(f => {
1737
+ .filter(field => !this.#state.fields.some(f => {
1582
1738
  if (isRaw(f)) {
1583
1739
  return f.sql === field && f.params.length === 0;
1584
1740
  }
1585
1741
  return f === field;
1586
1742
  }))
1587
- .forEach(field => this._fields.push(raw(field)));
1743
+ .forEach(field => this.#state.fields.push(raw(field)));
1588
1744
  }
1589
- QueryHelper.processObjectParams(this._data);
1590
- QueryHelper.processObjectParams(this._cond);
1591
- QueryHelper.processObjectParams(this._having);
1745
+ QueryHelper.processObjectParams(this.#state.data);
1746
+ QueryHelper.processObjectParams(this.#state.cond);
1747
+ QueryHelper.processObjectParams(this.#state.having);
1592
1748
  // automatically enable paginate flag when we detect to-many joins, but only if there is no `group by` clause
1593
- if (!this.flags.has(QueryFlag.DISABLE_PAGINATE) && this._groupBy.length === 0 && this.hasToManyJoins()) {
1594
- this.flags.add(QueryFlag.PAGINATE);
1595
- }
1596
- if (meta && !meta.virtual && this.flags.has(QueryFlag.PAGINATE) && !this.flags.has(QueryFlag.DISABLE_PAGINATE) && (this._limit > 0 || this._offset > 0)) {
1749
+ if (!this.#state.flags.has(QueryFlag.DISABLE_PAGINATE) &&
1750
+ this.#state.groupBy.length === 0 &&
1751
+ this.hasToManyJoins()) {
1752
+ this.#state.flags.add(QueryFlag.PAGINATE);
1753
+ }
1754
+ if (meta &&
1755
+ !meta.virtual &&
1756
+ this.#state.flags.has(QueryFlag.PAGINATE) &&
1757
+ !this.#state.flags.has(QueryFlag.DISABLE_PAGINATE) &&
1758
+ (this.#state.limit > 0 || this.#state.offset > 0)) {
1597
1759
  this.wrapPaginateSubQuery(meta);
1598
1760
  }
1599
- if (meta && (this.flags.has(QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(QueryFlag.DELETE_SUB_QUERY))) {
1761
+ if (meta &&
1762
+ (this.#state.flags.has(QueryFlag.UPDATE_SUB_QUERY) || this.#state.flags.has(QueryFlag.DELETE_SUB_QUERY))) {
1600
1763
  this.wrapModifySubQuery(meta);
1601
1764
  }
1602
- this.finalized = true;
1765
+ this.#state.finalized = true;
1603
1766
  }
1604
1767
  /** @internal */
1605
1768
  processPopulateHint() {
1606
- if (this.populateHintFinalized) {
1769
+ if (this.#state.populateHintFinalized) {
1607
1770
  return;
1608
1771
  }
1609
1772
  const meta = this.mainAlias.meta;
1610
- if (meta && this.flags.has(QueryFlag.AUTO_JOIN_ONE_TO_ONE_OWNER)) {
1611
- const relationsToPopulate = this._populate.map(({ field }) => field);
1773
+ if (meta && this.#state.flags.has(QueryFlag.AUTO_JOIN_ONE_TO_ONE_OWNER)) {
1774
+ const relationsToPopulate = this.#state.populate.map(({ field }) => field);
1612
1775
  meta.relations
1613
- .filter(prop => prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner && !relationsToPopulate.includes(prop.name) && !relationsToPopulate.includes(`${prop.name}:ref`))
1776
+ .filter(prop => prop.kind === ReferenceKind.ONE_TO_ONE &&
1777
+ !prop.owner &&
1778
+ !relationsToPopulate.includes(prop.name) &&
1779
+ !relationsToPopulate.includes(`${prop.name}:ref`))
1614
1780
  .map(prop => ({ field: `${prop.name}:ref` }))
1615
- .forEach(item => this._populate.push(item));
1781
+ .forEach(item => this.#state.populate.push(item));
1616
1782
  }
1617
- this._populate.forEach(({ field }) => {
1783
+ this.#state.populate.forEach(({ field }) => {
1618
1784
  const [fromAlias, fromField] = this.helper.splitField(field);
1619
1785
  const aliasedField = `${fromAlias}.${fromField}`;
1620
- const join = Object.keys(this._joins).find(k => `${aliasedField}#${this._joins[k].alias}` === k);
1621
- if (join && this._joins[join] && this.helper.isOneToOneInverse(fromField)) {
1622
- this._populateMap[join] = this._joins[join].alias;
1786
+ const join = Object.keys(this.#state.joins).find(k => `${aliasedField}#${this.#state.joins[k].alias}` === k);
1787
+ if (join && this.#state.joins[join] && this.helper.isOneToOneInverse(fromField)) {
1788
+ this.#state.populateMap[join] = this.#state.joins[join].alias;
1623
1789
  return;
1624
1790
  }
1625
1791
  if (meta && this.helper.isOneToOneInverse(fromField)) {
1626
1792
  const prop = meta.properties[fromField];
1627
1793
  const alias = this.getNextAlias(prop.pivotEntity ?? prop.targetMeta.class);
1628
1794
  const aliasedName = `${fromAlias}.${prop.name}#${alias}`;
1629
- this._joins[aliasedName] = this.helper.joinOneToReference(prop, this.mainAlias.aliasName, alias, JoinType.leftJoin);
1630
- this._joins[aliasedName].path = `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? meta.className)}.${prop.name}`;
1631
- this._populateMap[aliasedName] = this._joins[aliasedName].alias;
1795
+ this.#state.joins[aliasedName] = this.helper.joinOneToReference(prop, this.mainAlias.aliasName, alias, JoinType.leftJoin);
1796
+ this.#state.joins[aliasedName].path =
1797
+ `${Object.values(this.#state.joins).find(j => j.alias === fromAlias)?.path ?? meta.className}.${prop.name}`;
1798
+ this.#state.populateMap[aliasedName] = this.#state.joins[aliasedName].alias;
1632
1799
  this.createAlias(prop.targetMeta.class, alias);
1633
1800
  }
1634
1801
  });
1635
1802
  this.processPopulateWhere(false);
1636
1803
  this.processPopulateWhere(true);
1637
- this.populateHintFinalized = true;
1804
+ this.#state.populateHintFinalized = true;
1638
1805
  }
1639
1806
  processPopulateWhere(filter) {
1640
- const key = filter ? '_populateFilter' : '_populateWhere';
1641
- if (this[key] == null || this[key] === PopulateHint.ALL) {
1807
+ const value = filter ? this.#state.populateFilter : this.#state.populateWhere;
1808
+ if (value == null || value === PopulateHint.ALL) {
1642
1809
  return;
1643
1810
  }
1644
- let joins = Object.values(this._joins);
1811
+ let joins = Object.values(this.#state.joins);
1645
1812
  for (const join of joins) {
1646
1813
  join.cond_ ??= join.cond;
1647
1814
  join.cond = { ...join.cond };
1648
1815
  }
1649
- if (typeof this[key] === 'object') {
1650
- const cond = CriteriaNodeFactory
1651
- .createNode(this.metadata, this.mainAlias.entityName, this[key])
1652
- .process(this, { matchPopulateJoins: true, ignoreBranching: true, preferNoBranch: true, filter });
1816
+ if (typeof value === 'object') {
1817
+ const cond = CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, value).process(this, { matchPopulateJoins: true, ignoreBranching: true, preferNoBranch: true, filter });
1653
1818
  // there might be new joins created by processing the `populateWhere` object
1654
- joins = Object.values(this._joins);
1819
+ joins = Object.values(this.#state.joins);
1655
1820
  this.mergeOnConditions(joins, cond, filter);
1656
1821
  }
1657
1822
  }
@@ -1671,9 +1836,11 @@ export class QueryBuilder {
1671
1836
  // https://stackoverflow.com/a/56815807/3665878
1672
1837
  if (parentJoin && !filter) {
1673
1838
  const nested = (parentJoin.nested ??= new Set());
1674
- join.type = join.type === JoinType.innerJoin || ([ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(parentJoin.prop.kind))
1675
- ? JoinType.nestedInnerJoin
1676
- : JoinType.nestedLeftJoin;
1839
+ join.type =
1840
+ join.type === JoinType.innerJoin ||
1841
+ [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(parentJoin.prop.kind)
1842
+ ? JoinType.nestedInnerJoin
1843
+ : JoinType.nestedLeftJoin;
1677
1844
  nested.add(join);
1678
1845
  }
1679
1846
  if (join.cond[k]) {
@@ -1695,10 +1862,10 @@ export class QueryBuilder {
1695
1862
  * otherwise the inner join could discard rows of the root table.
1696
1863
  */
1697
1864
  processNestedJoins() {
1698
- if (this.flags.has(QueryFlag.DISABLE_NESTED_INNER_JOIN)) {
1865
+ if (this.#state.flags.has(QueryFlag.DISABLE_NESTED_INNER_JOIN)) {
1699
1866
  return;
1700
1867
  }
1701
- const joins = Object.values(this._joins);
1868
+ const joins = Object.values(this.#state.joins);
1702
1869
  const lookupParentGroup = (j) => {
1703
1870
  return j.nested ?? (j.parent ? lookupParentGroup(j.parent) : undefined);
1704
1871
  };
@@ -1707,48 +1874,44 @@ export class QueryBuilder {
1707
1874
  join.parent = joins.find(j => j.alias === join.ownerAlias);
1708
1875
  // https://stackoverflow.com/a/56815807/3665878
1709
1876
  if (join.parent?.type === JoinType.leftJoin || join.parent?.type === JoinType.nestedLeftJoin) {
1710
- const nested = ((join.parent).nested ??= new Set());
1711
- join.type = join.type === JoinType.innerJoin
1712
- ? JoinType.nestedInnerJoin
1713
- : JoinType.nestedLeftJoin;
1877
+ const nested = (join.parent.nested ??= new Set());
1878
+ join.type = join.type === JoinType.innerJoin ? JoinType.nestedInnerJoin : JoinType.nestedLeftJoin;
1714
1879
  nested.add(join);
1715
1880
  }
1716
1881
  else if (join.parent?.type === JoinType.nestedInnerJoin) {
1717
1882
  const group = lookupParentGroup(join.parent);
1718
- const nested = group ?? ((join.parent).nested ??= new Set());
1719
- join.type = join.type === JoinType.innerJoin
1720
- ? JoinType.nestedInnerJoin
1721
- : JoinType.nestedLeftJoin;
1883
+ const nested = group ?? (join.parent.nested ??= new Set());
1884
+ join.type = join.type === JoinType.innerJoin ? JoinType.nestedInnerJoin : JoinType.nestedLeftJoin;
1722
1885
  nested.add(join);
1723
1886
  }
1724
1887
  }
1725
1888
  }
1726
1889
  }
1727
1890
  hasToManyJoins() {
1728
- return Object.values(this._joins).some(join => {
1891
+ return Object.values(this.#state.joins).some(join => {
1729
1892
  return [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(join.prop.kind);
1730
1893
  });
1731
1894
  }
1732
1895
  wrapPaginateSubQuery(meta) {
1733
1896
  const schema = this.getSchema(this.mainAlias);
1734
1897
  const pks = this.prepareFields(meta.primaryKeys, 'sub-query', schema);
1735
- const subQuery = this.clone(['_orderBy', '_fields', 'lockMode', 'lockTableAliases'])
1898
+ const subQuery = this.clone(['orderBy', 'fields', 'lockMode', 'lockTables'])
1736
1899
  .select(pks)
1737
1900
  .groupBy(pks)
1738
- .limit(this._limit);
1901
+ .limit(this.#state.limit);
1739
1902
  // revert the on conditions added via populateWhere, we want to apply those only once
1740
- for (const join of Object.values(subQuery._joins)) {
1903
+ for (const join of Object.values(subQuery.#state.joins)) {
1741
1904
  if (join.cond_) {
1742
1905
  join.cond = join.cond_;
1743
1906
  }
1744
1907
  }
1745
- if (this._offset) {
1746
- subQuery.offset(this._offset);
1908
+ if (this.#state.offset) {
1909
+ subQuery.offset(this.#state.offset);
1747
1910
  }
1748
1911
  const addToSelect = [];
1749
- if (this._orderBy.length > 0) {
1912
+ if (this.#state.orderBy.length > 0) {
1750
1913
  const orderBy = [];
1751
- for (const orderMap of this._orderBy) {
1914
+ for (const orderMap of this.#state.orderBy) {
1752
1915
  for (const field of Utils.getObjectQueryKeys(orderMap)) {
1753
1916
  const direction = orderMap[field];
1754
1917
  if (RawQueryFragment.isKnownFragmentSymbol(field)) {
@@ -1769,11 +1932,11 @@ export class QueryBuilder {
1769
1932
  }
1770
1933
  subQuery.orderBy(orderBy);
1771
1934
  }
1772
- subQuery.finalized = true;
1935
+ subQuery.#state.finalized = true;
1773
1936
  const innerQuery = subQuery.as(this.mainAlias.aliasName).clear('select').select(pks);
1774
1937
  if (addToSelect.length > 0) {
1775
1938
  addToSelect.forEach(prop => {
1776
- const field = this._fields.find(field => {
1939
+ const field = this.#state.fields.find(field => {
1777
1940
  if (typeof field === 'object' && field && '__as' in field) {
1778
1941
  return field.__as === prop;
1779
1942
  }
@@ -1799,18 +1962,20 @@ export class QueryBuilder {
1799
1962
  // https://stackoverflow.com/questions/17892762/mysql-this-version-of-mysql-doesnt-yet-support-limit-in-all-any-some-subqu
1800
1963
  const subSubQuery = this.platform.createNativeQueryBuilder();
1801
1964
  subSubQuery.select(pks).from(innerQuery);
1802
- this._limit = undefined;
1803
- this._offset = undefined;
1965
+ this.#state.limit = undefined;
1966
+ this.#state.offset = undefined;
1804
1967
  // Save the original WHERE conditions before pruning joins
1805
- const originalCond = this._cond;
1968
+ const originalCond = this.#state.cond;
1806
1969
  const populatePaths = this.getPopulatePaths();
1807
- if (!this._fields.some(field => isRaw(field))) {
1970
+ if (!this.#state.fields.some(field => isRaw(field))) {
1808
1971
  this.pruneJoinsForPagination(meta, populatePaths);
1809
1972
  }
1810
1973
  // Transfer WHERE conditions to ORDER BY joins (GH #6160)
1811
1974
  this.transferConditionsForOrderByJoins(meta, originalCond, populatePaths);
1812
1975
  const { sql, params } = subSubQuery.compile();
1813
- this.select(this._fields).where({ [Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: raw(sql, params) } });
1976
+ this.select(this.#state.fields).where({
1977
+ [Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: raw(sql, params) },
1978
+ });
1814
1979
  }
1815
1980
  /**
1816
1981
  * Computes the set of populate paths from the _populate hints.
@@ -1827,7 +1992,7 @@ export class QueryBuilder {
1827
1992
  }
1828
1993
  }
1829
1994
  }
1830
- addPath(this._populate);
1995
+ addPath(this.#state.populate);
1831
1996
  return paths;
1832
1997
  }
1833
1998
  normalizeJoinPath(join, meta) {
@@ -1839,14 +2004,14 @@ export class QueryBuilder {
1839
2004
  * GH #6160
1840
2005
  */
1841
2006
  transferConditionsForOrderByJoins(meta, cond, populatePaths) {
1842
- if (!cond || this._orderBy.length === 0) {
2007
+ if (!cond || this.#state.orderBy.length === 0) {
1843
2008
  return;
1844
2009
  }
1845
- const orderByAliases = new Set(this._orderBy
2010
+ const orderByAliases = new Set(this.#state.orderBy
1846
2011
  .flatMap(hint => Object.keys(hint))
1847
2012
  .filter(k => !RawQueryFragment.isKnownFragmentSymbol(k))
1848
2013
  .map(k => k.split('.')[0]));
1849
- for (const join of Object.values(this._joins)) {
2014
+ for (const join of Object.values(this.#state.joins)) {
1850
2015
  const joinPath = this.normalizeJoinPath(join, meta);
1851
2016
  const isPopulateJoin = populatePaths.has(joinPath);
1852
2017
  // Only transfer conditions for joins used for ORDER BY but not for population
@@ -1859,10 +2024,8 @@ export class QueryBuilder {
1859
2024
  * Removes joins that are not used for population or ordering to improve performance.
1860
2025
  */
1861
2026
  pruneJoinsForPagination(meta, populatePaths) {
1862
- const orderByAliases = this._orderBy
1863
- .flatMap(hint => Object.keys(hint))
1864
- .map(k => k.split('.')[0]);
1865
- const joins = Object.entries(this._joins);
2027
+ const orderByAliases = this.#state.orderBy.flatMap(hint => Object.keys(hint)).map(k => k.split('.')[0]);
2028
+ const joins = Object.entries(this.#state.joins);
1866
2029
  const rootAlias = this.alias;
1867
2030
  function addParentAlias(alias) {
1868
2031
  const join = joins.find(j => j[1].alias === alias);
@@ -1877,7 +2040,7 @@ export class QueryBuilder {
1877
2040
  for (const [key, join] of joins) {
1878
2041
  const path = this.normalizeJoinPath(join, meta);
1879
2042
  if (!populatePaths.has(path) && !orderByAliases.includes(join.alias)) {
1880
- delete this._joins[key];
2043
+ delete this.#state.joins[key];
1881
2044
  }
1882
2045
  }
1883
2046
  }
@@ -1909,25 +2072,25 @@ export class QueryBuilder {
1909
2072
  }
1910
2073
  wrapModifySubQuery(meta) {
1911
2074
  const subQuery = this.clone();
1912
- subQuery.finalized = true;
2075
+ subQuery.#state.finalized = true;
1913
2076
  // wrap one more time to get around MySQL limitations
1914
2077
  // https://stackoverflow.com/questions/45494/mysql-error-1093-cant-specify-target-table-for-update-in-from-clause
1915
2078
  const subSubQuery = this.platform.createNativeQueryBuilder();
1916
- const method = this.flags.has(QueryFlag.UPDATE_SUB_QUERY) ? 'update' : 'delete';
2079
+ const method = this.#state.flags.has(QueryFlag.UPDATE_SUB_QUERY) ? 'update' : 'delete';
1917
2080
  const schema = this.getSchema(this.mainAlias);
1918
2081
  const pks = this.prepareFields(meta.primaryKeys, 'sub-query', schema);
1919
- this._cond = {}; // otherwise we would trigger validation error
1920
- this._joins = {}; // included in the subquery
2082
+ this.#state.cond = {}; // otherwise we would trigger validation error
2083
+ this.#state.joins = {}; // included in the subquery
1921
2084
  subSubQuery.select(pks).from(subQuery.as(this.mainAlias.aliasName));
1922
2085
  const { sql, params } = subSubQuery.compile();
1923
- this[method](this._data).where({
2086
+ this[method](this.#state.data).where({
1924
2087
  [Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: raw(sql, params) },
1925
2088
  });
1926
2089
  }
1927
2090
  getSchema(alias) {
1928
2091
  const { meta } = alias;
1929
2092
  const metaSchema = meta.schema && meta.schema !== '*' ? meta.schema : undefined;
1930
- const schema = this._schema ?? metaSchema ?? this.em?.schema ?? this.em?.config.getSchema(true);
2093
+ const schema = this.#state.schema ?? metaSchema ?? this.em?.schema ?? this.em?.config.getSchema(true);
1931
2094
  if (schema === this.platform.getDefaultSchemaName()) {
1932
2095
  return undefined;
1933
2096
  }
@@ -1937,35 +2100,51 @@ export class QueryBuilder {
1937
2100
  createAlias(entityName, aliasName, subQuery) {
1938
2101
  const meta = this.metadata.find(entityName);
1939
2102
  const alias = { aliasName, entityName, meta, subQuery };
1940
- this._aliases[aliasName] = alias;
2103
+ this.#state.aliases[aliasName] = alias;
1941
2104
  return alias;
1942
2105
  }
1943
2106
  createMainAlias(entityName, aliasName, subQuery) {
1944
- this._mainAlias = this.createAlias(entityName, aliasName, subQuery);
1945
- this._helper = this.createQueryBuilderHelper();
1946
- return this._mainAlias;
2107
+ this.#state.mainAlias = this.createAlias(entityName, aliasName, subQuery);
2108
+ this.#helper = this.createQueryBuilderHelper();
2109
+ return this.#state.mainAlias;
1947
2110
  }
1948
2111
  fromSubQuery(target, aliasName) {
1949
- const subQuery = target.getNativeQuery();
1950
2112
  const { entityName } = target.mainAlias;
1951
2113
  aliasName ??= this.getNextAlias(entityName);
2114
+ const subQuery = target.#state.unionQuery ? target.toRaw() : target.getNativeQuery();
1952
2115
  this.createMainAlias(entityName, aliasName, subQuery);
1953
2116
  }
1954
2117
  fromEntityName(entityName, aliasName) {
1955
- aliasName ??= this._mainAlias?.aliasName ?? this.getNextAlias(entityName);
2118
+ aliasName ??= this.#state.mainAlias?.aliasName ?? this.getNextAlias(entityName);
1956
2119
  this.createMainAlias(entityName, aliasName);
1957
2120
  }
2121
+ fromRawTable(tableName, aliasName) {
2122
+ aliasName ??= this.#state.mainAlias?.aliasName ?? this.getNextAlias(tableName);
2123
+ const meta = new EntityMetadata({
2124
+ className: tableName,
2125
+ collection: tableName,
2126
+ });
2127
+ meta.root = meta;
2128
+ this.#state.mainAlias = {
2129
+ aliasName,
2130
+ entityName: tableName,
2131
+ meta,
2132
+ rawTableName: tableName,
2133
+ };
2134
+ this.#state.aliases[aliasName] = this.#state.mainAlias;
2135
+ this.#helper = this.createQueryBuilderHelper();
2136
+ }
1958
2137
  createQueryBuilderHelper() {
1959
- return new QueryBuilderHelper(this.mainAlias.entityName, this.mainAlias.aliasName, this._aliases, this.subQueries, this.driver, this._tptAlias);
2138
+ return new QueryBuilderHelper(this.mainAlias.entityName, this.mainAlias.aliasName, this.#state.aliases, this.#state.subQueries, this.driver, this.#state.tptAlias);
1960
2139
  }
1961
2140
  ensureFromClause() {
1962
2141
  /* v8 ignore next */
1963
- if (!this._mainAlias) {
2142
+ if (!this.#state.mainAlias) {
1964
2143
  throw new Error(`Cannot proceed to build a query because the main alias is not set.`);
1965
2144
  }
1966
2145
  }
1967
2146
  ensureNotFinalized() {
1968
- if (this.finalized) {
2147
+ if (this.#state.finalized) {
1969
2148
  throw new Error('This QueryBuilder instance is already finalized, clone it first if you want to modify it.');
1970
2149
  }
1971
2150
  }
@@ -1974,28 +2153,35 @@ export class QueryBuilder {
1974
2153
  [Symbol.for('nodejs.util.inspect.custom')](depth = 2) {
1975
2154
  const object = { ...this };
1976
2155
  const hidden = ['metadata', 'driver', 'context', 'platform', 'type'];
1977
- Object.keys(object).filter(k => k.startsWith('_')).forEach(k => delete object[k]);
1978
- Object.keys(object).filter(k => object[k] == null).forEach(k => delete object[k]);
2156
+ Object.keys(object)
2157
+ .filter(k => k.startsWith('_'))
2158
+ .forEach(k => delete object[k]);
2159
+ Object.keys(object)
2160
+ .filter(k => object[k] == null)
2161
+ .forEach(k => delete object[k]);
1979
2162
  hidden.forEach(k => delete object[k]);
1980
2163
  let prefix = this.type ? this.type.substring(0, 1) + this.type.toLowerCase().substring(1) : '';
1981
- if (this._data) {
1982
- object.data = this._data;
2164
+ if (this.#state.data) {
2165
+ object.data = this.#state.data;
1983
2166
  }
1984
- if (this._schema) {
1985
- object.schema = this._schema;
2167
+ if (this.#state.schema) {
2168
+ object.schema = this.#state.schema;
1986
2169
  }
1987
- if (!Utils.isEmpty(this._cond)) {
1988
- object.where = this._cond;
2170
+ if (!Utils.isEmpty(this.#state.cond)) {
2171
+ object.where = this.#state.cond;
1989
2172
  }
1990
- if (this._onConflict?.[0]) {
2173
+ if (this.#state.onConflict?.[0]) {
1991
2174
  prefix = 'Upsert';
1992
- object.onConflict = this._onConflict[0];
2175
+ object.onConflict = this.#state.onConflict[0];
1993
2176
  }
1994
- if (!Utils.isEmpty(this._orderBy)) {
1995
- object.orderBy = this._orderBy;
2177
+ if (!Utils.isEmpty(this.#state.orderBy)) {
2178
+ object.orderBy = this.#state.orderBy;
1996
2179
  }
1997
- const name = this._mainAlias ? `${prefix}QueryBuilder<${Utils.className(this._mainAlias?.entityName)}>` : 'QueryBuilder';
2180
+ const name = this.#state.mainAlias
2181
+ ? `${prefix}QueryBuilder<${Utils.className(this.#state.mainAlias?.entityName)}>`
2182
+ : 'QueryBuilder';
1998
2183
  const ret = inspect(object, { depth });
1999
2184
  return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
2000
2185
  }
2001
2186
  }
2187
+ _a = QueryBuilder;