@mikro-orm/knex 6.4.6-dev.8 → 7.0.0-dev.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 (101) hide show
  1. package/AbstractSqlConnection.d.ts +15 -25
  2. package/AbstractSqlConnection.js +98 -126
  3. package/AbstractSqlDriver.d.ts +20 -13
  4. package/AbstractSqlDriver.js +73 -54
  5. package/AbstractSqlPlatform.d.ts +15 -3
  6. package/AbstractSqlPlatform.js +32 -11
  7. package/README.md +0 -2
  8. package/SqlEntityManager.d.ts +5 -6
  9. package/SqlEntityManager.js +5 -5
  10. package/SqlEntityRepository.d.ts +1 -6
  11. package/SqlEntityRepository.js +0 -6
  12. package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +12 -0
  13. package/dialects/mssql/MsSqlNativeQueryBuilder.js +161 -0
  14. package/dialects/mssql/index.d.ts +1 -1
  15. package/dialects/mssql/index.js +1 -1
  16. package/dialects/mysql/MySqlExceptionConverter.js +1 -0
  17. package/dialects/mysql/MySqlNativeQueryBuilder.d.ts +7 -0
  18. package/dialects/mysql/MySqlNativeQueryBuilder.js +81 -0
  19. package/dialects/mysql/MySqlPlatform.d.ts +5 -1
  20. package/dialects/mysql/MySqlPlatform.js +9 -1
  21. package/dialects/mysql/MySqlSchemaHelper.d.ts +6 -12
  22. package/dialects/mysql/MySqlSchemaHelper.js +42 -75
  23. package/dialects/mysql/index.d.ts +1 -3
  24. package/dialects/mysql/index.js +1 -3
  25. package/dialects/postgresql/PostgreSqlNativeQueryBuilder.d.ts +5 -0
  26. package/dialects/postgresql/PostgreSqlNativeQueryBuilder.js +12 -0
  27. package/dialects/postgresql/index.d.ts +1 -1
  28. package/dialects/postgresql/index.js +1 -1
  29. package/dialects/sqlite/BaseSqliteConnection.d.ts +0 -5
  30. package/dialects/sqlite/BaseSqliteConnection.js +4 -42
  31. package/dialects/sqlite/BaseSqlitePlatform.d.ts +15 -3
  32. package/dialects/sqlite/BaseSqlitePlatform.js +20 -4
  33. package/dialects/sqlite/SqliteExceptionConverter.d.ts +9 -0
  34. package/dialects/sqlite/SqliteExceptionConverter.js +55 -0
  35. package/dialects/sqlite/SqliteNativeQueryBuilder.d.ts +6 -0
  36. package/dialects/sqlite/SqliteNativeQueryBuilder.js +15 -0
  37. package/dialects/sqlite/SqliteSchemaHelper.d.ts +38 -0
  38. package/dialects/sqlite/SqliteSchemaHelper.js +384 -0
  39. package/dialects/sqlite/index.d.ts +3 -5
  40. package/dialects/sqlite/index.js +3 -5
  41. package/index.d.ts +1 -2
  42. package/index.js +3 -5
  43. package/index.mjs +10 -13
  44. package/package.json +4 -18
  45. package/query/CriteriaNodeFactory.js +5 -5
  46. package/query/NativeQueryBuilder.d.ts +108 -0
  47. package/query/NativeQueryBuilder.js +429 -0
  48. package/query/ObjectCriteriaNode.js +3 -3
  49. package/query/QueryBuilder.d.ts +30 -34
  50. package/query/QueryBuilder.js +112 -123
  51. package/query/QueryBuilderHelper.d.ts +27 -23
  52. package/query/QueryBuilderHelper.js +174 -168
  53. package/query/ScalarCriteriaNode.js +4 -0
  54. package/query/index.d.ts +1 -0
  55. package/query/index.js +1 -0
  56. package/schema/DatabaseSchema.js +9 -6
  57. package/schema/DatabaseTable.d.ts +2 -1
  58. package/schema/DatabaseTable.js +9 -5
  59. package/schema/SchemaComparator.d.ts +1 -2
  60. package/schema/SchemaComparator.js +31 -18
  61. package/schema/SchemaHelper.d.ts +27 -33
  62. package/schema/SchemaHelper.js +294 -184
  63. package/schema/SqlSchemaGenerator.d.ts +3 -9
  64. package/schema/SqlSchemaGenerator.js +105 -229
  65. package/typings.d.ts +7 -17
  66. package/MonkeyPatchable.d.ts +0 -18
  67. package/MonkeyPatchable.js +0 -60
  68. package/dialects/mssql/MsSqlColumnCompiler.d.ts +0 -4
  69. package/dialects/mssql/MsSqlColumnCompiler.js +0 -10
  70. package/dialects/mssql/MsSqlKnexDialect.d.ts +0 -6
  71. package/dialects/mssql/MsSqlKnexDialect.js +0 -22
  72. package/dialects/mssql/MsSqlQueryCompiler.d.ts +0 -12
  73. package/dialects/mssql/MsSqlQueryCompiler.js +0 -94
  74. package/dialects/mssql/MsSqlTableCompiler.d.ts +0 -9
  75. package/dialects/mssql/MsSqlTableCompiler.js +0 -40
  76. package/dialects/mysql/MariaDbKnexDialect.d.ts +0 -6
  77. package/dialects/mysql/MariaDbKnexDialect.js +0 -16
  78. package/dialects/mysql/MySqlColumnCompiler.d.ts +0 -7
  79. package/dialects/mysql/MySqlColumnCompiler.js +0 -26
  80. package/dialects/mysql/MySqlConnection.d.ts +0 -8
  81. package/dialects/mysql/MySqlConnection.js +0 -43
  82. package/dialects/mysql/MySqlKnexDialect.d.ts +0 -5
  83. package/dialects/mysql/MySqlKnexDialect.js +0 -17
  84. package/dialects/mysql/MySqlQueryCompiler.d.ts +0 -5
  85. package/dialects/mysql/MySqlQueryCompiler.js +0 -23
  86. package/dialects/postgresql/PostgreSqlKnexDialect.d.ts +0 -7
  87. package/dialects/postgresql/PostgreSqlKnexDialect.js +0 -20
  88. package/dialects/postgresql/PostgreSqlQueryCompiler.d.ts +0 -4
  89. package/dialects/postgresql/PostgreSqlQueryCompiler.js +0 -13
  90. package/dialects/postgresql/PostgreSqlTableCompiler.d.ts +0 -11
  91. package/dialects/postgresql/PostgreSqlTableCompiler.js +0 -89
  92. package/dialects/sqlite/BaseSqliteSchemaHelper.d.ts +0 -28
  93. package/dialects/sqlite/BaseSqliteSchemaHelper.js +0 -200
  94. package/dialects/sqlite/BetterSqliteKnexDialect.d.ts +0 -5
  95. package/dialects/sqlite/BetterSqliteKnexDialect.js +0 -15
  96. package/dialects/sqlite/LibSqlKnexDialect.d.ts +0 -11
  97. package/dialects/sqlite/LibSqlKnexDialect.js +0 -85
  98. package/dialects/sqlite/SqliteKnexDialect.d.ts +0 -8
  99. package/dialects/sqlite/SqliteKnexDialect.js +0 -67
  100. package/dialects/sqlite/SqliteTableCompiler.d.ts +0 -6
  101. package/dialects/sqlite/SqliteTableCompiler.js +0 -71
