@mikro-orm/core 7.0.3-dev.9 → 7.0.4-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.
package/EntityManager.js CHANGED
@@ -405,8 +405,22 @@ export class EntityManager {
405
405
  continue;
406
406
  }
407
407
  options = { ...options, filters: QueryHelper.mergePropertyFilters(prop.filters, options.filters) };
408
- const cond = await this.applyFilters(prop.targetMeta.class, {}, options.filters, 'read', options);
409
- if (!Utils.isEmpty(cond)) {
408
+ // For polymorphic relations, check all targets for filters (not just the first targetMeta)
409
+ let hasActiveFilter = false;
410
+ if (prop.polymorphic && prop.polymorphTargets?.length) {
411
+ for (const targetMeta of prop.polymorphTargets) {
412
+ const cond = await this.applyFilters(targetMeta.class, {}, options.filters, 'read', options);
413
+ if (!Utils.isEmpty(cond)) {
414
+ hasActiveFilter = true;
415
+ break;
416
+ }
417
+ }
418
+ }
419
+ else {
420
+ const cond = await this.applyFilters(prop.targetMeta.class, {}, options.filters, 'read', options);
421
+ hasActiveFilter = !Utils.isEmpty(cond);
422
+ }
423
+ if (hasActiveFilter) {
410
424
  const populated = options.populate.filter(({ field }) => field.split(':')[0] === prop.name);
411
425
  let found = false;
412
426
  for (const hint of populated) {
package/README.md CHANGED
@@ -64,7 +64,7 @@ export class Book extends BookSchema.class {}
64
64
  BookSchema.setClass(Book);
65
65
  ```
66
66
 
67
- You can also define entities using [decorators](https://mikro-orm.io/docs/defining-entities) or [`EntitySchema`](https://mikro-orm.io/docs/entity-schema). See the [defining entities guide](https://mikro-orm.io/docs/defining-entities) for all options.
67
+ You can also define entities using [decorators](https://mikro-orm.io/docs/using-decorators) or [`EntitySchema`](https://mikro-orm.io/docs/define-entity#entityschema-low-level-api). See the [defining entities guide](https://mikro-orm.io/docs/defining-entities) for all options.
68
68
 
69
69
  ### Initialize and Use
70
70
 
@@ -12,7 +12,7 @@ import type { Collection } from './Collection.js';
12
12
  import type { FilterOptions } from '../drivers/IDatabaseDriver.js';
13
13
  /** Union of all option keys supported across all property definition types (scalar, enum, embedded, relations). */
14
14
  export type UniversalPropertyKeys = keyof PropertyOptions<any> | keyof EnumOptions<any> | keyof EmbeddedOptions<any, any> | keyof ReferenceOptions<any, any> | keyof ManyToOneOptions<any, any> | keyof OneToManyOptions<any, any> | keyof OneToOneOptions<any, any> | keyof ManyToManyOptions<any, any>;
15
- type BuilderExtraKeys = '~options' | '~type' | '$type';
15
+ type BuilderExtraKeys = '~options' | '~type' | '$type' | 'strictNullable';
16
16
  type ExcludeKeys = 'entity' | 'items';
17
17
  type BuilderKeys = Exclude<UniversalPropertyKeys, ExcludeKeys> | BuilderExtraKeys;
18
18
  type IncludeKeysForProperty = Exclude<keyof PropertyOptions<any>, ExcludeKeys> | BuilderExtraKeys;
@@ -32,6 +32,10 @@ export interface PropertyChain<Value, Options> {
32
32
  nullable(): PropertyChain<Value, Omit<Options, 'nullable'> & {
33
33
  nullable: true;
34
34
  }>;
35
+ strictNullable(): PropertyChain<Value, Omit<Options, 'nullable' | 'strictNullable'> & {
36
+ nullable: true;
37
+ strictNullable: true;
38
+ }>;
35
39
  ref(): PropertyChain<Value, Omit<Options, 'ref'> & {
36
40
  ref: true;
37
41
  }>;
@@ -281,6 +285,14 @@ export declare class UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys
281
285
  nullable(): Pick<UniversalPropertyOptionsBuilder<Value, Omit<Options, 'nullable'> & {
282
286
  nullable: true;
283
287
  }, IncludeKeys>, IncludeKeys>;
288
+ /**
289
+ * Set column as nullable without adding `| undefined` to the type.
290
+ * Use this when the property is always explicitly set (e.g. in constructor) but can be `null`.
291
+ */
292
+ strictNullable(): Pick<UniversalPropertyOptionsBuilder<Value, Omit<Options, 'nullable' | 'strictNullable'> & {
293
+ nullable: true;
294
+ strictNullable: true;
295
+ }, IncludeKeys>, IncludeKeys>;
284
296
  /**
285
297
  * Set column as unsigned for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}. (SQL only)
286
298
  */
@@ -566,26 +578,26 @@ export interface EntityMetadataWithProperties<TName extends string, TTableName e
566
578
  concurrencyCheckKeys?: Set<AllKeys<TProperties, TBase>>;
567
579
  serializedPrimaryKey?: AllKeys<TProperties, TBase>;
568
580
  indexes?: {
569
- properties?: keyof TProperties | (keyof TProperties)[];
581
+ properties?: NoInfer<AllKeys<TProperties, TBase>> | NoInfer<AllKeys<TProperties, TBase>>[];
570
582
  name?: string;
571
583
  type?: string;
572
584
  options?: Dictionary;
573
585
  expression?: string | IndexCallback<InferEntityFromProperties<TProperties, TPK, TBase>>;
574
586
  columns?: IndexColumnOptions[];
575
- include?: keyof TProperties | (keyof TProperties)[];
587
+ include?: NoInfer<AllKeys<TProperties, TBase>> | NoInfer<AllKeys<TProperties, TBase>>[];
576
588
  fillFactor?: number;
577
589
  invisible?: boolean;
578
590
  disabled?: boolean;
579
591
  clustered?: boolean;
580
592
  }[];
581
593
  uniques?: {
582
- properties?: keyof TProperties | (keyof TProperties)[];
594
+ properties?: NoInfer<AllKeys<TProperties, TBase>> | NoInfer<AllKeys<TProperties, TBase>>[];
583
595
  name?: string;
584
596
  options?: Dictionary;
585
597
  expression?: string | IndexCallback<InferEntityFromProperties<TProperties, TPK, TBase>>;
586
598
  deferMode?: DeferMode | `${DeferMode}`;
587
599
  columns?: IndexColumnOptions[];
588
- include?: keyof TProperties | (keyof TProperties)[];
600
+ include?: NoInfer<AllKeys<TProperties, TBase>> | NoInfer<AllKeys<TProperties, TBase>>[];
589
601
  fillFactor?: number;
590
602
  disabled?: boolean;
591
603
  }[];
@@ -673,7 +685,9 @@ type MaybeMapToPk<Value, Options> = Options extends {
673
685
  } ? Primary<Value> : Value;
674
686
  type MaybeNullable<Value, Options> = Options extends {
675
687
  nullable: true;
676
- } ? Value | null | undefined : Value;
688
+ } ? Options extends {
689
+ strictNullable: true;
690
+ } ? Value | null : Value | null | undefined : Value;
677
691
  type MaybeRelationRef<Value, Options> = Options extends {
678
692
  mapToPk: true;
679
693
  } ? Value : Options extends {
@@ -145,6 +145,13 @@ export class UniversalPropertyOptionsBuilder {
145
145
  nullable() {
146
146
  return this.assignOptions({ nullable: true });
147
147
  }
148
+ /**
149
+ * Set column as nullable without adding `| undefined` to the type.
150
+ * Use this when the property is always explicitly set (e.g. in constructor) but can be `null`.
151
+ */
152
+ strictNullable() {
153
+ return this.assignOptions({ nullable: true });
154
+ }
148
155
  /**
149
156
  * Set column as unsigned for {@link https://mikro-orm.io/docs/schema-generator Schema Generator}. (SQL only)
150
157
  */
@@ -1726,12 +1726,12 @@ export class MetadataDiscovery {
1726
1726
  }
1727
1727
  }
1728
1728
  if (prop.kind === ReferenceKind.SCALAR && !(mappedType instanceof t.unknown)) {
1729
- if (!prop.columnTypes &&
1730
- prop.nativeEnumName &&
1729
+ if (prop.nativeEnumName &&
1731
1730
  meta.schema !== this.#platform.getDefaultSchemaName() &&
1732
1731
  meta.schema &&
1733
1732
  !prop.nativeEnumName.includes('.')) {
1734
- prop.columnTypes = [`${meta.schema}.${prop.nativeEnumName}`];
1733
+ const suffix = prop.columnTypes?.[0]?.endsWith('[]') ? '[]' : '';
1734
+ prop.columnTypes = [`${meta.schema}.${prop.nativeEnumName}${suffix}`];
1735
1735
  }
1736
1736
  else {
1737
1737
  prop.columnTypes ??= [mappedType.getColumnType(prop, this.#platform)];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
- "version": "7.0.3-dev.9",
3
+ "version": "7.0.4-dev.0",
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
  "keywords": [
6
6
  "data-mapper",
@@ -1,4 +1,4 @@
1
- import type { ArrayElement, AutoPath, CleanTypeConfig, SerializeDTO, FromEntityType, TypeConfig, UnboxArray } from '../typings.js';
1
+ import type { ArrayElement, AutoPath, CleanTypeConfig, ExtractFieldsHint, FromEntityType, SerializeDTO, TypeConfig, UnboxArray } from '../typings.js';
2
2
  import { type PopulatePath } from '../enums.js';
3
3
  /** Converts entity instances to plain DTOs via `serialize()`, with fine-grained control over populate, exclude, and serialization groups. */
4
4
  export declare class EntitySerializer {
@@ -41,4 +41,4 @@ export interface SerializeOptions<T, P extends string = never, E extends string
41
41
  * const dto2 = wrap(user).serialize({ exclude: ['id', 'email'], forceObject: true });
42
42
  * ```
43
43
  */
44
- export declare function serialize<Entity extends object, Naked extends FromEntityType<Entity> = FromEntityType<Entity>, Populate extends string = never, Exclude extends string = never, Config extends TypeConfig = never>(entity: Entity, options?: Config & SerializeOptions<UnboxArray<Entity>, Populate, Exclude>): Naked extends object[] ? SerializeDTO<ArrayElement<Naked>, Populate, Exclude, CleanTypeConfig<Config>>[] : SerializeDTO<Naked, Populate, Exclude, CleanTypeConfig<Config>>;
44
+ export declare function serialize<Entity extends object, Naked extends FromEntityType<Entity> = FromEntityType<Entity>, Populate extends string = never, Exclude extends string = never, Config extends TypeConfig = never>(entity: Entity, options?: Config & SerializeOptions<UnboxArray<Entity>, Populate, Exclude>): Naked extends object[] ? SerializeDTO<ArrayElement<Naked>, Populate, Exclude, CleanTypeConfig<Config>>[] : SerializeDTO<Naked, Populate, Exclude, CleanTypeConfig<Config>, ExtractFieldsHint<Entity>>;
package/typings.d.ts CHANGED
@@ -201,6 +201,7 @@ export interface TypeConfig {
201
201
  declare const __selectedType: unique symbol;
202
202
  declare const __loadedType: unique symbol;
203
203
  declare const __loadHint: unique symbol;
204
+ declare const __fieldsHint: unique symbol;
204
205
  /**
205
206
  * Expands a populate hint into all its prefixes.
206
207
  * e.g., Prefixes<'a.b.c'> = 'a' | 'a.b' | 'a.b.c'
@@ -527,13 +528,18 @@ export type EntityDTOFlat<T, C extends TypeConfig = never> = {
527
528
  */
528
529
  type SerializeTopHints<H extends string> = H extends `${infer Top}.${string}` ? Top : H;
529
530
  type SerializeSubHints<K extends string, H extends string> = H extends `${K}.${infer Rest}` ? Rest : never;
531
+ type SerializeSubFields<K extends string, F extends string> = K extends F ? '*' : [F extends `${K & string}.${infer Rest}` ? Rest : never] extends [never] ? '*' : F extends `${K & string}.${infer Rest}` ? Rest : never;
532
+ type SerializeFieldsFilter<T, K extends keyof T, F extends string> = K extends Prefix<T, F> | PrimaryProperty<T> ? K : never;
530
533
  type SerializePropValue<T, K extends keyof T, H extends string, C extends TypeConfig = never> = K & string extends SerializeTopHints<H> ? NonNullable<T[K]> extends CollectionShape<infer U> ? SerializeDTO<U & object, SerializeSubHints<K & string, H>, never, C>[] : SerializeDTO<ExpandProperty<T[K]>, SerializeSubHints<K & string, H>, never, C> | Extract<T[K], null | undefined> : EntityDTOProp<T, T[K], C>;
534
+ type SerializePropValueWithFields<T, K extends keyof T, H extends string, C extends TypeConfig, F extends string> = K & string extends SerializeTopHints<H> ? NonNullable<T[K]> extends CollectionShape<infer U> ? SerializeDTO<U & object, SerializeSubHints<K & string, H>, never, C, SerializeSubFields<K & string, F>>[] : SerializeDTO<ExpandProperty<T[K]>, SerializeSubHints<K & string, H>, never, C, SerializeSubFields<K & string, F>> | Extract<T[K], null | undefined> : EntityDTOProp<T, T[K], C>;
531
535
  /**
532
536
  * Return type of `serialize()`. Combines Loaded + EntityDTO in a single pass for better performance.
533
- * Respects populate hints (`H`) and exclude hints (`E`).
537
+ * Respects populate hints (`H`), exclude hints (`E`), and fields hints (`F`).
534
538
  */
535
- export type SerializeDTO<T, H extends string = never, E extends string = never, C extends TypeConfig = never> = string extends H ? EntityDTOFlat<T, C> : {
539
+ export type SerializeDTO<T, H extends string = never, E extends string = never, C extends TypeConfig = never, F extends string = '*'> = string extends H ? EntityDTOFlat<T, C> : [F] extends ['*'] ? {
536
540
  [K in keyof T as ExcludeHidden<T, K> & CleanKeys<T, K> & (IsNever<E> extends true ? K : Exclude<K, E>)]: SerializePropValue<T, K, H, C> | Extract<T[K], null | undefined>;
541
+ } : {
542
+ [K in keyof T as ExcludeHidden<T, K> & CleanKeys<T, K> & (IsNever<E> extends true ? K : Exclude<K, E>) & SerializeFieldsFilter<T, K, F>]: SerializePropValueWithFields<T, K, H, C, F> | Extract<T[K], null | undefined>;
537
543
  };
538
544
  type TargetKeys<T> = T extends EntityClass<infer P> ? keyof P : keyof T;
539
545
  type PropertyName<T> = IsUnknown<T> extends false ? TargetKeys<T> : string;
@@ -1186,6 +1192,7 @@ export type Selected<T, L extends string = never, F extends string = '*'> = {
1186
1192
  [K in keyof T as IsPrefixed<T, K, L | F | AddEager<T>> | FunctionKeys<T, K>]: T[K] extends Function ? T[K] : NonNullable<T[K]> extends Scalar ? T[K] : LoadedProp<NonNullable<T[K]>, Suffix<K, L, true>, Suffix<K, F, true>> | AddOptional<T[K]>;
1187
1193
  } & {
1188
1194
  [__selectedType]?: T;
1195
+ [__fieldsHint]?: (hint: F) => void;
1189
1196
  };
1190
1197
  type LoadedEntityType<T> = {
1191
1198
  [__loadedType]?: T;
@@ -1196,6 +1203,10 @@ type LoadedEntityType<T> = {
1196
1203
  export type EntityType<T> = T | LoadedEntityType<T>;
1197
1204
  /** Extracts the base entity type from a `Loaded`/`Selected` wrapper, or returns `T` as-is. */
1198
1205
  export type FromEntityType<T> = T extends LoadedEntityType<infer U> ? U : T;
1206
+ /** Extracts the fields hint (`F`) from a `Loaded`/`Selected` type, or returns `'*'` (all fields) for unwrapped entities. */
1207
+ export type ExtractFieldsHint<T> = T extends {
1208
+ [__fieldsHint]?: (hint: infer F extends string) => void;
1209
+ } ? F : '*';
1199
1210
  type LoadedInternal<T, L extends string = never, F extends string = '*', E extends string = never> = [F] extends ['*'] ? IsNever<E> extends true ? T & {
1200
1211
  [K in keyof T as IsPrefixed<T, K, ExpandHint<T, L>>]: LoadedProp<NonNullable<T[K]>, Suffix<K, L>, Suffix<K, F>, Suffix<K, E>> | AddOptional<T[K]>;
1201
1212
  } : {
package/utils/Utils.js CHANGED
@@ -129,7 +129,7 @@ export function parseJsonSafe(value) {
129
129
  /** Collection of general-purpose utility methods used throughout the ORM. */
130
130
  export class Utils {
131
131
  static PK_SEPARATOR = '~~~';
132
- static #ORM_VERSION = '7.0.3-dev.9';
132
+ static #ORM_VERSION = '7.0.4-dev.0';
133
133
  /**
134
134
  * Checks if the argument is instance of `Object`. Returns false for arrays.
135
135
  */
@@ -802,14 +802,11 @@ export class Utils {
802
802
  return await import(module);
803
803
  }
804
804
  catch (err) {
805
- if (err.code === 'ERR_MODULE_NOT_FOUND') {
806
- if (warning) {
807
- // eslint-disable-next-line no-console
808
- console.warn(warning);
809
- }
810
- return undefined;
805
+ if (warning && err.code === 'ERR_MODULE_NOT_FOUND') {
806
+ // eslint-disable-next-line no-console
807
+ console.warn(warning);
811
808
  }
812
- throw err;
809
+ return undefined;
813
810
  }
814
811
  }
815
812
  static xor(a, b) {