@rtpaulino/entity 0.23.0 → 0.24.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 +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/entity-definition.d.ts +288 -0
- package/dist/lib/entity-definition.d.ts.map +1 -0
- package/dist/lib/entity-definition.js +270 -0
- package/dist/lib/entity-definition.js.map +1 -0
- package/dist/lib/entity-utils.d.ts +14 -0
- package/dist/lib/entity-utils.d.ts.map +1 -1
- package/dist/lib/entity-utils.js +48 -25
- package/dist/lib/entity-utils.js.map +1 -1
- package/dist/lib/entity.d.ts +6 -0
- package/dist/lib/entity.d.ts.map +1 -1
- package/dist/lib/entity.js +2 -0
- package/dist/lib/entity.js.map +1 -1
- package/dist/lib/property.d.ts +90 -0
- package/dist/lib/property.d.ts.map +1 -1
- package/dist/lib/property.js +151 -51
- package/dist/lib/property.js.map +1 -1
- package/dist/lib/validation-utils.d.ts +6 -6
- package/dist/lib/validation-utils.d.ts.map +1 -1
- package/dist/lib/validation-utils.js +7 -7
- package/dist/lib/validation-utils.js.map +1 -1
- package/dist/lib/zod-property.d.ts +7 -0
- package/dist/lib/zod-property.d.ts.map +1 -1
- package/dist/lib/zod-property.js +22 -16
- package/dist/lib/zod-property.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -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,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"}
|
|
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;AAC3C,cAAc,4BAA4B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -12,5 +12,6 @@ export * from './lib/primitive-deserializers.js';
|
|
|
12
12
|
export * from './lib/validators.js';
|
|
13
13
|
export * from './lib/zod-property.js';
|
|
14
14
|
export * from './lib/injected-property.js';
|
|
15
|
+
export * from './lib/entity-definition.js';
|
|
15
16
|
|
|
16
17
|
//# sourceMappingURL=index.js.map
|
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/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"}
|
|
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';\nexport * from './lib/entity-definition.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;AAC3C,cAAc,6BAA6B"}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { PropertyOptions, type AnyCtor } from './types.js';
|
|
2
|
+
import { EntityOptions } from './entity.js';
|
|
3
|
+
import { Problem } from './problem.js';
|
|
4
|
+
import { stringPropertyOptions, enumPropertyOptions, numberPropertyOptions, intPropertyOptions, booleanPropertyOptions, datePropertyOptions, bigIntPropertyOptions, entityPropertyOptions, arrayPropertyOptions, passthroughPropertyOptions, discriminatedEntityPropertyOptions } from './property.js';
|
|
5
|
+
import { zodPropertyOptions } from './zod-property.js';
|
|
6
|
+
/**
|
|
7
|
+
* Configuration for defining an entity schema
|
|
8
|
+
*/
|
|
9
|
+
export interface EntitySchemaConfig<T = any> {
|
|
10
|
+
/**
|
|
11
|
+
* Name for the entity (required for schema-based entities)
|
|
12
|
+
*/
|
|
13
|
+
name: string;
|
|
14
|
+
/**
|
|
15
|
+
* Entity options (collection, stringifiable, etc.)
|
|
16
|
+
*/
|
|
17
|
+
options?: Omit<EntityOptions, 'name'>;
|
|
18
|
+
/**
|
|
19
|
+
* Property definitions - key is property name, value is property options
|
|
20
|
+
*/
|
|
21
|
+
properties: Record<string, PropertyOptions>;
|
|
22
|
+
/**
|
|
23
|
+
* Validator functions that will be attached to the entity class
|
|
24
|
+
* Each function receives the entity instance and returns problems
|
|
25
|
+
*/
|
|
26
|
+
validators?: Array<(instance: T) => Problem[] | Promise<Problem[]>>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Wrapper object returned by EntitySchema.define() with EntityUtils methods
|
|
30
|
+
*/
|
|
31
|
+
export interface EntitySchemaWrapper<T> {
|
|
32
|
+
/**
|
|
33
|
+
* The generated entity class
|
|
34
|
+
*/
|
|
35
|
+
readonly entityClass: AnyCtor<T>;
|
|
36
|
+
/**
|
|
37
|
+
* Parse data into an entity instance
|
|
38
|
+
*/
|
|
39
|
+
parse(data: unknown): Promise<T>;
|
|
40
|
+
/**
|
|
41
|
+
* Parse data into an entity instance without throwing
|
|
42
|
+
*/
|
|
43
|
+
safeParse(data: unknown): Promise<{
|
|
44
|
+
success: true;
|
|
45
|
+
data: T;
|
|
46
|
+
problems: Problem[];
|
|
47
|
+
} | {
|
|
48
|
+
success: false;
|
|
49
|
+
data: undefined;
|
|
50
|
+
problems: Problem[];
|
|
51
|
+
}>;
|
|
52
|
+
/**
|
|
53
|
+
* Parse only present properties without throwing
|
|
54
|
+
*/
|
|
55
|
+
parsePartial(data: unknown): Promise<Partial<T>>;
|
|
56
|
+
/**
|
|
57
|
+
* Parse only present properties without throwing
|
|
58
|
+
*/
|
|
59
|
+
safeParsePartial(data: unknown): Promise<{
|
|
60
|
+
success: true;
|
|
61
|
+
data: Partial<T>;
|
|
62
|
+
problems: Problem[];
|
|
63
|
+
} | {
|
|
64
|
+
success: false;
|
|
65
|
+
data: undefined;
|
|
66
|
+
problems: Problem[];
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* Serialize entity instance to plain object
|
|
70
|
+
*/
|
|
71
|
+
serialize(instance: T): unknown;
|
|
72
|
+
/**
|
|
73
|
+
* Update entity instance with new data
|
|
74
|
+
*/
|
|
75
|
+
update(instance: T, data: unknown): Promise<T>;
|
|
76
|
+
/**
|
|
77
|
+
* Update entity instance with new data without throwing
|
|
78
|
+
*/
|
|
79
|
+
safeUpdate(instance: T, data: unknown): Promise<{
|
|
80
|
+
success: true;
|
|
81
|
+
data: T;
|
|
82
|
+
problems: Problem[];
|
|
83
|
+
} | {
|
|
84
|
+
success: false;
|
|
85
|
+
data: T;
|
|
86
|
+
problems: Problem[];
|
|
87
|
+
}>;
|
|
88
|
+
/**
|
|
89
|
+
* Validate entity instance
|
|
90
|
+
*/
|
|
91
|
+
validate(instance: T): Promise<Problem[]>;
|
|
92
|
+
/**
|
|
93
|
+
* Check if two instances are equal
|
|
94
|
+
*/
|
|
95
|
+
equals(a: T, b: T): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Get differences between two instances
|
|
98
|
+
*/
|
|
99
|
+
diff(a: T, b: T): Record<string, {
|
|
100
|
+
from: unknown;
|
|
101
|
+
to: unknown;
|
|
102
|
+
}>;
|
|
103
|
+
/**
|
|
104
|
+
* Get changed values as partial object
|
|
105
|
+
*/
|
|
106
|
+
getChanges(a: T, b: T): Partial<T>;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Factory for creating schema-based entities without pre-defining a class
|
|
110
|
+
*/
|
|
111
|
+
export declare class EntitySchema {
|
|
112
|
+
/**
|
|
113
|
+
* Define a new entity schema and return a wrapper with EntityUtils methods
|
|
114
|
+
*
|
|
115
|
+
* @param config - Schema configuration with name, properties, options, and validators
|
|
116
|
+
* @returns Wrapper object with parse, serialize, validate, etc. methods
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* const UserSchema = EntitySchema.define({
|
|
121
|
+
* name: 'User',
|
|
122
|
+
* properties: {
|
|
123
|
+
* name: { type: () => String },
|
|
124
|
+
* age: { type: () => Number, optional: true },
|
|
125
|
+
* tags: { type: () => String, array: true },
|
|
126
|
+
* },
|
|
127
|
+
* validators: [
|
|
128
|
+
* (user) => user.name.length < 2 ? [{ path: 'name', message: 'Too short' }] : []
|
|
129
|
+
* ]
|
|
130
|
+
* });
|
|
131
|
+
*
|
|
132
|
+
* const user = await UserSchema.parse({ name: 'John', age: 30, tags: ['admin'] });
|
|
133
|
+
* const serialized = UserSchema.serialize(user);
|
|
134
|
+
* const isValid = (await UserSchema.validate(user)).length === 0;
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
static define<T extends object = any>(config: EntitySchemaConfig<T>): EntitySchemaWrapper<T>;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Property definition helpers for EntitySchema
|
|
141
|
+
* These mirror the decorator-based property helpers but return PropertyOptions objects
|
|
142
|
+
*/
|
|
143
|
+
export declare const EntityProps: {
|
|
144
|
+
/**
|
|
145
|
+
* String property with optional validation
|
|
146
|
+
* @example
|
|
147
|
+
* EntitySchema.define({
|
|
148
|
+
* name: 'User',
|
|
149
|
+
* properties: {
|
|
150
|
+
* name: EntityProps.String({ minLength: 2, maxLength: 50 }),
|
|
151
|
+
* email: EntityProps.String({ pattern: /^.+@.+\..+$/ }),
|
|
152
|
+
* }
|
|
153
|
+
* })
|
|
154
|
+
*/
|
|
155
|
+
String: typeof stringPropertyOptions;
|
|
156
|
+
/**
|
|
157
|
+
* Enum property (validates string against enum values)
|
|
158
|
+
* @example
|
|
159
|
+
* enum Status { Active = 'active', Inactive = 'inactive' }
|
|
160
|
+
* EntitySchema.define({
|
|
161
|
+
* name: 'User',
|
|
162
|
+
* properties: {
|
|
163
|
+
* status: EntityProps.Enum(Status),
|
|
164
|
+
* }
|
|
165
|
+
* })
|
|
166
|
+
*/
|
|
167
|
+
Enum: typeof enumPropertyOptions;
|
|
168
|
+
/**
|
|
169
|
+
* Number property with optional min/max validation
|
|
170
|
+
* @example
|
|
171
|
+
* EntitySchema.define({
|
|
172
|
+
* name: 'User',
|
|
173
|
+
* properties: {
|
|
174
|
+
* age: EntityProps.Number({ min: 0, max: 150 }),
|
|
175
|
+
* score: EntityProps.Number({ optional: true }),
|
|
176
|
+
* }
|
|
177
|
+
* })
|
|
178
|
+
*/
|
|
179
|
+
Number: typeof numberPropertyOptions;
|
|
180
|
+
/**
|
|
181
|
+
* Integer property (number that must be an integer)
|
|
182
|
+
* @example
|
|
183
|
+
* EntitySchema.define({
|
|
184
|
+
* name: 'User',
|
|
185
|
+
* properties: {
|
|
186
|
+
* age: EntityProps.Int({ min: 0 }),
|
|
187
|
+
* }
|
|
188
|
+
* })
|
|
189
|
+
*/
|
|
190
|
+
Int: typeof intPropertyOptions;
|
|
191
|
+
/**
|
|
192
|
+
* Boolean property
|
|
193
|
+
* @example
|
|
194
|
+
* EntitySchema.define({
|
|
195
|
+
* name: 'User',
|
|
196
|
+
* properties: {
|
|
197
|
+
* isActive: EntityProps.Boolean(),
|
|
198
|
+
* emailVerified: EntityProps.Boolean({ optional: true }),
|
|
199
|
+
* }
|
|
200
|
+
* })
|
|
201
|
+
*/
|
|
202
|
+
Boolean: typeof booleanPropertyOptions;
|
|
203
|
+
/**
|
|
204
|
+
* Date property
|
|
205
|
+
* @example
|
|
206
|
+
* EntitySchema.define({
|
|
207
|
+
* name: 'Event',
|
|
208
|
+
* properties: {
|
|
209
|
+
* createdAt: EntityProps.Date(),
|
|
210
|
+
* scheduledFor: EntityProps.Date({ optional: true }),
|
|
211
|
+
* }
|
|
212
|
+
* })
|
|
213
|
+
*/
|
|
214
|
+
Date: typeof datePropertyOptions;
|
|
215
|
+
/**
|
|
216
|
+
* BigInt property
|
|
217
|
+
* @example
|
|
218
|
+
* EntitySchema.define({
|
|
219
|
+
* name: 'Transaction',
|
|
220
|
+
* properties: {
|
|
221
|
+
* amount: EntityProps.BigInt(),
|
|
222
|
+
* }
|
|
223
|
+
* })
|
|
224
|
+
*/
|
|
225
|
+
BigInt: typeof bigIntPropertyOptions;
|
|
226
|
+
/**
|
|
227
|
+
* Entity property (nested entity)
|
|
228
|
+
* @example
|
|
229
|
+
* const AddressSchema = EntitySchema.define({ ... });
|
|
230
|
+
* EntitySchema.define({
|
|
231
|
+
* name: 'User',
|
|
232
|
+
* properties: {
|
|
233
|
+
* address: EntityProps.Entity(() => AddressSchema.entityClass),
|
|
234
|
+
* }
|
|
235
|
+
* })
|
|
236
|
+
*/
|
|
237
|
+
Entity: typeof entityPropertyOptions;
|
|
238
|
+
/**
|
|
239
|
+
* Array property
|
|
240
|
+
* @example
|
|
241
|
+
* EntitySchema.define({
|
|
242
|
+
* name: 'User',
|
|
243
|
+
* properties: {
|
|
244
|
+
* tags: EntityProps.Array(() => String),
|
|
245
|
+
* addresses: EntityProps.Array(() => AddressSchema.entityClass),
|
|
246
|
+
* }
|
|
247
|
+
* })
|
|
248
|
+
*/
|
|
249
|
+
Array: typeof arrayPropertyOptions;
|
|
250
|
+
/**
|
|
251
|
+
* Passthrough property (no deserialization/validation)
|
|
252
|
+
* @example
|
|
253
|
+
* EntitySchema.define({
|
|
254
|
+
* name: 'Config',
|
|
255
|
+
* properties: {
|
|
256
|
+
* metadata: EntityProps.Passthrough(),
|
|
257
|
+
* }
|
|
258
|
+
* })
|
|
259
|
+
*/
|
|
260
|
+
Passthrough: typeof passthroughPropertyOptions;
|
|
261
|
+
/**
|
|
262
|
+
* Zod schema property (validates using Zod schema)
|
|
263
|
+
* @example
|
|
264
|
+
* import { z } from 'zod';
|
|
265
|
+
* EntitySchema.define({
|
|
266
|
+
* name: 'User',
|
|
267
|
+
* properties: {
|
|
268
|
+
* data: EntityProps.Zod(z.object({
|
|
269
|
+
* name: z.string().min(3),
|
|
270
|
+
* age: z.number().int().min(0)
|
|
271
|
+
* })),
|
|
272
|
+
* }
|
|
273
|
+
* })
|
|
274
|
+
*/
|
|
275
|
+
Zod: typeof zodPropertyOptions;
|
|
276
|
+
/**
|
|
277
|
+
* Discriminated entity property (for polymorphic entities with discriminator)
|
|
278
|
+
* @example
|
|
279
|
+
* EntitySchema.define({
|
|
280
|
+
* name: 'Shape',
|
|
281
|
+
* properties: {
|
|
282
|
+
* shape: EntityProps.DiscriminatedEntity({ discriminatorProperty: 'type' }),
|
|
283
|
+
* }
|
|
284
|
+
* })
|
|
285
|
+
*/
|
|
286
|
+
DiscriminatedEntity: typeof discriminatedEntityPropertyOptions;
|
|
287
|
+
};
|
|
288
|
+
//# sourceMappingURL=entity-definition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-definition.d.ts","sourceRoot":"","sources":["../../src/lib/entity-definition.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */ import { ENTITY_METADATA_KEY, ENTITY_OPTIONS_METADATA_KEY, ENTITY_VALIDATOR_METADATA_KEY, PROPERTY_METADATA_KEY, PROPERTY_OPTIONS_METADATA_KEY } from './types.js';
|
|
2
|
+
import { EntityRegistry } from './entity-registry.js';
|
|
3
|
+
import { EntityUtils } from './entity-utils.js';
|
|
4
|
+
import { stringPropertyOptions, enumPropertyOptions, numberPropertyOptions, intPropertyOptions, booleanPropertyOptions, datePropertyOptions, bigIntPropertyOptions, entityPropertyOptions, arrayPropertyOptions, passthroughPropertyOptions, discriminatedEntityPropertyOptions } from './property.js';
|
|
5
|
+
import { zodPropertyOptions } from './zod-property.js';
|
|
6
|
+
/**
|
|
7
|
+
* Define entity metadata on an existing class programmatically
|
|
8
|
+
* This sets the same metadata that @Entity() and @Property() decorators would set
|
|
9
|
+
*
|
|
10
|
+
* @param entityClass - The class to define as an entity
|
|
11
|
+
* @param config - Configuration with properties, options, and validators
|
|
12
|
+
* @internal
|
|
13
|
+
*/ function defineEntity(entityClass, config) {
|
|
14
|
+
const entityName = config.name;
|
|
15
|
+
// 1. Mark as entity
|
|
16
|
+
Reflect.defineMetadata(ENTITY_METADATA_KEY, true, entityClass);
|
|
17
|
+
// 2. Set entity options with resolved name
|
|
18
|
+
const entityOptions = {
|
|
19
|
+
...config.options,
|
|
20
|
+
name: entityName
|
|
21
|
+
};
|
|
22
|
+
Reflect.defineMetadata(ENTITY_OPTIONS_METADATA_KEY, entityOptions, entityClass);
|
|
23
|
+
// 3. Register in EntityRegistry
|
|
24
|
+
EntityRegistry.register(entityName, entityClass);
|
|
25
|
+
// 4. Set property keys
|
|
26
|
+
const propertyKeys = Object.keys(config.properties);
|
|
27
|
+
Reflect.defineMetadata(PROPERTY_METADATA_KEY, propertyKeys, entityClass.prototype);
|
|
28
|
+
// 5. Set property options
|
|
29
|
+
Reflect.defineMetadata(PROPERTY_OPTIONS_METADATA_KEY, config.properties, entityClass.prototype);
|
|
30
|
+
// 6. Set up validators if provided
|
|
31
|
+
if (config.validators && config.validators.length > 0) {
|
|
32
|
+
const validatorMethodNames = [];
|
|
33
|
+
config.validators.forEach((validatorFn, index)=>{
|
|
34
|
+
const methodName = `__dynamicValidator${index}`;
|
|
35
|
+
validatorMethodNames.push(methodName);
|
|
36
|
+
// Attach validator as instance method that uses 'this'
|
|
37
|
+
entityClass.prototype[methodName] = function() {
|
|
38
|
+
return validatorFn(this);
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
Reflect.defineMetadata(ENTITY_VALIDATOR_METADATA_KEY, validatorMethodNames, entityClass.prototype);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Factory for creating schema-based entities without pre-defining a class
|
|
46
|
+
*/ export class EntitySchema {
|
|
47
|
+
/**
|
|
48
|
+
* Define a new entity schema and return a wrapper with EntityUtils methods
|
|
49
|
+
*
|
|
50
|
+
* @param config - Schema configuration with name, properties, options, and validators
|
|
51
|
+
* @returns Wrapper object with parse, serialize, validate, etc. methods
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const UserSchema = EntitySchema.define({
|
|
56
|
+
* name: 'User',
|
|
57
|
+
* properties: {
|
|
58
|
+
* name: { type: () => String },
|
|
59
|
+
* age: { type: () => Number, optional: true },
|
|
60
|
+
* tags: { type: () => String, array: true },
|
|
61
|
+
* },
|
|
62
|
+
* validators: [
|
|
63
|
+
* (user) => user.name.length < 2 ? [{ path: 'name', message: 'Too short' }] : []
|
|
64
|
+
* ]
|
|
65
|
+
* });
|
|
66
|
+
*
|
|
67
|
+
* const user = await UserSchema.parse({ name: 'John', age: 30, tags: ['admin'] });
|
|
68
|
+
* const serialized = UserSchema.serialize(user);
|
|
69
|
+
* const isValid = (await UserSchema.validate(user)).length === 0;
|
|
70
|
+
* ```
|
|
71
|
+
*/ static define(config) {
|
|
72
|
+
// Generate anonymous entity class
|
|
73
|
+
const entityClass = class {
|
|
74
|
+
constructor(data){
|
|
75
|
+
Object.assign(this, data);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
// Define entity metadata
|
|
79
|
+
defineEntity(entityClass, {
|
|
80
|
+
name: config.name,
|
|
81
|
+
options: config.options,
|
|
82
|
+
properties: config.properties,
|
|
83
|
+
validators: config.validators
|
|
84
|
+
});
|
|
85
|
+
// Create wrapper with EntityUtils methods
|
|
86
|
+
const wrapper = {
|
|
87
|
+
entityClass,
|
|
88
|
+
async parse (data) {
|
|
89
|
+
return EntityUtils.parse(entityClass, data);
|
|
90
|
+
},
|
|
91
|
+
async safeParse (data) {
|
|
92
|
+
return EntityUtils.safeParse(entityClass, data);
|
|
93
|
+
},
|
|
94
|
+
async parsePartial (data) {
|
|
95
|
+
return EntityUtils.partialParse(entityClass, data);
|
|
96
|
+
},
|
|
97
|
+
async safeParsePartial (data) {
|
|
98
|
+
return EntityUtils.safePartialParse(entityClass, data);
|
|
99
|
+
},
|
|
100
|
+
serialize (instance) {
|
|
101
|
+
return EntityUtils.toJSON(instance);
|
|
102
|
+
},
|
|
103
|
+
async update (instance, data) {
|
|
104
|
+
return EntityUtils.update(instance, data);
|
|
105
|
+
},
|
|
106
|
+
async safeUpdate (instance, data) {
|
|
107
|
+
return EntityUtils.safeUpdate(instance, data);
|
|
108
|
+
},
|
|
109
|
+
async validate (instance) {
|
|
110
|
+
return EntityUtils.validate(instance);
|
|
111
|
+
},
|
|
112
|
+
equals (a, b) {
|
|
113
|
+
return EntityUtils.equals(a, b);
|
|
114
|
+
},
|
|
115
|
+
diff (a, b) {
|
|
116
|
+
const diffs = EntityUtils.diff(a, b);
|
|
117
|
+
const result = {};
|
|
118
|
+
for (const diff of diffs){
|
|
119
|
+
result[diff.property] = {
|
|
120
|
+
from: diff.oldValue,
|
|
121
|
+
to: diff.newValue
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
},
|
|
126
|
+
getChanges (a, b) {
|
|
127
|
+
return EntityUtils.changes(a, b);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
return wrapper;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Property definition helpers for EntitySchema
|
|
135
|
+
* These mirror the decorator-based property helpers but return PropertyOptions objects
|
|
136
|
+
*/ export const EntityProps = {
|
|
137
|
+
/**
|
|
138
|
+
* String property with optional validation
|
|
139
|
+
* @example
|
|
140
|
+
* EntitySchema.define({
|
|
141
|
+
* name: 'User',
|
|
142
|
+
* properties: {
|
|
143
|
+
* name: EntityProps.String({ minLength: 2, maxLength: 50 }),
|
|
144
|
+
* email: EntityProps.String({ pattern: /^.+@.+\..+$/ }),
|
|
145
|
+
* }
|
|
146
|
+
* })
|
|
147
|
+
*/ String: stringPropertyOptions,
|
|
148
|
+
/**
|
|
149
|
+
* Enum property (validates string against enum values)
|
|
150
|
+
* @example
|
|
151
|
+
* enum Status { Active = 'active', Inactive = 'inactive' }
|
|
152
|
+
* EntitySchema.define({
|
|
153
|
+
* name: 'User',
|
|
154
|
+
* properties: {
|
|
155
|
+
* status: EntityProps.Enum(Status),
|
|
156
|
+
* }
|
|
157
|
+
* })
|
|
158
|
+
*/ Enum: enumPropertyOptions,
|
|
159
|
+
/**
|
|
160
|
+
* Number property with optional min/max validation
|
|
161
|
+
* @example
|
|
162
|
+
* EntitySchema.define({
|
|
163
|
+
* name: 'User',
|
|
164
|
+
* properties: {
|
|
165
|
+
* age: EntityProps.Number({ min: 0, max: 150 }),
|
|
166
|
+
* score: EntityProps.Number({ optional: true }),
|
|
167
|
+
* }
|
|
168
|
+
* })
|
|
169
|
+
*/ Number: numberPropertyOptions,
|
|
170
|
+
/**
|
|
171
|
+
* Integer property (number that must be an integer)
|
|
172
|
+
* @example
|
|
173
|
+
* EntitySchema.define({
|
|
174
|
+
* name: 'User',
|
|
175
|
+
* properties: {
|
|
176
|
+
* age: EntityProps.Int({ min: 0 }),
|
|
177
|
+
* }
|
|
178
|
+
* })
|
|
179
|
+
*/ Int: intPropertyOptions,
|
|
180
|
+
/**
|
|
181
|
+
* Boolean property
|
|
182
|
+
* @example
|
|
183
|
+
* EntitySchema.define({
|
|
184
|
+
* name: 'User',
|
|
185
|
+
* properties: {
|
|
186
|
+
* isActive: EntityProps.Boolean(),
|
|
187
|
+
* emailVerified: EntityProps.Boolean({ optional: true }),
|
|
188
|
+
* }
|
|
189
|
+
* })
|
|
190
|
+
*/ Boolean: booleanPropertyOptions,
|
|
191
|
+
/**
|
|
192
|
+
* Date property
|
|
193
|
+
* @example
|
|
194
|
+
* EntitySchema.define({
|
|
195
|
+
* name: 'Event',
|
|
196
|
+
* properties: {
|
|
197
|
+
* createdAt: EntityProps.Date(),
|
|
198
|
+
* scheduledFor: EntityProps.Date({ optional: true }),
|
|
199
|
+
* }
|
|
200
|
+
* })
|
|
201
|
+
*/ Date: datePropertyOptions,
|
|
202
|
+
/**
|
|
203
|
+
* BigInt property
|
|
204
|
+
* @example
|
|
205
|
+
* EntitySchema.define({
|
|
206
|
+
* name: 'Transaction',
|
|
207
|
+
* properties: {
|
|
208
|
+
* amount: EntityProps.BigInt(),
|
|
209
|
+
* }
|
|
210
|
+
* })
|
|
211
|
+
*/ BigInt: bigIntPropertyOptions,
|
|
212
|
+
/**
|
|
213
|
+
* Entity property (nested entity)
|
|
214
|
+
* @example
|
|
215
|
+
* const AddressSchema = EntitySchema.define({ ... });
|
|
216
|
+
* EntitySchema.define({
|
|
217
|
+
* name: 'User',
|
|
218
|
+
* properties: {
|
|
219
|
+
* address: EntityProps.Entity(() => AddressSchema.entityClass),
|
|
220
|
+
* }
|
|
221
|
+
* })
|
|
222
|
+
*/ Entity: entityPropertyOptions,
|
|
223
|
+
/**
|
|
224
|
+
* Array property
|
|
225
|
+
* @example
|
|
226
|
+
* EntitySchema.define({
|
|
227
|
+
* name: 'User',
|
|
228
|
+
* properties: {
|
|
229
|
+
* tags: EntityProps.Array(() => String),
|
|
230
|
+
* addresses: EntityProps.Array(() => AddressSchema.entityClass),
|
|
231
|
+
* }
|
|
232
|
+
* })
|
|
233
|
+
*/ Array: arrayPropertyOptions,
|
|
234
|
+
/**
|
|
235
|
+
* Passthrough property (no deserialization/validation)
|
|
236
|
+
* @example
|
|
237
|
+
* EntitySchema.define({
|
|
238
|
+
* name: 'Config',
|
|
239
|
+
* properties: {
|
|
240
|
+
* metadata: EntityProps.Passthrough(),
|
|
241
|
+
* }
|
|
242
|
+
* })
|
|
243
|
+
*/ Passthrough: passthroughPropertyOptions,
|
|
244
|
+
/**
|
|
245
|
+
* Zod schema property (validates using Zod schema)
|
|
246
|
+
* @example
|
|
247
|
+
* import { z } from 'zod';
|
|
248
|
+
* EntitySchema.define({
|
|
249
|
+
* name: 'User',
|
|
250
|
+
* properties: {
|
|
251
|
+
* data: EntityProps.Zod(z.object({
|
|
252
|
+
* name: z.string().min(3),
|
|
253
|
+
* age: z.number().int().min(0)
|
|
254
|
+
* })),
|
|
255
|
+
* }
|
|
256
|
+
* })
|
|
257
|
+
*/ Zod: zodPropertyOptions,
|
|
258
|
+
/**
|
|
259
|
+
* Discriminated entity property (for polymorphic entities with discriminator)
|
|
260
|
+
* @example
|
|
261
|
+
* EntitySchema.define({
|
|
262
|
+
* name: 'Shape',
|
|
263
|
+
* properties: {
|
|
264
|
+
* shape: EntityProps.DiscriminatedEntity({ discriminatorProperty: 'type' }),
|
|
265
|
+
* }
|
|
266
|
+
* })
|
|
267
|
+
*/ DiscriminatedEntity: discriminatedEntityPropertyOptions
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
//# sourceMappingURL=entity-definition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/entity-definition.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n ENTITY_METADATA_KEY,\n ENTITY_OPTIONS_METADATA_KEY,\n ENTITY_VALIDATOR_METADATA_KEY,\n PROPERTY_METADATA_KEY,\n PROPERTY_OPTIONS_METADATA_KEY,\n PropertyOptions,\n type AnyCtor,\n} from './types.js';\nimport { EntityOptions } from './entity.js';\nimport { EntityRegistry } from './entity-registry.js';\nimport { EntityUtils } from './entity-utils.js';\nimport { Problem } from './problem.js';\nimport {\n stringPropertyOptions,\n enumPropertyOptions,\n numberPropertyOptions,\n intPropertyOptions,\n booleanPropertyOptions,\n datePropertyOptions,\n bigIntPropertyOptions,\n entityPropertyOptions,\n arrayPropertyOptions,\n passthroughPropertyOptions,\n discriminatedEntityPropertyOptions,\n} from './property.js';\nimport { zodPropertyOptions } from './zod-property.js';\n\n/**\n * Configuration for defining an entity schema\n */\nexport interface EntitySchemaConfig<T = any> {\n /**\n * Name for the entity (required for schema-based entities)\n */\n name: string;\n /**\n * Entity options (collection, stringifiable, etc.)\n */\n options?: Omit<EntityOptions, 'name'>;\n /**\n * Property definitions - key is property name, value is property options\n */\n properties: Record<string, PropertyOptions>;\n /**\n * Validator functions that will be attached to the entity class\n * Each function receives the entity instance and returns problems\n */\n validators?: Array<(instance: T) => Problem[] | Promise<Problem[]>>;\n}\n\n/**\n * Wrapper object returned by EntitySchema.define() with EntityUtils methods\n */\nexport interface EntitySchemaWrapper<T> {\n /**\n * The generated entity class\n */\n readonly entityClass: AnyCtor<T>;\n\n /**\n * Parse data into an entity instance\n */\n parse(data: unknown): Promise<T>;\n\n /**\n * Parse data into an entity instance without throwing\n */\n safeParse(\n data: unknown,\n ): Promise<\n | { success: true; data: T; problems: Problem[] }\n | { success: false; data: undefined; problems: Problem[] }\n >;\n\n /**\n * Parse only present properties without throwing\n */\n parsePartial(data: unknown): Promise<Partial<T>>;\n\n /**\n * Parse only present properties without throwing\n */\n safeParsePartial(\n data: unknown,\n ): Promise<\n | { success: true; data: Partial<T>; problems: Problem[] }\n | { success: false; data: undefined; problems: Problem[] }\n >;\n\n /**\n * Serialize entity instance to plain object\n */\n serialize(instance: T): unknown;\n\n /**\n * Update entity instance with new data\n */\n update(instance: T, data: unknown): Promise<T>;\n\n /**\n * Update entity instance with new data without throwing\n */\n safeUpdate(\n instance: T,\n data: unknown,\n ): Promise<\n | { success: true; data: T; problems: Problem[] }\n | { success: false; data: T; problems: Problem[] }\n >;\n\n /**\n * Validate entity instance\n */\n validate(instance: T): Promise<Problem[]>;\n\n /**\n * Check if two instances are equal\n */\n equals(a: T, b: T): boolean;\n\n /**\n * Get differences between two instances\n */\n diff(a: T, b: T): Record<string, { from: unknown; to: unknown }>;\n\n /**\n * Get changed values as partial object\n */\n getChanges(a: T, b: T): Partial<T>;\n}\n\n/**\n * Define entity metadata on an existing class programmatically\n * This sets the same metadata that @Entity() and @Property() decorators would set\n *\n * @param entityClass - The class to define as an entity\n * @param config - Configuration with properties, options, and validators\n * @internal\n */\nfunction defineEntity<T>(\n entityClass: AnyCtor<T>,\n config: EntitySchemaConfig<T>,\n): void {\n const entityName = config.name;\n\n // 1. Mark as entity\n Reflect.defineMetadata(ENTITY_METADATA_KEY, true, entityClass);\n\n // 2. Set entity options with resolved name\n const entityOptions: EntityOptions = {\n ...config.options,\n name: entityName,\n };\n Reflect.defineMetadata(\n ENTITY_OPTIONS_METADATA_KEY,\n entityOptions,\n entityClass,\n );\n\n // 3. Register in EntityRegistry\n EntityRegistry.register(entityName, entityClass);\n\n // 4. Set property keys\n const propertyKeys = Object.keys(config.properties);\n Reflect.defineMetadata(\n PROPERTY_METADATA_KEY,\n propertyKeys,\n entityClass.prototype,\n );\n\n // 5. Set property options\n Reflect.defineMetadata(\n PROPERTY_OPTIONS_METADATA_KEY,\n config.properties,\n entityClass.prototype,\n );\n\n // 6. Set up validators if provided\n if (config.validators && config.validators.length > 0) {\n const validatorMethodNames: string[] = [];\n\n config.validators.forEach((validatorFn, index) => {\n const methodName = `__dynamicValidator${index}`;\n validatorMethodNames.push(methodName);\n\n // Attach validator as instance method that uses 'this'\n (entityClass.prototype as any)[methodName] = function ():\n | Problem[]\n | Promise<Problem[]> {\n return validatorFn(this);\n };\n });\n\n Reflect.defineMetadata(\n ENTITY_VALIDATOR_METADATA_KEY,\n validatorMethodNames,\n entityClass.prototype,\n );\n }\n}\n\n/**\n * Factory for creating schema-based entities without pre-defining a class\n */\nexport class EntitySchema {\n /**\n * Define a new entity schema and return a wrapper with EntityUtils methods\n *\n * @param config - Schema configuration with name, properties, options, and validators\n * @returns Wrapper object with parse, serialize, validate, etc. methods\n *\n * @example\n * ```typescript\n * const UserSchema = EntitySchema.define({\n * name: 'User',\n * properties: {\n * name: { type: () => String },\n * age: { type: () => Number, optional: true },\n * tags: { type: () => String, array: true },\n * },\n * validators: [\n * (user) => user.name.length < 2 ? [{ path: 'name', message: 'Too short' }] : []\n * ]\n * });\n *\n * const user = await UserSchema.parse({ name: 'John', age: 30, tags: ['admin'] });\n * const serialized = UserSchema.serialize(user);\n * const isValid = (await UserSchema.validate(user)).length === 0;\n * ```\n */\n static define<T extends object = any>(\n config: EntitySchemaConfig<T>,\n ): EntitySchemaWrapper<T> {\n // Generate anonymous entity class\n const entityClass = class {\n constructor(data: any) {\n Object.assign(this, data);\n }\n } as unknown as AnyCtor<T>;\n\n // Define entity metadata\n defineEntity(entityClass, {\n name: config.name,\n options: config.options,\n properties: config.properties,\n validators: config.validators,\n });\n\n // Create wrapper with EntityUtils methods\n const wrapper: EntitySchemaWrapper<T> = {\n entityClass,\n\n async parse(data: unknown): Promise<T> {\n return EntityUtils.parse(entityClass as any, data) as Promise<T>;\n },\n\n async safeParse(data: unknown) {\n return EntityUtils.safeParse(entityClass as any, data) as Promise<\n | { success: true; data: T; problems: Problem[] }\n | { success: false; data: undefined; problems: Problem[] }\n >;\n },\n\n async parsePartial(data: unknown): Promise<Partial<T>> {\n return EntityUtils.partialParse(entityClass as any, data) as Promise<\n Partial<T>\n >;\n },\n\n async safeParsePartial(data: unknown) {\n return EntityUtils.safePartialParse(\n entityClass as any,\n data,\n ) as unknown as Promise<\n | { success: true; data: Partial<T>; problems: Problem[] }\n | { success: false; data: undefined; problems: Problem[] }\n >;\n },\n\n serialize(instance: T): unknown {\n return EntityUtils.toJSON(instance as any);\n },\n\n async update(instance: T, data: unknown): Promise<T> {\n return EntityUtils.update(instance as any, data as any) as Promise<T>;\n },\n\n async safeUpdate(instance: T, data: unknown) {\n return EntityUtils.safeUpdate(instance as any, data as any) as Promise<\n | { success: true; data: T; problems: Problem[] }\n | { success: false; data: T; problems: Problem[] }\n >;\n },\n\n async validate(instance: T): Promise<Problem[]> {\n return EntityUtils.validate(instance as any);\n },\n\n equals(a: T, b: T): boolean {\n return EntityUtils.equals(a as any, b as any);\n },\n\n diff(a: T, b: T): Record<string, { from: unknown; to: unknown }> {\n const diffs = EntityUtils.diff(a as any, b as any);\n const result: Record<string, { from: unknown; to: unknown }> = {};\n for (const diff of diffs) {\n result[diff.property] = { from: diff.oldValue, to: diff.newValue };\n }\n return result;\n },\n\n getChanges(a: T, b: T): Partial<T> {\n return EntityUtils.changes(a as any, b as any) as Partial<T>;\n },\n };\n\n return wrapper;\n }\n}\n\n/**\n * Property definition helpers for EntitySchema\n * These mirror the decorator-based property helpers but return PropertyOptions objects\n */\nexport const EntityProps = {\n /**\n * String property with optional validation\n * @example\n * EntitySchema.define({\n * name: 'User',\n * properties: {\n * name: EntityProps.String({ minLength: 2, maxLength: 50 }),\n * email: EntityProps.String({ pattern: /^.+@.+\\..+$/ }),\n * }\n * })\n */\n String: stringPropertyOptions,\n\n /**\n * Enum property (validates string against enum values)\n * @example\n * enum Status { Active = 'active', Inactive = 'inactive' }\n * EntitySchema.define({\n * name: 'User',\n * properties: {\n * status: EntityProps.Enum(Status),\n * }\n * })\n */\n Enum: enumPropertyOptions,\n\n /**\n * Number property with optional min/max validation\n * @example\n * EntitySchema.define({\n * name: 'User',\n * properties: {\n * age: EntityProps.Number({ min: 0, max: 150 }),\n * score: EntityProps.Number({ optional: true }),\n * }\n * })\n */\n Number: numberPropertyOptions,\n\n /**\n * Integer property (number that must be an integer)\n * @example\n * EntitySchema.define({\n * name: 'User',\n * properties: {\n * age: EntityProps.Int({ min: 0 }),\n * }\n * })\n */\n Int: intPropertyOptions,\n\n /**\n * Boolean property\n * @example\n * EntitySchema.define({\n * name: 'User',\n * properties: {\n * isActive: EntityProps.Boolean(),\n * emailVerified: EntityProps.Boolean({ optional: true }),\n * }\n * })\n */\n Boolean: booleanPropertyOptions,\n\n /**\n * Date property\n * @example\n * EntitySchema.define({\n * name: 'Event',\n * properties: {\n * createdAt: EntityProps.Date(),\n * scheduledFor: EntityProps.Date({ optional: true }),\n * }\n * })\n */\n Date: datePropertyOptions,\n\n /**\n * BigInt property\n * @example\n * EntitySchema.define({\n * name: 'Transaction',\n * properties: {\n * amount: EntityProps.BigInt(),\n * }\n * })\n */\n BigInt: bigIntPropertyOptions,\n\n /**\n * Entity property (nested entity)\n * @example\n * const AddressSchema = EntitySchema.define({ ... });\n * EntitySchema.define({\n * name: 'User',\n * properties: {\n * address: EntityProps.Entity(() => AddressSchema.entityClass),\n * }\n * })\n */\n Entity: entityPropertyOptions,\n\n /**\n * Array property\n * @example\n * EntitySchema.define({\n * name: 'User',\n * properties: {\n * tags: EntityProps.Array(() => String),\n * addresses: EntityProps.Array(() => AddressSchema.entityClass),\n * }\n * })\n */\n Array: arrayPropertyOptions,\n\n /**\n * Passthrough property (no deserialization/validation)\n * @example\n * EntitySchema.define({\n * name: 'Config',\n * properties: {\n * metadata: EntityProps.Passthrough(),\n * }\n * })\n */\n Passthrough: passthroughPropertyOptions,\n\n /**\n * Zod schema property (validates using Zod schema)\n * @example\n * import { z } from 'zod';\n * EntitySchema.define({\n * name: 'User',\n * properties: {\n * data: EntityProps.Zod(z.object({\n * name: z.string().min(3),\n * age: z.number().int().min(0)\n * })),\n * }\n * })\n */\n Zod: zodPropertyOptions,\n\n /**\n * Discriminated entity property (for polymorphic entities with discriminator)\n * @example\n * EntitySchema.define({\n * name: 'Shape',\n * properties: {\n * shape: EntityProps.DiscriminatedEntity({ discriminatorProperty: 'type' }),\n * }\n * })\n */\n DiscriminatedEntity: discriminatedEntityPropertyOptions,\n};\n"],"names":["ENTITY_METADATA_KEY","ENTITY_OPTIONS_METADATA_KEY","ENTITY_VALIDATOR_METADATA_KEY","PROPERTY_METADATA_KEY","PROPERTY_OPTIONS_METADATA_KEY","EntityRegistry","EntityUtils","stringPropertyOptions","enumPropertyOptions","numberPropertyOptions","intPropertyOptions","booleanPropertyOptions","datePropertyOptions","bigIntPropertyOptions","entityPropertyOptions","arrayPropertyOptions","passthroughPropertyOptions","discriminatedEntityPropertyOptions","zodPropertyOptions","defineEntity","entityClass","config","entityName","name","Reflect","defineMetadata","entityOptions","options","register","propertyKeys","Object","keys","properties","prototype","validators","length","validatorMethodNames","forEach","validatorFn","index","methodName","push","EntitySchema","define","data","assign","wrapper","parse","safeParse","parsePartial","partialParse","safeParsePartial","safePartialParse","serialize","instance","toJSON","update","safeUpdate","validate","equals","a","b","diff","diffs","result","property","from","oldValue","to","newValue","getChanges","changes","EntityProps","String","Enum","Number","Int","Boolean","Date","BigInt","Entity","Array","Passthrough","Zod","DiscriminatedEntity"],"mappings":"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"}
|
|
@@ -88,6 +88,15 @@ export declare class EntityUtils {
|
|
|
88
88
|
* ```
|
|
89
89
|
*/
|
|
90
90
|
static isStringifiable(entityOrClass: unknown): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Gets the "wrapper" property name for entities that act as transparent wrappers.
|
|
93
|
+
* When set, this property name is excluded from error paths during validation.
|
|
94
|
+
*
|
|
95
|
+
* @param entityOrClass - The entity instance or class to check
|
|
96
|
+
* @returns The wrapper property name, or undefined if not a wrapper entity
|
|
97
|
+
* @private
|
|
98
|
+
*/
|
|
99
|
+
private static getWrapperPropertyName;
|
|
91
100
|
static sameEntity(a: object, b: object): boolean;
|
|
92
101
|
static getPropertyKeys(target: object): string[];
|
|
93
102
|
static getPropertyOptions(target: object, propertyKey: string): PropertyOptions | undefined;
|
|
@@ -436,6 +445,11 @@ export declare class EntityUtils {
|
|
|
436
445
|
* @private
|
|
437
446
|
*/
|
|
438
447
|
private static validatePropertyValue;
|
|
448
|
+
/**
|
|
449
|
+
* Checks if an array contains any entity elements
|
|
450
|
+
* @private
|
|
451
|
+
*/
|
|
452
|
+
private static hasEntityElements;
|
|
439
453
|
/**
|
|
440
454
|
* Runs property validators for a given property value
|
|
441
455
|
* @private
|