@@ -6,6 +6,7 @@ const core_1 = require("@mikro-orm/core");
6
6
  const enums_1 = require("./enums");
7
7
  const QueryBuilderHelper_1 = require("./QueryBuilderHelper");
8
8
  const CriteriaNodeFactory_1 = require("./CriteriaNodeFactory");
9
+ const NativeQueryBuilder_1 = require("./NativeQueryBuilder");
9
10
  /**
10
11
  * SQL query builder with fluent interface.
11
12
  *
@@ -43,19 +44,12 @@ class QueryBuilder {
43
44
  this.ensureFromClause();
44
45
  return this._helper;
45
46
  }
46
- /** @internal */
47
- type;
48
- /** @internal */
49
- _fields;
47
+ get type() {
48
+ return this._type ?? enums_1.QueryType.SELECT;
49
+ }
50
50
  /** @internal */
51
51
  _populate = [];
52
52
  /** @internal */
53
- _populateWhere;
54
- /** @internal */
55
- _populateFilter;
56
- /** @internal */
57
- __populateWhere;
58
- /** @internal */
59
53
  _populateMap = {};
60
54
  /** @internal */
61
55
  rawFragments = new Set();
@@ -90,7 +84,6 @@ class QueryBuilder {
90
84
  _helper;
91
85
  _query;
92
86
  platform;
93
- knex;
94
87
  /**
95
88
  * @internal
96
89
  */
@@ -102,7 +95,6 @@ class QueryBuilder {
102
95
  this.em = em;
103
96
  this.loggerContext = loggerContext;
104
97
  this.platform = this.driver.getPlatform();
105
- this.knex = this.driver.getConnection(this.connectionType).getKnex();
106
98
  if (alias) {
107
99
  this.aliasCounter++;
108
100
  this._explicitAlias = true;
@@ -120,7 +112,7 @@ class QueryBuilder {
120
112
  }
121
113
  addSelect(fields) {
122
114
  this.ensureNotFinalized();
123
- if (this.type && this.type !== enums_1.QueryType.SELECT) {
115
+ if (this._type && this._type !== enums_1.QueryType.SELECT) {
124
116
  return this;
125
117
  }
126
118
  return this.select([...core_1.Utils.asArray(this._fields), ...core_1.Utils.asArray(fields)]);
@@ -170,23 +162,24 @@ class QueryBuilder {
170
162
  this.join(field, alias, cond, enums_1.JoinType.innerJoin, undefined, schema);
171
163
  return this;
172
164
  }
173
- innerJoinLateral(field, alias, cond = {}, schema) {
165
+ innerJoinLateral(field, alias, cond, schema) {
174
166
  this.join(field, alias, cond, enums_1.JoinType.innerJoinLateral, undefined, schema);
175
167
  return this;
176
168
  }
177
169
  leftJoin(field, alias, cond = {}, schema) {
178
170
  return this.join(field, alias, cond, enums_1.JoinType.leftJoin, undefined, schema);
179
171
  }
180
- leftJoinLateral(field, alias, cond = {}, schema) {
172
+ leftJoinLateral(field, alias, cond, schema) {
181
173
  return this.join(field, alias, cond, enums_1.JoinType.leftJoinLateral, undefined, schema);
182
174
  }
183
175
  joinAndSelect(field, alias, cond = {}, type = enums_1.JoinType.innerJoin, path, fields, schema) {
184
- if (!this.type) {
176
+ if (!this._type) {
185
177
  this.select('*');
186
178
  }
187
179
  let subquery;
188
180
  if (Array.isArray(field)) {
189
- subquery = field[1] instanceof QueryBuilder ? field[1].getFormattedQuery() : field[1].toString();
181
+ const rawFragment = field[1] instanceof QueryBuilder ? field[1].toRaw() : field[1];
182
+ subquery = this.platform.formatQuery(rawFragment.sql, rawFragment.params);
190
183
  field = field[0];
191
184
  }
192
185
  const prop = this.joinReference(field, alias, cond, type, path, schema, subquery);
@@ -269,7 +262,12 @@ class QueryBuilder {
269
262
  }
270
263
  withSubQuery(subQuery, alias) {
271
264
  this.ensureNotFinalized();
272
- this.subQueries[alias] = subQuery.toString();
265
+ if (subQuery instanceof core_1.RawQueryFragment) {
266
+ this.subQueries[alias] = this.platform.formatQuery(subQuery.sql, subQuery.params);
267
+ }
268
+ else {
269
+ this.subQueries[alias] = subQuery.toString();
270
+ }
273
271
  return this;
274
272
  }
275
273
  where(cond, params, operator) {
@@ -291,7 +289,7 @@ class QueryBuilder {
291
289
  metadata: this.metadata,
292
290
  platform: this.platform,
293
291
  aliasMap: this.getAliasMap(),
294
- aliased: !this.type || [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
292
+ aliased: [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
295
293
  convertCustomTypes: this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES),
296
294
  });
297
295
  }
@@ -336,7 +334,7 @@ class QueryBuilder {
336
334
  metadata: this.metadata,
337
335
  platform: this.platform,
338
336
  aliasMap: this.getAliasMap(),
339
- aliased: !this.type || [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
337
+ aliased: [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
340
338
  convertCustomTypes: false,
341
339
  type: 'orderBy',
342
340
  });
@@ -375,7 +373,7 @@ class QueryBuilder {
375
373
  this.ensureNotFinalized();
376
374
  this._onConflict ??= [];
377
375
  this._onConflict.push({
378
- fields: core_1.Utils.isRawSql(fields)
376
+ fields: (0, core_1.isRaw)(fields)
379
377
  ? fields
380
378
  : core_1.Utils.asArray(fields).flatMap(f => {
381
379
  const key = f.toString();
@@ -506,38 +504,33 @@ class QueryBuilder {
506
504
  }
507
505
  return this;
508
506
  }
509
- getKnexQuery(processVirtualEntity = true) {
507
+ getNativeQuery(processVirtualEntity = true) {
510
508
  if (this._query?.qb) {
511
509
  return this._query.qb;
512
510
  }
513
511
  this._query = {};
514
512
  this.finalize();
515
513
  const qb = this.getQueryBase(processVirtualEntity);
516
- const type = this.type ?? enums_1.QueryType.SELECT;
517
- qb.__raw = true; // tag it as there is now way to check via `instanceof`
518
- core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(type, this._cond, qb), this._cond && !this._onConflict);
514
+ core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._cond, qb), this._cond && !this._onConflict);
519
515
  core_1.Utils.runIfNotEmpty(() => qb.groupBy(this.prepareFields(this._groupBy, 'groupBy')), this._groupBy);
520
- core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(type, this._having, qb, undefined, 'having'), this._having);
516
+ core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._having, qb, undefined, 'having'), this._having);
521
517
  core_1.Utils.runIfNotEmpty(() => {
522
- const queryOrder = this.helper.getQueryOrder(type, this._orderBy, this._populateMap);
518
+ const queryOrder = this.helper.getQueryOrder(this.type, this._orderBy, this._populateMap);
523
519
  if (queryOrder.length > 0) {
524
520
  const sql = core_1.Utils.unique(queryOrder).join(', ');
525
- qb.orderByRaw(sql);
521
+ qb.orderBy(sql);
526
522
  return;
527
523
  }
528
524
  }, this._orderBy);
529
525
  core_1.Utils.runIfNotEmpty(() => qb.limit(this._limit), this._limit != null);
530
526
  core_1.Utils.runIfNotEmpty(() => qb.offset(this._offset), this._offset);
531
- core_1.Utils.runIfNotEmpty(() => this._comments.forEach(comment => qb.comment(comment)), this._comments);
532
- core_1.Utils.runIfNotEmpty(() => this._hintComments.forEach(comment => qb.hintComment(comment)), this._hintComments);
527
+ core_1.Utils.runIfNotEmpty(() => qb.comment(this._comments), this._comments);
528
+ core_1.Utils.runIfNotEmpty(() => qb.hintComment(this._hintComments), this._hintComments);
533
529
  core_1.Utils.runIfNotEmpty(() => this.helper.appendOnConflictClause(enums_1.QueryType.UPSERT, this._onConflict, qb), this._onConflict);
534
- if (this.type === enums_1.QueryType.TRUNCATE && this.platform.usesCascadeStatement()) {
535
- return this._query.qb = this.knex.raw(qb.toSQL().toNative().sql + ' cascade');
536
- }
537
530
  if (this.lockMode) {
538
531
  this.helper.getLockSQL(qb, this.lockMode, this.lockTables);
539
532
  }
540
- this.helper.finalize(type, qb, this.mainAlias.metadata, this._data, this._returning);
533
+ this.helper.finalize(this.type, qb, this.mainAlias.metadata, this._data, this._returning);
541
534
  this.clearRawFragmentsCache();
542
535
  return this._query.qb = qb;
543
536
  }
@@ -554,16 +547,21 @@ class QueryBuilder {
554
547
  getQuery() {
555
548
  return this.toQuery().sql;
556
549
  }
550
+ /**
551
+ * Returns raw fragment representation of this QueryBuilder.
552
+ */
553
+ toRaw() {
554
+ const { sql, params } = this.toQuery();
555
+ return (0, core_1.raw)(sql, params);
556
+ }
557
557
  toQuery() {
558
558
  if (this._query?.sql) {
559
- return { sql: this._query.sql, _sql: this._query._sql, params: this._query.params };
559
+ return { sql: this._query.sql, params: this._query.params };
560
560
  }
561
- const sql = this.getKnexQuery().toSQL();
562
- const query = sql.toNative();
561
+ const query = this.getNativeQuery().compile();
563
562
  this._query.sql = query.sql;
564
- this._query._sql = sql;
565
- this._query.params = query.bindings ?? [];
566
- return { sql: this._query.sql, _sql: this._query._sql, params: this._query.params };
563
+ this._query.params = query.params;
564
+ return { sql: this._query.sql, params: this._query.params };
567
565
  }
568
566
  /**
569
567
  * Returns the list of all parameters for this query.
@@ -575,8 +573,8 @@ class QueryBuilder {
575
573
  * Returns raw interpolated query string with all the parameters inlined.
576
574
  */
577
575
  getFormattedQuery() {
578
- const query = this.toQuery()._sql;
579
- return this.platform.formatQuery(query.sql, query.bindings);
576
+ const query = this.toQuery();
577
+ return this.platform.formatQuery(query.sql, query.params);
580
578
  }
581
579
  /**
582
580
  * @internal
@@ -642,7 +640,7 @@ class QueryBuilder {
642
640
  options = typeof options === 'boolean' ? { mapResults: options } : (options ?? {});
643
641
  options.mergeResults ??= true;
644
642
  options.mapResults ??= true;
645
- const isRunType = [enums_1.QueryType.INSERT, enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE, enums_1.QueryType.TRUNCATE].includes(this.type ?? enums_1.QueryType.SELECT);
643
+ const isRunType = [enums_1.QueryType.INSERT, enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE, enums_1.QueryType.TRUNCATE].includes(this.type);
646
644
  method ??= isRunType ? 'run' : 'all';
647
645
  if (!this.connectionType && isRunType) {
648
646
  this.connectionType = 'write';
@@ -650,15 +648,15 @@ class QueryBuilder {
650
648
  if (!this.finalized && method === 'get' && this.type === enums_1.QueryType.SELECT) {
651
649
  this.limit(1);
652
650
  }
653
- const query = this.toQuery()._sql;
654
- const cached = await this.em?.tryCache(this.mainAlias.entityName, this._cache, ['qb.execute', query.sql, query.bindings, method]);
651
+ const query = this.toQuery();
652
+ const cached = await this.em?.tryCache(this.mainAlias.entityName, this._cache, ['qb.execute', query.sql, query.params, method]);
655
653
  if (cached?.data) {
656
654
  return cached.data;
657
655
  }
658
656
  const write = method === 'run' || !this.platform.getConfig().get('preferReadReplicas');
659
657
  const type = this.connectionType || (write ? 'write' : 'read');
660
658
  const loggerContext = { id: this.em?.id, ...this.loggerContext };
661
- const res = await this.driver.getConnection(type).execute(query.sql, query.bindings, method, this.context, loggerContext);
659
+ const res = await this.driver.getConnection(type).execute(query.sql, query.params, method, this.context, loggerContext);
662
660
  const meta = this.mainAlias.metadata;
663
661
  if (!options.mapResults || !meta) {
664
662
  await this.em?.storeCache(this._cache, cached, res);
@@ -742,7 +740,7 @@ class QueryBuilder {
742
740
  res = await this.execute('get', false);
743
741
  }
744
742
  else {
745
- const qb = this.type === undefined ? this : this.clone();
743
+ const qb = this._type === undefined ? this : this.clone();
746
744
  qb.processPopulateHint(); // needs to happen sooner so `qb.hasToManyJoins()` reports correctly
747
745
  qb.count(field, distinct ?? qb.hasToManyJoins()).limit(undefined).offset(undefined).orderBy([]);
748
746
  res = await qb.execute('get', false);
@@ -762,7 +760,7 @@ class QueryBuilder {
762
760
  * Provides promise-like interface so we can await the QB instance.
763
761
  */
764
762
  then(onfulfilled, onrejected) {
765
- let type = this.type ?? enums_1.QueryType.SELECT;
763
+ let type = this.type;
766
764
  if (this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(core_1.QueryFlag.DELETE_SUB_QUERY)) {
767
765
  type = enums_1.QueryType.UPDATE;
768
766
  }
@@ -779,21 +777,21 @@ class QueryBuilder {
779
777
  }
780
778
  }
781
779
  /**
782
- * Returns knex instance with sub-query aliased with given alias.
780
+ * Returns native query builder instance with sub-query aliased with given alias.
783
781
  * You can provide `EntityName.propName` as alias, then the field name will be used based on the metadata
784
782
  */
785
783
  as(alias) {
786
- const qb = this.getKnexQuery();
784
+ const qb = this.getNativeQuery();
787
785
  if (alias.includes('.')) {
788
786
  const [a, f] = alias.split('.');
789
787
  const meta = this.metadata.find(a);
790
788
  /* istanbul ignore next */
791
789
  alias = meta?.properties[f]?.fieldNames[0] ?? alias;
792
790
  }
793
- const ret = qb.as(alias);
791
+ qb.as(alias);
794
792
  // tag the instance, so it is possible to detect it easily
795
- Object.defineProperty(ret, '__as', { enumerable: false, value: alias });
796
- return ret;
793
+ Object.defineProperty(qb, '__as', { enumerable: false, value: alias });
794
+ return qb;
797
795
  }
798
796
  clone(reset) {
799
797
  const qb = new QueryBuilder(this.mainAlias.entityName, this.metadata, this.driver, this.context, this.mainAlias.aliasName, this.connectionType, this.em);
@@ -809,7 +807,7 @@ class QueryBuilder {
809
807
  ];
810
808
  core_1.RawQueryFragment.cloneRegistry = this.rawFragments;
811
809
  for (const prop of Object.keys(this)) {
812
- if (reset.includes(prop) || prop === '_helper') {
810
+ if (reset.includes(prop) || ['_helper', '_query'].includes(prop)) {
813
811
  continue;
814
812
  }
815
813
  qb[prop] = properties.includes(prop) ? core_1.Utils.copy(this[prop]) : this[prop];
@@ -824,28 +822,6 @@ class QueryBuilder {
824
822
  qb.finalized = false;
825
823
  return qb;
826
824
  }
827
- getKnex(processVirtualEntity = true) {
828
- const qb = this.knex.queryBuilder();
829
- const { subQuery, aliasName, entityName, metadata } = this.mainAlias;
830
- const ref = subQuery ? subQuery : this.knex.ref(this.helper.getTableName(entityName));
831
- if (this.finalized && (this._explicitAlias || this.helper.isTableNameAliasRequired(this.type))) {
832
- ref.as(aliasName);
833
- }
834
- const schema = this.getSchema(this.mainAlias);
835
- if (schema && schema !== this.platform.getDefaultSchemaName()) {
836
- ref.withSchema(schema);
837
- }
838
- if (metadata?.virtual && processVirtualEntity) {
839
- qb.fromRaw(this.fromVirtual(metadata));
840
- }
841
- else {
842
- qb.from(ref);
843
- }
844
- if (this.context) {
845
- qb.transacting(this.context);
846
- }
847
- return qb;
848
- }
849
825
  /**
850
826
  * Sets logger context for this query builder.
851
827
  */
@@ -870,9 +846,8 @@ class QueryBuilder {
870
846
  if (res instanceof QueryBuilder) {
871
847
  return `(${res.getFormattedQuery()}) as ${this.platform.quoteIdentifier(this.alias)}`;
872
848
  }
873
- if (core_1.Utils.isObject(res)) {
874
- const { sql, bindings } = res.toSQL();
875
- const query = this.platform.formatQuery(sql, bindings);
849
+ if (res instanceof core_1.RawQueryFragment) {
850
+ const query = this.platform.formatQuery(res.sql, res.params);
876
851
  return `(${query}) as ${this.platform.quoteIdentifier(this.alias)}`;
877
852
  }
878
853
  /* istanbul ignore next */
@@ -888,7 +863,10 @@ class QueryBuilder {
888
863
  if (field instanceof QueryBuilder) {
889
864
  prop.type = field.mainAlias.entityName;
890
865
  prop.targetMeta = field.mainAlias.metadata;
891
- field = field.getKnexQuery();
866
+ field = field.getNativeQuery();
867
+ }
868
+ if (field instanceof core_1.RawQueryFragment) {
869
+ field = this.platform.formatQuery(field.sql, field.params);
892
870
  }
893
871
  this._joins[`${this.alias}.${prop.name}#${alias}`] = {
894
872
  prop,
@@ -922,7 +900,7 @@ class QueryBuilder {
922
900
  metadata: this.metadata,
923
901
  platform: this.platform,
924
902
  aliasMap: this.getAliasMap(),
925
- aliased: !this.type || [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
903
+ aliased: [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
926
904
  });
927
905
  let aliasedName = `${fromAlias}.${prop.name}#${alias}`;
928
906
  path ??= `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? entityName)}.${prop.name}`;
@@ -954,16 +932,12 @@ class QueryBuilder {
954
932
  prepareFields(fields, type = 'where') {
955
933
  const ret = [];
956
934
  const getFieldName = (name) => {
957
- if (type === 'groupBy') {
958
- return this.helper.mapper(name, this.type, undefined, null);
959
- }
960
- return this.helper.mapper(name, this.type);
935
+ return this.helper.mapper(name, this.type, undefined, type === 'groupBy' ? null : undefined);
961
936
  };
962
937
  fields.forEach(field => {
963
- const rawField = core_1.RawQueryFragment.getKnownFragment(field);
938
+ const rawField = core_1.RawQueryFragment.getKnownFragment(field, false);
964
939
  if (rawField) {
965
- const sql = this.platform.formatQuery(rawField.sql, rawField.params);
966
- ret.push(this.knex.raw(sql));
940
+ ret.push(rawField);
967
941
  return;
968
942
  }
969
943
  if (!core_1.Utils.isString(field)) {
@@ -972,7 +946,7 @@ class QueryBuilder {
972
946
  }
973
947
  const join = Object.keys(this._joins).find(k => field === k.substring(0, k.indexOf('#')));
974
948
  if (join && type === 'where') {
975
- ret.push(...this.helper.mapJoinColumns(this.type ?? enums_1.QueryType.SELECT, this._joins[join]));
949
+ ret.push(...this.helper.mapJoinColumns(this.type, this._joins[join]));
976
950
  return;
977
951
  }
978
952
  const [a, f] = this.helper.splitField(field);
@@ -1020,7 +994,7 @@ class QueryBuilder {
1020
994
  }
1021
995
  for (const f of Object.keys(this._populateMap)) {
1022
996
  if (type === 'where' && this._joins[f]) {
1023
- const cols = this.helper.mapJoinColumns(this.type ?? enums_1.QueryType.SELECT, this._joins[f]);
997
+ const cols = this.helper.mapJoinColumns(this.type, this._joins[f]);
1024
998
  for (const col of cols) {
1025
999
  ret.push(col);
1026
1000
  }
@@ -1030,7 +1004,7 @@ class QueryBuilder {
1030
1004
  }
1031
1005
  init(type, data, cond) {
1032
1006
  this.ensureNotFinalized();
1033
- this.type = type;
1007
+ this._type = type;
1034
1008
  if ([enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE].includes(type) && core_1.Utils.hasObjectKeys(this._cond)) {
1035
1009
  throw new Error(`You are trying to call \`qb.where().${type.toLowerCase()}()\`. Calling \`qb.${type.toLowerCase()}()\` before \`qb.where()\` is required.`);
1036
1010
  }
@@ -1049,18 +1023,22 @@ class QueryBuilder {
1049
1023
  return this;
1050
1024
  }
1051
1025
  getQueryBase(processVirtualEntity) {
1052
- const qb = this.getKnex(processVirtualEntity);
1026
+ const qb = this.platform.createNativeQueryBuilder().setFlags(this.flags);
1027
+ const { subQuery, aliasName, entityName, metadata } = this.mainAlias;
1028
+ const requiresAlias = this.finalized && (this._explicitAlias || this.helper.isTableNameAliasRequired(this.type));
1029
+ const alias = requiresAlias ? aliasName : undefined;
1053
1030
  const schema = this.getSchema(this.mainAlias);
1054
- // Joined tables doesn't need to belong to the same schema as the main table
1031
+ const tableName = subQuery ? subQuery.as(aliasName) : this.helper.getTableName(entityName);
1055
1032
  const joinSchema = this._schema ?? this.em?.schema ?? schema;
1056
- if (schema && schema !== this.platform.getDefaultSchemaName()) {
1057
- qb.withSchema(schema);
1033
+ if (metadata?.virtual && processVirtualEntity) {
1034
+ qb.from((0, core_1.raw)(this.fromVirtual(metadata)), { indexHint: this._indexHint });
1058
1035
  }
1059
- if (this._indexHint) {
1060
- const alias = this.helper.isTableNameAliasRequired(this.type) ? ` as ${this.platform.quoteIdentifier(this.mainAlias.aliasName)}` : '';
1061
- const schemaQuoted = schema ? this.platform.quoteIdentifier(schema) + '.' : '';
1062
- const tableName = schemaQuoted + this.platform.quoteIdentifier(this.helper.getTableName(this.mainAlias.entityName)) + alias;
1063
- qb.from(this.knex.raw(`${tableName} ${this._indexHint}`));
1036
+ else {
1037
+ qb.from(tableName, {
1038
+ schema,
1039
+ alias,
1040
+ indexHint: this._indexHint,
1041
+ });
1064
1042
  }
1065
1043
  switch (this.type) {
1066
1044
  case enums_1.QueryType.SELECT:
@@ -1074,8 +1052,8 @@ class QueryBuilder {
1074
1052
  this.helper.processJoins(qb, this._joins, joinSchema);
1075
1053
  break;
1076
1054
  case enums_1.QueryType.COUNT: {
1077
- const m = this.flags.has(core_1.QueryFlag.DISTINCT) ? 'countDistinct' : 'count';
1078
- qb[m]({ count: this._fields.map(f => this.helper.mapper(f, this.type)) });
1055
+ const fields = this._fields.map(f => this.helper.mapper(f, this.type));
1056
+ qb.count(fields, this.flags.has(core_1.QueryFlag.DISTINCT));
1079
1057
  this.helper.processJoins(qb, this._joins, joinSchema);
1080
1058
  break;
1081
1059
  }
@@ -1118,7 +1096,7 @@ class QueryBuilder {
1118
1096
  if (this.finalized) {
1119
1097
  return;
1120
1098
  }
1121
- if (!this.type) {
1099
+ if (!this._type) {
1122
1100
  this.select('*');
1123
1101
  }
1124
1102
  const meta = this.mainAlias.metadata;
@@ -1128,8 +1106,8 @@ class QueryBuilder {
1128
1106
  meta.props
1129
1107
  .filter(prop => prop.formula && (!prop.lazy || this.flags.has(core_1.QueryFlag.INCLUDE_LAZY_FORMULAS)))
1130
1108
  .map(prop => {
1131
- const alias = this.knex.ref(this.mainAlias.aliasName).toString();
1132
- const aliased = this.knex.ref(prop.fieldNames[0]).toString();
1109
+ const alias = this.platform.quoteIdentifier(this.mainAlias.aliasName);
1110
+ const aliased = this.platform.quoteIdentifier(prop.fieldNames[0]);
1133
1111
  return `${prop.formula(alias)} as ${aliased}`;
1134
1112
  })
1135
1113
  .filter(field => !this._fields.some(f => {
@@ -1280,14 +1258,15 @@ class QueryBuilder {
1280
1258
  if (!prop?.persist && !prop?.formula && !prop?.hasConvertToJSValueSQL && !pks.includes(fieldName)) {
1281
1259
  addToSelect.push(fieldName);
1282
1260
  }
1283
- const key = (0, core_1.raw)(`min(${this.knex.ref(fieldName)}${type})`);
1261
+ const quoted = this.platform.quoteIdentifier(fieldName);
1262
+ const key = (0, core_1.raw)(`min(${quoted}${type})`);
1284
1263
  orderBy.push({ [key]: direction });
1285
1264
  }
1286
1265
  }
1287
1266
  subQuery.orderBy(orderBy);
1288
1267
  }
1289
1268
  subQuery.finalized = true;
1290
- const knexQuery = subQuery.as(this.mainAlias.aliasName).clearSelect().select(pks);
1269
+ const innerQuery = subQuery.as(this.mainAlias.aliasName).clear('select').select(pks);
1291
1270
  if (addToSelect.length > 0) {
1292
1271
  addToSelect.forEach(prop => {
1293
1272
  const field = this._fields.find(field => {
@@ -1302,24 +1281,29 @@ class QueryBuilder {
1302
1281
  });
1303
1282
  /* istanbul ignore next */
1304
1283
  if (field instanceof core_1.RawQueryFragment) {
1305
- const sql = this.platform.formatQuery(field.sql, field.params);
1306
- knexQuery.select(this.knex.raw(sql));
1284
+ innerQuery.select(field);
1285
+ }
1286
+ else if (field instanceof NativeQueryBuilder_1.NativeQueryBuilder) {
1287
+ innerQuery.select(field.toRaw());
1307
1288
  }
1308
1289
  else if (field) {
1309
- knexQuery.select(field);
1290
+ innerQuery.select(field);
1310
1291
  }
1311
1292
  });
1312
1293
  }
1313
1294
  // multiple sub-queries are needed to get around mysql limitations with order by + limit + where in + group by (o.O)
1314
1295
  // https://stackoverflow.com/questions/17892762/mysql-this-version-of-mysql-doesnt-yet-support-limit-in-all-any-some-subqu
1315
- const subSubQuery = this.getKnex().select(pks).from(knexQuery);
1316
- subSubQuery.__raw = true; // tag it as there is now way to check via `instanceof`
1296
+ const subSubQuery = this.platform.createNativeQueryBuilder();
1297
+ subSubQuery.select(pks).from(innerQuery);
1317
1298
  this._limit = undefined;
1318
1299
  this._offset = undefined;
1319
- if (this._fields.some(f => core_1.RawQueryFragment.isKnownFragment(f))) {
1320
- this.select(this._fields).where({ [core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: subSubQuery } });
1321
- return;
1300
+ if (!this._fields.some(f => core_1.RawQueryFragment.isKnownFragment(f))) {
1301
+ this.pruneExtraJoins(meta);
1322
1302
  }
1303
+ const { sql, params } = subSubQuery.compile();
1304
+ this.select(this._fields).where({ [core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: (0, core_1.raw)(sql, params) } });
1305
+ }
1306
+ pruneExtraJoins(meta) {
1323
1307
  // remove joins that are not used for population or ordering to improve performance
1324
1308
  const populate = new Set();
1325
1309
  const orderByAliases = this._orderBy
@@ -1353,26 +1337,31 @@ class QueryBuilder {
1353
1337
  delete this._joins[key];
1354
1338
  }
1355
1339
  }
1356
- this.select(this._fields).where({ [core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: subSubQuery } });
1357
1340
  }
1358
1341
  wrapModifySubQuery(meta) {
1359
1342
  const subQuery = this.clone();
1360
1343
  subQuery.finalized = true;
1361
1344
  // wrap one more time to get around MySQL limitations
1362
1345
  // https://stackoverflow.com/questions/45494/mysql-error-1093-cant-specify-target-table-for-update-in-from-clause
1363
- const subSubQuery = this.getKnex().select(this.prepareFields(meta.primaryKeys)).from(subQuery.as(this.mainAlias.aliasName));
1364
- subSubQuery.__raw = true; // tag it as there is now way to check via `instanceof`
1346
+ const subSubQuery = this.platform.createNativeQueryBuilder();
1365
1347
  const method = this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) ? 'update' : 'delete';
1348
+ const pks = this.prepareFields(meta.primaryKeys, 'sub-query');
1366
1349
  this._cond = {}; // otherwise we would trigger validation error
1367
1350
  this._joins = {}; // included in the subquery
1351
+ subSubQuery.select(pks).from(subQuery.as(this.mainAlias.aliasName));
1352
+ const { sql, params } = subSubQuery.compile();
1368
1353
  this[method](this._data).where({
1369
- [core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: subSubQuery },
1354
+ [core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: (0, core_1.raw)(sql, params) },
1370
1355
  });
1371
1356
  }
1372
1357
  getSchema(alias) {
1373
1358
  const { metadata } = alias;
1374
1359
  const metaSchema = metadata?.schema && metadata.schema !== '*' ? metadata.schema : undefined;
1375
- return this._schema ?? metaSchema ?? this.em?.schema ?? this.em?.config.getSchema(true);
1360
+ const schema = this._schema ?? metaSchema ?? this.em?.schema ?? this.em?.config.getSchema(true);
1361
+ if (schema === this.platform.getDefaultSchemaName()) {
1362
+ return undefined;
1363
+ }
1364
+ return schema;
1376
1365
  }
1377
1366
  createAlias(entityName, aliasName, subQuery) {
1378
1367
  const metadata = this.metadata.find(entityName);
@@ -1386,7 +1375,7 @@ class QueryBuilder {
1386
1375
  return this._mainAlias;
1387
1376
  }
1388
1377
  fromSubQuery(target, aliasName) {
1389
- const subQuery = target.getKnexQuery();
1378
+ const subQuery = target.getNativeQuery();
1390
1379
  const { entityName } = target.mainAlias;
1391
1380
  aliasName ??= this.getNextAlias(entityName);
1392
1381
  this.createMainAlias(entityName, aliasName, subQuery);
@@ -1396,7 +1385,7 @@ class QueryBuilder {
1396
1385
  this.createMainAlias(entityName, aliasName);
1397
1386
  }
1398
1387
  createQueryBuilderHelper() {
1399
- return new QueryBuilderHelper_1.QueryBuilderHelper(this.mainAlias.entityName, this.mainAlias.aliasName, this._aliases, this.subQueries, this.knex, this.driver);
1388
+ return new QueryBuilderHelper_1.QueryBuilderHelper(this.mainAlias.entityName, this.mainAlias.aliasName, this._aliases, this.subQueries, this.driver);
1400
1389
  }
1401
1390
  ensureFromClause() {
1402
1391
  /* istanbul ignore next */
@@ -1413,7 +1402,7 @@ class QueryBuilder {
1413
1402
  /** @ignore */
1414
1403
  [node_util_1.inspect.custom](depth = 2) {
1415
1404
  const object = { ...this };
1416
- const hidden = ['metadata', 'driver', 'context', 'platform', 'knex', 'type'];
1405
+ const hidden = ['metadata', 'driver', 'context', 'platform', 'type'];
1417
1406
  Object.keys(object).filter(k => k.startsWith('_')).forEach(k => delete object[k]);
1418
1407
  Object.keys(object).filter(k => object[k] == null).forEach(k => delete object[k]);
1419
1408
  hidden.forEach(k => delete object[k]);