@mikro-orm/knex 6.6.5-dev.5 → 6.6.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.
@@ -61,7 +61,7 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
61
61
  /**
62
62
  * @internal
63
63
  */
64
- mapPropToFieldNames<T extends object>(qb: QueryBuilder<T, any, any, any>, prop: EntityProperty<T>, tableAlias?: string, explicitFields?: Field<T>[]): Field<T>[];
64
+ mapPropToFieldNames<T extends object>(qb: QueryBuilder<T, any, any, any>, prop: EntityProperty<T>, tableAlias: string | undefined, meta: EntityMetadata<T>, schema?: string, explicitFields?: readonly Field<T>[]): Field<T>[];
65
65
  /** @internal */
66
66
  createQueryBuilder<T extends object>(entityName: EntityName<T> | QueryBuilder<T, any, any, any>, ctx?: Transaction<Knex.Transaction>, preferredConnectionType?: ConnectionType, convertCustomTypes?: boolean, loggerContext?: LoggingOptions, alias?: string, em?: SqlEntityManager): QueryBuilder<T, any, any, any>;
67
67
  protected resolveConnectionType(args: {
@@ -77,5 +77,5 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
77
77
  protected buildJoinedPropsOrderBy<T extends object>(qb: QueryBuilder<T, any, any, any>, meta: EntityMetadata<T>, populate: PopulateOptions<T>[], options?: Pick<FindOptions<any>, 'strategy' | 'orderBy' | 'populateOrderBy'>, parentPath?: string): QueryOrderMap<T>[];
78
78
  protected normalizeFields<T extends object>(fields: Field<T>[], prefix?: string): string[];
79
79
  protected processField<T extends object>(meta: EntityMetadata<T>, prop: EntityProperty<T> | undefined, field: string, ret: Field<T>[]): void;
80
- protected buildFields<T extends object>(meta: EntityMetadata<T>, populate: PopulateOptions<T>[], joinedProps: PopulateOptions<T>[], qb: QueryBuilder<T, any, any, any>, alias: string, options: Pick<FindOptions<T, any, any, any>, 'strategy' | 'fields' | 'exclude'>): Field<T>[];
80
+ protected buildFields<T extends object>(meta: EntityMetadata<T>, populate: PopulateOptions<T>[], joinedProps: PopulateOptions<T>[], qb: QueryBuilder<T, any, any, any>, alias: string, options: Pick<FindOptions<T, any, any, any>, 'strategy' | 'fields' | 'exclude'>, schema?: string): Field<T>[];
81
81
  }
@@ -31,9 +31,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
31
31
  }
32
32
  const populate = this.autoJoinOneToOneOwner(meta, options.populate, options.fields);
33
33
  const joinedProps = this.joinedProps(meta, populate, options);
34
+ const schema = this.getSchemaName(meta, options);
34
35
  const qb = this.createQueryBuilder(entityName, options.ctx, options.connectionType, false, options.logging)
35
- .withSchema(this.getSchemaName(meta, options));
36
- const fields = this.buildFields(meta, populate, joinedProps, qb, qb.alias, options);
36
+ .withSchema(schema);
37
+ const fields = this.buildFields(meta, populate, joinedProps, qb, qb.alias, options, schema);
37
38
  const orderBy = this.buildOrderBy(qb, meta, populate, options);
38
39
  const populateWhere = this.buildPopulateWhere(meta, joinedProps, options);
39
40
  core_1.Utils.asArray(options.flags).forEach(flag => qb.setFlag(flag));
@@ -320,10 +321,11 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
320
321
  options = { populate: [], ...options };
321
322
  const populate = options.populate;
322
323
  const joinedProps = this.joinedProps(meta, populate, options);
324
+ const schema = this.getSchemaName(meta, options);
323
325
  const qb = this.createQueryBuilder(entityName, options.ctx, options.connectionType, false, options.logging);
324
326
  const populateWhere = this.buildPopulateWhere(meta, joinedProps, options);
