dyna-record 0.6.3 → 0.6.5
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/README.md +86 -1
- package/dist/src/decorators/attributes/ObjectAttribute.d.ts +6 -1
- package/dist/src/decorators/attributes/ObjectAttribute.d.ts.map +1 -1
- package/dist/src/decorators/attributes/ObjectAttribute.js +67 -20
- package/dist/src/decorators/attributes/index.d.ts +1 -1
- package/dist/src/decorators/attributes/index.d.ts.map +1 -1
- package/dist/src/decorators/attributes/serializers.d.ts +19 -0
- package/dist/src/decorators/attributes/serializers.d.ts.map +1 -1
- package/dist/src/decorators/attributes/serializers.js +56 -0
- package/dist/src/decorators/attributes/types.d.ts +101 -7
- package/dist/src/decorators/attributes/types.d.ts.map +1 -1
- package/dist/src/operations/utils/flattenObjectForUpdate.d.ts +2 -1
- package/dist/src/operations/utils/flattenObjectForUpdate.d.ts.map +1 -1
- package/dist/src/operations/utils/flattenObjectForUpdate.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -212,7 +212,7 @@ class Store extends MyTable {
|
|
|
212
212
|
}
|
|
213
213
|
```
|
|
214
214
|
|
|
215
|
-
- **Supported field types:** `"string"`, `"number"`, `"boolean"`, `"date"` (stored as ISO strings, exposed as `Date` objects), `"enum"` (via `values`), nested `"object"` (via `fields`),
|
|
215
|
+
- **Supported field types:** `"string"`, `"number"`, `"boolean"`, `"date"` (stored as ISO strings, exposed as `Date` objects), `"enum"` (via `values`), nested `"object"` (via `fields`), `"array"` (via `items`), and `"discriminatedUnion"` (via `discriminator` + `variants`)
|
|
216
216
|
- **Nullable fields:** Set `nullable: true` on individual non-object fields within the schema to make them optional
|
|
217
217
|
- **Object attributes are never nullable:** DynamoDB cannot update nested document paths (e.g., `address.geo.lat`) if the parent object does not exist. To prevent this, `@ObjectAttribute` fields always exist as at least an empty object `{}`. Nested object fields within the schema are also never nullable. Non-object fields (primitives, enums, dates, arrays) can still be nullable.
|
|
218
218
|
- **Alias support:** Use the `alias` option to map to a different DynamoDB attribute name
|
|
@@ -249,6 +249,82 @@ const schema = {
|
|
|
249
249
|
|
|
250
250
|
The schema must be declared with `as const satisfies ObjectSchema` so TypeScript preserves the literal string values for type inference. At runtime, providing an invalid value (e.g., `status: "unknown"`) throws a `ValidationError`.
|
|
251
251
|
|
|
252
|
+
##### Discriminated union fields
|
|
253
|
+
|
|
254
|
+
Use `{ type: "discriminatedUnion", discriminator: "...", variants: { ... } }` to define a field that is a tagged union of object types. Each variant is an `ObjectSchema` keyed by its discriminator value. The discriminator key is automatically included in each variant's inferred type as a string literal.
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
const drawingSchema = {
|
|
258
|
+
shape: {
|
|
259
|
+
type: "discriminatedUnion",
|
|
260
|
+
discriminator: "kind",
|
|
261
|
+
variants: {
|
|
262
|
+
circle: { radius: { type: "number" } },
|
|
263
|
+
square: { side: { type: "number" } }
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
} as const satisfies ObjectSchema;
|
|
267
|
+
|
|
268
|
+
@Entity
|
|
269
|
+
class Drawing extends MyTable {
|
|
270
|
+
declare readonly type: "Drawing";
|
|
271
|
+
|
|
272
|
+
@ObjectAttribute({ alias: "Drawing", schema: drawingSchema })
|
|
273
|
+
public readonly drawing: InferObjectSchema<typeof drawingSchema>;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// TypeScript infers:
|
|
277
|
+
// drawing.shape → { kind: "circle"; radius: number } | { kind: "square"; side: number }
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Unlike nested `"object"` fields, discriminated union fields **can be nullable** (`nullable: true`) because they always use **full replacement** on update rather than document path expressions:
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
// Replaces the entire shape field — no partial merge
|
|
284
|
+
await Drawing.update("123", {
|
|
285
|
+
drawing: { shape: { kind: "square", side: 10 } }
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
##### Arrays of discriminated unions
|
|
290
|
+
|
|
291
|
+
Discriminated unions can be used as array items. Each element in the array is validated and serialized using variant-aware logic:
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
const dashboardSchema = {
|
|
295
|
+
widgets: {
|
|
296
|
+
type: "array",
|
|
297
|
+
items: {
|
|
298
|
+
type: "discriminatedUnion",
|
|
299
|
+
discriminator: "type",
|
|
300
|
+
variants: {
|
|
301
|
+
"metric-card": {
|
|
302
|
+
label: { type: "string" },
|
|
303
|
+
value: { type: "number" }
|
|
304
|
+
},
|
|
305
|
+
chart: {
|
|
306
|
+
title: { type: "string" },
|
|
307
|
+
chartType: { type: "enum", values: ["bar", "line", "pie"] }
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
} as const satisfies ObjectSchema;
|
|
313
|
+
|
|
314
|
+
// TypeScript infers:
|
|
315
|
+
// dashboard.widgets → Array<
|
|
316
|
+
// | { type: "metric-card"; label: string; value: number }
|
|
317
|
+
// | { type: "chart"; title: string; chartType: "bar" | "line" | "pie" }
|
|
318
|
+
// >
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Arrays of discriminated unions use **full replacement** on update (the entire array is replaced), consistent with all array fields.
|
|
322
|
+
|
|
323
|
+
**Scoping constraints:**
|
|
324
|
+
|
|
325
|
+
- Supported at the ObjectAttribute root level, as fields within an ObjectSchema, and as array items
|
|
326
|
+
- Not supported nested inside other discriminated unions
|
|
327
|
+
|
|
252
328
|
### Foreign Keys
|
|
253
329
|
|
|
254
330
|
Define foreign keys in order to support [@BelongsTo](https://docs.dyna-record.com/functions/BelongsTo.html) relationships. A foreign key is required for [@HasOne](https://docs.dyna-record.com/functions/HasOne.html) and [@HasMany](https://docs.dyna-record.com/functions/HasMany.html) relationships.
|
|
@@ -990,6 +1066,15 @@ await Store.update("123", {
|
|
|
990
1066
|
});
|
|
991
1067
|
```
|
|
992
1068
|
|
|
1069
|
+
**Discriminated unions** within objects are also **full replacement** (not merged):
|
|
1070
|
+
|
|
1071
|
+
```typescript
|
|
1072
|
+
// Replaces the entire shape — switches from circle to square
|
|
1073
|
+
await Drawing.update("123", {
|
|
1074
|
+
drawing: { shape: { kind: "square", side: 10 } }
|
|
1075
|
+
});
|
|
1076
|
+
```
|
|
1077
|
+
|
|
993
1078
|
The instance `update` method returns a deep-merged result, preserving existing fields:
|
|
994
1079
|
|
|
995
1080
|
```typescript
|
|
@@ -10,7 +10,7 @@ import type { ObjectSchema, InferObjectSchema } from "./types";
|
|
|
10
10
|
* `ValidationException: The document path provided in the update expression is invalid for update`.
|
|
11
11
|
* To avoid this, `@ObjectAttribute` fields always exist as at least an empty object `{}`.
|
|
12
12
|
*
|
|
13
|
-
* The schema supports all {@link FieldDef} types: primitives, enums, nested objects, and
|
|
13
|
+
* The schema supports all {@link FieldDef} types: primitives, enums, nested objects, arrays, and discriminated unions.
|
|
14
14
|
* Non-object fields within the schema may still be nullable.
|
|
15
15
|
*
|
|
16
16
|
* @template S The specific ObjectSchema type used for type inference
|
|
@@ -47,6 +47,7 @@ export interface ObjectAttributeOptions<S extends ObjectSchema> extends NonNullA
|
|
|
47
47
|
* - `"date"` — dates stored as ISO strings (support `nullable: true`)
|
|
48
48
|
* - `"object"` — nested objects, arbitrarily deep (**never nullable**)
|
|
49
49
|
* - `"array"` — lists of any field type (support `nullable: true`, full replacement on update)
|
|
50
|
+
* - `"discriminatedUnion"` — tagged unions via `discriminator` + `variants` (support `nullable: true`, full replacement on update)
|
|
50
51
|
*
|
|
51
52
|
* Objects within arrays are not subject to the document path limitation because arrays
|
|
52
53
|
* use full replacement on update. Partial updates of individual objects within arrays
|
|
@@ -102,6 +103,10 @@ export interface ObjectAttributeOptions<S extends ObjectSchema> extends NonNullA
|
|
|
102
103
|
* await MyEntity.update("id", { address: { zip: null } });
|
|
103
104
|
* ```
|
|
104
105
|
*
|
|
106
|
+
* **Discriminated union fields** always use **full replacement** on update — the user
|
|
107
|
+
* must provide a complete variant object. See {@link DiscriminatedUnionFieldDef} for
|
|
108
|
+
* the rationale.
|
|
109
|
+
*
|
|
105
110
|
* Object attributes support filtering in queries using dot-path notation for nested fields
|
|
106
111
|
* and the {@link ContainsFilter | $contains} operator for List membership checks.
|
|
107
112
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectAttribute.d.ts","sourceRoot":"","sources":["../../../../src/decorators/attributes/ObjectAttribute.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAE/C,OAAO,KAAK,EACV,yBAAyB,EACzB,uBAAuB,EACxB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ObjectAttribute.d.ts","sourceRoot":"","sources":["../../../../src/decorators/attributes/ObjectAttribute.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAE/C,OAAO,KAAK,EACV,yBAAyB,EACzB,uBAAuB,EACxB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EAGlB,MAAM,SAAS,CAAC;AAGjB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,sBAAsB,CAAC,CAAC,SAAS,YAAY,CAC5D,SAAQ,uBAAuB;IAC/B;;;;OAIG;IACH,MAAM,EAAE,CAAC,CAAC;CACX;AAkKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0FG;AACH,iBAAS,eAAe,CAAC,CAAC,SAAS,UAAU,EAAE,KAAK,CAAC,CAAC,SAAS,YAAY,EACzE,KAAK,EAAE,sBAAsB,CAAC,CAAC,CAAC,YAGtB,SAAS,WACR,yBAAyB,CAChC,CAAC,EACD,iBAAiB,CAAC,CAAC,CAAC,EACpB,sBAAsB,CAAC,CAAC,CAAC,CAC1B,UAoBJ;AAED,eAAe,eAAe,CAAC"}
|
|
@@ -6,6 +6,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const zod_1 = require("zod");
|
|
7
7
|
const metadata_1 = __importDefault(require("../../metadata"));
|
|
8
8
|
const serializers_1 = require("./serializers");
|
|
9
|
+
/**
|
|
10
|
+
* Builds a Zod shape record from an {@link ObjectSchema} using the provided
|
|
11
|
+
* field converter function. Shared by both full and partial schema builders.
|
|
12
|
+
*/
|
|
13
|
+
function buildZodShape(schema, fieldConverter) {
|
|
14
|
+
const shape = {};
|
|
15
|
+
for (const [key, fieldDef] of Object.entries(schema)) {
|
|
16
|
+
shape[key] = fieldConverter(fieldDef);
|
|
17
|
+
}
|
|
18
|
+
return shape;
|
|
19
|
+
}
|
|
9
20
|
/**
|
|
10
21
|
* Converts an {@link ObjectSchema} to a partial Zod schema for update validation.
|
|
11
22
|
*
|
|
@@ -17,23 +28,26 @@ const serializers_1 = require("./serializers");
|
|
|
17
28
|
* @returns A ZodType that validates partial objects matching the schema
|
|
18
29
|
*/
|
|
19
30
|
function objectSchemaToZodPartial(schema) {
|
|
20
|
-
|
|
21
|
-
for (const [key, fieldDef] of Object.entries(schema)) {
|
|
22
|
-
shape[key] = fieldDefToZodPartial(fieldDef);
|
|
23
|
-
}
|
|
24
|
-
return zod_1.z.object(shape).partial();
|
|
31
|
+
return zod_1.z.object(buildZodShape(schema, fieldDefToZodPartial)).partial();
|
|
25
32
|
}
|
|
26
33
|
/**
|
|
27
34
|
* Converts a single {@link FieldDef} to the corresponding partial Zod type.
|
|
28
35
|
* Nested objects use partial schemas; all other types use the standard schema.
|
|
29
36
|
* Object fields are never nullable — they always exist as at least `{}`.
|
|
37
|
+
* Discriminated union fields use the full schema (not partial) since they
|
|
38
|
+
* always use full replacement on update.
|
|
30
39
|
*/
|
|
31
40
|
function fieldDefToZodPartial(fieldDef) {
|
|
32
|
-
|
|
33
|
-
|
|
41
|
+
switch (fieldDef.type) {
|
|
42
|
+
case "object":
|
|
43
|
+
return objectSchemaToZodPartial(fieldDef.fields);
|
|
44
|
+
case "discriminatedUnion":
|
|
45
|
+
// Discriminated unions use full replacement — same schema as create
|
|
46
|
+
return discriminatedUnionToZod(fieldDef);
|
|
47
|
+
default:
|
|
48
|
+
// For non-object fields, use the standard schema (includes nullable wrapping)
|
|
49
|
+
return fieldDefToZod(fieldDef);
|
|
34
50
|
}
|
|
35
|
-
// For non-object fields, use the standard schema (includes nullable wrapping)
|
|
36
|
-
return fieldDefToZod(fieldDef);
|
|
37
51
|
}
|
|
38
52
|
/**
|
|
39
53
|
* Converts an {@link ObjectSchema} to a Zod schema for runtime validation.
|
|
@@ -42,11 +56,34 @@ function fieldDefToZodPartial(fieldDef) {
|
|
|
42
56
|
* @returns A ZodType that validates objects matching the schema
|
|
43
57
|
*/
|
|
44
58
|
function objectSchemaToZod(schema) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
59
|
+
return zod_1.z.object(buildZodShape(schema, fieldDefToZod));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Builds a Zod `discriminatedUnion` schema from a {@link DiscriminatedUnionFieldDef}.
|
|
63
|
+
*
|
|
64
|
+
* Each variant's ObjectSchema is converted to a `z.object()` and extended with a
|
|
65
|
+
* `z.literal()` for the discriminator key. The resulting schemas are wrapped in
|
|
66
|
+
* `z.discriminatedUnion()`.
|
|
67
|
+
*
|
|
68
|
+
* @param fieldDef The discriminated union field definition
|
|
69
|
+
* @returns A ZodType that validates discriminated union values
|
|
70
|
+
*/
|
|
71
|
+
function discriminatedUnionToZod(fieldDef) {
|
|
72
|
+
const variantEntries = Object.entries(fieldDef.variants);
|
|
73
|
+
if (variantEntries.length === 0) {
|
|
74
|
+
throw new Error("DiscriminatedUnionFieldDef requires at least one variant");
|
|
75
|
+
}
|
|
76
|
+
const variantSchemas = variantEntries.map(([variantKey, variantObjectSchema]) => {
|
|
77
|
+
const variantZod = objectSchemaToZod(variantObjectSchema);
|
|
78
|
+
return variantZod.extend({
|
|
79
|
+
[fieldDef.discriminator]: zod_1.z.literal(variantKey)
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
let zodType = zod_1.z.discriminatedUnion(fieldDef.discriminator, variantSchemas);
|
|
83
|
+
if (fieldDef.nullable === true) {
|
|
84
|
+
zodType = zodType.optional().nullable();
|
|
48
85
|
}
|
|
49
|
-
return
|
|
86
|
+
return zodType;
|
|
50
87
|
}
|
|
51
88
|
/**
|
|
52
89
|
* Converts a single {@link FieldDef} to the corresponding Zod type for runtime validation.
|
|
@@ -54,6 +91,7 @@ function objectSchemaToZod(schema) {
|
|
|
54
91
|
* Handles all field types:
|
|
55
92
|
* - `"object"` → recursively builds a `z.object()` via {@link objectSchemaToZod}.
|
|
56
93
|
* Object fields are never nullable — DynamoDB requires them to exist for document path updates.
|
|
94
|
+
* - `"discriminatedUnion"` → `z.discriminatedUnion()` via {@link discriminatedUnionToZod}
|
|
57
95
|
* - `"array"` → `z.array()` wrapping a recursive call for the `items` type
|
|
58
96
|
* - `"string"` → `z.string()`
|
|
59
97
|
* - `"number"` → `z.number()`
|
|
@@ -66,9 +104,12 @@ function objectSchemaToZod(schema) {
|
|
|
66
104
|
* @returns A ZodType that validates values matching the field definition
|
|
67
105
|
*/
|
|
68
106
|
function fieldDefToZod(fieldDef) {
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
107
|
+
// These types handle their own nullable semantics or are never nullable
|
|
108
|
+
switch (fieldDef.type) {
|
|
109
|
+
case "object":
|
|
110
|
+
return objectSchemaToZod(fieldDef.fields);
|
|
111
|
+
case "discriminatedUnion":
|
|
112
|
+
return discriminatedUnionToZod(fieldDef);
|
|
72
113
|
}
|
|
73
114
|
let zodType;
|
|
74
115
|
switch (fieldDef.type) {
|
|
@@ -118,6 +159,7 @@ function fieldDefToZod(fieldDef) {
|
|
|
118
159
|
* - `"date"` — dates stored as ISO strings (support `nullable: true`)
|
|
119
160
|
* - `"object"` — nested objects, arbitrarily deep (**never nullable**)
|
|
120
161
|
* - `"array"` — lists of any field type (support `nullable: true`, full replacement on update)
|
|
162
|
+
* - `"discriminatedUnion"` — tagged unions via `discriminator` + `variants` (support `nullable: true`, full replacement on update)
|
|
121
163
|
*
|
|
122
164
|
* Objects within arrays are not subject to the document path limitation because arrays
|
|
123
165
|
* use full replacement on update. Partial updates of individual objects within arrays
|
|
@@ -173,6 +215,10 @@ function fieldDefToZod(fieldDef) {
|
|
|
173
215
|
* await MyEntity.update("id", { address: { zip: null } });
|
|
174
216
|
* ```
|
|
175
217
|
*
|
|
218
|
+
* **Discriminated union fields** always use **full replacement** on update — the user
|
|
219
|
+
* must provide a complete variant object. See {@link DiscriminatedUnionFieldDef} for
|
|
220
|
+
* the rationale.
|
|
221
|
+
*
|
|
176
222
|
* Object attributes support filtering in queries using dot-path notation for nested fields
|
|
177
223
|
* and the {@link ContainsFilter | $contains} operator for List membership checks.
|
|
178
224
|
*
|
|
@@ -188,11 +234,12 @@ function fieldDefToZod(fieldDef) {
|
|
|
188
234
|
*/
|
|
189
235
|
function ObjectAttribute(props) {
|
|
190
236
|
return function (_value, context) {
|
|
237
|
+
// Fail fast: surface schema validation errors at class definition time.
|
|
238
|
+
const { schema, ...restProps } = props;
|
|
239
|
+
const zodSchema = objectSchemaToZod(schema);
|
|
240
|
+
const partialZodSchema = objectSchemaToZodPartial(schema);
|
|
241
|
+
const serializers = (0, serializers_1.createObjectSerializer)(schema);
|
|
191
242
|
context.addInitializer(function () {
|
|
192
|
-
const { schema, ...restProps } = props;
|
|
193
|
-
const zodSchema = objectSchemaToZod(schema);
|
|
194
|
-
const partialZodSchema = objectSchemaToZodPartial(schema);
|
|
195
|
-
const serializers = (0, serializers_1.createObjectSerializer)(schema);
|
|
196
243
|
metadata_1.default.addEntityAttribute(this.constructor.name, {
|
|
197
244
|
attributeName: context.name.toString(),
|
|
198
245
|
type: zodSchema,
|
|
@@ -10,5 +10,5 @@ export { default as IdAttribute } from "./IdAttribute";
|
|
|
10
10
|
export { default as ObjectAttribute } from "./ObjectAttribute";
|
|
11
11
|
export type { ObjectAttributeOptions } from "./ObjectAttribute";
|
|
12
12
|
export * from "./serializers";
|
|
13
|
-
export type { ObjectSchema, InferObjectSchema, FieldDef, PrimitiveFieldDef, ObjectFieldDef, ArrayFieldDef, EnumFieldDef, DateFieldDef } from "./types";
|
|
13
|
+
export type { ObjectSchema, NonUnionObjectSchema, InferObjectSchema, InferDiscriminatedUnion, FieldDef, NonUnionFieldDef, PrimitiveFieldDef, ObjectFieldDef, ArrayFieldDef, EnumFieldDef, DateFieldDef, DiscriminatedUnionFieldDef } from "./types";
|
|
14
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/decorators/attributes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/D,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,cAAc,eAAe,CAAC;AAC9B,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,QAAQ,EACR,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,YAAY,EACZ,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/decorators/attributes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/D,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,cAAc,eAAe,CAAC;AAC9B,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,0BAA0B,EAC3B,MAAM,SAAS,CAAC"}
|
|
@@ -19,6 +19,8 @@ export declare const dateSerializer: {
|
|
|
19
19
|
* - `"date"` fields are converted from `Date` objects to ISO 8601 strings.
|
|
20
20
|
* - `"object"` fields recurse into their nested schema.
|
|
21
21
|
* - `"array"` fields map each item through the same conversion.
|
|
22
|
+
* - `"discriminatedUnion"` fields look up the variant schema by discriminator value
|
|
23
|
+
* and recurse into that variant's object schema, preserving the discriminator key.
|
|
22
24
|
* - `null` and `undefined` values are stripped from the result so that nullable
|
|
23
25
|
* fields set to `null` are removed from the stored object rather than persisted
|
|
24
26
|
* as `null` in DynamoDB.
|
|
@@ -29,6 +31,21 @@ export declare const dateSerializer: {
|
|
|
29
31
|
* @returns A new object suitable for DynamoDB storage
|
|
30
32
|
*/
|
|
31
33
|
export declare function objectToTableItem(schema: ObjectSchema, value: Record<string, unknown>): Record<string, unknown>;
|
|
34
|
+
/**
|
|
35
|
+
* Converts a single field value to its DynamoDB table representation based on
|
|
36
|
+
* the field definition.
|
|
37
|
+
*
|
|
38
|
+
* - `"date"` → ISO 8601 string
|
|
39
|
+
* - `"object"` → recursively converts via {@link objectToTableItem}
|
|
40
|
+
* - `"array"` → maps each item through the same conversion
|
|
41
|
+
* - `"discriminatedUnion"` → looks up the variant schema by discriminator value,
|
|
42
|
+
* converts via {@link objectToTableItem}, and preserves the discriminator key
|
|
43
|
+
* - All other types pass through unchanged
|
|
44
|
+
*
|
|
45
|
+
* @param fieldDef The {@link FieldDef} describing the field's type
|
|
46
|
+
* @param val The entity-level value to convert
|
|
47
|
+
* @returns The DynamoDB-compatible value
|
|
48
|
+
*/
|
|
32
49
|
export declare function convertFieldToTableItem(fieldDef: FieldDef, val: unknown): unknown;
|
|
33
50
|
/**
|
|
34
51
|
* Recursively walks an {@link ObjectSchema} and converts a DynamoDB table item
|
|
@@ -37,6 +54,8 @@ export declare function convertFieldToTableItem(fieldDef: FieldDef, val: unknown
|
|
|
37
54
|
* - `"date"` fields are converted from ISO 8601 strings to `Date` objects.
|
|
38
55
|
* - `"object"` fields recurse into their nested schema.
|
|
39
56
|
* - `"array"` fields map each item through the same conversion.
|
|
57
|
+
* - `"discriminatedUnion"` fields look up the variant schema by discriminator value
|
|
58
|
+
* and recurse into that variant's object schema, preserving the discriminator key.
|
|
40
59
|
* - `null` and `undefined` values are stripped from the result so that absent
|
|
41
60
|
* fields are represented as `undefined` (omitted) on the entity, consistent
|
|
42
61
|
* with root-level nullable attribute behaviour.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serializers.d.ts","sourceRoot":"","sources":["../../../../src/decorators/attributes/serializers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc;6BACA,oBAAoB,KAAG,OAAO;4BAM/B,OAAO;CAEhC,CAAC;
|
|
1
|
+
{"version":3,"file":"serializers.d.ts","sourceRoot":"","sources":["../../../../src/decorators/attributes/serializers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc;6BACA,oBAAoB,KAAG,OAAO;4BAM/B,OAAO;CAEhC,CAAC;AAuBF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzB;AAwBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,OAAO,GACX,OAAO,CAmBT;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzB;AA8BD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW,CAOxE"}
|
|
@@ -21,6 +21,20 @@ exports.dateSerializer = {
|
|
|
21
21
|
},
|
|
22
22
|
toTableAttribute: (val) => val instanceof Date ? val.toISOString() : undefined
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Resolves the variant schema for a discriminated union value by reading the
|
|
26
|
+
* discriminator key and looking up the corresponding variant in the field definition.
|
|
27
|
+
*
|
|
28
|
+
* Uses `Object.hasOwn` to guard against prototype property pollution — only
|
|
29
|
+
* own-enumerable variant keys are matched.
|
|
30
|
+
*/
|
|
31
|
+
function resolveVariantSchema(fieldDef, value) {
|
|
32
|
+
const discriminatorValue = value[fieldDef.discriminator];
|
|
33
|
+
if (!Object.hasOwn(fieldDef.variants, discriminatorValue)) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
return fieldDef.variants[discriminatorValue];
|
|
37
|
+
}
|
|
24
38
|
/**
|
|
25
39
|
* Recursively walks an {@link ObjectSchema} and converts the entity value to its
|
|
26
40
|
* DynamoDB representation.
|
|
@@ -28,6 +42,8 @@ exports.dateSerializer = {
|
|
|
28
42
|
* - `"date"` fields are converted from `Date` objects to ISO 8601 strings.
|
|
29
43
|
* - `"object"` fields recurse into their nested schema.
|
|
30
44
|
* - `"array"` fields map each item through the same conversion.
|
|
45
|
+
* - `"discriminatedUnion"` fields look up the variant schema by discriminator value
|
|
46
|
+
* and recurse into that variant's object schema, preserving the discriminator key.
|
|
31
47
|
* - `null` and `undefined` values are stripped from the result so that nullable
|
|
32
48
|
* fields set to `null` are removed from the stored object rather than persisted
|
|
33
49
|
* as `null` in DynamoDB.
|
|
@@ -48,6 +64,33 @@ function objectToTableItem(schema, value) {
|
|
|
48
64
|
}
|
|
49
65
|
return result;
|
|
50
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Resolves and converts a discriminated union value using the provided schema
|
|
69
|
+
* converter function. Shared by both serialization and deserialization paths.
|
|
70
|
+
*/
|
|
71
|
+
function convertDiscriminatedUnion(fieldDef, value, schemaConverter) {
|
|
72
|
+
const variantSchema = resolveVariantSchema(fieldDef, value);
|
|
73
|
+
if (variantSchema === undefined)
|
|
74
|
+
return value;
|
|
75
|
+
const result = schemaConverter(variantSchema, value);
|
|
76
|
+
result[fieldDef.discriminator] = value[fieldDef.discriminator];
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Converts a single field value to its DynamoDB table representation based on
|
|
81
|
+
* the field definition.
|
|
82
|
+
*
|
|
83
|
+
* - `"date"` → ISO 8601 string
|
|
84
|
+
* - `"object"` → recursively converts via {@link objectToTableItem}
|
|
85
|
+
* - `"array"` → maps each item through the same conversion
|
|
86
|
+
* - `"discriminatedUnion"` → looks up the variant schema by discriminator value,
|
|
87
|
+
* converts via {@link objectToTableItem}, and preserves the discriminator key
|
|
88
|
+
* - All other types pass through unchanged
|
|
89
|
+
*
|
|
90
|
+
* @param fieldDef The {@link FieldDef} describing the field's type
|
|
91
|
+
* @param val The entity-level value to convert
|
|
92
|
+
* @returns The DynamoDB-compatible value
|
|
93
|
+
*/
|
|
51
94
|
function convertFieldToTableItem(fieldDef, val) {
|
|
52
95
|
switch (fieldDef.type) {
|
|
53
96
|
case "date":
|
|
@@ -56,6 +99,8 @@ function convertFieldToTableItem(fieldDef, val) {
|
|
|
56
99
|
return objectToTableItem(fieldDef.fields, val);
|
|
57
100
|
case "array":
|
|
58
101
|
return val.map(item => convertFieldToTableItem(fieldDef.items, item));
|
|
102
|
+
case "discriminatedUnion":
|
|
103
|
+
return convertDiscriminatedUnion(fieldDef, val, objectToTableItem);
|
|
59
104
|
default:
|
|
60
105
|
return val;
|
|
61
106
|
}
|
|
@@ -67,6 +112,8 @@ function convertFieldToTableItem(fieldDef, val) {
|
|
|
67
112
|
* - `"date"` fields are converted from ISO 8601 strings to `Date` objects.
|
|
68
113
|
* - `"object"` fields recurse into their nested schema.
|
|
69
114
|
* - `"array"` fields map each item through the same conversion.
|
|
115
|
+
* - `"discriminatedUnion"` fields look up the variant schema by discriminator value
|
|
116
|
+
* and recurse into that variant's object schema, preserving the discriminator key.
|
|
70
117
|
* - `null` and `undefined` values are stripped from the result so that absent
|
|
71
118
|
* fields are represented as `undefined` (omitted) on the entity, consistent
|
|
72
119
|
* with root-level nullable attribute behaviour.
|
|
@@ -87,6 +134,13 @@ function tableItemToObject(schema, value) {
|
|
|
87
134
|
}
|
|
88
135
|
return result;
|
|
89
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Converts a single DynamoDB field value back to its entity representation.
|
|
139
|
+
*
|
|
140
|
+
* Mirrors {@link convertFieldToTableItem} in reverse: dates become `Date` objects,
|
|
141
|
+
* objects and discriminated unions recurse through their schemas, arrays map each item,
|
|
142
|
+
* and all other types pass through unchanged.
|
|
143
|
+
*/
|
|
90
144
|
function convertFieldToEntityValue(fieldDef, val) {
|
|
91
145
|
switch (fieldDef.type) {
|
|
92
146
|
case "date":
|
|
@@ -95,6 +149,8 @@ function convertFieldToEntityValue(fieldDef, val) {
|
|
|
95
149
|
return tableItemToObject(fieldDef.fields, val);
|
|
96
150
|
case "array":
|
|
97
151
|
return val.map(item => convertFieldToEntityValue(fieldDef.items, item));
|
|
152
|
+
case "discriminatedUnion":
|
|
153
|
+
return convertDiscriminatedUnion(fieldDef, val, tableItemToObject);
|
|
98
154
|
default:
|
|
99
155
|
return val;
|
|
100
156
|
}
|
|
@@ -91,7 +91,12 @@ export interface ObjectFieldDef {
|
|
|
91
91
|
export interface ArrayFieldDef {
|
|
92
92
|
/** Must be `"array"` to indicate a list/array field. */
|
|
93
93
|
type: "array";
|
|
94
|
-
/**
|
|
94
|
+
/**
|
|
95
|
+
* A {@link FieldDef} describing the type of each array element.
|
|
96
|
+
* All field types are supported as array items, including discriminated unions.
|
|
97
|
+
* Arrays always use full replacement on update, so discriminated union items
|
|
98
|
+
* are serialized per-element using variant-aware logic.
|
|
99
|
+
*/
|
|
95
100
|
items: FieldDef;
|
|
96
101
|
/** When `true`, the field becomes optional. */
|
|
97
102
|
nullable?: boolean;
|
|
@@ -171,6 +176,70 @@ export interface DateFieldDef {
|
|
|
171
176
|
/** When `true`, the field becomes optional (`Date | undefined`). */
|
|
172
177
|
nullable?: boolean;
|
|
173
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* A schema field definition for a discriminated union type.
|
|
181
|
+
*
|
|
182
|
+
* The `discriminator` names the key used to distinguish variants, and `variants`
|
|
183
|
+
* maps each discriminator value to an {@link ObjectSchema} describing that variant's
|
|
184
|
+
* fields. The discriminator key is automatically added to each variant's inferred type
|
|
185
|
+
* as a string literal.
|
|
186
|
+
*
|
|
187
|
+
* **Update semantics:** Discriminated union fields always use **full replacement** on
|
|
188
|
+
* update (`SET #field = :value`), never document path merging. This is because:
|
|
189
|
+
* - Different variants have different field sets — a partial document path update could
|
|
190
|
+
* leave orphaned fields from a previous variant leaking through when variants change.
|
|
191
|
+
* - Avoiding orphaned fields without full replacement would require a read-before-write
|
|
192
|
+
* to determine the current discriminator value.
|
|
193
|
+
* - This matches array update semantics (also full replacement).
|
|
194
|
+
*
|
|
195
|
+
* Unlike {@link ObjectFieldDef}, discriminated union fields **can be nullable** because
|
|
196
|
+
* they always use full replacement on update rather than document path expressions,
|
|
197
|
+
* so there is no risk of DynamoDB failing on a missing parent path.
|
|
198
|
+
*
|
|
199
|
+
* **Scoping constraints:**
|
|
200
|
+
* - Supported at the ObjectAttribute root level, as fields within an ObjectSchema,
|
|
201
|
+
* and as array items
|
|
202
|
+
* - Not supported nested inside other discriminated unions
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```typescript
|
|
206
|
+
* const schema = {
|
|
207
|
+
* shape: {
|
|
208
|
+
* type: "discriminatedUnion",
|
|
209
|
+
* discriminator: "kind",
|
|
210
|
+
* variants: {
|
|
211
|
+
* circle: { radius: { type: "number" } },
|
|
212
|
+
* square: { side: { type: "number" } }
|
|
213
|
+
* }
|
|
214
|
+
* }
|
|
215
|
+
* } as const satisfies ObjectSchema;
|
|
216
|
+
*
|
|
217
|
+
* type T = InferObjectSchema<typeof schema>;
|
|
218
|
+
* // { shape: { kind: "circle"; radius: number } | { kind: "square"; side: number } }
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
export interface DiscriminatedUnionFieldDef {
|
|
222
|
+
/** Must be `"discriminatedUnion"` to indicate a discriminated union field. */
|
|
223
|
+
type: "discriminatedUnion";
|
|
224
|
+
/** The key name used to discriminate between variants. */
|
|
225
|
+
discriminator: string;
|
|
226
|
+
/**
|
|
227
|
+
* A record mapping each discriminator value to a {@link NonUnionObjectSchema}
|
|
228
|
+
* describing that variant's fields (excluding the discriminator itself).
|
|
229
|
+
* Discriminated unions cannot be nested inside other discriminated unions.
|
|
230
|
+
*/
|
|
231
|
+
variants: Readonly<Record<string, NonUnionObjectSchema>>;
|
|
232
|
+
/** When `true`, the field becomes optional (`T | undefined`). */
|
|
233
|
+
nullable?: boolean;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* A field definition that excludes {@link DiscriminatedUnionFieldDef}.
|
|
237
|
+
*
|
|
238
|
+
* Used in contexts where discriminated unions are not allowed:
|
|
239
|
+
* - {@link DiscriminatedUnionFieldDef} `variants` — discriminated unions cannot
|
|
240
|
+
* be nested inside other discriminated unions
|
|
241
|
+
*/
|
|
242
|
+
export type NonUnionFieldDef = PrimitiveFieldDef | DateFieldDef | ObjectFieldDef | ArrayFieldDef | EnumFieldDef;
|
|
174
243
|
/**
|
|
175
244
|
* A field definition within an {@link ObjectSchema}.
|
|
176
245
|
*
|
|
@@ -180,10 +249,17 @@ export interface DateFieldDef {
|
|
|
180
249
|
* - {@link ObjectFieldDef} — nested objects via `fields`
|
|
181
250
|
* - {@link ArrayFieldDef} — arrays/lists via `items`
|
|
182
251
|
* - {@link EnumFieldDef} — string literal enums via `values`
|
|
252
|
+
* - {@link DiscriminatedUnionFieldDef} — discriminated unions via `discriminator` + `variants`
|
|
183
253
|
*
|
|
184
254
|
* Each variant is discriminated by the `type` property.
|
|
185
255
|
*/
|
|
186
|
-
export type FieldDef =
|
|
256
|
+
export type FieldDef = NonUnionFieldDef | DiscriminatedUnionFieldDef;
|
|
257
|
+
/**
|
|
258
|
+
* ObjectSchema that excludes discriminated union fields.
|
|
259
|
+
* Used for {@link DiscriminatedUnionFieldDef} variant schemas where
|
|
260
|
+
* nested discriminated unions are not allowed.
|
|
261
|
+
*/
|
|
262
|
+
export type NonUnionObjectSchema = Record<string, NonUnionFieldDef>;
|
|
187
263
|
/**
|
|
188
264
|
* Declarative schema for describing the shape of an object attribute.
|
|
189
265
|
*
|
|
@@ -205,18 +281,36 @@ export type FieldDef = PrimitiveFieldDef | DateFieldDef | ObjectFieldDef | Array
|
|
|
205
281
|
* ```
|
|
206
282
|
*/
|
|
207
283
|
export type ObjectSchema = Record<string, FieldDef>;
|
|
284
|
+
/**
|
|
285
|
+
* Infers the TypeScript type of a {@link DiscriminatedUnionFieldDef}.
|
|
286
|
+
*
|
|
287
|
+
* Iterates over the variant keys and for each produces a union member that is
|
|
288
|
+
* `{ [discriminator]: VariantKey } & InferObjectSchema<VariantSchema>`.
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* ```typescript
|
|
292
|
+
* // Given: discriminator: "kind", variants: { circle: { radius: { type: "number" } }, square: { side: { type: "number" } } }
|
|
293
|
+
* // Produces: { kind: "circle"; radius: number } | { kind: "square"; side: number }
|
|
294
|
+
* ```
|
|
295
|
+
*/
|
|
296
|
+
export type InferDiscriminatedUnion<F extends DiscriminatedUnionFieldDef> = {
|
|
297
|
+
[V in keyof F["variants"] & string]: {
|
|
298
|
+
[D in F["discriminator"]]: V;
|
|
299
|
+
} & InferObjectSchema<F["variants"][V]>;
|
|
300
|
+
}[keyof F["variants"] & string];
|
|
208
301
|
/**
|
|
209
302
|
* Infers the TypeScript type of a single {@link FieldDef}.
|
|
210
303
|
*
|
|
211
304
|
* Used internally by {@link InferObjectSchema} and for recursive array item inference.
|
|
212
305
|
*
|
|
213
306
|
* Resolution order:
|
|
214
|
-
* 1. {@link
|
|
215
|
-
* 2. {@link
|
|
216
|
-
* 3. {@link
|
|
217
|
-
* 4. {@link
|
|
307
|
+
* 1. {@link DiscriminatedUnionFieldDef} → `InferDiscriminatedUnion<F>`
|
|
308
|
+
* 2. {@link ArrayFieldDef} → `Array<InferFieldDef<items>>`
|
|
309
|
+
* 3. {@link ObjectFieldDef} → `InferObjectSchema<fields>`
|
|
310
|
+
* 4. {@link EnumFieldDef} → `values[number]` (string literal union)
|
|
311
|
+
* 5. {@link PrimitiveFieldDef} → `PrimitiveTypeMap[type]`
|
|
218
312
|
*/
|
|
219
|
-
export type InferFieldDef<F extends FieldDef> = F extends ArrayFieldDef ? Array<InferFieldDef<F["items"]>> : F extends ObjectFieldDef ? InferObjectSchema<F["fields"]> : F extends EnumFieldDef ? F["values"][number] : F extends PrimitiveFieldDef ? PrimitiveTypeMap[F["type"]] : never;
|
|
313
|
+
export type InferFieldDef<F extends FieldDef> = F extends DiscriminatedUnionFieldDef ? InferDiscriminatedUnion<F> : F extends ArrayFieldDef ? Array<InferFieldDef<F["items"]>> : F extends ObjectFieldDef ? InferObjectSchema<F["fields"]> : F extends EnumFieldDef ? F["values"][number] : F extends PrimitiveFieldDef ? PrimitiveTypeMap[F["type"]] : never;
|
|
220
314
|
/**
|
|
221
315
|
* Infers the TypeScript type from an {@link ObjectSchema} definition.
|
|
222
316
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/decorators/attributes/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;CACZ;AAED;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,gBAAgB,CAAC;AAExD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAChC,mEAAmE;IACnE,IAAI,EAAE,kBAAkB,CAAC;IACzB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,cAAc;IAC7B,4DAA4D;IAC5D,IAAI,EAAE,QAAQ,CAAC;IACf,qEAAqE;IACrE,MAAM,EAAE,YAAY,CAAC;CACtB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,IAAI,EAAE,OAAO,CAAC;IACd
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/decorators/attributes/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,8 @@ import type { DocumentPathOperation } from "./types";
|
|
|
8
8
|
* - `undefined` → skip (not being updated)
|
|
9
9
|
* - `null` → REMOVE operation
|
|
10
10
|
* - Nested object (`fieldDef.type === "object"`) → recurse, prepending parent path
|
|
11
|
-
* - Everything else (primitives, arrays, dates, enums) → serialize and SET
|
|
11
|
+
* - Everything else (primitives, arrays, dates, enums, discriminated unions) → serialize and SET
|
|
12
|
+
*
|
|
12
13
|
*
|
|
13
14
|
* @param parentPath Path segments leading to this object (e.g. ["address"] or ["address", "geo"])
|
|
14
15
|
* @param schema The ObjectSchema describing the object shape
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flattenObjectForUpdate.d.ts","sourceRoot":"","sources":["../../../../src/operations/utils/flattenObjectForUpdate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAEtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAErD
|
|
1
|
+
{"version":3,"file":"flattenObjectForUpdate.d.ts","sourceRoot":"","sources":["../../../../src/operations/utils/flattenObjectForUpdate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAEtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAErD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAAE,EACpB,MAAM,EAAE,YAAY,EACpB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACpC,qBAAqB,EAAE,CAkCzB"}
|
|
@@ -10,7 +10,8 @@ const serializers_1 = require("../../decorators/attributes/serializers");
|
|
|
10
10
|
* - `undefined` → skip (not being updated)
|
|
11
11
|
* - `null` → REMOVE operation
|
|
12
12
|
* - Nested object (`fieldDef.type === "object"`) → recurse, prepending parent path
|
|
13
|
-
* - Everything else (primitives, arrays, dates, enums) → serialize and SET
|
|
13
|
+
* - Everything else (primitives, arrays, dates, enums, discriminated unions) → serialize and SET
|
|
14
|
+
*
|
|
14
15
|
*
|
|
15
16
|
* @param parentPath Path segments leading to this object (e.g. ["address"] or ["address", "geo"])
|
|
16
17
|
* @param schema The ObjectSchema describing the object shape
|
|
@@ -37,7 +38,6 @@ function flattenObjectForUpdate(parentPath, schema, partialValue) {
|
|
|
37
38
|
ops.push(...nestedOps);
|
|
38
39
|
continue;
|
|
39
40
|
}
|
|
40
|
-
// Primitives, arrays, dates, enums → serialize and SET
|
|
41
41
|
const serialized = (0, serializers_1.convertFieldToTableItem)(fieldDef, val);
|
|
42
42
|
ops.push({ type: "set", path: fieldPath, value: serialized });
|
|
43
43
|
}
|