@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,6 +1,17 @@
1
1
  import { type Dictionary, LockMode, type QueryFlag, RawQueryFragment, type Subquery } from '@mikro-orm/core';
2
2
  import { QueryType } from './enums.js';
3
3
  import type { AbstractSqlPlatform } from '../AbstractSqlPlatform.js';
4
+ export interface CteOptions {
5
+ columns?: string[];
6
+ /** PostgreSQL: MATERIALIZED / NOT MATERIALIZED */
7
+ materialized?: boolean;
8
+ }
9
+ interface CteClause extends CteOptions {
10
+ name: string;
11
+ sql: string;
12
+ params: unknown[];
13
+ recursive?: boolean;
14
+ }
4
15
  interface Options {
5
16
  tableName?: string | RawQueryFragment;
6
17
  indexHint?: string;
@@ -27,13 +38,14 @@ interface Options {
27
38
  onConflict?: OnConflictClause;
28
39
  lockMode?: LockMode;
29
40
  lockTables?: string[];
30
- returning?: (string | RawQueryFragment)[];
41
+ returning?: (string | RawQueryFragment | [name: string, type: unknown])[];
31
42
  comment?: string[];
32
43
  hintComment?: string[];
33
44
  flags?: Set<QueryFlag>;
34
45
  wrap?: [prefix: string, suffix: string];
46
+ ctes?: CteClause[];
35
47
  }
36
- interface TableOptions {
48
+ export interface TableOptions {
37
49
  schema?: string;
38
50
  indexHint?: string;
39
51
  alias?: string;
@@ -65,6 +77,17 @@ export declare class NativeQueryBuilder implements Subquery {
65
77
  groupBy(groupBy: (string | RawQueryFragment)[]): this;
66
78
  join(sql: string, params: unknown[]): this;
67
79
  orderBy(orderBy: string): this;
80
+ /**
81
+ * The sub-query is compiled eagerly at call time — later mutations to the
82
+ * sub-query builder will not be reflected in this CTE.
83
+ */
84
+ with(name: string, query: NativeQueryBuilder | RawQueryFragment, options?: CteOptions): this;
85
+ /**
86
+ * Adds a recursive CTE (`WITH RECURSIVE` on PostgreSQL/MySQL/SQLite, plain `WITH` on MSSQL).
87
+ * The sub-query is compiled eagerly — later mutations will not be reflected.
88
+ */
89
+ withRecursive(name: string, query: NativeQueryBuilder | RawQueryFragment, options?: CteOptions): this;
90
+ private addCte;
68
91
  toString(): string;
69
92
  compile(): {
70
93
  sql: string;
@@ -85,7 +108,7 @@ export declare class NativeQueryBuilder implements Subquery {
85
108
  distinct(): this;
86
109
  distinctOn(fields: string[]): this;
87
110
  onConflict(options: OnConflictClause): OnConflictClause;
88
- returning(fields: (string | RawQueryFragment)[]): this;
111
+ returning(fields: (string | RawQueryFragment | [name: string, type: unknown])[]): this;
89
112
  lockMode(lockMode: LockMode, lockTables?: string[]): this;
90
113
  comment(comment: string | string[]): this;
91
114
  hintComment(comment: string | string[]): this;
@@ -103,6 +126,8 @@ export declare class NativeQueryBuilder implements Subquery {
103
126
  protected compileDelete(): void;
104
127
  protected compileTruncate(): void;
105
128
  protected addHintComment(): void;
129
+ protected compileCtes(): void;
130
+ protected getCteKeyword(hasRecursive: boolean): string;
106
131
  protected getTableName(): string;
107
132
  protected quote(id: string | RawQueryFragment | NativeQueryBuilder): string;
108
133
  }
@@ -1,4 +1,4 @@
1
- import { LockMode, raw, RawQueryFragment, Utils } from '@mikro-orm/core';
1
+ import { LockMode, raw, RawQueryFragment, Utils, } from '@mikro-orm/core';
2
2
  import { QueryType } from './enums.js';
3
3
  /** @internal */
4
4
  export class NativeQueryBuilder {
@@ -30,7 +30,8 @@ export class NativeQueryBuilder {
30
30
  tableName = tableName.toRaw();
31
31
  }
32
32
  if (typeof tableName === 'string') {
33
- const alias = options?.alias ? ` as ${this.platform.quoteIdentifier(options.alias)}` : '';
33
+ const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
34
+ const alias = options?.alias ? `${asKeyword}${this.platform.quoteIdentifier(options.alias)}` : '';
34
35
  const schema = options?.schema && options.schema !== this.platform.getDefaultSchemaName() ? `${options.schema}.` : '';
35
36
  tableName = this.quote(schema + tableName) + alias;
36
37
  }
@@ -59,6 +60,36 @@ export class NativeQueryBuilder {
59
60
  this.options.orderBy = orderBy;
60
61
  return this;
61
62
  }
63
+ /**
64
+ * The sub-query is compiled eagerly at call time — later mutations to the
65
+ * sub-query builder will not be reflected in this CTE.
66
+ */
67
+ with(name, query, options) {
68
+ return this.addCte(name, query, options);
69
+ }
70
+ /**
71
+ * Adds a recursive CTE (`WITH RECURSIVE` on PostgreSQL/MySQL/SQLite, plain `WITH` on MSSQL).
72
+ * The sub-query is compiled eagerly — later mutations will not be reflected.
73
+ */
74
+ withRecursive(name, query, options) {
75
+ return this.addCte(name, query, options, true);
76
+ }
77
+ addCte(name, query, options, recursive) {
78
+ this.options.ctes ??= [];
79
+ if (this.options.ctes.some(cte => cte.name === name)) {
80
+ throw new Error(`CTE with name '${name}' already exists`);
81
+ }
82
+ const { sql, params } = query instanceof NativeQueryBuilder ? query.compile() : { sql: query.sql, params: [...query.params] };
83
+ this.options.ctes.push({
84
+ name,
85
+ sql,
86
+ params,
87
+ recursive,
88
+ columns: options?.columns,
89
+ materialized: options?.materialized,
90
+ });
91
+ return this;
92
+ }
62
93
  toString() {
63
94
  const { sql, params } = this.compile();
64
95
  return this.platform.formatQuery(sql, params);
@@ -72,6 +103,7 @@ export class NativeQueryBuilder {
72
103
  if (this.options.comment) {
73
104
  this.parts.push(...this.options.comment.map(comment => `/* ${comment} */`));
74
105
  }
106
+ this.compileCtes();
75
107
  switch (this.type) {
76
108
  case QueryType.SELECT:
77
109
  case QueryType.COUNT:
@@ -387,6 +419,35 @@ export class NativeQueryBuilder {
387
419
  this.parts.push(`/*+ ${this.options.hintComment.join(' ')} */`);
388
420
  }
389
421
  }
422
+ compileCtes() {
423
+ const ctes = this.options.ctes;
424
+ if (!ctes || ctes.length === 0) {
425
+ return;
426
+ }
427
+ const hasRecursive = ctes.some(cte => cte.recursive);
428
+ const keyword = this.getCteKeyword(hasRecursive);
429
+ const cteParts = [];
430
+ for (const cte of ctes) {
431
+ let part = this.quote(cte.name);
432
+ if (cte.columns?.length) {
433
+ part += ` (${cte.columns.map(c => this.quote(c)).join(', ')})`;
434
+ }
435
+ part += ' as';
436
+ if (cte.materialized === true) {
437
+ part += ' materialized';
438
+ }
439
+ else if (cte.materialized === false) {
440
+ part += ' not materialized';
441
+ }
442
+ part += ` (${cte.sql})`;
443
+ this.params.push(...cte.params);
444
+ cteParts.push(part);
445
+ }
446
+ this.parts.push(`${keyword} ${cteParts.join(', ')}`);
447
+ }
448
+ getCteKeyword(hasRecursive) {
449
+ return hasRecursive ? 'with recursive' : 'with';
450
+ }
390
451
  getTableName() {
391
452
  if (!this.options.tableName) {
392
453
  throw new Error('No table name provided');
@@ -414,7 +475,8 @@ export class NativeQueryBuilder {
414
475
  const parts = id.split(/ as /i);
415
476
  const a = this.platform.quoteIdentifier(parts[0]);
416
477
  const b = this.platform.quoteIdentifier(parts[1]);
417
- return `${a} as ${b}`;
478
+ const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
479
+ return `${a}${asKeyword}${b}`;
418
480
  }
419
481
  if (id === '*') {
420
482
  return id;
@@ -7,7 +7,8 @@ const COLLECTION_OPERATORS = ['$some', '$none', '$every', '$size'];
7
7
  */
8
8
  export class ObjectCriteriaNode extends CriteriaNode {
9
9
  process(qb, options) {
10
- const matchPopulateJoins = options?.matchPopulateJoins || (this.prop && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(this.prop.kind));
10
+ const matchPopulateJoins = options?.matchPopulateJoins ||
11
+ (this.prop && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(this.prop.kind));
11
12
  const nestedAlias = qb.getAliasForJoinPath(this.getPath(options), { ...options, matchPopulateJoins });
12
13
  const ownerAlias = options?.alias || qb.alias;
13
14
  const keys = Utils.getObjectQueryKeys(this.payload);
@@ -20,13 +21,15 @@ export class ObjectCriteriaNode extends CriteriaNode {
20
21
  if (![ReferenceKind.MANY_TO_MANY, ReferenceKind.ONE_TO_MANY].includes(this.prop.kind)) {
21
22
  // ignore collection operators when used on a non-relational property - this can happen when they get into
22
23
  // populateWhere via `infer` on m:n properties with select-in strategy
23
- if (this.parent?.parent) { // we validate only usage on top level
24
+ if (this.parent?.parent) {
25
+ // we validate only usage on top level
24
26
  return {};
25
27
  }
26
28
  throw new Error(`Collection operators can be used only inside a collection property context, but it was used for ${this.getPath()}.`);
27
29
  }
28
30
  const $and = [];
29
- const knownKey = [ReferenceKind.SCALAR, ReferenceKind.MANY_TO_ONE, ReferenceKind.EMBEDDED].includes(this.prop.kind) || (this.prop.kind === ReferenceKind.ONE_TO_ONE && this.prop.owner);
31
+ const knownKey = [ReferenceKind.SCALAR, ReferenceKind.MANY_TO_ONE, ReferenceKind.EMBEDDED].includes(this.prop.kind) ||
32
+ (this.prop.kind === ReferenceKind.ONE_TO_ONE && this.prop.owner);
30
33
  const parentMeta = this.metadata.find(this.parent.entityName);
31
34
  const primaryKeys = parentMeta.primaryKeys.map(pk => {
32
35
  return [QueryType.SELECT, QueryType.COUNT].includes(qb.type) ? `${knownKey ? alias : ownerAlias}.${pk}` : pk;
@@ -36,7 +39,7 @@ export class ObjectCriteriaNode extends CriteriaNode {
36
39
  throw new Error('Mixing collection operators with other filters is not allowed.');
37
40
  }
38
41
  const payload = this.payload[key].unwrap();
39
- const qb2 = qb.clone(true, ['_schema']);
42
+ const qb2 = qb.clone(true, ['schema']);
40
43
  const joinAlias = qb2.getNextAlias(this.prop.targetMeta.class);
41
44
  const sub = qb2
42
45
  .from(parentMeta.class)
@@ -48,7 +51,9 @@ export class ObjectCriteriaNode extends CriteriaNode {
48
51
  const pks = this.prop.referencedColumnNames;
49
52
  const countExpr = raw(`count(${pks.map(() => '??').join(', ')})`, pks.map(pk => `${joinAlias}.${pk}`));
50
53
  sub.groupBy(parentMeta.primaryKeys);
51
- sub.having({ $and: Object.keys(sizeCondition).map(op => ({ [countExpr]: { [op]: sizeCondition[op] } })) });
54
+ sub.having({
55
+ $and: Object.keys(sizeCondition).map(op => ({ [countExpr]: { [op]: sizeCondition[op] } })),
56
+ });
52
57
  }
53
58
  else if (key === '$every') {
54
59
  sub.where({ $not: { [this.key]: payload } });
@@ -111,7 +116,11 @@ export class ObjectCriteriaNode extends CriteriaNode {
111
116
  // use '??' placeholder to properly quote the identifier
112
117
  o[raw('??', [field])] = payload;
113
118
  }
114
- else if (primaryKey || virtual || operator || field.includes('.') || ![QueryType.SELECT, QueryType.COUNT].includes(qb.type)) {
119
+ else if (primaryKey ||
120
+ virtual ||
121
+ operator ||
122
+ field.includes('.') ||
123
+ ![QueryType.SELECT, QueryType.COUNT].includes(qb.type)) {
115
124
  this.inlineCondition(field.replaceAll(ALIAS_REPLACEMENT, alias), o, payload);
116
125
  }
117
126
  else {
@@ -121,9 +130,10 @@ export class ObjectCriteriaNode extends CriteriaNode {
121
130
  }, {});
122
131
  }
123
132
  isStrict() {
124
- return this.strict || Utils.getObjectQueryKeys(this.payload).some(key => {
125
- return this.payload[key].isStrict();
126
- });
133
+ return (this.strict ||
134
+ Utils.getObjectQueryKeys(this.payload).some(key => {
135
+ return this.payload[key].isStrict();
136
+ }));
127
137
  }
128
138
  unwrap() {
129
139
  return Utils.getObjectQueryKeys(this.payload).reduce((o, field) => {
@@ -148,8 +158,18 @@ export class ObjectCriteriaNode extends CriteriaNode {
148
158
  }
149
159
  shouldInline(payload) {
150
160
  const rawField = RawQueryFragment.isKnownFragmentSymbol(this.key);
151
- const scalar = Utils.isPrimaryKey(payload) || payload instanceof RegExp || payload instanceof Date || rawField;
152
- const operator = Utils.isObject(payload) && Utils.getObjectQueryKeys(payload).every(k => Utils.isOperator(k, false));
161
+ const scalar = Utils.isPrimaryKey(payload) ||
162
+ payload instanceof RegExp ||
163
+ payload instanceof Date ||
164
+ rawField;
165
+ const operator = Utils.isObject(payload) &&
166
+ Utils.getObjectQueryKeys(payload).every(k => {
167
+ if (k === '$not' && Utils.isPlainObject(payload[k])) {
168
+ // $not wrapping non-operator conditions (entity props) should be inlined
169
+ return Utils.getObjectQueryKeys(payload[k]).every(ik => Utils.isOperator(ik, false));
170
+ }
171
+ return Utils.isOperator(k, false);
172
+ });
153
173
  return !!this.prop && this.prop.kind !== ReferenceKind.SCALAR && !scalar && !operator;
154
174
  }
155
175
  getChildKey(k, prop, childAlias, alias) {
@@ -161,7 +181,9 @@ export class ObjectCriteriaNode extends CriteriaNode {
161
181
  inlineArrayChildPayload(obj, payload, k, prop, childAlias, alias) {
162
182
  const key = this.getChildKey(k, prop, childAlias);
163
183
  const value = payload.map((child) => Utils.getObjectQueryKeys(child).reduce((inner, childKey) => {
164
- const key = (RawQueryFragment.isKnownFragmentSymbol(childKey) || this.isPrefixed(childKey) || Utils.isOperator(childKey)) ? childKey : this.aliased(childKey, childAlias);
184
+ const key = RawQueryFragment.isKnownFragmentSymbol(childKey) || this.isPrefixed(childKey) || Utils.isOperator(childKey)
185
+ ? childKey
186
+ : this.aliased(childKey, childAlias);
165
187
  inner[key] = child[childKey];
166
188
  return inner;
167
189
  }, {}));
@@ -173,6 +195,12 @@ export class ObjectCriteriaNode extends CriteriaNode {
173
195
  if (RawQueryFragment.isKnownFragmentSymbol(k)) {
174
196
  o[k] = payload[k];
175
197
  }
198
+ else if (k === '$not' &&
199
+ Utils.isPlainObject(payload[k]) &&
200
+ Utils.getObjectQueryKeys(payload[k]).some(ik => !Utils.isOperator(ik, false))) {
201
+ // $not wraps entity conditions (from auto-join), inline at current level
202
+ this.inlineCondition(k, o, payload[k]);
203
+ }
176
204
  else if (Utils.isOperator(k, false)) {
177
205
  const tmp = payload[k];
178
206
  delete payload[k];
@@ -218,24 +246,42 @@ export class ObjectCriteriaNode extends CriteriaNode {
218
246
  }
219
247
  const meta = this.metadata.find(this.entityName);
220
248
  const embeddable = this.prop.kind === ReferenceKind.EMBEDDED;
221
- const knownKey = [ReferenceKind.SCALAR, ReferenceKind.MANY_TO_ONE, ReferenceKind.EMBEDDED].includes(this.prop.kind) || (this.prop.kind === ReferenceKind.ONE_TO_ONE && this.prop.owner);
222
- const operatorKeys = knownKey && keys.every(key => Utils.isOperator(key, false));
223
- const primaryKeys = knownKey && keys.every(key => {
224
- if (typeof key !== 'string' || !meta.primaryKeys.includes(key)) {
225
- return false;
226
- }
227
- if (!Utils.isPlainObject(this.payload[key].payload) || ![ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(meta.properties[key].kind)) {
228
- return true;
229
- }
230
- return Utils.getObjectQueryKeys(this.payload[key].payload).every(k => typeof k === 'string' && meta.properties[key].targetMeta.primaryKeys.includes(k));
231
- });
249
+ const knownKey = [ReferenceKind.SCALAR, ReferenceKind.MANY_TO_ONE, ReferenceKind.EMBEDDED].includes(this.prop.kind) ||
250
+ (this.prop.kind === ReferenceKind.ONE_TO_ONE && this.prop.owner);
251
+ const operatorKeys = knownKey &&
252
+ keys.every(key => {
253
+ if (key === '$not') {
254
+ // $not wraps conditions like $and/$or, check if it wraps entity property conditions (needs auto-join)
255
+ // vs simple operator conditions on the FK (doesn't need auto-join)
256
+ const childPayload = this.payload[key].payload;
257
+ if (Utils.isPlainObject(childPayload)) {
258
+ return Utils.getObjectQueryKeys(childPayload).every(k => Utils.isOperator(k, false));
259
+ }
260
+ }
261
+ return Utils.isOperator(key, false);
262
+ });
263
+ const primaryKeys = knownKey &&
264
+ keys.every(key => {
265
+ if (typeof key !== 'string' || !meta.primaryKeys.includes(key)) {
266
+ return false;
267
+ }
268
+ if (!Utils.isPlainObject(this.payload[key].payload) ||
269
+ ![ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(meta.properties[key].kind)) {
270
+ return true;
271
+ }
272
+ return Utils.getObjectQueryKeys(this.payload[key].payload).every(k => typeof k === 'string' && meta.properties[key].targetMeta.primaryKeys.includes(k));
273
+ });
232
274
  return !primaryKeys && !nestedAlias && !operatorKeys && !embeddable;
233
275
  }
234
276
  autoJoin(qb, alias, options) {
235
277
  const nestedAlias = qb.getNextAlias(this.prop?.pivotEntity ?? this.entityName);
236
278
  const rawField = RawQueryFragment.isKnownFragmentSymbol(this.key);
237
- const scalar = Utils.isPrimaryKey(this.payload) || this.payload instanceof RegExp || this.payload instanceof Date || rawField;
238
- const operator = Utils.isPlainObject(this.payload) && Utils.getObjectQueryKeys(this.payload).every(k => Utils.isOperator(k, false));
279
+ const scalar = Utils.isPrimaryKey(this.payload) ||
280
+ this.payload instanceof RegExp ||
281
+ this.payload instanceof Date ||
282
+ rawField;
283
+ const operator = Utils.isPlainObject(this.payload) &&
284
+ Utils.getObjectQueryKeys(this.payload).every(k => Utils.isOperator(k, false));
239
285
  const field = `${alias}.${this.prop.name}`;
240
286
  const method = qb.hasFlag(QueryFlag.INFER_POPULATE) ? 'joinAndSelect' : 'join';
241
287
  const path = this.getPath();
@@ -243,14 +289,12 @@ export class ObjectCriteriaNode extends CriteriaNode {
243
289
  qb.join(field, nestedAlias, undefined, JoinType.pivotJoin, path);
244
290
  }
245
291
  else {
246
- const prev = qb._fields?.slice();
292
+ const prev = qb.state.fields?.slice();
247
293
  const toOneProperty = [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(this.prop.kind);
248
- const joinType = toOneProperty && !this.prop.nullable
249
- ? JoinType.innerJoin
250
- : JoinType.leftJoin;
294
+ const joinType = toOneProperty && !this.prop.nullable ? JoinType.innerJoin : JoinType.leftJoin;
251
295
  qb[method](field, nestedAlias, undefined, joinType, path);
252
296
  if (!qb.hasFlag(QueryFlag.INFER_POPULATE)) {
253
- qb._fields = prev;
297
+ qb.state.fields = prev;
254
298
  }
255
299
  }
256
300
  if (options?.type !== 'orderBy') {
@@ -259,6 +303,6 @@ export class ObjectCriteriaNode extends CriteriaNode {
259
303
  return nestedAlias;
260
304
  }
261
305
  isPrefixed(field) {
262
- return !!field.match(/\w+\./);
306
+ return !!/\w+\./.exec(field);
263
307
  }
264
308
  }