@mikro-orm/knex 6.0.3-dev.4 → 6.0.3-dev.5

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.
@@ -699,6 +699,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
699
699
  for (const field of targetFields) {
700
700
  const f = field.toString();
701
701
  fields.unshift(f.includes('.') ? field : `${targetAlias}.${f}`);
702
+ if (core_1.RawQueryFragment.isKnownFragment(field)) {
703
+ qb.rawFragments.add(f);
704
+ }
702
705
  }
703
706
  // we need to handle 1:1 owner auto-joins explicitly, as the QB type is the pivot table, not the target
704
707
  populate.forEach(hint => {
@@ -722,6 +725,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
722
725
  }
723
726
  const res = owners.length ? await this.rethrow(qb.execute('all', { mergeResults: false, mapResults: false })) : [];
724
727
  const items = res.map((row) => super.mapResult(row, prop.targetMeta));
728
+ qb.clearRawFragmentsCache();
725
729
  const map = {};
726
730
  const pkProps = ownerMeta.getPrimaryProps();
727
731
  owners.forEach(owner => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/knex",
3
- "version": "6.0.3-dev.4",
3
+ "version": "6.0.3-dev.5",
4
4
  "description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
@@ -66,6 +66,6 @@
66
66
  "@mikro-orm/core": "^6.0.2"
67
67
  },
68
68
  "peerDependencies": {
69
- "@mikro-orm/core": "6.0.3-dev.4"
69
+ "@mikro-orm/core": "6.0.3-dev.5"
70
70
  }
71
71
  }
