@rtpaulino/entity 0.21.0 → 0.23.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/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import 'reflect-metadata';
2
2
  export * from './lib/entity.js';
3
3
  export * from './lib/entity-utils.js';
4
4
  export * from './lib/entity-di.js';
5
+ export * from './lib/entity-registry.js';
5
6
  export * from './lib/types.js';
6
7
  export * from './lib/property.js';
7
8
  export * from './lib/validation-error.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC"}
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ import 'reflect-metadata';
2
2
  export * from './lib/entity.js';
3
3
  export * from './lib/entity-utils.js';
4
4
  export * from './lib/entity-di.js';
5
+ export * from './lib/entity-registry.js';
5
6
  export * from './lib/types.js';
6
7
  export * from './lib/property.js';
7
8
  export * from './lib/validation-error.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import 'reflect-metadata';\n\nexport * from './lib/entity.js';\nexport * from './lib/entity-utils.js';\nexport * from './lib/entity-di.js';\nexport * from './lib/types.js';\nexport * from './lib/property.js';\nexport * from './lib/validation-error.js';\nexport * from './lib/problem.js';\nexport * from './lib/validation-utils.js';\nexport * from './lib/primitive-deserializers.js';\nexport * from './lib/validators.js';\nexport * from './lib/zod-property.js';\nexport * from './lib/injected-property.js';\n"],"names":[],"mappings":"AAAA,OAAO,mBAAmB;AAE1B,cAAc,kBAAkB;AAChC,cAAc,wBAAwB;AACtC,cAAc,qBAAqB;AACnC,cAAc,iBAAiB;AAC/B,cAAc,oBAAoB;AAClC,cAAc,4BAA4B;AAC1C,cAAc,mBAAmB;AACjC,cAAc,4BAA4B;AAC1C,cAAc,mCAAmC;AACjD,cAAc,sBAAsB;AACpC,cAAc,wBAAwB;AACtC,cAAc,6BAA6B"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import 'reflect-metadata';\n\nexport * from './lib/entity.js';\nexport * from './lib/entity-utils.js';\nexport * from './lib/entity-di.js';\nexport * from './lib/entity-registry.js';\nexport * from './lib/types.js';\nexport * from './lib/property.js';\nexport * from './lib/validation-error.js';\nexport * from './lib/problem.js';\nexport * from './lib/validation-utils.js';\nexport * from './lib/primitive-deserializers.js';\nexport * from './lib/validators.js';\nexport * from './lib/zod-property.js';\nexport * from './lib/injected-property.js';\n"],"names":[],"mappings":"AAAA,OAAO,mBAAmB;AAE1B,cAAc,kBAAkB;AAChC,cAAc,wBAAwB;AACtC,cAAc,qBAAqB;AACnC,cAAc,2BAA2B;AACzC,cAAc,iBAAiB;AAC/B,cAAc,oBAAoB;AAClC,cAAc,4BAA4B;AAC1C,cAAc,mBAAmB;AACjC,cAAc,4BAA4B;AAC1C,cAAc,mCAAmC;AACjD,cAAc,sBAAsB;AACpC,cAAc,wBAAwB;AACtC,cAAc,6BAA6B"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Registry for entity classes decorated with @Entity()
