@mikro-orm/knex 6.3.13-dev.8 → 6.3.13

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.
@@ -55,7 +55,8 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
55
55
  protected getFieldsForJoinedLoad<T extends object>(qb: QueryBuilder<T, any, any, any>, meta: EntityMetadata<T>, explicitFields?: Field<T>[], exclude?: Field<T>[], populate?: PopulateOptions<T>[], options?: {
56
56
  strategy?: Options['loadStrategy'];
57
57
  populateWhere?: FindOptions<any>['populateWhere'];
58
- }, parentTableAlias?: string, parentJoinPath?: string): Field<T>[];
58
+ populateFilter?: FindOptions<any>['populateFilter'];
59
+ }, parentTableAlias?: string, parentJoinPath?: string, count?: boolean): Field<T>[];
59
60
  /**
60
61
  * @internal
61
62
  */
@@ -76,5 +77,5 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
76
77
  protected normalizeFields<T extends object>(fields: Field<T>[], prefix?: string): string[];
77
78
  protected processField<T extends object>(meta: EntityMetadata<T>, prop: EntityProperty<T> | undefined, field: string, ret: Field<T>[], populate: PopulateOptions<T>[], joinedProps: PopulateOptions<T>[], qb: QueryBuilder<T, any, any, any>): void;
78
79
  protected isPopulated<T extends object>(meta: EntityMetadata<T>, prop: EntityProperty<T>, hint: PopulateOptions<T>, name?: string): boolean;
79
- 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'>, count?: boolean): Field<T>[];
80
81
  }
@@ -311,15 +311,21 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
311
311
  if (meta?.virtual) {
312
312
  return this.countVirtual(entityName, where, options);
313
313
  }
314
+ const joinedProps = meta ? this.joinedProps(meta, options.populate ?? []) : [];
315
+ const populateWhere = meta ? this.buildPopulateWhere(meta, joinedProps, options) : undefined;
316
+ const populate = options.populate ?? [];
314
317
  const qb = this.createQueryBuilder(entityName, options.ctx, options.connectionType, false, options.logging)
315
318
  .indexHint(options.indexHint)
316
319
  .comment(options.comments)
317
320
  .hintComment(options.hintComments)
318
321
  .groupBy(options.groupBy)
319
322
  .having(options.having)
320
- .populate(options.populate ?? [])
323
+ .populate(populate, joinedProps.length > 0 ? populateWhere : undefined, joinedProps.length > 0 ? options.populateFilter : undefined)
321
324
  .withSchema(this.getSchemaName(meta, options))
322
325
  .where(where);
326
+ if (meta && !core_1.Utils.isEmpty(populate)) {
327
+ this.buildFields(meta, populate, joinedProps, qb, qb.alias, options, true);
328
+ }
323
329
  return this.rethrow(qb.getCount());
324
330
  }
325
331
  async nativeInsert(entityName, data, options = {}) {
@@ -909,7 +915,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
909
915
  }
910
916
  return res;
911
917
  }