325
327
  if (meta && !core_1.Utils.isEmpty(populate)) {
326
- this.buildFields(meta, populate, joinedProps, qb, qb.alias, options);
328
+ this.buildFields(meta, populate, joinedProps, qb, qb.alias, options, schema);
327
329
  }
328
330
  qb.__populateWhere = options._populateWhere;
329
331
  qb.indexHint(options.indexHint)
@@ -332,7 +334,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
332
334
  .groupBy(options.groupBy)
333
335
  .having(options.having)
334
336
  .populate(populate, joinedProps.length > 0 ? populateWhere : undefined, joinedProps.length > 0 ? options.populateFilter : undefined)
335
- .withSchema(this.getSchemaName(meta, options))
337
+ .withSchema(schema)
336
338
  .where(where);
337
339
  if (options.em) {
338
340
  await qb.applyJoinedFilters(options.em, options.filters);
@@ -952,7 +954,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
952
954
  // alias all fields in the primary table
953
955
  meta.props
954
956
  .filter(prop => this.shouldHaveColumn(meta, prop, populate, explicitFields, exclude))
955
- .forEach(prop => fields.push(...this.mapPropToFieldNames(qb, prop, parentTableAlias, explicitFields)));
957
+ .forEach(prop => fields.push(...this.mapPropToFieldNames(qb, prop, parentTableAlias, meta, undefined, explicitFields)));
956
958
  }
