@mikro-orm/knex 6.0.0-dev.4 → 6.0.0-dev.41

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 (56) hide show
  1. package/{dist/AbstractSqlConnection.js → AbstractSqlConnection.js} +6 -1
  2. package/AbstractSqlDriver.d.ts +66 -0
  3. package/{dist/AbstractSqlDriver.js → AbstractSqlDriver.js} +277 -95
  4. package/{dist/AbstractSqlPlatform.d.ts → AbstractSqlPlatform.d.ts} +7 -7
  5. package/{dist/AbstractSqlPlatform.js → AbstractSqlPlatform.js} +12 -14
  6. package/{dist/README.md → README.md} +2 -2
  7. package/{dist/SqlEntityManager.d.ts → SqlEntityManager.d.ts} +5 -5
  8. package/{dist/SqlEntityManager.js → SqlEntityManager.js} +1 -2
  9. package/{dist/SqlEntityRepository.d.ts → SqlEntityRepository.d.ts} +3 -4
  10. package/{dist/SqlEntityRepository.js → SqlEntityRepository.js} +1 -2
  11. package/{dist/index.d.ts → index.d.ts} +1 -0
  12. package/{dist/index.js → index.js} +6 -1
  13. package/index.mjs +194 -0
  14. package/package.json +18 -47
  15. package/query/ArrayCriteriaNode.d.ts +9 -0
  16. package/{dist/query → query}/CriteriaNode.d.ts +8 -8
  17. package/{dist/query → query}/CriteriaNode.js +15 -12
  18. package/query/CriteriaNodeFactory.d.ts +12 -0
  19. package/{dist/query → query}/CriteriaNodeFactory.js +10 -10
  20. package/{dist/query → query}/ObjectCriteriaNode.d.ts +3 -3
  21. package/{dist/query → query}/ObjectCriteriaNode.js +19 -6
  22. package/{dist/query → query}/QueryBuilder.d.ts +66 -24
  23. package/{dist/query → query}/QueryBuilder.js +381 -94
  24. package/{dist/query → query}/QueryBuilderHelper.d.ts +19 -11
  25. package/{dist/query → query}/QueryBuilderHelper.js +227 -116
  26. package/{dist/query → query}/ScalarCriteriaNode.d.ts +2 -2
  27. package/{dist/query → query}/ScalarCriteriaNode.js +6 -6
  28. package/{dist/query → query}/index.js +5 -1
  29. package/{dist/schema → schema}/DatabaseSchema.d.ts +1 -1
  30. package/{dist/schema → schema}/DatabaseSchema.js +11 -19
  31. package/{dist/schema → schema}/DatabaseTable.d.ts +9 -9
  32. package/{dist/schema → schema}/DatabaseTable.js +22 -22
  33. package/{dist/schema → schema}/SchemaComparator.d.ts +7 -5
  34. package/{dist/schema → schema}/SchemaComparator.js +60 -10
  35. package/{dist/schema → schema}/SchemaHelper.d.ts +15 -10
  36. package/{dist/schema → schema}/SchemaHelper.js +46 -8
  37. package/{dist/schema/SchemaGenerator.d.ts → schema/SqlSchemaGenerator.d.ts} +10 -12
  38. package/{dist/schema/SchemaGenerator.js → schema/SqlSchemaGenerator.js} +89 -45
  39. package/{dist/schema → schema}/index.d.ts +1 -1
  40. package/{dist/schema → schema}/index.js +6 -2
  41. package/{dist/typings.d.ts → typings.d.ts} +21 -16
  42. package/CHANGELOG.md +0 -661
  43. package/dist/AbstractSqlDriver.d.ts +0 -55
  44. package/dist/LICENSE +0 -21
  45. package/dist/index.mjs +0 -26
  46. package/dist/package.json +0 -99
  47. package/dist/query/ArrayCriteriaNode.d.ts +0 -9
  48. package/dist/query/CriteriaNodeFactory.d.ts +0 -12
  49. /package/{dist/AbstractSqlConnection.d.ts → AbstractSqlConnection.d.ts} +0 -0
  50. /package/{dist/MonkeyPatchable.d.ts → MonkeyPatchable.d.ts} +0 -0
  51. /package/{dist/MonkeyPatchable.js → MonkeyPatchable.js} +0 -0
  52. /package/{dist/query → query}/ArrayCriteriaNode.js +0 -0
  53. /package/{dist/query → query}/enums.d.ts +0 -0
  54. /package/{dist/query → query}/enums.js +0 -0
  55. /package/{dist/query → query}/index.d.ts +0 -0
  56. /package/{dist/typings.js → typings.js} +0 -0
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.QueryBuilder = void 0;
4
+ const util_1 = require("util");
4
5
  const core_1 = require("@mikro-orm/core");
5
6
  const enums_1 = require("./enums");
6
7
  const QueryBuilderHelper_1 = require("./QueryBuilderHelper");