3
+ * Stores entity constructors by name for discriminated entity deserialization
4
+ */
5
+ export declare class EntityRegistry {
6
+ private static readonly registry;
7
+ /**
8
+ * Registers an entity class with a name
9
+ * @param name - The name to register the entity under
10
+ * @param entityClass - The entity class constructor
11
+ * @throws Error if an entity with this name is already registered
12
+ */
13
+ static register(name: string, entityClass: Function): void;
14
+ /**
15
+ * Gets an entity class by name
16
+ * @param name - The name of the entity to retrieve
17
+ * @returns The entity class constructor, or undefined if not found
18
+ */
19
+ static get(name: string): Function | undefined;
20
+ /**
21
+ * Checks if an entity with the given name is registered
22
+ * @param name - The name to check
23
+ * @returns true if an entity with this name is registered
24
+ */
25
+ static has(name: string): boolean;
26
+ /**
27
+ * Gets all registered entity names
28
+ * @returns Array of all registered entity names
29
+ */
30
+ static getAllNames(): string[];
31
+ }
32
+ //# sourceMappingURL=entity-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-registry.d.ts","sourceRoot":"","sources":["../../src/lib/entity-registry.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAA+B;IAE/D;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,GAAG,IAAI;IAW1D;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI9C;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjC;;;OAGG;IACH,MAAM,CAAC,WAAW,IAAI,MAAM,EAAE;CAG/B"}
@@ -0,0 +1,42 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-unsafe-function-type */ /**
2
+ * Registry for entity classes decorated with @Entity()
3
+ * Stores entity constructors by name for discriminated entity deserialization
4
+ */ export class EntityRegistry {
5
+ static{
6
+ this.registry = new Map();
7
+ }
8
+ /**
9
+ * Registers an entity class with a name
10
+ * @param name - The name to register the entity under
11
+ * @param entityClass - The entity class constructor
12
+ * @throws Error if an entity with this name is already registered
13
+ */ static register(name, entityClass) {
14
+ const existing = this.registry.get(name);
15
+ if (existing && existing !== entityClass) {
16
+ throw new Error(`Entity name conflict: An entity with name '${name}' is already registered. ` + `Existing: ${existing.name}, New: ${entityClass.name}`);
17
+ }
18
+ this.registry.set(name, entityClass);
19
+ }
20
+ /**
21
+ * Gets an entity class by name
22
+ * @param name - The name of the entity to retrieve
23
+ * @returns The entity class constructor, or undefined if not found
24
+ */ static get(name) {
25
+ return this.registry.get(name);
26
+ }
27
+ /**
28
+ * Checks if an entity with the given name is registered
29
+ * @param name - The name to check
30
+ * @returns true if an entity with this name is registered
31
+ */ static has(name) {
32
+ return this.registry.has(name);
33
+ }
34
+ /**
35
+ * Gets all registered entity names
36
+ * @returns Array of all registered entity names
37
+ */ static getAllNames() {
38
+ return Array.from(this.registry.keys());
39
+ }
40
+ }
41
+
42
+ //# sourceMappingURL=entity-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/entity-registry.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-function-type */\n\n/**\n * Registry for entity classes decorated with @Entity()\n * Stores entity constructors by name for discriminated entity deserialization\n */\nexport class EntityRegistry {\n private static readonly registry = new Map<string, Function>();\n\n /**\n * Registers an entity class with a name\n * @param name - The name to register the entity under\n * @param entityClass - The entity class constructor\n * @throws Error if an entity with this name is already registered\n */\n static register(name: string, entityClass: Function): void {\n const existing = this.registry.get(name);\n if (existing && existing !== entityClass) {\n throw new Error(\n `Entity name conflict: An entity with name '${name}' is already registered. ` +\n `Existing: ${existing.name}, New: ${entityClass.name}`,\n );\n }\n this.registry.set(name, entityClass);\n }\n\n /**\n * Gets an entity class by name\n * @param name - The name of the entity to retrieve\n * @returns The entity class constructor, or undefined if not found\n */\n static get(name: string): Function | undefined {\n return this.registry.get(name);\n }\n\n /**\n * Checks if an entity with the given name is registered\n * @param name - The name to check\n * @returns true if an entity with this name is registered\n */\n static has(name: string): boolean {\n return this.registry.has(name);\n }\n\n /**\n * Gets all registered entity names\n * @returns Array of all registered entity names\n */\n static getAllNames(): string[] {\n return Array.from(this.registry.keys());\n }\n}\n"],"names":["EntityRegistry","registry","Map","register","name","entityClass","existing","get","Error","set","has","getAllNames","Array","from","keys"],"mappings":"AAAA,qDAAqD,GACrD,6DAA6D,GAE7D;;;CAGC,GACD,OAAO,MAAMA;;aACaC,WAAW,IAAIC;;IAEvC;;;;;GAKC,GACD,OAAOC,SAASC,IAAY,EAAEC,WAAqB,EAAQ;QACzD,MAAMC,WAAW,IAAI,CAACL,QAAQ,CAACM,GAAG,CAACH;QACnC,IAAIE,YAAYA,aAAaD,aAAa;YACxC,MAAM,IAAIG,MACR,CAAC,2CAA2C,EAAEJ,KAAK,yBAAyB,CAAC,GAC3E,CAAC,UAAU,EAAEE,SAASF,IAAI,CAAC,OAAO,EAAEC,YAAYD,IAAI,EAAE;QAE5D;QACA,IAAI,CAACH,QAAQ,CAACQ,GAAG,CAACL,MAAMC;IAC1B;IAEA;;;;GAIC,GACD,OAAOE,IAAIH,IAAY,EAAwB;QAC7C,OAAO,IAAI,CAACH,QAAQ,CAACM,GAAG,CAACH;IAC3B;IAEA;;;;GAIC,GACD,OAAOM,IAAIN,IAAY,EAAW;QAChC,OAAO,IAAI,CAACH,QAAQ,CAACS,GAAG,CAACN;IAC3B;IAEA;;;GAGC,GACD,OAAOO,cAAwB;QAC7B,OAAOC,MAAMC,IAAI,CAAC,IAAI,CAACZ,QAAQ,CAACa,IAAI;IACtC;AACF"}
@@ -30,6 +30,24 @@ export declare class EntityUtils {
30
30
  * @private
31
31
  */
32
32
  private static getEntityOptions;
33
+ /**
34
+ * Gets the registered name for an entity class or instance
35
+ *
36
+ * @param entityOrClass - The entity class constructor or instance
37
+ * @returns The entity name, or undefined if not found
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * @Entity({ name: 'CustomUser' })
42
+ * class User {
43
+ * name: string;
44
+ * }
45
+ *
46
+ * console.log(EntityUtils.getEntityName(User)); // 'CustomUser'
47
+ * console.log(EntityUtils.getEntityName(new User())); // 'CustomUser'
48
+ * ```
49
+ */
50
+ static getEntityName(entityOrClass: unknown): string | undefined;
33
51
  /**
34
52
  * Checks if a given entity is marked as a collection entity
35
53
  *
@@ -50,6 +68,26 @@ export declare class EntityUtils {
50
68
  * ```
51
69
  */
52
70
  static isCollectionEntity(entityOrClass: unknown): boolean;
71
+ /**
72
+ * Checks if a given entity is marked as a stringifiable entity
73
+ *
74
+ * @param entityOrClass - The entity instance or class to check
75
+ * @returns true if the entity is a stringifiable entity, false otherwise
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * @Stringifiable()
80
+ * class UserId {
81
+ * @StringProperty()
82
+ * value: string;
83
+ * }
84
+ *
85
+ * const userId = new UserId({ value: 'user-123' });
86
+ * console.log(EntityUtils.isStringifiable(userId)); // true
87
+ * console.log(EntityUtils.isStringifiable(UserId)); // true
88
+ * ```
89
+ */
90
+ static isStringifiable(entityOrClass: unknown): boolean;
53
91
  static sameEntity(a: object, b: object): boolean;
54
92
  static getPropertyKeys(target: object): string[];
55
93
  static getPropertyOptions(target: object, propertyKey: string): PropertyOptions | undefined;
@@ -387,6 +425,11 @@ export declare class EntityUtils {
387
425
  * @private
388
426
  */
389
427
  private static deserializeSingleValue;
428
+ /**
429
+ * Deserializes a discriminated entity value by reading the discriminator and looking up the entity class
430
+ * @private
431
+ */
432
+ private static deserializeDiscriminatedValue;
390
433
  /**
391
434
  * Validates a property value by running validators and nested entity validation.
392
435
  * Prepends the property path to all returned problems.
@@ -1 +1 @@
1
- {"version":3,"file":"entity-utils.d.ts","sourceRoot":"","sources":["../../src/lib/entity-utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,YAAY,EAGZ,eAAe,EACf,mBAAmB,EACpB,MAAM,YAAY,CAAC;AASpB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAuBvC,qBAAa,WAAW;IACtB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,MAAM;IAmB5C;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAa/B;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAAM,CAAC,kBAAkB,CAAC,aAAa,EAAE,OAAO,GAAG,OAAO;IAU1D,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;IAQhD,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IAoChD,MAAM,CAAC,kBAAkB,CACvB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,eAAe,GAAG,SAAS;IA8B9B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO;IA2B9C,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,MAAM,EAC1B,SAAS,EAAE,CAAC,EACZ,SAAS,EAAE,CAAC,GACX;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,EAAE;IAoC/D,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAaxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4DG;IACH,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,OAAO;IAyCnD;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAsD7B;;;OAGG;mBACkB,cAAc;IA8GnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2CG;WACU,KAAK,CAAC,CAAC,SAAS,MAAM,EACjC,WAAW,EAAE,KAAK,IAAI,EAAE,GAAG,KAAK,CAAC,EACjC,WAAW,EAAE,OAAO,EACpB,YAAY,GAAE,YAAiB,GAC9B,OAAO,CAAC,CAAC,CAAC;IA4Bb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqCG;WACU,SAAS,CAAC,CAAC,SAAS,MAAM,EACrC,WAAW,EAAE,KAAK,IAAI,EAAE,GAAG,KAAK,CAAC,EACjC,WAAW,EAAE,OAAO,EACpB,YAAY,CAAC,EAAE,YAAY,GAC1B,mBAAmB,CAAC,CAAC,CAAC;IAsBzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoCG;WACU,YAAY,CAAC,CAAC,SAAS,MAAM,EACxC,WAAW,EAAE,KAAK,IAAI,EAAE,GAAG,KAAK,CAAC,EACjC,WAAW,EAAE,OAAO,EACpB,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAO,GACjC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IActB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqCG;WACU,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAC5C,WAAW,EAAE,KAAK,IAAI,EAAE,GAAG,KAAK,CAAC,EACjC,WAAW,EAAE,OAAO,EACpB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAC7B,OAAO,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAwC3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;WACU,MAAM,CAAC,CAAC,SAAS,MAAM,EAClC,QAAQ,EAAE,CAAC,EACX,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAC7B,OAAO,CAAC,CAAC,CAAC;IAuCb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqCG;WACU,UAAU,CAAC,CAAC,SAAS,MAAM,EACtC,QAAQ,EAAE,CAAC,EACX,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAC7B,mBAAmB,CAAC,CAAC,CAAC;IAsBzB;;;OAGG;mBACkB,gBAAgB;IA0ErC;;;;OAIG;mBACkB,sBAAsB;IAsB3C;;;;OAIG;mBACkB,qBAAqB;IAuC1C;;;OAGG;mBACkB,qBAAqB;IAoD1C;;;OAGG;mBACkB,kBAAkB;mBAyBlB,uBAAuB;IAoB5C;;;;;;;;;;;;;;;;;OAiBG;WACU,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAuBxE;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,OAAO,EAAE;IAI5D;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI;IAQ5E;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,OAAO;IAI1D;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,MAAM,EACjC,QAAQ,EAAE,CAAC,EACX,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC5C,IAAI;IAQP;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;CA6BnC"}
1
+ {"version":3,"file":"entity-utils.d.ts","sourceRoot":"","sources":["../../src/lib/entity-utils.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ import { Problem } from './problem.js';
7
7
  import { prependPropertyPath, prependArrayIndex, createValidationError, combinePropertyPaths } from './validation-utils.js';
8
8
  import { isPrimitiveConstructor, deserializePrimitive } from './primitive-deserializers.js';
9
9
  import { ok } from 'assert';
10
+ import { EntityRegistry } from './entity-registry.js';
10
11
  /**
11
12
  * WeakMap to store validation problems for entity instances
12
13
  */ const problemsStorage = new WeakMap();
@@ -60,6 +61,29 @@ export class EntityUtils {
60
61
  return options ?? {};
61
62
  }
62
63
  /**
64
+ * Gets the registered name for an entity class or instance
65
+ *
66
+ * @param entityOrClass - The entity class constructor or instance
67
+ * @returns The entity name, or undefined if not found
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * @Entity({ name: 'CustomUser' })
72
+ * class User {
73
+ * name: string;
74
+ * }
75
+ *
76
+ * console.log(EntityUtils.getEntityName(User)); // 'CustomUser'
77
+ * console.log(EntityUtils.getEntityName(new User())); // 'CustomUser'
78
+ * ```
79
+ */ static getEntityName(entityOrClass) {
80
+ if (!this.isEntity(entityOrClass)) {
81
+ return undefined;
82
+ }
83
+ const options = this.getEntityOptions(entityOrClass);
84
+ return options.name;
85
+ }
86
+ /**
63
87
  * Checks if a given entity is marked as a collection entity
64
88
  *
65
89
  * @param entityOrClass - The entity instance or class to check
@@ -84,6 +108,31 @@ export class EntityUtils {
84
108
  const options = this.getEntityOptions(entityOrClass);
85
109
  return options.collection === true;
86
110
  }
111
+ /**
112
+ * Checks if a given entity is marked as a stringifiable entity
113
+ *
114
+ * @param entityOrClass - The entity instance or class to check
115
+ * @returns true if the entity is a stringifiable entity, false otherwise
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * @Stringifiable()
120
+ * class UserId {
121
+ * @StringProperty()
122
+ * value: string;
123
+ * }
124
+ *
125
+ * const userId = new UserId({ value: 'user-123' });
126
+ * console.log(EntityUtils.isStringifiable(userId)); // true
127
+ * console.log(EntityUtils.isStringifiable(UserId)); // true
128
+ * ```
129
+ */ static isStringifiable(entityOrClass) {
130
+ if (!this.isEntity(entityOrClass)) {
131
+ return false;
132
+ }
133
+ const options = this.getEntityOptions(entityOrClass);
134
+ return options.stringifiable === true;
135
+ }
87
136
  static sameEntity(a, b) {
88
137
  if (!this.isEntity(a) || !this.isEntity(b)) {
89
138
  return false;
@@ -254,6 +303,19 @@ export class EntityUtils {
254
303
  * // ['a', 'b'] - unwrapped to array
255
304
  * ```
256
305
  */ static toJSON(entity) {
306
+ if (this.isStringifiable(entity)) {
307
+ const valuePropertyOptions = this.getPropertyOptions(entity, 'value');
308
+ if (!valuePropertyOptions) {
309
+ throw new Error(`Stringifiable entity 'value' property is missing metadata`);
310
+ }
311
+ if (valuePropertyOptions.array) {
312
+ throw new Error(`Stringifiable entity 'value' property must not be an array`);
313
+ }
314
+ if (valuePropertyOptions.type?.() !== String) {
315
+ throw new Error(`Stringifiable entity 'value' property must be of type String`);
316
+ }
317
+ return this.serializeValue(entity.value, valuePropertyOptions);
318
+ }
257
319
  if (this.isCollectionEntity(entity)) {
258
320
  const collectionPropertyOptions = this.getPropertyOptions(entity, 'collection');
259
321
  if (!collectionPropertyOptions) {
@@ -296,7 +358,7 @@ export class EntityUtils {
296
358
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
297
359
  return value.map((item)=>options.serialize(item));
298
360
  }
299
- return value.map((item)=>this.serializeValue(item));
361
+ return value.map((item)=>this.serializeValue(item, options));
300
362
  }
301
363
  if (options?.serialize) {
302
364
  return options.serialize(value);
@@ -308,7 +370,25 @@ export class EntityUtils {
308
370
  return value.toString();
309
371
  }
310
372
  if (this.isEntity(value)) {
311
- return this.toJSON(value);
373
+ const serialized = this.toJSON(value);
374
+ // If this is a discriminated entity property, add the discriminator inline
375
+ if (options?.discriminated === true) {
376
+ const discriminatorProperty = options.discriminatorProperty;
377
+ ok(discriminatorProperty, 'Discriminator property must be defined');
378
+ const entityClass = Object.getPrototypeOf(value).constructor;
379
+ const entityName = this.getEntityName(entityClass);
380
+ if (!entityName) {
381
+ throw new Error(`Cannot serialize discriminated entity: Entity class '${entityClass.name}' is not registered. Ensure it's decorated with @Entity().`);
382
+ }
383
+ if (typeof serialized !== 'object' || Array.isArray(serialized) || serialized === null) {
384
+ throw new Error(`Cannot serialize discriminated entity: Expected serialized value to be an object.`);
385
+ }
386
+ return {
387
+ ...serialized,
388
+ [discriminatorProperty]: entityName
389
+ };
390
+ }
391
+ return serialized;
312
392
  }
313
393
  if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
314
394
  return value;
@@ -319,7 +399,11 @@ export class EntityUtils {
319
399
  * Internal parse implementation with extended options
320
400
  * @private
321
401
  */ static async _parseInternal(entityClass, plainObject, options = {}) {
322
- if (this.isCollectionEntity(entityClass)) {
402
+ if (this.isStringifiable(entityClass)) {
403
+ plainObject = {
404
+ value: plainObject
405
+ };
406
+ } else if (this.isCollectionEntity(entityClass)) {
323
407
  plainObject = {
324
408
  collection: plainObject
325
409
  };
@@ -750,10 +834,9 @@ export class EntityUtils {
750
834
  * Deserializes a single value according to the type metadata
751
835
  * @private
752
836
  */ static async deserializeValue(value, options, parseOptions) {
753
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
754
- const typeConstructor = options.type();
755
837
  const isArray = options.array === true;
756
838
  const isSparse = options.sparse === true;
839
+ const isDiscriminated = options.discriminated === true;
757
840
  if (isArray) {
758
841
  if (!Array.isArray(value)) {
759
842
  throw createValidationError(`Expects an array but received ${typeof value}`);
@@ -774,7 +857,11 @@ export class EntityUtils {
774
857
  try {
775
858
  if (options.deserialize) {
776
859
  result.push(options.deserialize(item));
860
+ } else if (isDiscriminated) {
861
+ result.push(await this.deserializeDiscriminatedValue(item, options));
777
862
  } else {
863
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
864
+ const typeConstructor = options.type();
778
865
  result.push(await this.deserializeSingleValue(item, typeConstructor, parseOptions));
779
866
  }
780
867
  } catch (error) {
@@ -795,6 +882,11 @@ export class EntityUtils {
795
882
  if (options.deserialize) {
796
883
  return options.deserialize(value);
797
884
  }
885
+ if (isDiscriminated) {
886
+ return await this.deserializeDiscriminatedValue(value, options);
887
+ }
888
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
889
+ const typeConstructor = options.type();
798
890
  return await this.deserializeSingleValue(value, typeConstructor, parseOptions);
799
891
  }
800
892
  /**
@@ -811,6 +903,28 @@ export class EntityUtils {
811
903
  throw createValidationError(`Has unknown type constructor. Supported types are: String, Number, Boolean, Date, BigInt, and @Entity() classes. Use passthrough: true to explicitly allow unknown types.`);
812
904
  }
813
905
  /**
906
+ * Deserializes a discriminated entity value by reading the discriminator and looking up the entity class
907
+ * @private
908
+ */ static async deserializeDiscriminatedValue(value, options) {
909
+ if (value == null) {
910
+ throw createValidationError(`Cannot deserialize discriminated entity from null or undefined`);
911
+ }
912
+ if (typeof value !== 'object' || Array.isArray(value)) {
913
+ throw createValidationError(`Discriminated entity must be an object, received ${typeof value}`);
914
+ }
915
+ const discriminatorProperty = options.discriminatorProperty;
916
+ ok(discriminatorProperty, 'Discriminator property must be defined');
917
+ const discriminatorValue = value[discriminatorProperty];
918
+ if (typeof discriminatorValue !== 'string' || discriminatorValue.trim() === '') {
919
+ throw createValidationError(`Missing or invalid discriminator property '${discriminatorProperty}'. Expected a non-empty string.`);
920
+ }
921
+ const entityClass = EntityRegistry.get(discriminatorValue);
922
+ if (!entityClass) {
923
+ throw createValidationError(`Unknown entity type '${discriminatorValue}'. No entity registered with this name.`);
924
+ }
925
+ return await this.parse(entityClass, value, {});
926
+ }
927
+ /**
814
928
  * Validates a property value by running validators and nested entity validation.
815
929
  * Prepends the property path to all returned problems.
816
930
  * @private