957
959
  for (const hint of joinedProps) {
958
960
  const [propName, ref] = hint.field.split(':', 2);
@@ -1003,14 +1005,14 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
1003
1005
  /**
1004
1006
  * @internal
1005
1007
  */
1006
- mapPropToFieldNames(qb, prop, tableAlias, explicitFields) {
1008
+ mapPropToFieldNames(qb, prop, tableAlias, meta, schema, explicitFields) {
1007
1009
  if (prop.kind === core_1.ReferenceKind.EMBEDDED && !prop.object) {
1008
1010
  return Object.entries(prop.embeddedProps).flatMap(([name, childProp]) => {
1009
1011
  const childFields = explicitFields ? core_1.Utils.extractChildElements(explicitFields, prop.name) : [];
1010
1012
  if (!this.shouldHaveColumn(prop.targetMeta, { ...childProp, name }, [], childFields.length > 0 ? childFields : undefined)) {
1011
1013
  return [];
1012
1014
  }
1013
- return this.mapPropToFieldNames(qb, childProp, tableAlias, childFields);
1015
+ return this.mapPropToFieldNames(qb, childProp, tableAlias, meta, schema, childFields);
1014
1016
  });
1015
1017
  }
1016
1018
  const aliased = this.platform.quoteIdentifier(tableAlias ? `${tableAlias}__${prop.fieldNames[0]}` : prop.fieldNames[0]);
@@ -1030,7 +1032,17 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
1030
1032
  }
1031
1033
  if (prop.formula) {
1032
1034
  const alias = this.platform.quoteIdentifier(tableAlias ?? qb.alias);
1033
- return [(0, core_1.raw)(`${prop.formula(alias)} as ${aliased}`)];
1035
+ const effectiveSchema = schema ?? (meta.schema !== '*' ? meta.schema : undefined);
1036
+ const qualifiedName = effectiveSchema ? `${effectiveSchema}.${meta.tableName}` : meta.tableName;
1037
+ const table = {
1038
+ alias: alias.toString(),
1039
+ name: meta.tableName,
1040
+ schema: effectiveSchema,
1041
+ qualifiedName,
1042
+ toString: () => alias.toString(),
1043
+ };
1044
+ const columns = meta.createColumnMappingObject();
1045
+ return [(0, core_1.raw)(`${(prop.formula(table, columns))} as ${aliased}`)];
1034
1046
  }
1035
1047
  if (tableAlias) {
1036
1048
  return prop.fieldNames.map(fieldName => {
@@ -1260,7 +1272,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
1260
1272
  }
1261
1273
  ret.push(prop.name);
1262
1274
  }
1263
- buildFields(meta, populate, joinedProps, qb, alias, options) {
1275
+ buildFields(meta, populate, joinedProps, qb, alias, options, schema) {
1264
1276
  const lazyProps = meta.props.filter(prop => prop.lazy && !populate.some(p => this.isPopulated(meta, prop, p)));
1265
1277
  const hasLazyFormulas = meta.props.some(p => p.lazy && p.formula);
1266
1278
  const requiresSQLConversion = meta.props.some(p => p.customType?.convertToJSValueSQL && p.persist !== false);
@@ -1305,6 +1317,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
1305
1317
  ret.push('*');
1306
1318
  }
1307
1319
  if (ret.length > 0 && !hasExplicitFields && addFormulas) {
1320
+ const columns = meta.createColumnMappingObject();
1321
+ const effectiveSchema = schema ?? (meta.schema !== '*' ? meta.schema : undefined);
1308
1322
  for (const prop of meta.props) {
1309
1323
  if (lazyProps.includes(prop)) {
1310
1324
  continue;
@@ -1312,7 +1326,15 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
1312
1326
  if (prop.formula) {
1313
1327
  const a = this.platform.quoteIdentifier(alias);
1314
1328
  const aliased = this.platform.quoteIdentifier(prop.fieldNames[0]);
1315
- ret.push((0, core_1.raw)(`${prop.formula(a)} as ${aliased}`));
1329
+ const qualifiedName = effectiveSchema ? `${effectiveSchema}.${meta.tableName}` : meta.tableName;
1330
+ const table = {
1331
+ alias: a.toString(),
1332
+ name: meta.tableName,
1333
+ schema: effectiveSchema,
1334
+ qualifiedName,
1335
+ toString: () => a.toString(),
1336
+ };
1337
+ ret.push((0, core_1.raw)(`${(prop.formula(table, columns))} as ${aliased}`));
1316
1338
  }
1317
1339
  if (!prop.object && (prop.hasConvertToDatabaseValueSQL || prop.hasConvertToJSValueSQL)) {
1318
1340
  ret.push(prop.name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/knex",
3
- "version": "6.6.5-dev.5",
3
+ "version": "6.6.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",
@@ -63,10 +63,10 @@
63
63
  "sqlstring": "2.3.3"
64
64
  },
65
65
  "devDependencies": {
66
- "@mikro-orm/core": "^6.6.4"
66
+ "@mikro-orm/core": "^6.6.5"
67
67
  },
68
68
  "peerDependencies": {
69
- "@mikro-orm/core": "6.6.5-dev.5",
69
+ "@mikro-orm/core": "^6.0.0",
70
70
  "better-sqlite3": "*",
71
71
  "libsql": "*",
72
72
  "mariadb": "*"
@@ -222,6 +222,8 @@ class QueryBuilder {
222
222
  const fields = [];
223
223
  const populate = [];
224
224
  const joinKey = Object.keys(this._joins).find(join => join.endsWith(`#${alias}`));
225
+ const targetMeta = prop.targetMeta;
226
+ const schema = this._schema ?? (targetMeta.schema !== '*' ? targetMeta.schema : undefined);
225
227
  if (joinKey) {
226
228
  const path = this._joins[joinKey].path.split('.').slice(1);
227
229
  let children = this._populate;
@@ -234,29 +236,29 @@ class QueryBuilder {
234
236
  }
235
237
  populate.push(...children);
236
238
  }
237
- for (const p of prop.targetMeta.getPrimaryProps()) {
238
- fields.push(...this.driver.mapPropToFieldNames(this, p, alias));
239
+ for (const p of targetMeta.getPrimaryProps()) {
240
+ fields.push(...this.driver.mapPropToFieldNames(this, p, alias, targetMeta, schema));
239
241
  }
240
242
  if (explicitFields) {
241
243
  for (const field of explicitFields) {
242
244
  const [a, f] = this.helper.splitField(field);
243
- const p = prop.targetMeta.properties[f];
245
+ const p = targetMeta.properties[f];
244
246
  if (p) {
245
- fields.push(...this.driver.mapPropToFieldNames(this, p, alias));
247
+ fields.push(...this.driver.mapPropToFieldNames(this, p, alias, targetMeta, schema));
246
248
  }
247
249
  else {
248
250
  fields.push(`${a}.${f} as ${a}__${f}`);
249
251
  }
250
252
  }
251
253
  }
252
- prop.targetMeta.props
254
+ targetMeta.props
253
255
  .filter(prop => {
254
256
  if (!explicitFields) {
255
257
  return this.platform.shouldHaveColumn(prop, populate);
256
258
  }
257
259
  return prop.primary && !explicitFields.includes(prop.name) && !explicitFields.includes(`${alias}.${prop.name}`);
258
260
  })
259
- .forEach(prop => fields.push(...this.driver.mapPropToFieldNames(this, prop, alias)));
261
+ .forEach(prop => fields.push(...this.driver.mapPropToFieldNames(this, prop, alias, targetMeta, schema)));
260
262
  return fields;
261
263
  }
262
264
  /**
@@ -1164,12 +1166,15 @@ class QueryBuilder {
1164
1166
  this.processPopulateHint();
1165
1167
  this.processNestedJoins();
1166
1168
  if (meta && (this._fields?.includes('*') || this._fields?.includes(`${this.mainAlias.aliasName}.*`))) {
1169
+ const schema = this.getSchema(this.mainAlias);
1170
+ const columns = meta.createColumnMappingObject();
1167
1171
  meta.props
1168
1172
  .filter(prop => prop.formula && (!prop.lazy || this.flags.has(core_1.QueryFlag.INCLUDE_LAZY_FORMULAS)))
1169
1173
  .map(prop => {
1170
- const alias = this.knex.ref(this.mainAlias.aliasName).toString();
1171
- const aliased = this.knex.ref(prop.fieldNames[0]).toString();
1172
- return `${prop.formula(alias)} as ${aliased}`;
1174
+ const alias = this.platform.quoteIdentifier(this.mainAlias.aliasName);
1175
+ const aliased = this.platform.quoteIdentifier(prop.fieldNames[0]);
1176
+ const table = this.helper.createFormulaTable(alias.toString(), meta, schema);
1177
+ return `${(prop.formula(table, columns))} as ${aliased}`;
1173
1178
  })
1174
1179
  .filter(field => !this._fields.some(f => {
1175
1180
  if (f instanceof core_1.RawQueryFragment) {
@@ -1,5 +1,5 @@
1
1
  import type { Knex } from 'knex';
2
- import { type Dictionary, type EntityData, type EntityKey, type EntityMetadata, type EntityProperty, type FlatQueryOrderMap, LockMode, type QBFilterQuery, RawQueryFragment } from '@mikro-orm/core';
2
+ import { type Dictionary, type EntityData, type EntityKey, type EntityMetadata, type EntityProperty, type FlatQueryOrderMap, type FormulaTable, LockMode, type QBFilterQuery, RawQueryFragment } from '@mikro-orm/core';
3
3
  import { JoinType, QueryType } from './enums';
4
4
  import type { Field, JoinOptions } from '../typings';
5
5
  import type { AbstractSqlDriver } from '../AbstractSqlDriver';
@@ -17,7 +17,7 @@ export declare class QueryBuilderHelper {
17
17
  private readonly metadata;
18
18
  constructor(entityName: string, alias: string, aliasMap: Dictionary<Alias<any>>, subQueries: Dictionary<string>, knex: Knex, driver: AbstractSqlDriver);
19
19
  mapper(field: string | Knex.Raw, type?: QueryType): string;
20
- mapper(field: string | Knex.Raw, type?: QueryType, value?: any, alias?: string | null): string;
20
+ mapper(field: string | Knex.Raw, type?: QueryType, value?: any, alias?: string | null, schema?: string): string;
21
21
  processData(data: Dictionary, convertCustomTypes: boolean, multi?: boolean): any;
22
22
  joinOneToReference(prop: EntityProperty, ownerAlias: string, alias: string, type: JoinType, cond?: Dictionary, schema?: string): JoinOptions;
23
23
  joinManyToOneReference(prop: EntityProperty, ownerAlias: string, alias: string, type: JoinType, cond?: Dictionary, schema?: string): JoinOptions;
@@ -60,6 +60,7 @@ export declare class QueryBuilderHelper {
60
60
  getProperty(field: string, alias?: string): EntityProperty | undefined;
61
61
  isTableNameAliasRequired(type?: QueryType): boolean;
62
62
  processOnConflictCondition(cond: QBFilterQuery, schema?: string): QBFilterQuery;
63
+ createFormulaTable(alias: string, meta: EntityMetadata, schema?: string): FormulaTable;
63
64
  }
64
65
  export interface Alias<T> {
65
66
  aliasName: string;
@@ -26,7 +26,7 @@ class QueryBuilderHelper {
26
26
  this.platform = this.driver.getPlatform();
27
27
  this.metadata = this.driver.getMetadata();
28
28
  }
29
- mapper(field, type = enums_1.QueryType.SELECT, value, alias) {
29
+ mapper(field, type = enums_1.QueryType.SELECT, value, alias, schema) {
30
30
  if (core_1.Utils.isRawSql(field)) {
31
31
  return this.knex.raw(field.sql, field.params);
32
32
  }
@@ -87,7 +87,10 @@ class QueryBuilderHelper {
87
87
  const alias2 = this.knex.ref(a).toString();
88
88
  const aliased = this.knex.ref(prop.fieldNames[0]).toString();
89
89
  const as = alias === null ? '' : ` as ${aliased}`;
90
- let value = prop.formula(alias2);
90
+ const meta = this.aliasMap[a]?.metadata ?? this.metadata.get(this.entityName);
91
+ const table = this.createFormulaTable(alias2, meta, schema);
92
+ const columns = meta.createColumnMappingObject();
93
+ let value = prop.formula(table, columns);
91
94
  if (!this.isTableNameAliasRequired(type)) {
92
95
  value = value.replaceAll(alias2 + '.', '');
93
96
  }
@@ -208,7 +211,10 @@ class QueryBuilderHelper {
208
211
  const right = `${join.alias}.${join.joinColumns[idx]}`;
209
212
  if (join.prop.formula) {
210
213
  const alias = this.platform.quoteIdentifier(join.ownerAlias);
211
- const left = join.prop.formula(alias);
214
+ const ownerMeta = this.aliasMap[join.ownerAlias]?.metadata ?? this.metadata.get(this.entityName);
215
+ const table = this.createFormulaTable(alias.toString(), ownerMeta, schema);
216
+ const columns = ownerMeta.createColumnMappingObject();
217
+ const left = join.prop.formula(table, columns);
212
218
  conditions.push(`${left} = ${this.knex.ref(right)}`);
213
219
  return;
214
220
  }
@@ -770,5 +776,16 @@ class QueryBuilderHelper {
770
776
  }
771
777
  return cond;
772
778
  }
779
+ createFormulaTable(alias, meta, schema) {
780
+ const effectiveSchema = schema ?? (meta.schema !== '*' ? meta.schema : undefined);
781
+ const qualifiedName = effectiveSchema ? `${effectiveSchema}.${meta.tableName}` : meta.tableName;
782
+ return {
783
+ alias,
784
+ name: meta.tableName,
785
+ schema: effectiveSchema,
786
+ qualifiedName,
787
+ toString: () => alias,
788
+ };
789
+ }
773
790
  }
774
791
  exports.QueryBuilderHelper = QueryBuilderHelper;