@mikro-orm/core 6.3.4-dev.6 → 6.3.4-dev.7

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.
@@ -68,12 +68,14 @@ export interface FindAllOptions<T, P extends string = never, F extends string =
68
68
  where?: FilterQuery<T>;
69
69
  }
70
70
  export type FilterOptions = Dictionary<boolean | Dictionary> | string[] | boolean;
71
- export interface FindOptions<Entity, Hint extends string = never, Fields extends string = PopulatePath.ALL, Excludes extends string = never> {
71
+ export interface LoadHint<Entity, Hint extends string = never, Fields extends string = PopulatePath.ALL, Excludes extends string = never> {
72
72
  populate?: Populate<Entity, Hint>;
73
- populateWhere?: ObjectQuery<Entity> | PopulateHint | `${PopulateHint}`;
74
- populateOrderBy?: OrderDefinition<Entity>;
75
73
  fields?: readonly AutoPath<Entity, Fields, `${PopulatePath.ALL}`>[];
76
74
  exclude?: readonly AutoPath<Entity, Excludes>[];
75
+ }
76
+ export interface FindOptions<Entity, Hint extends string = never, Fields extends string = PopulatePath.ALL, Excludes extends string = never> extends LoadHint<Entity, Hint, Fields, Excludes> {
77
+ populateWhere?: ObjectQuery<Entity> | PopulateHint | `${PopulateHint}`;
78
+ populateOrderBy?: OrderDefinition<Entity>;
77
79
  orderBy?: OrderDefinition<Entity>;
78
80
  cache?: boolean | number | [string, number];
79
81
  limit?: number;
@@ -24,6 +24,7 @@ export declare class Collection<T extends object, O extends object = object> ext
24
24
  * Returns the Collection instance (itself), works the same as `Reference.load()`.
25
25
  */
26
26
  load<TT extends T, P extends string = never>(options?: InitCollectionOptions<TT, P>): Promise<LoadedCollection<Loaded<TT, P>>>;
27
+ private setSerializationContext;
27
28
  /**
28
29
  * Initializes the collection and returns the items
29
30
  */
@@ -37,12 +37,20 @@ class Collection extends ArrayCollection_1.ArrayCollection {
37
37
  if (this.isInitialized(true) && !options.refresh) {
38
38
  const em = this.getEntityManager(this.items, false);
39
39
  await em?.populate(this.items, options.populate, options);
40
+ this.setSerializationContext(options);
40
41
  }
41
42
  else {
42
43
  await this.init({ refresh: false, ...options });
43
44
  }
44
45
  return this;
45
46
  }
47
+ setSerializationContext(options) {
48
+ (0, wrap_1.helper)(this.owner).setSerializationContext({
49
+ populate: Array.isArray(options.populate)
50
+ ? options.populate.map(hint => `${this.property.name}.${hint}`)
51
+ : options.populate ?? [this.property.name],
52
+ });
53
+ }
46
54
  /**
47
55
  * Initializes the collection and returns the items
48
56
  */
@@ -86,6 +94,7 @@ class Collection extends ArrayCollection_1.ArrayCollection {
86
94
  }
87
95
  if (options.store) {
88
96
  this.hydrate(items, true);
97
+ this.setSerializationContext(options);
89
98
  this.populated();
90
99
  this.readonly = true;
91
100
  }
@@ -33,16 +33,11 @@ export declare class EntityLoader {
33
33
  populate<Entity extends object, Fields extends string = PopulatePath.ALL>(entityName: string, entities: Entity[], populate: PopulateOptions<Entity>[] | boolean, options: EntityLoaderOptions<Entity, Fields>): Promise<void>;
34
34
  normalizePopulate<Entity>(entityName: string, populate: (PopulateOptions<Entity> | boolean)[] | PopulateOptions<Entity> | boolean, strategy?: LoadStrategy, lookup?: boolean): PopulateOptions<Entity>[];
35
35
  private setSerializationContext;
36
- private expandDotPaths;
37
36
  /**
38
37
  * Merge multiple populates for the same entity with different children. Also skips `*` fields, those can come from
39
38
  * partial loading hints (`fields`) that are used to infer the `populate` hint if missing.
40
39
  */
41
40
  private mergeNestedPopulate;
42
- /**
43
- * Expands `books.perex` like populate to use `children` array instead of the dot syntax
44
- */
45
- private expandNestedPopulate;
46
41
  /**
47
42
  * preload everything in one call (this will update already existing references in IM)
48
43
  */
@@ -8,6 +8,7 @@ const enums_1 = require("../enums");
8
8
  const Reference_1 = require("./Reference");
9
9
  const wrap_1 = require("./wrap");
10
10
  const RawQueryFragment_1 = require("../utils/RawQueryFragment");
11
+ const utils_1 = require("./utils");
11
12
  class EntityLoader {
12
13
  em;
13
14
  metadata;
@@ -64,11 +65,11 @@ class EntityLoader {
64
65
  normalized = this.lookupAllRelationships(entityName);
65
66
  }
66
67
  // convert nested `field` with dot syntax to PopulateOptions with `children` array
67
- this.expandDotPaths(normalized, meta);
68
+ (0, utils_1.expandDotPaths)(meta, normalized, true);
68
69
  if (lookup && populate !== false) {
69
70
  normalized = this.lookupEagerLoadedRelationships(entityName, normalized, strategy);
70
71
  // convert nested `field` with dot syntax produced by eager relations
71
- this.expandDotPaths(normalized, meta);
72
+ (0, utils_1.expandDotPaths)(meta, normalized, true);
72
73
  }
73
74
  // merge same fields
74
75
  return this.mergeNestedPopulate(normalized);
@@ -90,34 +91,6 @@ class EntityLoader {
90
91
  }
91
92
  }
92
93
  }
93
- expandDotPaths(normalized, meta) {
94
- for (const p of normalized) {
95
- if (!p.field.includes('.')) {
96
- continue;
97
- }
98
- const [f, ...parts] = p.field.split('.');
99
- p.field = f;
100
- p.children ??= [];
101
- const prop = meta.properties[f];
102
- p.strategy ??= prop.strategy;
103
- if (parts[0] === enums_1.PopulatePath.ALL) {
104
- prop.targetMeta.props
105
- .filter(prop => prop.lazy || prop.kind !== enums_1.ReferenceKind.SCALAR)
106
- .forEach(prop => p.children.push({ field: prop.name, strategy: p.strategy }));
107
- }
108
- else if (prop.kind === enums_1.ReferenceKind.EMBEDDED) {
109
- normalized.push({
110
- ...p,
111
- field: Object.values(prop.embeddedProps).find(c => c.embedded[1] === parts[0])?.name,
112
- children: [],
113
- });
114
- p.children.push(this.expandNestedPopulate(prop.type, parts, p.strategy, p.all));
115
- }
116
- else {
117
- p.children.push(this.expandNestedPopulate(prop.type, parts, p.strategy, p.all));
118
- }
119
- }
120
- }
121
94
  /**
122
95
  * Merge multiple populates for the same entity with different children. Also skips `*` fields, those can come from
123
96
  * partial loading hints (`fields`) that are used to infer the `populate` hint if missing.
@@ -146,19 +119,6 @@ class EntityLoader {
146
119
  return item;
147
120
  });
148
121
  }
149
- /**
150
- * Expands `books.perex` like populate to use `children` array instead of the dot syntax
151
- */
152
- expandNestedPopulate(entityName, parts, strategy, all) {
153
- const meta = this.metadata.find(entityName);
154
- const field = parts.shift();
155
- const prop = meta.properties[field];
156
- const ret = { field, strategy, all };
157
- if (parts.length > 0) {
158
- ret.children = [this.expandNestedPopulate(prop.type, parts, strategy)];
159
- }
160
- return ret;
161
- }
162
122
  /**
163
123
  * preload everything in one call (this will update already existing references in IM)
164
124
  */
@@ -8,7 +8,7 @@ import type { EntityLoaderOptions } from './EntityLoader';
8
8
  import type { EntityIdentifier } from './EntityIdentifier';
9
9
  import type { SerializationContext } from '../serialization/SerializationContext';
10
10
  import { type SerializeOptions } from '../serialization/EntitySerializer';
11
- import type { FindOneOptions } from '../drivers/IDatabaseDriver';
11
+ import type { FindOneOptions, LoadHint } from '../drivers/IDatabaseDriver';
12
12
  export declare class WrappedEntity<Entity extends object> {
13
13
  __initialized: boolean;
14
14
  __touched: boolean;
@@ -17,14 +17,15 @@ export declare class WrappedEntity<Entity extends object> {
17
17
  __onLoadFired?: boolean;
18
18
  __schema?: string;
19
19
  __em?: EntityManager;
20
+ __loadedProperties: Set<string>;
21
+ __data: Dictionary;
22
+ __processing: boolean;
20
23
  __serializationContext: {
21
24
  root?: SerializationContext<Entity>;
22
25
  populate?: PopulateOptions<Entity>[];
23
- fields?: string[];
26
+ fields?: Set<string>;
27
+ exclude?: readonly string[];
24
28
  };
25
- __loadedProperties: Set<string>;
26
- __data: Dictionary;
27
- __processing: boolean;
28
29
  /** stores last known primary key, as its current state might be broken due to propagation/orphan removal, but we need to know the PK to be able t remove the entity */
29
30
  __pk?: Primary<Entity>;
30
31
  /** holds the reference wrapper instance (if created), so we can maintain the identity on reference wrappers too */
@@ -43,6 +44,7 @@ export declare class WrappedEntity<Entity extends object> {
43
44
  isTouched(): boolean;
44
45
  isManaged(): boolean;
45
46
  populated(populated?: boolean | undefined): void;
47
+ setSerializationContext<Hint extends string = never, Fields extends string = '*', Exclude extends string = never>(options: LoadHint<Entity, Hint, Fields, Exclude>): void;
46
48
  toReference(): Ref<Entity> & LoadedReference<Loaded<Entity, AddEager<Entity>>>;
47
49
  toObject<Ignored extends EntityKey<Entity> = never>(ignoreFields?: Ignored[]): Omit<EntityDTO<Entity>, Ignored>;
48
50
  serialize<Hint extends string = never, Exclude extends string = never>(options?: SerializeOptions<Entity, Hint, Exclude>): EntityDTO<Loaded<Entity, Hint>>;
@@ -9,6 +9,7 @@ const Utils_1 = require("../utils/Utils");
9
9
  const errors_1 = require("../errors");
10
10
  const wrap_1 = require("./wrap");
11
11
  const EntitySerializer_1 = require("../serialization/EntitySerializer");
12
+ const utils_1 = require("./utils");
12
13
  class WrappedEntity {
13
14
  constructor(entity, hydrator, pkGetter, pkSerializer, pkGetterConverted) {
14
15
  this.entity = entity;
@@ -35,6 +36,22 @@ class WrappedEntity {
35
36
  populated(populated = true) {
36
37
  this.__populated = populated;
37
38
  }
39
+ setSerializationContext(options) {
40
+ const exclude = options.exclude ?? [];
41
+ const context = this.__serializationContext;
42
+ const populate = (0, utils_1.expandDotPaths)(this.__meta, options.populate);
43
+ context.populate = context.populate ? context.populate.concat(populate) : populate;
44
+ context.exclude = context.exclude ? context.exclude.concat(exclude) : exclude;
45
+ if (context.fields && options.fields) {
46
+ options.fields.forEach(f => context.fields.add(f));
47
+ }
48
+ else if (options.fields) {
49
+ context.fields = new Set(options.fields);
50
+ }
51
+ else {
52
+ context.fields = new Set(['*']);
53
+ }
54
+ }
38
55
  toReference() {
39
56
  this.__reference ??= new Reference_1.Reference(this.entity);
40
57
  return this.__reference;
@@ -0,0 +1,5 @@
1
+ import type { EntityMetadata, PopulateOptions } from '../typings';
2
+ /**
3
+ * @internal
4
+ */
5
+ export declare function expandDotPaths<Entity>(meta: EntityMetadata<Entity>, populate?: readonly (string | PopulateOptions<Entity>)[], normalized?: boolean): PopulateOptions<Entity>[];
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.expandDotPaths = expandDotPaths;
4
+ const enums_1 = require("../enums");
5
+ const core_1 = require("@mikro-orm/core");
6
+ /**
7
+ * Expands `books.perex` like populate to use `children` array instead of the dot syntax
8
+ */
9
+ function expandNestedPopulate(parentProp, parts, strategy, all) {
10
+ const meta = parentProp.targetMeta;
11
+ const field = parts.shift();
12
+ const prop = meta.properties[field];
13
+ const ret = { field, strategy, all };
14
+ if (parts.length > 0) {
15
+ ret.children = [expandNestedPopulate(prop, parts, strategy)];
16
+ }
17
+ return ret;
18
+ }
19
+ /**
20
+ * @internal
21
+ */
22
+ function expandDotPaths(meta, populate, normalized = false) {
23
+ const ret = normalized ? populate : core_1.Utils.asArray(populate).map(field => {
24
+ if (typeof field === 'string') {
25
+ return { field };
26
+ }
27
+ return typeof field === 'boolean' || field.field === enums_1.PopulatePath.ALL
28
+ ? { all: !!field, field: meta.primaryKeys[0] }
29
+ : field;
30
+ });
31
+ for (const p of ret) {
32
+ if (!p.field.includes('.')) {
33
+ continue;
34
+ }
35
+ const [f, ...parts] = p.field.split('.');
36
+ p.field = f;
37
+ p.children ??= [];
38
+ const prop = meta.properties[p.field];
39
+ p.strategy ??= prop.strategy;
40
+ if (parts[0] === enums_1.PopulatePath.ALL) {
41
+ prop.targetMeta.props
42
+ .filter(prop => prop.lazy || prop.kind !== enums_1.ReferenceKind.SCALAR)
43
+ .forEach(prop => p.children.push({ field: prop.name, strategy: p.strategy }));
44
+ }
45
+ else if (prop.kind === enums_1.ReferenceKind.EMBEDDED) {
46
+ ret.push({
47
+ ...p,
48
+ field: Object.values(prop.embeddedProps).find(c => c.embedded[1] === parts[0])?.name,
49
+ children: [],
50
+ });
51
+ p.children.push(expandNestedPopulate(prop, parts, p.strategy, p.all));
52
+ }
53
+ else {
54
+ p.children.push(expandNestedPopulate(prop, parts, p.strategy, p.all));
55
+ }
56
+ }
57
+ return ret;
58
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
- "version": "6.3.4-dev.6",
3
+ "version": "6.3.4-dev.7",
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",
@@ -64,7 +64,7 @@
64
64
  "esprima": "4.0.1",
65
65
  "fs-extra": "11.2.0",
66
66
  "globby": "11.1.0",
67
- "mikro-orm": "6.3.4-dev.6",
67
+ "mikro-orm": "6.3.4-dev.7",
68
68
  "reflect-metadata": "0.2.2"
69
69
  }
70
70
  }
package/typings.d.ts CHANGED
@@ -8,7 +8,7 @@ import type { Platform } from './platforms';
8
8
  import type { Configuration } from './utils';
9
9
  import type { EntityManager } from './EntityManager';
10
10
  import type { EventSubscriber } from './events';
11
- import type { FindOneOptions, FindOptions } from './drivers';
11
+ import type { FindOneOptions, FindOptions, LoadHint } from './drivers';
12
12
  export type Constructor<T = unknown> = new (...args: any[]) => T;
13
13
  export type Dictionary<T = any> = {
14
14
  [k: string]: T;
@@ -135,7 +135,7 @@ export interface IWrappedEntity<Entity extends object> {
135
135
  isManaged(): boolean;
136
136
  populated(populated?: boolean): void;
137
137
  populate<Hint extends string = never>(populate: AutoPath<Entity, Hint>[] | false, options?: EntityLoaderOptions<Entity>): Promise<Loaded<Entity, Hint>>;
138
- init<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(options?: FindOneOptions<Entity, Hint, Fields, Excludes>): Promise<Loaded<Entity, Hint, Fields, Excludes> | null>;
138
+ init<Hint extends string = never, Fields extends string = '*', Exclude extends string = never>(options?: FindOneOptions<Entity, Hint, Fields, Exclude>): Promise<Loaded<Entity, Hint, Fields, Exclude> | null>;
139
139
  toReference(): Ref<Entity> & LoadedReference<Loaded<Entity, AddEager<Entity>>>;
140
140
  toObject(): EntityDTO<Entity>;
141
141
  toObject(ignoreFields: never[]): EntityDTO<Entity>;
@@ -143,6 +143,7 @@ export interface IWrappedEntity<Entity extends object> {
143
143
  toJSON(...args: any[]): EntityDTO<Entity>;
144
144
  toPOJO(): EntityDTO<Entity>;
145
145
  serialize<Hint extends string = never, Exclude extends string = never>(options?: SerializeOptions<Entity, Hint, Exclude>): EntityDTO<Loaded<Entity, Hint>>;
146
+ setSerializationContext<Hint extends string = never, Fields extends string = '*', Exclude extends string = never>(options: LoadHint<Entity, Hint, Fields, Exclude>): void;
146
147
  assign<Naked extends FromEntityType<Entity> = FromEntityType<Entity>, Convert extends boolean = false, Data extends EntityData<Naked, Convert> | Partial<EntityDTO<Naked>> = EntityData<Naked, Convert> | Partial<EntityDTO<Naked>>>(data: Data & IsSubset<EntityData<Naked, Convert>, Data>, options?: AssignOptions<Convert>): MergeSelected<Entity, Naked, keyof Data & string>;
147
148
  getSchema(): string | undefined;
148
149
  setSchema(schema?: string): void;