912
- getFieldsForJoinedLoad(qb, meta, explicitFields, exclude, populate = [], options, parentTableAlias, parentJoinPath) {
918
+ getFieldsForJoinedLoad(qb, meta, explicitFields, exclude, populate = [], options, parentTableAlias, parentJoinPath, count) {
913
919
  const fields = [];
914
920
  const joinedProps = this.joinedProps(meta, populate, options);
915
921
  const shouldHaveColumn = (prop, populate, fields) => {
@@ -929,12 +935,15 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
929
935
  .filter(prop => shouldHaveColumn(prop, populate, explicitFields))
930
936
  .forEach(prop => fields.push(...this.mapPropToFieldNames(qb, prop, parentTableAlias)));
931
937
  }
932
- joinedProps.forEach(hint => {
938
+ for (const hint of joinedProps) {
933
939
  const [propName, ref] = hint.field.split(':', 2);
934
940
  const prop = meta.properties[propName];
935
941
  // ignore ref joins of known FKs unless it's a filter hint
936
942
  if (ref && !hint.filter && (prop.kind === core_1.ReferenceKind.MANY_TO_ONE || (prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner))) {
937
- return;
943
+ continue;
944
+ }
945
+ if (count && (!options?.populateFilter || !options.populateFilter[prop.name])) {
946
+ continue;
938
947
  }
939
948
  const meta2 = this.metadata.find(prop.type);
940
949
  const pivotRefJoin = prop.kind === core_1.ReferenceKind.MANY_TO_MANY && ref;
@@ -954,7 +963,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
954
963
  fields.push(...prop.joinColumns.map(col => qb.helper.mapper(`${tableAlias}.${col}`, qb.type, undefined, `${tableAlias}__${col}`)), ...prop.inverseJoinColumns.map(col => qb.helper.mapper(`${tableAlias}.${col}`, qb.type, undefined, `${tableAlias}__${col}`)));
955
964
  }
956
965
  if (prop.kind === core_1.ReferenceKind.ONE_TO_MANY && ref) {
957
- fields.push(...this.getFieldsForJoinedLoad(qb, meta2, prop.referencedColumnNames, undefined, hint.children, options, tableAlias, path));
966
+ fields.push(...this.getFieldsForJoinedLoad(qb, meta2, prop.referencedColumnNames, undefined, hint.children, options, tableAlias, path, count));
958
967
  }
959
968
  const childExplicitFields = explicitFields?.filter(f => core_1.Utils.isPlainObject(f)).map(o => o[prop.name])[0] || [];
960
969
  explicitFields?.forEach(f => {
@@ -964,12 +973,12 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
964
973
  });
965
974
  const childExclude = exclude ? core_1.Utils.extractChildElements(exclude, prop.name) : exclude;
966
975
  if (!ref) {
967
- fields.push(...this.getFieldsForJoinedLoad(qb, meta2, childExplicitFields.length === 0 ? undefined : childExplicitFields, childExclude, hint.children, options, tableAlias, path));
976
+ fields.push(...this.getFieldsForJoinedLoad(qb, meta2, childExplicitFields.length === 0 ? undefined : childExplicitFields, childExclude, hint.children, options, tableAlias, path, count));
968
977
  }
969
978
  else if (hint.filter) {
970
979
  fields.push(...prop.referencedColumnNames.map(col => qb.helper.mapper(`${tableAlias}.${col}`, qb.type, undefined, `${tableAlias}__${col}`)));
971
980
  }
972
- });
981
+ }
973
982
  return fields;
974
983
  }
975
984
  /**
@@ -1232,7 +1241,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
1232
1241
  }
1233
1242
  return false;
1234
1243
  }
1235
- buildFields(meta, populate, joinedProps, qb, alias, options) {
1244
+ buildFields(meta, populate, joinedProps, qb, alias, options, count = false) {
1236
1245
  const lazyProps = meta.props.filter(prop => prop.lazy && !populate.some(p => this.isPopulated(meta, prop, p)));
1237
1246
  const hasLazyFormulas = meta.props.some(p => p.lazy && p.formula);
1238
1247
  const requiresSQLConversion = meta.props.some(p => p.customType?.convertToJSValueSQL && p.persist !== false);
@@ -1287,7 +1296,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
1287
1296
  }
1288
1297
  // add joined relations after the root entity fields
1289
1298
  if (joinedProps.length > 0) {
1290
- ret.push(...this.getFieldsForJoinedLoad(qb, meta, options.fields, options.exclude, populate, options, alias));
1299
+ ret.push(...this.getFieldsForJoinedLoad(qb, meta, options.fields, options.exclude, populate, options, alias, undefined, count));
1291
1300
  }
1292
1301
  return core_1.Utils.unique(ret);
1293
1302
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/knex",
3
- "version": "6.3.13-dev.8",
3
+ "version": "6.3.13",
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.3.12"
66
+ "@mikro-orm/core": "^6.3.13"
67
67
  },
68
68
  "peerDependencies": {
69
- "@mikro-orm/core": "6.3.13-dev.8",
69
+ "@mikro-orm/core": "^6.0.0",
70
70
  "better-sqlite3": "*",
71
71
  "libsql": "*",
72
72
  "mariadb": "*"
@@ -31,6 +31,7 @@ type EntityRelations<T> = EntityKey<T, true>;
31
31
  type AddAliasesFromContext<Context> = Context[keyof Context] extends infer Join ? Join extends any ? Join extends [string, infer Alias, infer Type, any] ? `${Alias & string}.${EntityRelations<Type & {}>}` : never : never : never;
32
32
  export type QBField<Entity, RootAlias extends string, Context> = (EntityRelations<Entity> | `${RootAlias}.${EntityRelations<Entity>}` | AddAliasesFromContext<Context>) & {} | AnyString;
33
33
  export type QBField2<Entity, RootAlias extends string, Context> = (EntityKey<Entity> | `${RootAlias}.${EntityKey<Entity>}` | AddAliasesFromContext<Context>) & {} | AnyString;
34
+ type EntityKeyOrString<Entity extends object = AnyEntity> = AnyString | keyof Entity;
34
35
  /**
35
36
  * SQL query builder with fluent interface.
36
37
  *
@@ -125,12 +126,12 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
125
126
  addSelect(fields: Field<Entity> | Field<Entity>[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
126
127
  distinct(): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
127
128
  /** postgres only */