@@ -25,11 +26,21 @@ const CriteriaNodeFactory_1 = require("./CriteriaNodeFactory");
25
26
  * ```
26
27
  */
27
28
  class QueryBuilder {
29
+ get mainAlias() {
30
+ this.ensureFromClause();
31
+ return this._mainAlias;
32
+ }
33
+ get alias() {
34
+ return this.mainAlias.aliasName;
35
+ }
36
+ get helper() {
37
+ this.ensureFromClause();
38
+ return this._helper;
39
+ }
28
40
  /**
29
41
  * @internal
30
42
  */
31
43
  constructor(entityName, metadata, driver, context, alias, connectionType, em) {
32
- this.entityName = entityName;
33
44
  this.metadata = metadata;
34
45
  this.driver = driver;
35
46
  this.context = context;
@@ -43,23 +54,25 @@ class QueryBuilder {
43
54
  this.flags = new Set([core_1.QueryFlag.CONVERT_CUSTOM_TYPES]);
44
55
  this.finalized = false;
45
56
  this._joins = {};
46
- this._aliasMap = {};
57
+ this._explicitAlias = false;
47
58
  this._cond = {};
48
59
  this._orderBy = [];
49
60
  this._groupBy = [];
50
61
  this._having = {};
51
62
  this._joinedProps = new Map();
52
63
  this.subQueries = {};
64
+ this._aliases = {};
53
65
  this.platform = this.driver.getPlatform();
54
66
  this.knex = this.driver.getConnection(this.connectionType).getKnex();
55
67
  if (alias) {
56
68
  this.aliasCounter++;
69
+ this._explicitAlias = true;
57
70
  }
58
- this.alias = alias ?? this.getNextAlias(this.entityName);
59
- this._aliasMap[this.alias] = this.entityName;
60
- this.helper = new QueryBuilderHelper_1.QueryBuilderHelper(this.entityName, this.alias, this._aliasMap, this.subQueries, this.metadata, this.knex, this.platform);
71
+ // @ts-expect-error union type does not match the overloaded method signature
72
+ this.from(entityName, alias);
61
73
  }
62
74
  select(fields, distinct = false) {
75
+ this.ensureNotFinalized();
63
76
  this._fields = core_1.Utils.asArray(fields);
64
77
  if (distinct) {
65
78
  this.flags.add(core_1.QueryFlag.DISTINCT);
@@ -67,11 +80,22 @@ class QueryBuilder {
67
80
  return this.init(enums_1.QueryType.SELECT);
68
81
  }
69
82
  addSelect(fields) {
83
+ this.ensureNotFinalized();
70
84
  if (this.type && this.type !== enums_1.QueryType.SELECT) {
71
85
  return this;
72
86
  }
73
87
  return this.select([...core_1.Utils.asArray(this._fields), ...core_1.Utils.asArray(fields)]);
74
88
  }
89
+ distinct() {
90
+ this.ensureNotFinalized();
91
+ return this.setFlag(core_1.QueryFlag.DISTINCT);
92
+ }
93
+ /** postgres only */
94
+ distinctOn(fields) {
95
+ this.ensureNotFinalized();
96
+ this._distinctOn = core_1.Utils.asArray(fields);
97
+ return this;
98
+ }
75
99
  insert(data) {
76
100
  return this.init(enums_1.QueryType.INSERT, data);
77
101
  }
@@ -85,7 +109,15 @@ class QueryBuilder {
85
109
  return this.init(enums_1.QueryType.TRUNCATE);
86
110
  }
87
111
  count(field, distinct = false) {
88
- this._fields = [...(field ? core_1.Utils.asArray(field) : this.metadata.find(this.entityName).primaryKeys)];
112
+ if (field) {
113
+ this._fields = core_1.Utils.asArray(field);
114
+ }
115
+ else if (this.hasToManyJoins()) {
116
+ this._fields = this.mainAlias.metadata.primaryKeys;
117
+ }
118
+ else {
119
+ this._fields = [this.raw('*')];
120
+ }
89
121
  if (distinct) {
90
122
  this.flags.add(core_1.QueryFlag.DISTINCT);
91
123
  }
@@ -99,6 +131,9 @@ class QueryBuilder {
99
131
  return this.join(field, alias, cond, 'leftJoin');
100
132
  }
101
133
  joinAndSelect(field, alias, cond = {}, type = 'innerJoin', path) {
134
+ if (!this.type) {
135
+ this.select('*');
136
+ }
102
137
  const prop = this.joinReference(field, alias, cond, type, path);
103
138
  this.addSelect(this.getFieldsForJoinedLoad(prop, alias));
104
139
  const [fromAlias] = this.helper.splitField(field);
@@ -124,24 +159,34 @@ class QueryBuilder {
124
159
  return fields;
125
160
  }
126
161
  withSubQuery(subQuery, alias) {
162
+ this.ensureNotFinalized();
127
163
  this.subQueries[alias] = subQuery.toString();
128
164
  return this;
129
165
  }
130
166
  where(cond, params, operator) {
167
+ this.ensureNotFinalized();
131
168
  if (core_1.Utils.isString(cond)) {
132
169
  cond = { [`(${cond})`]: core_1.Utils.asArray(params) };
133
170
  operator = operator || '$and';
134
171
  }
135
172
  else {
136
- cond = core_1.QueryHelper.processWhere(cond, this.entityName, this.metadata, this.platform, this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES));
173
+ cond = core_1.QueryHelper.processWhere({
174
+ where: cond,
175
+ entityName: this.mainAlias.entityName,
176
+ metadata: this.metadata,
177
+ platform: this.platform,
178
+ aliasMap: this.getAliasMap(),
179
+ aliased: !this.type || [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
180
+ convertCustomTypes: this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES),
181
+ });
137
182
  }
138
183
  const op = operator || params;
139
184
  const topLevel = !op || !core_1.Utils.hasObjectKeys(this._cond);
140
- const criteriaNode = CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.entityName, cond);
185
+ const criteriaNode = CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond);
141
186
  if ([enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE].includes(this.type) && criteriaNode.willAutoJoin(this)) {
142
187
  // use sub-query to support joining
143
188
  this.setFlag(this.type === enums_1.QueryType.UPDATE ? core_1.QueryFlag.UPDATE_SUB_QUERY : core_1.QueryFlag.DELETE_SUB_QUERY);
144
- this.select(this.metadata.find(this.entityName).primaryKeys, true);
189
+ this.select(this.mainAlias.metadata.primaryKeys, true);
145
190
  }
146
191
  if (topLevel) {
147
192
  this._cond = criteriaNode.process(this);
@@ -166,27 +211,39 @@ class QueryBuilder {
166
211
  return this.where(cond, params, '$or');
167
212
  }
168
213
  orderBy(orderBy) {
214
+ this.ensureNotFinalized();
169
215
  this._orderBy = [];
170
216
  core_1.Utils.asArray(orderBy).forEach(o => {
171
- const processed = core_1.QueryHelper.processWhere(o, this.entityName, this.metadata, this.platform, false);
172
- this._orderBy.push(CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.entityName, processed).process(this));
217
+ const processed = core_1.QueryHelper.processWhere({
218
+ where: o,
219
+ entityName: this.mainAlias.entityName,
220
+ metadata: this.metadata,
221
+ platform: this.platform,
222
+ aliasMap: this.getAliasMap(),
223
+ aliased: !this.type || [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
224
+ convertCustomTypes: false,
225
+ });
226
+ this._orderBy.push(CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, processed).process(this));
173
227
  });
174
228
  return this;
175
229
  }
176
230
  groupBy(fields) {
231
+ this.ensureNotFinalized();
177
232
  this._groupBy = core_1.Utils.asArray(fields);
178
233
  return this;
179
234
  }
180
235
  having(cond = {}, params) {
236
+ this.ensureNotFinalized();
181
237
  if (core_1.Utils.isString(cond)) {
182
238
  cond = { [`(${cond})`]: core_1.Utils.asArray(params) };
183
239
  }
184
- this._having = CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.entityName, cond).process(this);
240
+ this._having = CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond).process(this);
185
241
  return this;
186
242
  }
187
243
  onConflict(fields = []) {
244
+ this.ensureNotFinalized();
188
245
  this._onConflict = this._onConflict || [];
189
- this._onConflict.push({ fields: core_1.Utils.asArray(fields) });
246
+ this._onConflict.push({ fields: core_1.Utils.asArray(fields).map(f => f.toString()) });
190
247
  return this;
191
248
  }
192
249
  ignore() {
@@ -200,14 +257,19 @@ class QueryBuilder {
200
257
  if (!this._onConflict) {
201
258
  throw new Error('You need to call `qb.onConflict()` first to use `qb.merge()`');
202
259
  }
260
+ if (Array.isArray(data) && data.length === 0) {
261
+ return this.ignore();
262
+ }
203
263
  this._onConflict[this._onConflict.length - 1].merge = data;
204
264
  return this;
205
265
  }
206
266
  /**
207
267
  * @internal
208
268
  */
209
- populate(populate) {
269
+ populate(populate, populateWhere) {
270
+ this.ensureNotFinalized();
210
271
  this._populate = populate;
272
+ this._populateWhere = populateWhere;
211
273
  return this;
212
274
  }
213
275
  /**
@@ -222,6 +284,7 @@ class QueryBuilder {
222
284
  return raw;
223
285
  }
224
286
  limit(limit, offset = 0) {
287
+ this.ensureNotFinalized();
225
288
  this._limit = limit;
226
289
  if (offset) {
227
290
  this.offset(offset);
@@ -229,14 +292,17 @@ class QueryBuilder {
229
292
  return this;
230
293
  }
231
294
  offset(offset) {
295
+ this.ensureNotFinalized();
232
296
  this._offset = offset;
233
297
  return this;
234
298
  }
235
299
  withSchema(schema) {
300
+ this.ensureNotFinalized();
236
301
  this._schema = schema;
237
302
  return this;
238
303
  }
239
304
  setLockMode(mode, tables) {
305
+ this.ensureNotFinalized();
240
306
  if (mode != null && mode !== core_1.LockMode.OPTIMISTIC && !this.context) {
241
307
  throw core_1.ValidationError.transactionRequired();
242
308
  }
@@ -245,18 +311,22 @@ class QueryBuilder {
245
311
  return this;
246
312
  }
247
313
  setFlushMode(flushMode) {
314
+ this.ensureNotFinalized();
248
315
  this.flushMode = flushMode;
249
316
  return this;
250
317
  }
251
318
  setFlag(flag) {
319
+ this.ensureNotFinalized();
252
320
  this.flags.add(flag);
253
321
  return this;
254
322
  }
255
323
  unsetFlag(flag) {
324
+ this.ensureNotFinalized();
256
325
  this.flags.delete(flag);
257
326
  return this;
258
327
  }
259
328
  cache(config = true) {
329
+ this.ensureNotFinalized();
260
330
  this._cache = config;
261
331
  return this;
262
332
  }
@@ -264,31 +334,47 @@ class QueryBuilder {
264
334
  * Adds index hint to the FROM clause.
265
335
  */
266
336
  indexHint(sql) {
337
+ this.ensureNotFinalized();
267
338
  this._indexHint = sql;
268
339
  return this;
269
340
  }
341
+ from(target, aliasName) {
342
+ this.ensureNotFinalized();
343
+ if (target instanceof QueryBuilder) {
344
+ this.fromSubQuery(target, aliasName);
345
+ }
346
+ else {
347
+ const entityName = core_1.Utils.className(target);
348
+ if (aliasName && this._mainAlias && entityName !== this._mainAlias.aliasName) {
349
+ throw new Error(`Cannot override the alias to '${aliasName}' since a query already contains references to '${this._mainAlias.aliasName}'`);
350
+ }
351
+ this.fromEntityName(entityName, aliasName);
352
+ }
353
+ return this;
354
+ }
270
355
  getKnexQuery() {
271
356
  this.finalize();
272
357
  const qb = this.getQueryBase();
273
- core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._cond, qb), this._cond && !this._onConflict);
358
+ core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type ?? enums_1.QueryType.SELECT, this._cond, qb), this._cond && !this._onConflict);
274
359
  core_1.Utils.runIfNotEmpty(() => qb.groupBy(this.prepareFields(this._groupBy, 'groupBy')), this._groupBy);
275
- core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._having, qb, undefined, 'having'), this._having);
360
+ core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type ?? enums_1.QueryType.SELECT, this._having, qb, undefined, 'having'), this._having);
276
361
  core_1.Utils.runIfNotEmpty(() => {
277
- const queryOrder = this.helper.getQueryOrder(this.type, this._orderBy, this._populateMap);
362
+ const queryOrder = this.helper.getQueryOrder(this.type ?? enums_1.QueryType.SELECT, this._orderBy, this._populateMap);
278
363
  if (queryOrder) {
279
- return qb.orderByRaw(queryOrder);
364
+ qb.orderByRaw(queryOrder);
365
+ return;
280
366
  }
281
367
  }, this._orderBy);
282
368
  core_1.Utils.runIfNotEmpty(() => qb.limit(this._limit), this._limit != null);
283
369
  core_1.Utils.runIfNotEmpty(() => qb.offset(this._offset), this._offset);
284
- core_1.Utils.runIfNotEmpty(() => this.helper.appendOnConflictClause(this.type, this._onConflict, qb), this._onConflict);
370
+ core_1.Utils.runIfNotEmpty(() => this.helper.appendOnConflictClause(this.type ?? enums_1.QueryType.SELECT, this._onConflict, qb), this._onConflict);
285
371
  if (this.type === enums_1.QueryType.TRUNCATE && this.platform.usesCascadeStatement()) {
286
372
  return this.knex.raw(qb.toSQL().toNative().sql + ' cascade');
287
373
  }
288
374
  if (this.lockMode) {
289
375
  this.helper.getLockSQL(qb, this.lockMode, this.lockTables);
290
376
  }
291
- this.helper.finalize(this.type, qb, this.metadata.find(this.entityName));
377
+ this.helper.finalize(this.type ?? enums_1.QueryType.SELECT, qb, this.mainAlias.metadata);
292
378
  return qb;
293
379
  }
294
380
  /**
@@ -310,9 +396,12 @@ class QueryBuilder {
310
396
  const query = this.getKnexQuery().toSQL();
311
397
  return this.platform.formatQuery(query.sql, query.bindings);
312
398
  }
399
+ /**
400
+ * @internal
401
+ */
313
402
  getAliasForJoinPath(path) {
314
- if (!path || path === this.entityName) {
315
- return this.alias;
403
+ if (!path || path === this.mainAlias.entityName) {
404
+ return this.mainAlias.aliasName;
316
405
  }
317
406
  const join = Object.values(this._joins).find(j => j.path === path);
318
407
  if (path.endsWith('[pivot]') && join) {
@@ -320,25 +409,34 @@ class QueryBuilder {
320
409
  }
321
410
  return join?.inverseAlias || join?.alias;
322
411
  }
412
+ /**
413
+ * @internal
414
+ */
323
415
  getNextAlias(entityName = 'e') {
324
416
  return this.driver.config.getNamingStrategy().aliasName(entityName, this.aliasCounter++);
325
417
  }
418
+ /**
419
+ * @internal
420
+ */
421
+ getAliasMap() {
422
+ return Object.fromEntries(Object.entries(this._aliases).map(([key, value]) => [key, value.entityName]));
423
+ }
326
424
  /**
327
425
  * Executes this QB and returns the raw results, mapped to the property names (unless disabled via last parameter).
328
426
  * Use `method` to specify what kind of result you want to get (array/single/meta).
329
427
  */
330
428
  async execute(method = 'all', mapResults = true) {
331
- if (!this.connectionType && method !== 'run' && [enums_1.QueryType.INSERT, enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE, enums_1.QueryType.TRUNCATE].includes(this.type)) {
429
+ if (!this.connectionType && method !== 'run' && [enums_1.QueryType.INSERT, enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE, enums_1.QueryType.TRUNCATE].includes(this.type ?? enums_1.QueryType.SELECT)) {
332
430
  this.connectionType = 'write';
333
431
  }
334
432
  const query = this.getKnexQuery().toSQL();
335
- const cached = await this.em?.tryCache(this.entityName, this._cache, ['qb.execute', query.sql, query.bindings, method]);
433
+ const cached = await this.em?.tryCache(this.mainAlias.entityName, this._cache, ['qb.execute', query.sql, query.bindings, method]);
336
434
  if (cached?.data) {
337
435
  return cached.data;
338
436
  }
339
437
  const type = this.connectionType || (method === 'run' ? 'write' : 'read');
340
438
  const res = await this.driver.getConnection(type).execute(query.sql, query.bindings, method, this.context);
341
- const meta = this.metadata.find(this.entityName);
439
+ const meta = this.mainAlias.metadata;
342
440
  if (!mapResults || !meta) {
343
441
  await this.em?.storeCache(this._cache, cached, res);
344
442
  return res;
@@ -363,12 +461,32 @@ class QueryBuilder {
363
461
  * Executes the query, returning array of results
364
462
  */
365
463
  async getResultList() {
366
- await this.em.tryFlush(this.entityName, { flushMode: this.flushMode });
464
+ await this.em.tryFlush(this.mainAlias.entityName, { flushMode: this.flushMode });
367
465
  let res = await this.execute('all', true);
368
466
  if (this._joinedProps.size > 0) {
369
- res = this.driver.mergeJoinedResult(res, this.metadata.find(this.entityName));
467
+ res = this.driver.mergeJoinedResult(res, this.mainAlias.metadata);
468
+ }
469
+ const entities = [];
470
+ function propagatePopulateHint(entity, hint) {
471
+ (0, core_1.helper)(entity).__serializationContext.populate ??= hint;
472
+ hint.forEach(pop => {
473
+ const value = entity[pop.field];
474
+ if (core_1.Utils.isEntity(value, true)) {
475
+ (0, core_1.helper)(value).populated();
476
+ propagatePopulateHint(value, pop.children ?? []);
477
+ }
478
+ else if (core_1.Utils.isCollection(value)) {
479
+ value.populated();
480
+ value.getItems(false).forEach(item => propagatePopulateHint(item, pop.children ?? []));
481
+ }
482
+ });
370
483
  }
371
- return res.map(r => this.em.map(this.entityName, r, { schema: this._schema }));
484
+ for (const r of res) {
485
+ const entity = this.em.map(this.mainAlias.entityName, r, { schema: this._schema });
486
+ propagatePopulateHint(entity, this._populate);
487
+ entities.push(entity);
488
+ }
489
+ return entities;
372
490
  }
373
491
  /**
374
492
  * Executes the query, returning the first result or null
@@ -380,35 +498,41 @@ class QueryBuilder {
380
498
  /**
381
499
  * Executes count query (without offset and limit), returning total count of results
382
500
  */
383
- async getCount(field, distinct = false) {
384
- const qb = this.clone();
385
- qb.count(field, distinct).limit(undefined).offset(undefined);
386
- const res = await qb.execute('get', false);
501
+ async getCount(field, distinct) {
502
+ let res;
503
+ if (this.type === enums_1.QueryType.COUNT) {
504
+ res = await this.execute('get', false);
505
+ }
506
+ else {
507
+ const qb = this.clone();
508
+ qb.count(field, distinct ?? qb.hasToManyJoins()).limit(undefined).offset(undefined).orderBy([]);
509
+ res = await qb.execute('get', false);
510
+ }
387
511
  return res ? +res.count : 0;
388
512
  }
513
+ /**
514
+ * Executes the query, returning both array of results and total count query (without offset and limit).
515
+ */
516
+ async getResultAndCount() {
517
+ return Promise.all([
518
+ this.getResultList(),
519
+ this.getCount(),
520
+ ]);
521
+ }
389
522
  /**
390
523
  * Provides promise-like interface so we can await the QB instance.
391
524
  */
392
525
  then(onfulfilled, onrejected) {
393
- return this.getInnerPromise().then(onfulfilled, onrejected);
394
- }
395
- getInnerPromise() {
396
- if (!this.innerPromise) {
397
- this.innerPromise = (async () => {
398
- switch (this.type) {
399
- case enums_1.QueryType.INSERT:
400
- case enums_1.QueryType.UPDATE:
401
- case enums_1.QueryType.DELETE:
402
- case enums_1.QueryType.TRUNCATE:
403
- return this.execute('run');
404
- case enums_1.QueryType.SELECT:
405
- return this.getResultList();
406
- case enums_1.QueryType.COUNT:
407
- return this.getCount();
408
- }
409
- })();
526
+ switch (this.type ?? enums_1.QueryType.SELECT) {
527
+ case enums_1.QueryType.INSERT:
528
+ case enums_1.QueryType.UPDATE:
529
+ case enums_1.QueryType.DELETE:
530
+ case enums_1.QueryType.TRUNCATE:
531
+ return this.execute('run').then(onfulfilled, onrejected);
532
+ case enums_1.QueryType.COUNT:
533
+ return this.getCount().then(onfulfilled, onrejected);
534
+ case enums_1.QueryType.SELECT: return this.getResultList().then(onfulfilled, onrejected);
410
535
  }
411
- return this.innerPromise;
412
536
  }
413
537
  /**
414
538
  * Returns knex instance with sub-query aliased with given alias.
@@ -425,11 +549,11 @@ class QueryBuilder {
425
549
  return qb.as(alias);
426
550
  }
427
551
  clone() {
428
- const qb = new QueryBuilder(this.entityName, this.metadata, this.driver, this.context, this.alias, this.connectionType, this.em);
552
+ const qb = new QueryBuilder(this.mainAlias.entityName, this.metadata, this.driver, this.context, this.mainAlias.aliasName, this.connectionType, this.em);
429
553
  Object.assign(qb, this);
430
554
  // clone array/object properties
431
555
  const properties = [
432
- 'flags', '_populate', '_populateMap', '_joins', '_joinedProps', '_aliasMap', '_cond', '_data', '_orderBy',
556
+ 'flags', '_populate', '_populateWhere', '_populateMap', '_joins', '_joinedProps', '_cond', '_data', '_orderBy',
433
557
  '_schema', '_indexHint', '_cache', 'subQueries', 'lockMode', 'lockTables',
434
558
  ];
435
559
  properties.forEach(prop => qb[prop] = core_1.Utils.copy(this[prop]));
@@ -437,44 +561,62 @@ class QueryBuilder {
437
561
  if (this._fields) {
438
562
  qb._fields = [...this._fields];
439
563
  }
564
+ qb._aliases = { ...this._aliases };
440
565
  qb.finalized = false;
441
566
  return qb;
442
567
  }
443
568
  getKnex() {
444
- const tableName = this.helper.getTableName(this.entityName) + (this.finalized && this.helper.isTableNameAliasRequired(this.type) ? ` as ${this.alias}` : '');
445
- const qb = this.knex(tableName);
569
+ const qb = this.knex.queryBuilder();
570
+ const { subQuery, aliasName, entityName } = this.mainAlias;
571
+ const ref = subQuery ? subQuery : this.knex.ref(this.helper.getTableName(entityName));
572
+ if (this.finalized && (this._explicitAlias || this.helper.isTableNameAliasRequired(this.type))) {
573
+ ref.as(aliasName);
574
+ }
575
+ const schema = this.getSchema(this.mainAlias);
576
+ if (schema) {
577
+ ref.withSchema(schema);
578
+ }
579
+ qb.from(ref);
446
580
  if (this.context) {
447
581
  qb.transacting(this.context);
448
582
  }
449
583
  return qb;
450
584
  }
451
585
  joinReference(field, alias, cond, type, path) {
586
+ this.ensureNotFinalized();
452
587
  const [fromAlias, fromField] = this.helper.splitField(field);
453
- const entityName = this._aliasMap[fromAlias];
588
+ const entityName = this._aliases[fromAlias]?.entityName;
454
589
  const meta = this.metadata.get(entityName);
455
590
  const prop = meta.properties[fromField];
456
591
  if (!prop) {
457
592
  throw new Error(`Trying to join ${field}, but ${fromField} is not a defined relation on ${meta.className}`);
458
593
  }
459
- this._aliasMap[alias] = prop.type;
460
- cond = core_1.QueryHelper.processWhere(cond, this.entityName, this.metadata, this.platform);
594
+ this.createAlias(prop.type, alias);
595
+ cond = core_1.QueryHelper.processWhere({
596
+ where: cond,
597
+ entityName: this.mainAlias.entityName,
598
+ metadata: this.metadata,
599
+ platform: this.platform,
600
+ aliasMap: this.getAliasMap(),
601
+ aliased: !this.type || [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
602
+ });
461
603
  let aliasedName = `${fromAlias}.${prop.name}#${alias}`;