@@ -54,6 +54,8 @@ export declare class QueryBuilder<T extends object = AnyEntity> {
54
54
  __populateWhere?: ObjectQuery<T> | PopulateHint | `${PopulateHint}`;
55
55
  /** @internal */
56
56
  _populateMap: Dictionary<string>;
57
+ /** @internal */
58
+ readonly rawFragments: Set<string>;
57
59
  private aliasCounter;
58
60
  private flags;
59
61
  private finalized;
@@ -157,6 +159,10 @@ export declare class QueryBuilder<T extends object = AnyEntity> {
157
159
  from<T extends AnyEntity<T> = AnyEntity>(target: QueryBuilder<T>, aliasName?: string): SelectQueryBuilder<T>;
158
160
  from<T extends AnyEntity<T> = AnyEntity>(target: EntityName<T>): SelectQueryBuilder<T>;
159
161
  getKnexQuery(processVirtualEntity?: boolean): Knex.QueryBuilder;
162
+ /**
163
+ * @internal
164
+ */
165
+ clearRawFragmentsCache(): void;
160
166
  /**
161
167
  * Returns the query with parameters as wildcards.
162
168
  */
@@ -224,7 +230,7 @@ export declare class QueryBuilder<T extends object = AnyEntity> {
224
230
  * You can provide `EntityName.propName` as alias, then the field name will be used based on the metadata
225
231
  */
226
232
  as(alias: string): Knex.QueryBuilder;
227
- clone(reset?: boolean): QueryBuilder<T>;
233
+ clone(reset?: boolean | string[]): QueryBuilder<T>;
228
234
  getKnex(processVirtualEntity?: boolean): Knex.QueryBuilder;
229
235
  private fromVirtual;
230
236
  private joinReference;
@@ -55,6 +55,8 @@ class QueryBuilder {
55
55
  __populateWhere;
56
56
  /** @internal */
57
57
  _populateMap = {};
58
+ /** @internal */
59
+ rawFragments = new Set();
58
60
  aliasCounter = 0;
59
61
  flags = new Set([core_1.QueryFlag.CONVERT_CUSTOM_TYPES]);
60
62
  finalized = false;
@@ -484,8 +486,16 @@ class QueryBuilder {
484
486
  this.helper.getLockSQL(qb, this.lockMode, this.lockTables);
485
487
  }
486
488
  this.helper.finalize(type, qb, this.mainAlias.metadata, this._data, this._returning);
489
+ this.clearRawFragmentsCache();
487
490
  return qb;
488
491
  }
492
+ /**
493
+ * @internal
494
+ */
495
+ clearRawFragmentsCache() {
496
+ this.rawFragments.forEach(key => core_1.RawQueryFragment.remove(key));
497
+ this.rawFragments.clear();
498
+ }
489
499
  /**
490
500
  * Returns the query with parameters as wildcards.
491
501
  */
@@ -719,19 +729,26 @@ class QueryBuilder {
719
729
  }
720
730
  clone(reset) {
721
731
  const qb = new QueryBuilder(this.mainAlias.entityName, this.metadata, this.driver, this.context, this.mainAlias.aliasName, this.connectionType, this.em);
722
- if (reset) {
732
+ if (reset === true) {
723
733
  return qb;
724
734
  }
725
- Object.assign(qb, this);
735
+ reset = reset || [];
726
736
  // clone array/object properties
727
737
  const properties = [
728
738
  'flags', '_populate', '_populateWhere', '__populateWhere', '_populateMap', '_joins', '_joinedProps', '_cond', '_data', '_orderBy',
729
739
  '_schema', '_indexHint', '_cache', 'subQueries', 'lockMode', 'lockTables', '_groupBy', '_having', '_returning',
730
- '_comments', '_hintComments',
740
+ '_comments', '_hintComments', 'rawFragments',
731
741
  ];
732
- properties.forEach(prop => qb[prop] = core_1.Utils.copy(this[prop]));
742
+ core_1.RawQueryFragment.cloneRegistry = this.rawFragments;
743
+ for (const prop of Object.keys(this)) {
744
+ if (reset.includes(prop)) {
745
+ continue;
746
+ }
747
+ qb[prop] = properties.includes(prop) ? core_1.Utils.copy(this[prop]) : this[prop];
748
+ }
749
+ delete core_1.RawQueryFragment.cloneRegistry;
733
750
  /* istanbul ignore else */
734
- if (this._fields) {
751
+ if (this._fields && !reset.includes('_fields')) {
735
752
  qb._fields = [...this._fields];
736
753
  }
737
754
  qb._aliases = { ...this._aliases };
@@ -1120,7 +1137,7 @@ class QueryBuilder {
1120
1137
  }
1121
1138
  wrapPaginateSubQuery(meta) {
1122
1139
  const pks = this.prepareFields(meta.primaryKeys, 'sub-query');
1123
- const subQuery = this.clone().select(pks).groupBy(pks).limit(this._limit);
1140
+ const subQuery = this.clone(['_orderBy', '_fields']).select(pks).groupBy(pks).limit(this._limit);
1124
1141
  // revert the on conditions added via populateWhere, we want to apply those only once
1125
1142
  Object.values(subQuery._joins).forEach(join => join.cond = join.cond_ ?? {});
1126
1143
  if (this._offset) {
@@ -1131,6 +1148,12 @@ class QueryBuilder {
1131
1148
  const orderBy = [];
1132
1149
  for (const orderMap of this._orderBy) {
1133
1150
  for (const [field, direction] of Object.entries(orderMap)) {
1151
+ if (core_1.RawQueryFragment.isKnownFragment(field)) {
1152
+ const rawField = core_1.RawQueryFragment.getKnownFragment(field, false);
1153
+ this.rawFragments.add(field);
1154
+ orderBy.push({ [rawField.clone()]: direction });
1155
+ continue;
1156
+ }
1134
1157
  const [a, f] = this.helper.splitField(field);
1135
1158
  const prop = this.helper.getProperty(f, a);
1136
1159
  const type = this.platform.castColumn(prop);
@@ -1138,7 +1161,8 @@ class QueryBuilder {
1138
1161
  if (!prop?.persist && !prop?.formula) {
1139
1162
  addToSelect.push(fieldName);
1140
1163
  }
1141
- orderBy.push({ [(0, core_1.raw)(`min(${this.knex.ref(fieldName)}${type})`)]: direction });
1164
+ const key = (0, core_1.raw)(`min(${this.knex.ref(fieldName)}${type})`);
1165
+ orderBy.push({ [key]: direction });
1142
1166
  }
1143
1167
  }
1144
1168
  subQuery.orderBy(orderBy);
@@ -1151,10 +1175,17 @@ class QueryBuilder {
1151
1175
  if (typeof field === 'object' && field && '__as' in field) {
1152
1176
  return field.__as === prop;
1153
1177
  }
1178
+ if (field instanceof core_1.RawQueryFragment) {
1179
+ // not perfect, but should work most of the time, ideally we should check only the alias (`... as alias`)
1180
+ return field.sql.includes(prop);
1181
+ }
1154
1182
  // not perfect, but should work most of the time, ideally we should check only the alias (`... as alias`)
1155
1183
  return field.toString().includes(prop);
1156
1184
  });
1157
- if (field) {
1185
+ if (field instanceof core_1.RawQueryFragment) {
1186
+ knexQuery.select(this.platform.formatQuery(field.sql, field.params));
1187
+ }
1188
+ else if (field) {
1158
1189
  knexQuery.select(field);
1159
1190
  }
1160
1191
  });
@@ -1241,6 +1272,9 @@ class QueryBuilder {
1241
1272
  prefix = 'Upsert';
1242
1273
  object.onConflict = this._onConflict[0];
1243
1274
  }
1275
+ if (!core_1.Utils.isEmpty(this._orderBy)) {
1276
+ object.orderBy = this._orderBy;
1277
+ }
1244
1278
  const name = this._mainAlias ? `${prefix}QueryBuilder<${this._mainAlias?.entityName}>` : 'QueryBuilder';
1245
1279
  const ret = (0, util_1.inspect)(object, { depth });
1246
1280
  return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;