128
- distinctOn(fields: string | string[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
129
+ distinctOn(fields: EntityKeyOrString<Entity> | EntityKeyOrString<Entity>[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
129
130
  insert(data: RequiredEntityData<Entity> | RequiredEntityData<Entity>[]): InsertQueryBuilder<Entity>;
130
131
  update(data: EntityData<Entity>): UpdateQueryBuilder<Entity>;
131
132
  delete(cond?: QBFilterQuery): DeleteQueryBuilder<Entity>;
132
133
  truncate(): TruncateQueryBuilder<Entity>;
133
- count(field?: string | string[], distinct?: boolean): CountQueryBuilder<Entity>;
134
+ count(field?: EntityKeyOrString<Entity> | EntityKeyOrString<Entity>[], distinct?: boolean): CountQueryBuilder<Entity>;
134
135
  join<Field extends QBField<Entity, RootAlias, Context>, Alias extends string>(field: Field | Knex.QueryBuilder | QueryBuilder<any>, alias: Alias, cond?: QBFilterQuery, type?: JoinType, path?: string, schema?: string): SelectQueryBuilder<Entity, RootAlias, ModifyHint<RootAlias, Context, Hint, Field> & {}, ModifyContext<Entity, Context, Field, Alias>>;
135
136
  innerJoin<Field extends QBField<Entity, RootAlias, Context>, Alias extends string>(field: Field | Knex.QueryBuilder | QueryBuilder<any>, alias: Alias, cond?: QBFilterQuery, schema?: string): SelectQueryBuilder<Entity, RootAlias, ModifyHint<RootAlias, Context, Hint, Field> & {}, ModifyContext<Entity, Context, Field, Alias>>;
136
137
  innerJoinLateral(field: Knex.QueryBuilder | QueryBuilder<any>, alias: string, cond?: QBFilterQuery, schema?: string): this;
@@ -154,7 +155,7 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
154
155
  orWhere(cond: QBFilterQuery<Entity>): this;
155
156
  orWhere(cond: string, params?: any[]): this;
156
157
  orderBy(orderBy: QBQueryOrderMap<Entity> | QBQueryOrderMap<Entity>[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
157
- groupBy(fields: (string | keyof Entity) | readonly (string | keyof Entity)[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
158
+ groupBy(fields: EntityKeyOrString<Entity> | readonly EntityKeyOrString<Entity>[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
158
159
  having(cond?: QBFilterQuery | string, params?: any[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
159
160
  onConflict(fields?: Field<Entity> | Field<Entity>[]): InsertQueryBuilder<Entity>;
160
161
  ignore(): this;
@@ -251,7 +252,7 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
251
252
  /**
252
253
  * Executes count query (without offset and limit), returning total count of results
253
254
  */
254
- getCount(field?: string | string[], distinct?: boolean): Promise<number>;
255
+ getCount(field?: EntityKeyOrString<Entity> | EntityKeyOrString<Entity>[], distinct?: boolean): Promise<number>;
255
256
  /**
256
257
  * Executes the query, returning both array of results and total count query (without offset and limit).
257
258
  */
@@ -1172,7 +1172,6 @@ class QueryBuilder {
1172
1172
  let joins = Object.values(this._joins);
1173
1173
  for (const join of joins) {
1174
1174
  join.cond_ ??= join.cond;
1175
- // join.cond = {};
1176
1175
  join.cond = filter ? { ...join.cond } : {};
1177
1176
  }
1178
1177
  if (typeof this[key] === 'object') {
@@ -1335,6 +1334,7 @@ class QueryBuilder {
1335
1334
  // wrap one more time to get around MySQL limitations
1336
1335
  // https://stackoverflow.com/questions/45494/mysql-error-1093-cant-specify-target-table-for-update-in-from-clause
1337
1336
  const subSubQuery = this.getKnex().select(this.prepareFields(meta.primaryKeys)).from(subQuery.as(this.mainAlias.aliasName));
1337
+ subSubQuery.__raw = true; // tag it as there is now way to check via `instanceof`
1338
1338
  const method = this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) ? 'update' : 'delete';
1339
1339
  this._cond = {}; // otherwise we would trigger validation error
1340
1340
  this[method](this._data).where({
@@ -390,7 +390,7 @@ class SchemaComparator {
390
390
  const toProp = this.mapColumnToProperty({ ...toColumn, autoincrement: false });
391
391
  const fromColumnType = this.platform.normalizeColumnType(fromColumn.mappedType.getColumnType(fromProp, this.platform).toLowerCase(), fromProp);
392
392
  const fromNativeEnum = fromTable.nativeEnums[fromColumnType] ?? Object.values(fromTable.nativeEnums).find(e => e.name === fromColumnType && e.schema !== '*');
393
- const toColumnType = this.platform.normalizeColumnType(toColumn.mappedType.getColumnType(toProp, this.platform).toLowerCase(), toProp);
393
+ let toColumnType = this.platform.normalizeColumnType(toColumn.mappedType.getColumnType(toProp, this.platform).toLowerCase(), toProp);
394
394
  const log = (msg, params) => {
395
395
  if (tableName) {
396
396
  const copy = core_1.Utils.copy(params);
@@ -402,8 +402,13 @@ class SchemaComparator {
402
402
  (!fromNativeEnum || `${fromNativeEnum.schema}.${fromNativeEnum.name}` !== toColumnType) &&
403
403
  !(fromColumn.ignoreSchemaChanges?.includes('type') || toColumn.ignoreSchemaChanges?.includes('type')) &&
404
404
  !fromColumn.generated && !toColumn.generated) {
405
- log(`'type' changed for column ${tableName}.${fromColumn.name}`, { fromColumnType, toColumnType });
406
- changedProperties.add('type');
405
+ if (!toColumnType.includes('.') && fromTable.schema && fromTable.schema !== this.platform.getDefaultSchemaName()) {
406
+ toColumnType = `${fromTable.schema}.${toColumnType}`;
407
+ }
408
+ if (fromColumnType !== toColumnType) {
409
+ log(`'type' changed for column ${tableName}.${fromColumn.name}`, { fromColumnType, toColumnType });
410
+ changedProperties.add('type');
411
+ }
407
412
  }
408
413
  if (fromColumn.nullable !== toColumn.nullable && !fromColumn.generated && !toColumn.generated) {
409
414
  log(`'nullable' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
@@ -284,7 +284,9 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
284
284
  if (!column.nativeEnumName) {
285
285
  continue;
286
286
  }
287
- const key = schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' + column.nativeEnumName : column.nativeEnumName;
287
+ const key = schemaName && schemaName !== this.platform.getDefaultSchemaName() && !column.nativeEnumName.includes('.')
288
+ ? schemaName + '.' + column.nativeEnumName
289
+ : column.nativeEnumName;
288
290
  if (changedProperties.has('enumItems') && key in diff.fromTable.nativeEnums) {
289
291
  changedNativeEnums.push([column.nativeEnumName, column.enumItems, diff.fromTable.nativeEnums[key].items]);
290
292
  }
@@ -293,6 +295,11 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
293
295
  // postgres allows only adding new items, the values are case insensitive
294
296
  itemsOld = itemsOld.map(v => v.toLowerCase());
295
297
  const newItems = itemsNew.filter(val => !itemsOld.includes(val.toLowerCase()));
298
+ if (enumName.includes('.')) {
299
+ const [enumSchemaName, rawEnumName] = enumName.split('.');
300
+ ret.push(...newItems.map(val => this.knex.schema.raw(this.helper.getAlterNativeEnumSQL(rawEnumName, enumSchemaName, val, itemsNew, itemsOld))));
301
+ return;
302
+ }
296
303
  ret.push(...newItems.map(val => this.knex.schema.raw(this.helper.getAlterNativeEnumSQL(enumName, schemaName, val, itemsNew, itemsOld))));
297
304
  });
298
305
  }