462
- path ?? (path = `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? entityName)}.${prop.name}`);
463
- if (prop.reference === core_1.ReferenceType.ONE_TO_MANY) {
604
+ path ??= `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? entityName)}.${prop.name}`;
605
+ if (prop.kind === core_1.ReferenceKind.ONE_TO_MANY) {
464
606
  this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond);
465
607
  }
466
- else if (prop.reference === core_1.ReferenceType.MANY_TO_MANY) {
608
+ else if (prop.kind === core_1.ReferenceKind.MANY_TO_MANY) {
467
609
  let pivotAlias = alias;
468
610
  if (type !== 'pivotJoin') {
469
611
  const oldPivotAlias = this.getAliasForJoinPath(path + '[pivot]');
470
- pivotAlias = oldPivotAlias ?? this.getNextAlias(prop.pivotTable);
612
+ pivotAlias = oldPivotAlias ?? this.getNextAlias(prop.pivotEntity);
471
613
  aliasedName = `${fromAlias}.${prop.name}#${pivotAlias}`;
472
614
  }
473
615
  const joins = this.helper.joinManyToManyReference(prop, fromAlias, alias, pivotAlias, type, cond, path);
474
616
  Object.assign(this._joins, joins);
475
- this._aliasMap[pivotAlias] = prop.pivotTable;
617
+ this.createAlias(prop.pivotEntity, pivotAlias);
476
618
  }
477
- else if (prop.reference === core_1.ReferenceType.ONE_TO_ONE) {
619
+ else if (prop.kind === core_1.ReferenceKind.ONE_TO_ONE) {
478
620
  this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond);
479
621
  }
480
622
  else { // MANY_TO_ONE
@@ -489,30 +631,58 @@ class QueryBuilder {
489
631
  const ret = [];
490
632
  fields.forEach(field => {
491
633
  if (!core_1.Utils.isString(field)) {
492
- return ret.push(field);
634
+ ret.push(field);
635
+ return;
493
636
  }
494
637
  const join = Object.keys(this._joins).find(k => field === k.substring(0, k.indexOf('#')));
495
638
  if (join && type === 'where') {
496
- return ret.push(...this.helper.mapJoinColumns(this.type, this._joins[join]));
639
+ ret.push(...this.helper.mapJoinColumns(this.type ?? enums_1.QueryType.SELECT, this._joins[join]));
640
+ return;
497
641
  }
498
642
  const [a, f] = this.helper.splitField(field);
499
643
  const prop = this.helper.getProperty(f, a);
500
- if (prop && [core_1.ReferenceType.ONE_TO_MANY, core_1.ReferenceType.MANY_TO_MANY].includes(prop.reference)) {
644
+ /* istanbul ignore next */
645
+ if (prop && [core_1.ReferenceKind.ONE_TO_MANY, core_1.ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
646
+ return;
647
+ }
648
+ if (prop?.embedded) {
649
+ const fieldName = this.helper.mapper(prop.fieldNames[0], this.type);
650
+ ret.push(fieldName);
651
+ return;
652
+ }
653
+ if (prop?.kind === core_1.ReferenceKind.EMBEDDED) {
654
+ if (prop.object) {
655
+ ret.push(this.helper.mapper(prop.fieldNames[0], this.type));
656
+ }
657
+ else {
658
+ const nest = (prop) => {
659
+ for (const childProp of Object.values(prop.embeddedProps)) {
660
+ if (childProp.fieldNames) {
661
+ ret.push(this.helper.mapper(childProp.fieldNames[0], this.type));
662
+ }
663
+ else {
664
+ nest(childProp);
665
+ }
666
+ }
667
+ };
668
+ nest(prop);
669
+ }
501
670
  return;
502
671
  }
503
672
  ret.push(this.helper.mapper(field, this.type));
504
673
  });
505
- const meta = this.metadata.find(this.entityName);
674
+ const meta = this.mainAlias.metadata;
506
675
  /* istanbul ignore next */
507
676
  const requiresSQLConversion = meta?.props.filter(p => p.customType?.convertToJSValueSQL) ?? [];
508
- if (this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES) && (fields.includes('*') || fields.includes(`${this.alias}.*`)) && requiresSQLConversion.length > 0) {
677
+ if (this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES) && (fields.includes('*') || fields.includes(`${this.mainAlias.aliasName}.*`)) && requiresSQLConversion.length > 0) {
509
678
  requiresSQLConversion.forEach(p => ret.push(this.helper.mapper(p.name, this.type)));
510
679
  }
511
680
  Object.keys(this._populateMap).forEach(f => {
512
681
  if (!fields.includes(f.replace(/#\w+$/, '')) && type === 'where') {
513
- ret.push(...this.helper.mapJoinColumns(this.type, this._joins[f]));
682
+ const cols = this.helper.mapJoinColumns(this.type ?? enums_1.QueryType.SELECT, this._joins[f]);
683
+ ret.push(...cols);
514
684
  }
515
- if (this._joins[f].prop.reference !== core_1.ReferenceType.ONE_TO_ONE && this._joins[f].inverseJoinColumns) {
685
+ if (this._joins[f].prop.kind !== core_1.ReferenceKind.ONE_TO_ONE && this._joins[f].inverseJoinColumns) {
516
686
  this._joins[f].inverseJoinColumns.forEach(inverseJoinColumn => {
517
687
  core_1.Utils.renameKey(this._cond, inverseJoinColumn, `${this._joins[f].alias}.${inverseJoinColumn}`);
518
688
  });
@@ -521,8 +691,8 @@ class QueryBuilder {
521
691
  return ret;
522
692
  }
523
693
  init(type, data, cond) {
694
+ this.ensureNotFinalized();
524
695
  this.type = type;
525
- this._aliasMap[this.alias] = this.entityName;
526
696
  if ([enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE].includes(type) && core_1.Utils.hasObjectKeys(this._cond)) {
527
697
  throw new Error(`You are trying to call \`qb.where().${type.toLowerCase()}()\`. Calling \`qb.${type.toLowerCase()}()\` before \`qb.where()\` is required.`);
528
698
  }
@@ -530,6 +700,9 @@ class QueryBuilder {
530
700
  delete this._fields;
531
701
  }
532
702
  if (data) {
703
+ if (core_1.Utils.isEntity(data)) {
704
+ data = this.em?.getComparator().prepareEntity(data) ?? (0, core_1.serialize)(data);
705
+ }
533
706
  this._data = this.helper.processData(data, this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES));
534
707
  }
535
708
  if (cond) {
@@ -539,22 +712,23 @@ class QueryBuilder {
539
712
  }
540
713
  getQueryBase() {
541
714
  const qb = this.getKnex();
542
- const meta = this.metadata.find(this.entityName);
543
- const metaSchema = meta?.schema && meta.schema !== '*' ? meta.schema : undefined;
544
- const schema = this._schema ?? metaSchema ?? this.em?.config.get('schema');
715
+ const schema = this.getSchema(this.mainAlias);
545
716
  if (schema) {
546
717
  qb.withSchema(schema);
547
718
  }
548
719
  if (this._indexHint) {
549
- const alias = this.helper.isTableNameAliasRequired(this.type) ? ` as ${this.platform.quoteIdentifier(this.alias)}` : '';
720
+ const alias = this.helper.isTableNameAliasRequired(this.type) ? ` as ${this.platform.quoteIdentifier(this.mainAlias.aliasName)}` : '';
550
721
  const schemaQuoted = schema ? this.platform.quoteIdentifier(schema) + '.' : '';
551
- const tableName = schemaQuoted + this.platform.quoteIdentifier(this.helper.getTableName(this.entityName)) + alias;
722
+ const tableName = schemaQuoted + this.platform.quoteIdentifier(this.helper.getTableName(this.mainAlias.entityName)) + alias;
552
723
  qb.from(this.knex.raw(`${tableName} ${this._indexHint}`));
553
724
  }
554
725
  switch (this.type) {
555
726
  case enums_1.QueryType.SELECT:
556
727
  qb.select(this.prepareFields(this._fields));
557
- if (this.flags.has(core_1.QueryFlag.DISTINCT)) {
728
+ if (this._distinctOn) {
729
+ qb.distinctOn(this._distinctOn);
730
+ }
731
+ else if (this.flags.has(core_1.QueryFlag.DISTINCT)) {
558
732
  qb.distinct();
559
733
  }
560
734
  this.helper.processJoins(qb, this._joins, schema);
@@ -588,11 +762,11 @@ class QueryBuilder {
588
762
  if (!this.type) {
589
763
  this.select('*');
590
764
  }
591
- const meta = this.metadata.find(this.entityName);
765
+ const meta = this.mainAlias.metadata;
592
766
  if (meta && this.flags.has(core_1.QueryFlag.AUTO_JOIN_ONE_TO_ONE_OWNER)) {
593
767
  const relationsToPopulate = this._populate.map(({ field }) => field);
594
768
  meta.relations
595
- .filter(prop => prop.reference === core_1.ReferenceType.ONE_TO_ONE && !prop.owner && !relationsToPopulate.includes(prop.name))
769
+ .filter(prop => prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner && !relationsToPopulate.includes(prop.name))
596
770
  .map(prop => ({ field: prop.name }))
597
771
  .forEach(item => this._populate.push(item));
598
772
  }
@@ -600,44 +774,92 @@ class QueryBuilder {
600
774
  const [fromAlias, fromField] = this.helper.splitField(field);
601
775
  const aliasedField = `${fromAlias}.${fromField}`;
602
776
  const join = Object.keys(this._joins).find(k => `${aliasedField}#${this._joins[k].alias}` === k);
603
- if (this._joins[join] && this.helper.isOneToOneInverse(fromField)) {
604
- return this._populateMap[join] = this._joins[join].alias;
777
+ if (join && this._joins[join] && this.helper.isOneToOneInverse(fromField)) {
778
+ this._populateMap[join] = this._joins[join].alias;
779
+ return;
605
780
  }
606
781
  if (this.metadata.find(field)?.pivotTable) { // pivot table entity
607
782
  this.autoJoinPivotTable(field);
608
783
  }
609
784
  else if (meta && this.helper.isOneToOneInverse(fromField)) {
610
785
  const prop = meta.properties[fromField];
611
- const alias = this.getNextAlias(prop.pivotTable ?? prop.type);
612
- this._joins[join] = this.helper.joinOneToReference(prop, this.alias, alias, 'leftJoin');
613
- this._populateMap[join] = this._joins[join].alias;
786
+ const alias = this.getNextAlias(prop.pivotEntity ?? prop.type);
787
+ const aliasedName = `${fromAlias}.${prop.name}#${alias}`;
788
+ this._joins[aliasedName] = this.helper.joinOneToReference(prop, this.mainAlias.aliasName, alias, 'leftJoin');
789
+ this._populateMap[aliasedName] = this._joins[aliasedName].alias;
614
790
  }
615
791
  });
616
- if (meta && (this._fields?.includes('*') || this._fields?.includes(`${this.alias}.*`))) {
792
+ if (meta && (this._fields?.includes('*') || this._fields?.includes(`${this.mainAlias.aliasName}.*`))) {
617
793
  meta.props
618
794
  .filter(prop => prop.formula && (!prop.lazy || this.flags.has(core_1.QueryFlag.INCLUDE_LAZY_FORMULAS)))
619
795
  .map(prop => {
620
- const alias = this.knex.ref(this.alias).toString();
796
+ const alias = this.knex.ref(this.mainAlias.aliasName).toString();
621
797
  const aliased = this.knex.ref(prop.fieldNames[0]).toString();
622
798
  return `${prop.formula(alias)} as ${aliased}`;
623
799
  })
624
800
  .filter(field => !this._fields.includes(field))
625
801
  .forEach(field => this.addSelect(field));
626
802
  }
803
+ this.processPopulateWhere();
627
804
  core_1.QueryHelper.processObjectParams(this._data);
628
805
  core_1.QueryHelper.processObjectParams(this._cond);
629
806
  core_1.QueryHelper.processObjectParams(this._having);
630
- this.finalized = true;
631
- if (meta && this.flags.has(core_1.QueryFlag.PAGINATE) && this._limit > 0) {
807
+ // automatically enable paginate flag when we detect to-many joins
808
+ if (!this.flags.has(core_1.QueryFlag.DISABLE_PAGINATE) && this.hasToManyJoins()) {
809
+ this.flags.add(core_1.QueryFlag.PAGINATE);
810
+ }
811
+ if (meta && this.flags.has(core_1.QueryFlag.PAGINATE) && (this._limit > 0 || this._offset > 0)) {
632
812
  this.wrapPaginateSubQuery(meta);
633
813
  }
634
814
  if (meta && (this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(core_1.QueryFlag.DELETE_SUB_QUERY))) {
635
815
  this.wrapModifySubQuery(meta);
636
816
  }
817
+ this.finalized = true;
818
+ }
819
+ processPopulateWhere() {
820
+ if (this._populateWhere == null || this._populateWhere === core_1.PopulateHint.ALL) {
821
+ return;
822
+ }
823
+ const joins = Object.values(this._joins);
824
+ joins.forEach(join => {
825
+ join.cond_ = join.cond;
826
+ join.cond = {};
827
+ });
828
+ const replaceOnConditions = (cond) => {
829
+ Object.keys(cond).forEach(k => {
830
+ if (core_1.Utils.isOperator(k)) {
831
+ if (Array.isArray(cond[k])) {
832
+ return cond[k].forEach((c) => replaceOnConditions(c));
833
+ }
834
+ return replaceOnConditions(cond[k]);
835
+ }
836
+ const [a] = this.helper.splitField(k);
837
+ const join = joins.find(j => j.alias === a);
838
+ if (join) {
839
+ join.cond = { ...join.cond, [k]: cond[k] };
840
+ }
841
+ });
842
+ };
843
+ if (this._populateWhere === core_1.PopulateHint.INFER) {
844
+ replaceOnConditions(this._cond);
845
+ }
846
+ else if (typeof this._populateWhere === 'object') {
847
+ const cond = CriteriaNodeFactory_1.CriteriaNodeFactory
848
+ .createNode(this.metadata, this.mainAlias.entityName, this._populateWhere)
849
+ .process(this);
850
+ replaceOnConditions(cond);
851
+ }
852
+ }
853
+ hasToManyJoins() {
854
+ return Object.values(this._joins).some(join => {
855
+ return [core_1.ReferenceKind.ONE_TO_MANY, core_1.ReferenceKind.MANY_TO_MANY].includes(join.prop.kind);
856
+ });
637
857
  }
638
858
  wrapPaginateSubQuery(meta) {
639
859
  const pks = this.prepareFields(meta.primaryKeys, 'sub-query');
640
860
  const subQuery = this.clone().select(pks).groupBy(pks).limit(this._limit);
861
+ // revert the on conditions added via populateWhere, we want to apply those only once
862
+ Object.values(subQuery._joins).forEach(join => join.cond = join.cond_ ?? {});
641
863
  if (this._offset) {
642
864
  subQuery.offset(this._offset);
643
865
  }
@@ -645,15 +867,18 @@ class QueryBuilder {
645
867
  const orderBy = [];
646
868
  for (const orderMap of this._orderBy) {
647
869
  for (const [field, direction] of Object.entries(orderMap)) {
870
+ const [a, f] = this.helper.splitField(field);
871
+ const prop = this.helper.getProperty(f, a);
872
+ const type = this.platform.castColumn(prop);
648
873
  orderBy.push({
649
- [`min(${this.ref(field)})`]: direction,
874
+ [`min(${this.ref(this.helper.mapper(field, this.type, undefined, null))}${type})`]: direction,
650
875
  });
651
876
  }
652
877
  }
653
878
  subQuery.orderBy(orderBy);
654
879
  }
655
880
  subQuery.finalized = true;
656
- const knexQuery = subQuery.as(this.alias).clearSelect().select(pks);
881
+ const knexQuery = subQuery.as(this.mainAlias.aliasName).clearSelect().select(pks);
657
882
  // multiple sub-queries are needed to get around mysql limitations with order by + limit + where in + group by (o.O)
658
883
  // https://stackoverflow.com/questions/17892762/mysql-this-version-of-mysql-doesnt-yet-support-limit-in-all-any-some-subqu
659
884
  const subSubQuery = this.getKnex().select(pks).from(knexQuery);
@@ -666,7 +891,7 @@ class QueryBuilder {
666
891
  subQuery.finalized = true;
667
892
  // wrap one more time to get around MySQL limitations
668
893
  // https://stackoverflow.com/questions/45494/mysql-error-1093-cant-specify-target-table-for-update-in-from-clause
669
- const subSubQuery = this.getKnex().select(this.prepareFields(meta.primaryKeys)).from(subQuery.as(this.alias));
894
+ const subSubQuery = this.getKnex().select(this.prepareFields(meta.primaryKeys)).from(subQuery.as(this.mainAlias.aliasName));
670
895
  const method = this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) ? 'update' : 'delete';
671
896
  this._cond = {}; // otherwise we would trigger validation error
672
897
  this[method](this._data).where({
@@ -675,14 +900,76 @@ class QueryBuilder {
675
900
  }
676
901
  autoJoinPivotTable(field) {
677
902
  const pivotMeta = this.metadata.find(field);
678
- const owner = pivotMeta.props.find(prop => prop.reference === core_1.ReferenceType.MANY_TO_ONE && prop.owner);
679
- const inverse = pivotMeta.props.find(prop => prop.reference === core_1.ReferenceType.MANY_TO_ONE && !prop.owner);
903
+ const owner = pivotMeta.relations[0];
904
+ const inverse = pivotMeta.relations[1];
680
905
  const prop = this._cond[pivotMeta.name + '.' + owner.name] || this._orderBy[pivotMeta.name + '.' + owner.name] ? inverse : owner;
681
906
  const pivotAlias = this.getNextAlias(pivotMeta.name);
682
- this._joins[field] = this.helper.joinPivotTable(field, prop, this.alias, pivotAlias, 'leftJoin');
907
+ this._joins[field] = this.helper.joinPivotTable(field, prop, this.mainAlias.aliasName, pivotAlias, 'leftJoin');
683
908
  core_1.Utils.renameKey(this._cond, `${field}.${owner.name}`, core_1.Utils.getPrimaryKeyHash(owner.fieldNames.map(fieldName => `${pivotAlias}.${fieldName}`)));
684
909
  core_1.Utils.renameKey(this._cond, `${field}.${inverse.name}`, core_1.Utils.getPrimaryKeyHash(inverse.fieldNames.map(fieldName => `${pivotAlias}.${fieldName}`)));
685
910
  this._populateMap[field] = this._joins[field].alias;
686
911
  }
912
+ getSchema(alias) {
913
+ const { metadata } = alias;
914
+ const metaSchema = metadata?.schema && metadata.schema !== '*' ? metadata.schema : undefined;
915
+ return this._schema ?? metaSchema ?? this.em?.config.get('schema');
916
+ }
917
+ createAlias(entityName, aliasName, subQuery) {
918
+ const metadata = this.metadata.find(entityName);
919
+ const alias = { aliasName, entityName, metadata, subQuery };
920
+ this._aliases[aliasName] = alias;
921
+ return alias;
922
+ }
923
+ createMainAlias(entityName, aliasName, subQuery) {
924
+ this._mainAlias = this.createAlias(entityName, aliasName, subQuery);
925
+ this._helper = this.createQueryBuilderHelper();
926
+ return this._mainAlias;
927
+ }
928
+ fromSubQuery(target, aliasName) {
929
+ const subQuery = target.getKnexQuery();
930
+ const { entityName } = target.mainAlias;
931
+ aliasName ??= this.getNextAlias(entityName);
932
+ this.createMainAlias(entityName, aliasName, subQuery);
933
+ }
934
+ fromEntityName(entityName, aliasName) {
935
+ aliasName ??= this._mainAlias?.aliasName ?? this.getNextAlias(entityName);
936
+ this.createMainAlias(entityName, aliasName);
937
+ }
938
+ createQueryBuilderHelper() {
939
+ return new QueryBuilderHelper_1.QueryBuilderHelper(this.mainAlias.entityName, this.mainAlias.aliasName, this._aliases, this.subQueries, this.knex, this.driver);
940
+ }
941
+ ensureFromClause() {
942
+ /* istanbul ignore next */
943
+ if (!this._mainAlias) {
944
+ throw new Error(`Cannot proceed to build a query because the main alias is not set.`);
945
+ }
946
+ }
947
+ ensureNotFinalized() {
948
+ if (this.finalized) {
949
+ throw new Error('This QueryBuilder instance is already finalized, clone it first if you want to modify it.');
950
+ }
951
+ }
952
+ /* istanbul ignore next */
953
+ [util_1.inspect.custom](depth) {
954
+ const object = { ...this };
955
+ const hidden = ['metadata', 'driver', 'context', 'platform', 'knex', 'type'];
956
+ Object.keys(object).filter(k => k.startsWith('_')).forEach(k => delete object[k]);
957
+ Object.keys(object).filter(k => object[k] == null).forEach(k => delete object[k]);
958
+ hidden.forEach(k => delete object[k]);
959
+ let prefix = this.type ? this.type.substring(0, 1) + this.type.toLowerCase().substring(1) : '';
960
+ if (this._data) {
961
+ object.data = this._data;
962
+ }
963
+ if (!core_1.Utils.isEmpty(this._cond)) {
964
+ object.where = this._cond;
965
+ }
966
+ if (this._onConflict?.[0]) {
967
+ prefix = 'Upsert';
968
+ object.onConflict = this._onConflict[0];
969
+ }
970
+ const name = this._mainAlias ? `${prefix}QueryBuilder<${this._mainAlias?.entityName}>` : 'QueryBuilder';
971
+ const ret = (0, util_1.inspect)(object, { depth });
972
+ return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
973
+ }
687
974
  }
688
975
  exports.QueryBuilder = QueryBuilder;