dyna-record 0.4.10 → 0.5.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/README.md +56 -8
- package/dist/src/DynaRecord.d.ts +17 -1
- package/dist/src/DynaRecord.d.ts.map +1 -1
- package/dist/src/DynaRecord.js +24 -6
- package/dist/src/decorators/attributes/ObjectAttribute.d.ts +40 -17
- package/dist/src/decorators/attributes/ObjectAttribute.d.ts.map +1 -1
- package/dist/src/decorators/attributes/ObjectAttribute.js +77 -17
- 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 +49 -0
- package/dist/src/decorators/attributes/serializers.d.ts.map +1 -1
- package/dist/src/decorators/attributes/serializers.js +99 -0
- package/dist/src/decorators/attributes/types.d.ts +51 -14
- package/dist/src/decorators/attributes/types.d.ts.map +1 -1
- package/dist/src/metadata/AttributeMetadata.d.ts +3 -0
- package/dist/src/metadata/AttributeMetadata.d.ts.map +1 -1
- package/dist/src/metadata/AttributeMetadata.js +5 -0
- package/dist/src/metadata/EntityMetadata.d.ts.map +1 -1
- package/dist/src/metadata/EntityMetadata.js +8 -1
- package/dist/src/metadata/types.d.ts +11 -0
- package/dist/src/metadata/types.d.ts.map +1 -1
- package/dist/src/operations/Update/Update.d.ts +6 -1
- package/dist/src/operations/Update/Update.d.ts.map +1 -1
- package/dist/src/operations/Update/Update.js +25 -3
- package/dist/src/operations/Update/types.d.ts +26 -2
- package/dist/src/operations/Update/types.d.ts.map +1 -1
- package/dist/src/operations/utils/expressionBuilder.d.ts +4 -3
- package/dist/src/operations/utils/expressionBuilder.d.ts.map +1 -1
- package/dist/src/operations/utils/expressionBuilder.js +63 -2
- package/dist/src/operations/utils/flattenObjectForUpdate.d.ts +19 -0
- package/dist/src/operations/utils/flattenObjectForUpdate.d.ts.map +1 -0
- package/dist/src/operations/utils/flattenObjectForUpdate.js +45 -0
- package/dist/src/operations/utils/index.d.ts +2 -0
- package/dist/src/operations/utils/index.d.ts.map +1 -1
- package/dist/src/operations/utils/index.js +2 -0
- package/dist/src/operations/utils/mergePartialObjectAttributes.d.ts +8 -0
- package/dist/src/operations/utils/mergePartialObjectAttributes.d.ts.map +1 -0
- package/dist/src/operations/utils/mergePartialObjectAttributes.js +52 -0
- package/dist/src/operations/utils/types.d.ts +16 -0
- package/dist/src/operations/utils/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,6 +22,7 @@ Note: ACID compliant according to DynamoDB [limitations](https://docs.aws.amazon
|
|
|
22
22
|
- [Query](#query)
|
|
23
23
|
- [Filtering on Object Attributes](#filtering-on-object-attributes)
|
|
24
24
|
- [Update](#update)
|
|
25
|
+
- [Updating Object Attributes](#updating-object-attributes)
|
|
25
26
|
- [Delete](#delete)
|
|
26
27
|
- [Type Safety Features](#type-safety-features)
|
|
27
28
|
- [Best Practices](#best-practices)
|
|
@@ -183,6 +184,7 @@ const addressSchema = {
|
|
|
183
184
|
zip: { type: "number", nullable: true },
|
|
184
185
|
tags: { type: "array", items: { type: "string" } },
|
|
185
186
|
category: { type: "enum", values: ["home", "work", "other"] },
|
|
187
|
+
createdDate: { type: "date" },
|
|
186
188
|
geo: {
|
|
187
189
|
type: "object",
|
|
188
190
|
fields: {
|
|
@@ -196,18 +198,15 @@ const addressSchema = {
|
|
|
196
198
|
class Store extends MyTable {
|
|
197
199
|
@ObjectAttribute({ alias: "Address", schema: addressSchema })
|
|
198
200
|
public readonly address: InferObjectSchema<typeof addressSchema>;
|
|
199
|
-
|
|
200
|
-
@ObjectAttribute({ alias: "Metadata", schema: metaSchema, nullable: true })
|
|
201
|
-
public readonly metadata?: InferObjectSchema<typeof metaSchema>;
|
|
202
201
|
}
|
|
203
202
|
```
|
|
204
203
|
|
|
205
|
-
- **Supported field types:** `"string"`, `"number"`, `"boolean"`, `"enum"` (via `values`), nested `"object"` (via `fields`), and `"array"` (via `items`)
|
|
206
|
-
- **Nullable fields:** Set `nullable: true` on individual fields within the schema to
|
|
207
|
-
- **
|
|
204
|
+
- **Supported field types:** `"string"`, `"number"`, `"boolean"`, `"date"` (stored as ISO strings, exposed as `Date` objects), `"enum"` (via `values`), nested `"object"` (via `fields`), and `"array"` (via `items`)
|
|
205
|
+
- **Nullable fields:** Set `nullable: true` on individual non-object fields within the schema to make them optional
|
|
206
|
+
- **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.
|
|
208
207
|
- **Alias support:** Use the `alias` option to map to a different DynamoDB attribute name
|
|
209
208
|
- **Storage:** Objects are stored as native DynamoDB Map types
|
|
210
|
-
- **
|
|
209
|
+
- **Partial updates:** Updates are partial — only the fields you provide are modified. Omitted fields are preserved. Nested objects are recursively merged. See [Updating Object Attributes](#updating-object-attributes)
|
|
211
210
|
- **Filtering:** Object attributes support dot-path filtering in queries — see [Filtering on Object Attributes](#filtering-on-object-attributes)
|
|
212
211
|
|
|
213
212
|
##### Enum fields
|
|
@@ -221,7 +220,7 @@ const schema = {
|
|
|
221
220
|
// Top-level enum: inferred as "active" | "inactive"
|
|
222
221
|
status: { type: "enum", values: ["active", "inactive"] },
|
|
223
222
|
|
|
224
|
-
// Nullable enum: inferred as "home" | "work" | "other" |
|
|
223
|
+
// Nullable enum: inferred as "home" | "work" | "other" | undefined
|
|
225
224
|
category: { type: "enum", values: ["home", "work", "other"], nullable: true },
|
|
226
225
|
|
|
227
226
|
// Enum inside a nested object
|
|
@@ -695,6 +694,55 @@ await Pet.update("123", {
|
|
|
695
694
|
});
|
|
696
695
|
```
|
|
697
696
|
|
|
697
|
+
#### Updating Object Attributes
|
|
698
|
+
|
|
699
|
+
Object attribute updates are **partial** — only the fields you provide are modified, and omitted fields are preserved. This uses DynamoDB document path expressions under the hood (e.g., `SET #address.#street = :address_street`) for efficient field-level updates.
|
|
700
|
+
|
|
701
|
+
```typescript
|
|
702
|
+
// Only updates street — city, zip, geo, etc. are preserved
|
|
703
|
+
await Store.update("123", {
|
|
704
|
+
address: { street: "456 New St" }
|
|
705
|
+
});
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
**Nested objects** are recursively merged:
|
|
709
|
+
|
|
710
|
+
```typescript
|
|
711
|
+
// Only updates lat — lng and accuracy are preserved
|
|
712
|
+
await Store.update("123", {
|
|
713
|
+
address: {
|
|
714
|
+
geo: { lat: 42 }
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
**Nullable fields** within the object can be removed by setting them to `null`:
|
|
720
|
+
|
|
721
|
+
```typescript
|
|
722
|
+
// Removes zip, preserves all other fields
|
|
723
|
+
await Store.update("123", {
|
|
724
|
+
address: { zip: null }
|
|
725
|
+
});
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
**Arrays** within objects are **full replacement** (not merged):
|
|
729
|
+
|
|
730
|
+
```typescript
|
|
731
|
+
// Replaces the entire tags array
|
|
732
|
+
await Store.update("123", {
|
|
733
|
+
address: { tags: ["new-tag-1", "new-tag-2"] }
|
|
734
|
+
});
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
The instance `update` method returns a deep-merged result, preserving existing fields:
|
|
738
|
+
|
|
739
|
+
```typescript
|
|
740
|
+
const updated = await storeInstance.update({
|
|
741
|
+
address: { street: "New Street" }
|
|
742
|
+
});
|
|
743
|
+
// updated.address.city → still has the original value
|
|
744
|
+
```
|
|
745
|
+
|
|
698
746
|
#### Instance Method
|
|
699
747
|
|
|
700
748
|
There is an instance `update` method that has the same rules above, but returns the full updated instance.
|
package/dist/src/DynaRecord.d.ts
CHANGED
|
@@ -231,12 +231,21 @@ declare abstract class DynaRecord implements DynaRecordBase {
|
|
|
231
231
|
* { referentialIntegrityCheck: false }
|
|
232
232
|
* );
|
|
233
233
|
* ```
|
|
234
|
+
*
|
|
235
|
+
* @example Partial update of an ObjectAttribute (only provided fields are modified, omitted fields are preserved)
|
|
236
|
+
* ```typescript
|
|
237
|
+
* await User.update("userId", { address: { street: "456 Oak Ave" } });
|
|
238
|
+
* ```
|
|
234
239
|
*/
|
|
235
240
|
static update<T extends DynaRecord>(this: EntityClass<T>, id: string, attributes: UpdateOptions<T>, options?: {
|
|
236
241
|
referentialIntegrityCheck?: boolean;
|
|
237
242
|
}): Promise<void>;
|
|
238
243
|
/**
|
|
239
|
-
* Same as the static `update` method but on an instance. Returns the full updated instance
|
|
244
|
+
* Same as the static `update` method but on an instance. Returns the full updated instance.
|
|
245
|
+
*
|
|
246
|
+
* For `@ObjectAttribute` fields, the returned instance deep merges the partial update
|
|
247
|
+
* with the existing object value — omitted fields are preserved, and fields set to `null`
|
|
248
|
+
* are removed.
|
|
240
249
|
*
|
|
241
250
|
* @example Updating an entity.
|
|
242
251
|
* ```typescript
|
|
@@ -248,6 +257,13 @@ declare abstract class DynaRecord implements DynaRecordBase {
|
|
|
248
257
|
* const updatedInstance = await instance.update({ email: "newemail@example.com", someKey: null });
|
|
249
258
|
* ```
|
|
250
259
|
*
|
|
260
|
+
* @example Partial ObjectAttribute update with deep merge
|
|
261
|
+
* ```typescript
|
|
262
|
+
* // instance.address is { street: "123 Main", city: "Springfield", zip: 12345 }
|
|
263
|
+
* const updated = await instance.update({ address: { street: "456 Oak Ave" } });
|
|
264
|
+
* // updated.address is { street: "456 Oak Ave", city: "Springfield", zip: 12345 }
|
|
265
|
+
* ```
|
|
266
|
+
*
|
|
251
267
|
* @example With referential integrity check disabled
|
|
252
268
|
* ```typescript
|
|
253
269
|
* const updatedInstance = await instance.update(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DynaRecord.d.ts","sourceRoot":"","sources":["../../src/DynaRecord.ts"],"names":[],"mappings":"AAAA,OAAiB,EAAsB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE9E,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EAExB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,MAAM,EACN,KAAK,aAAa,EAElB,KAAK,aAAa,EAGlB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EAEtB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"DynaRecord.d.ts","sourceRoot":"","sources":["../../src/DynaRecord.ts"],"names":[],"mappings":"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"}
|
package/dist/src/DynaRecord.js
CHANGED
|
@@ -70,7 +70,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
70
70
|
const metadata_1 = __importStar(require("./metadata"));
|
|
71
71
|
const decorators_1 = require("./decorators");
|
|
72
72
|
const operations_1 = require("./operations");
|
|
73
|
-
const utils_1 = require("./utils");
|
|
73
|
+
const utils_1 = require("./operations/utils");
|
|
74
|
+
const utils_2 = require("./utils");
|
|
74
75
|
/**
|
|
75
76
|
* Serves as an abstract base class for entities in the ORM system. It defines standard fields such as `id`, `type`, `createdAt`, and `updatedAt`, and provides static methods for CRUD operations and queries. This class encapsulates common behaviors and properties that all entities share, leveraging decorators for attribute metadata and supporting operations like finding, creating, updating, and deleting entities.
|
|
76
77
|
*
|
|
@@ -195,13 +196,22 @@ let DynaRecord = (() => {
|
|
|
195
196
|
* { referentialIntegrityCheck: false }
|
|
196
197
|
* );
|
|
197
198
|
* ```
|
|
199
|
+
*
|
|
200
|
+
* @example Partial update of an ObjectAttribute (only provided fields are modified, omitted fields are preserved)
|
|
201
|
+
* ```typescript
|
|
202
|
+
* await User.update("userId", { address: { street: "456 Oak Ave" } });
|
|
203
|
+
* ```
|
|
198
204
|
*/
|
|
199
205
|
static async update(id, attributes, options) {
|
|
200
206
|
const op = new operations_1.Update(this);
|
|
201
207
|
await op.run(id, attributes, options);
|
|
202
208
|
}
|
|
203
209
|
/**
|
|
204
|
-
* Same as the static `update` method but on an instance. Returns the full updated instance
|
|
210
|
+
* Same as the static `update` method but on an instance. Returns the full updated instance.
|
|
211
|
+
*
|
|
212
|
+
* For `@ObjectAttribute` fields, the returned instance deep merges the partial update
|
|
213
|
+
* with the existing object value — omitted fields are preserved, and fields set to `null`
|
|
214
|
+
* are removed.
|
|
205
215
|
*
|
|
206
216
|
* @example Updating an entity.
|
|
207
217
|
* ```typescript
|
|
@@ -213,6 +223,13 @@ let DynaRecord = (() => {
|
|
|
213
223
|
* const updatedInstance = await instance.update({ email: "newemail@example.com", someKey: null });
|
|
214
224
|
* ```
|
|
215
225
|
*
|
|
226
|
+
* @example Partial ObjectAttribute update with deep merge
|
|
227
|
+
* ```typescript
|
|
228
|
+
* // instance.address is { street: "123 Main", city: "Springfield", zip: 12345 }
|
|
229
|
+
* const updated = await instance.update({ address: { street: "456 Oak Ave" } });
|
|
230
|
+
* // updated.address is { street: "456 Oak Ave", city: "Springfield", zip: 12345 }
|
|
231
|
+
* ```
|
|
232
|
+
*
|
|
216
233
|
* @example With referential integrity check disabled
|
|
217
234
|
* ```typescript
|
|
218
235
|
* const updatedInstance = await instance.update(
|
|
@@ -226,11 +243,12 @@ let DynaRecord = (() => {
|
|
|
226
243
|
const op = new operations_1.Update(InstanceClass);
|
|
227
244
|
const updatedAttributes = await op.run(this.id, attributes, options);
|
|
228
245
|
const clone = structuredClone(this);
|
|
229
|
-
|
|
230
|
-
|
|
246
|
+
const entityAttrs = metadata_1.default.getEntityAttributes(InstanceClass.name);
|
|
247
|
+
// Deep merge ObjectAttributes, shallow assign everything else
|
|
248
|
+
(0, utils_1.mergePartialObjectAttributes)(clone, updatedAttributes, entityAttrs);
|
|
231
249
|
const updatedInstance = Object.fromEntries(Object.entries(clone).filter(([_, value]) => value !== null));
|
|
232
250
|
// Return the updated instance, which is of type `this`
|
|
233
|
-
return (0,
|
|
251
|
+
return (0, utils_2.createInstance)(InstanceClass, updatedInstance);
|
|
234
252
|
}
|
|
235
253
|
/**
|
|
236
254
|
* Delete an entity by ID
|
|
@@ -270,7 +288,7 @@ let DynaRecord = (() => {
|
|
|
270
288
|
if (tableItem[typeAlias] !== this.name) {
|
|
271
289
|
throw new Error("Unable to convert dynamo item to entity. Invalid type");
|
|
272
290
|
}
|
|
273
|
-
return (0,
|
|
291
|
+
return (0, utils_2.tableItemToEntity)(this, tableItem);
|
|
274
292
|
}
|
|
275
293
|
/**
|
|
276
294
|
* Get the partition key for an entity
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import type DynaRecord from "../../DynaRecord";
|
|
2
|
-
import type { AttributeDecoratorContext,
|
|
2
|
+
import type { AttributeDecoratorContext, NonNullAttributeOptions } from "../types";
|
|
3
3
|
import type { ObjectSchema, InferObjectSchema } from "./types";
|
|
4
4
|
/**
|
|
5
5
|
* Options for the `@ObjectAttribute` decorator.
|
|
6
|
-
* Extends {@link
|
|
6
|
+
* Extends {@link NonNullAttributeOptions} with a required `schema` field describing the object shape.
|
|
7
|
+
*
|
|
8
|
+
* **Object attributes are never nullable.** DynamoDB cannot update nested document paths
|
|
9
|
+
* (e.g. `address.geo.lat`) if the parent object does not exist, which causes:
|
|
10
|
+
* `ValidationException: The document path provided in the update expression is invalid for update`.
|
|
11
|
+
* To avoid this, `@ObjectAttribute` fields always exist as at least an empty object `{}`.
|
|
7
12
|
*
|
|
8
13
|
* The schema supports all {@link FieldDef} types: primitives, enums, nested objects, and arrays.
|
|
14
|
+
* Non-object fields within the schema may still be nullable.
|
|
9
15
|
*
|
|
10
16
|
* @template S The specific ObjectSchema type used for type inference
|
|
11
17
|
*
|
|
@@ -13,12 +19,9 @@ import type { ObjectSchema, InferObjectSchema } from "./types";
|
|
|
13
19
|
* ```typescript
|
|
14
20
|
* @ObjectAttribute({ alias: "Address", schema: addressSchema })
|
|
15
21
|
* public readonly address: InferObjectSchema<typeof addressSchema>;
|
|
16
|
-
*
|
|
17
|
-
* @ObjectAttribute({ alias: "Meta", schema: metaSchema, nullable: true })
|
|
18
|
-
* public readonly meta?: InferObjectSchema<typeof metaSchema>;
|
|
19
22
|
* ```
|
|
20
23
|
*/
|
|
21
|
-
export interface ObjectAttributeOptions<S extends ObjectSchema> extends
|
|
24
|
+
export interface ObjectAttributeOptions<S extends ObjectSchema> extends NonNullAttributeOptions {
|
|
22
25
|
/**
|
|
23
26
|
* The {@link ObjectSchema} defining the structure of the object attribute.
|
|
24
27
|
*
|
|
@@ -32,21 +35,28 @@ export interface ObjectAttributeOptions<S extends ObjectSchema> extends Attribut
|
|
|
32
35
|
* Objects are stored as native DynamoDB Map types and validated at runtime against the provided schema.
|
|
33
36
|
* The TypeScript type is inferred from the schema using {@link InferObjectSchema}.
|
|
34
37
|
*
|
|
35
|
-
*
|
|
38
|
+
* **Object attributes are never nullable.** DynamoDB cannot update nested document paths
|
|
39
|
+
* (e.g. `address.geo.lat`) if the parent object does not exist, which causes:
|
|
40
|
+
* `ValidationException: The document path provided in the update expression is invalid for update`.
|
|
41
|
+
* To prevent this, `@ObjectAttribute` fields must always exist as at least an empty object `{}`.
|
|
42
|
+
* Similarly, nested object fields within the schema cannot be nullable.
|
|
36
43
|
*
|
|
37
44
|
* **Supported field types within the schema:**
|
|
38
|
-
* - `"string"`, `"number"`, `"boolean"` — primitives
|
|
39
|
-
* - `"enum"` — string literal unions
|
|
40
|
-
* - `"
|
|
41
|
-
* - `"
|
|
45
|
+
* - `"string"`, `"number"`, `"boolean"` — primitives (support `nullable: true`)
|
|
46
|
+
* - `"enum"` — string literal unions (support `nullable: true`)
|
|
47
|
+
* - `"date"` — dates stored as ISO strings (support `nullable: true`)
|
|
48
|
+
* - `"object"` — nested objects, arbitrarily deep (**never nullable**)
|
|
49
|
+
* - `"array"` — lists of any field type (support `nullable: true`, full replacement on update)
|
|
42
50
|
*
|
|
43
|
-
*
|
|
51
|
+
* Objects within arrays are not subject to the document path limitation because arrays
|
|
52
|
+
* use full replacement on update. Partial updates of individual objects within arrays
|
|
53
|
+
* are not supported.
|
|
44
54
|
*
|
|
45
55
|
* @template T The class type that the decorator is applied to
|
|
46
56
|
* @template S The ObjectSchema type used for validation and type inference
|
|
47
57
|
* @template K The inferred TypeScript type from the schema
|
|
48
58
|
* @template P The decorator options type
|
|
49
|
-
* @param props An {@link ObjectAttributeOptions} object providing the `schema` and optional `alias
|
|
59
|
+
* @param props An {@link ObjectAttributeOptions} object providing the `schema` and optional `alias`.
|
|
50
60
|
* @returns A class field decorator function
|
|
51
61
|
*
|
|
52
62
|
* Usage example:
|
|
@@ -69,9 +79,6 @@ export interface ObjectAttributeOptions<S extends ObjectSchema> extends Attribut
|
|
|
69
79
|
* class MyEntity extends MyTable {
|
|
70
80
|
* @ObjectAttribute({ alias: 'Address', schema: addressSchema })
|
|
71
81
|
* public address: InferObjectSchema<typeof addressSchema>;
|
|
72
|
-
*
|
|
73
|
-
* @ObjectAttribute({ alias: 'Meta', schema: metaSchema, nullable: true })
|
|
74
|
-
* public meta?: InferObjectSchema<typeof metaSchema>;
|
|
75
82
|
* }
|
|
76
83
|
*
|
|
77
84
|
* // TypeScript infers:
|
|
@@ -79,6 +86,22 @@ export interface ObjectAttributeOptions<S extends ObjectSchema> extends Attribut
|
|
|
79
86
|
* // address.geo.accuracy → "precise" | "approximate"
|
|
80
87
|
* ```
|
|
81
88
|
*
|
|
89
|
+
* **Partial updates:** When updating an entity, `@ObjectAttribute` fields support partial
|
|
90
|
+
* updates — only the fields you provide are modified, omitted fields are preserved. Under
|
|
91
|
+
* the hood, dyna-record generates DynamoDB document path expressions
|
|
92
|
+
* (e.g., `SET #address.#street = :address_street`) instead of replacing the entire map.
|
|
93
|
+
* Nested objects are recursively merged. Arrays within objects are full replacement.
|
|
94
|
+
* Setting a nullable field within an object to `null` generates a `REMOVE` expression
|
|
95
|
+
* for that specific field.
|
|
96
|
+
*
|
|
97
|
+
* ```typescript
|
|
98
|
+
* // Only updates street — city, zip, geo are preserved
|
|
99
|
+
* await MyEntity.update("id", { address: { street: "456 Oak Ave" } });
|
|
100
|
+
*
|
|
101
|
+
* // Remove a nullable field within the object
|
|
102
|
+
* await MyEntity.update("id", { address: { zip: null } });
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
82
105
|
* Object attributes support filtering in queries using dot-path notation for nested fields
|
|
83
106
|
* and the {@link ContainsFilter | $contains} operator for List membership checks.
|
|
84
107
|
*
|
|
@@ -92,6 +115,6 @@ export interface ObjectAttributeOptions<S extends ObjectSchema> extends Attribut
|
|
|
92
115
|
* });
|
|
93
116
|
* ```
|
|
94
117
|
*/
|
|
95
|
-
declare function ObjectAttribute<T extends DynaRecord, const S extends ObjectSchema
|
|
118
|
+
declare function ObjectAttribute<T extends DynaRecord, const S extends ObjectSchema>(props: ObjectAttributeOptions<S>): (_value: undefined, context: AttributeDecoratorContext<T, InferObjectSchema<S>, ObjectAttributeOptions<S>>) => void;
|
|
96
119
|
export default ObjectAttribute;
|
|
97
120
|
//# sourceMappingURL=ObjectAttribute.d.ts.map
|
|
@@ -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,
|
|
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,EAAE,YAAY,EAAE,iBAAiB,EAAY,MAAM,SAAS,CAAC;AAGzE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,sBAAsB,CAAC,CAAC,SAAS,YAAY,CAC5D,SAAQ,uBAAuB;IAC/B;;;;OAIG;IACH,MAAM,EAAE,CAAC,CAAC;CACX;AA8GD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqFG;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,UAqBJ;AAED,eAAe,eAAe,CAAC"}
|
|
@@ -5,6 +5,36 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const zod_1 = require("zod");
|
|
7
7
|
const metadata_1 = __importDefault(require("../../metadata"));
|
|
8
|
+
const serializers_1 = require("./serializers");
|
|
9
|
+
/**
|
|
10
|
+
* Converts an {@link ObjectSchema} to a partial Zod schema for update validation.
|
|
11
|
+
*
|
|
12
|
+
* All fields become optional (can be omitted). Nullable fields accept `null`.
|
|
13
|
+
* Non-nullable fields reject `null`. Nested objects are recursively partial.
|
|
14
|
+
* Array items validate normally (full replacement).
|
|
15
|
+
*
|
|
16
|
+
* @param schema The object schema definition
|
|
17
|
+
* @returns A ZodType that validates partial objects matching the schema
|
|
18
|
+
*/
|
|
19
|
+
function objectSchemaToZodPartial(schema) {
|
|
20
|
+
const shape = {};
|
|
21
|
+
for (const [key, fieldDef] of Object.entries(schema)) {
|
|
22
|
+
shape[key] = fieldDefToZodPartial(fieldDef);
|
|
23
|
+
}
|
|
24
|
+
return zod_1.z.object(shape).partial();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Converts a single {@link FieldDef} to the corresponding partial Zod type.
|
|
28
|
+
* Nested objects use partial schemas; all other types use the standard schema.
|
|
29
|
+
* Object fields are never nullable — they always exist as at least `{}`.
|
|
30
|
+
*/
|
|
31
|
+
function fieldDefToZodPartial(fieldDef) {
|
|
32
|
+
if (fieldDef.type === "object") {
|
|
33
|
+
return objectSchemaToZodPartial(fieldDef.fields);
|
|
34
|
+
}
|
|
35
|
+
// For non-object fields, use the standard schema (includes nullable wrapping)
|
|
36
|
+
return fieldDefToZod(fieldDef);
|
|
37
|
+
}
|
|
8
38
|
/**
|
|
9
39
|
* Converts an {@link ObjectSchema} to a Zod schema for runtime validation.
|
|
10
40
|
*
|
|
@@ -22,24 +52,26 @@ function objectSchemaToZod(schema) {
|
|
|
22
52
|
* Converts a single {@link FieldDef} to the corresponding Zod type for runtime validation.
|
|
23
53
|
*
|
|
24
54
|
* Handles all field types:
|
|
25
|
-
* - `"object"` → recursively builds a `z.object()` via {@link objectSchemaToZod}
|
|
55
|
+
* - `"object"` → recursively builds a `z.object()` via {@link objectSchemaToZod}.
|
|
56
|
+
* Object fields are never nullable — DynamoDB requires them to exist for document path updates.
|
|
26
57
|
* - `"array"` → `z.array()` wrapping a recursive call for the `items` type
|
|
27
58
|
* - `"string"` → `z.string()`
|
|
28
59
|
* - `"number"` → `z.number()`
|
|
29
60
|
* - `"boolean"` → `z.boolean()`
|
|
30
61
|
* - `"enum"` → `z.enum(values)` for string literal validation
|
|
31
62
|
*
|
|
32
|
-
* When `nullable` is `true
|
|
63
|
+
* When `nullable` is `true` (non-object fields only), wraps the type with `.optional().nullable()`.
|
|
33
64
|
*
|
|
34
65
|
* @param fieldDef The field definition to convert
|
|
35
66
|
* @returns A ZodType that validates values matching the field definition
|
|
36
67
|
*/
|
|
37
68
|
function fieldDefToZod(fieldDef) {
|
|
69
|
+
// Object fields return early — they are never nullable
|
|
70
|
+
if (fieldDef.type === "object") {
|
|
71
|
+
return objectSchemaToZod(fieldDef.fields);
|
|
72
|
+
}
|
|
38
73
|
let zodType;
|
|
39
74
|
switch (fieldDef.type) {
|
|
40
|
-
case "object":
|
|
41
|
-
zodType = objectSchemaToZod(fieldDef.fields);
|
|
42
|
-
break;
|
|
43
75
|
case "array":
|
|
44
76
|
zodType = zod_1.z.array(fieldDefToZod(fieldDef.items));
|
|
45
77
|
break;
|
|
@@ -52,6 +84,9 @@ function fieldDefToZod(fieldDef) {
|
|
|
52
84
|
case "boolean":
|
|
53
85
|
zodType = zod_1.z.boolean();
|
|
54
86
|
break;
|
|
87
|
+
case "date":
|
|
88
|
+
zodType = zod_1.z.date();
|
|
89
|
+
break;
|
|
55
90
|
case "enum":
|
|
56
91
|
zodType = zod_1.z.enum(fieldDef.values);
|
|
57
92
|
break;
|
|
@@ -62,7 +97,7 @@ function fieldDefToZod(fieldDef) {
|
|
|
62
97
|
}
|
|
63
98
|
}
|
|
64
99
|
if (fieldDef.nullable === true) {
|
|
65
|
-
zodType = zodType.
|
|
100
|
+
zodType = zodType.optional().nullable();
|
|
66
101
|
}
|
|
67
102
|
return zodType;
|
|
68
103
|
}
|
|
@@ -72,21 +107,28 @@ function fieldDefToZod(fieldDef) {
|
|
|
72
107
|
* Objects are stored as native DynamoDB Map types and validated at runtime against the provided schema.
|
|
73
108
|
* The TypeScript type is inferred from the schema using {@link InferObjectSchema}.
|
|
74
109
|
*
|
|
75
|
-
*
|
|
110
|
+
* **Object attributes are never nullable.** DynamoDB cannot update nested document paths
|
|
111
|
+
* (e.g. `address.geo.lat`) if the parent object does not exist, which causes:
|
|
112
|
+
* `ValidationException: The document path provided in the update expression is invalid for update`.
|
|
113
|
+
* To prevent this, `@ObjectAttribute` fields must always exist as at least an empty object `{}`.
|
|
114
|
+
* Similarly, nested object fields within the schema cannot be nullable.
|
|
76
115
|
*
|
|
77
116
|
* **Supported field types within the schema:**
|
|
78
|
-
* - `"string"`, `"number"`, `"boolean"` — primitives
|
|
79
|
-
* - `"enum"` — string literal unions
|
|
80
|
-
* - `"
|
|
81
|
-
* - `"
|
|
117
|
+
* - `"string"`, `"number"`, `"boolean"` — primitives (support `nullable: true`)
|
|
118
|
+
* - `"enum"` — string literal unions (support `nullable: true`)
|
|
119
|
+
* - `"date"` — dates stored as ISO strings (support `nullable: true`)
|
|
120
|
+
* - `"object"` — nested objects, arbitrarily deep (**never nullable**)
|
|
121
|
+
* - `"array"` — lists of any field type (support `nullable: true`, full replacement on update)
|
|
82
122
|
*
|
|
83
|
-
*
|
|
123
|
+
* Objects within arrays are not subject to the document path limitation because arrays
|
|
124
|
+
* use full replacement on update. Partial updates of individual objects within arrays
|
|
125
|
+
* are not supported.
|
|
84
126
|
*
|
|
85
127
|
* @template T The class type that the decorator is applied to
|
|
86
128
|
* @template S The ObjectSchema type used for validation and type inference
|
|
87
129
|
* @template K The inferred TypeScript type from the schema
|
|
88
130
|
* @template P The decorator options type
|
|
89
|
-
* @param props An {@link ObjectAttributeOptions} object providing the `schema` and optional `alias
|
|
131
|
+
* @param props An {@link ObjectAttributeOptions} object providing the `schema` and optional `alias`.
|
|
90
132
|
* @returns A class field decorator function
|
|
91
133
|
*
|
|
92
134
|
* Usage example:
|
|
@@ -109,9 +151,6 @@ function fieldDefToZod(fieldDef) {
|
|
|
109
151
|
* class MyEntity extends MyTable {
|
|
110
152
|
* @ObjectAttribute({ alias: 'Address', schema: addressSchema })
|
|
111
153
|
* public address: InferObjectSchema<typeof addressSchema>;
|
|
112
|
-
*
|
|
113
|
-
* @ObjectAttribute({ alias: 'Meta', schema: metaSchema, nullable: true })
|
|
114
|
-
* public meta?: InferObjectSchema<typeof metaSchema>;
|
|
115
154
|
* }
|
|
116
155
|
*
|
|
117
156
|
* // TypeScript infers:
|
|
@@ -119,6 +158,22 @@ function fieldDefToZod(fieldDef) {
|
|
|
119
158
|
* // address.geo.accuracy → "precise" | "approximate"
|
|
120
159
|
* ```
|
|
121
160
|
*
|
|
161
|
+
* **Partial updates:** When updating an entity, `@ObjectAttribute` fields support partial
|
|
162
|
+
* updates — only the fields you provide are modified, omitted fields are preserved. Under
|
|
163
|
+
* the hood, dyna-record generates DynamoDB document path expressions
|
|
164
|
+
* (e.g., `SET #address.#street = :address_street`) instead of replacing the entire map.
|
|
165
|
+
* Nested objects are recursively merged. Arrays within objects are full replacement.
|
|
166
|
+
* Setting a nullable field within an object to `null` generates a `REMOVE` expression
|
|
167
|
+
* for that specific field.
|
|
168
|
+
*
|
|
169
|
+
* ```typescript
|
|
170
|
+
* // Only updates street — city, zip, geo are preserved
|
|
171
|
+
* await MyEntity.update("id", { address: { street: "456 Oak Ave" } });
|
|
172
|
+
*
|
|
173
|
+
* // Remove a nullable field within the object
|
|
174
|
+
* await MyEntity.update("id", { address: { zip: null } });
|
|
175
|
+
* ```
|
|
176
|
+
*
|
|
122
177
|
* Object attributes support filtering in queries using dot-path notation for nested fields
|
|
123
178
|
* and the {@link ContainsFilter | $contains} operator for List membership checks.
|
|
124
179
|
*
|
|
@@ -138,10 +193,15 @@ function ObjectAttribute(props) {
|
|
|
138
193
|
context.addInitializer(function () {
|
|
139
194
|
const { schema, ...restProps } = props;
|
|
140
195
|
const zodSchema = objectSchemaToZod(schema);
|
|
196
|
+
const partialZodSchema = objectSchemaToZodPartial(schema);
|
|
197
|
+
const serializers = (0, serializers_1.createObjectSerializer)(schema);
|
|
141
198
|
metadata_1.default.addEntityAttribute(this.constructor.name, {
|
|
142
199
|
attributeName: context.name.toString(),
|
|
143
|
-
nullable: props?.nullable,
|
|
144
200
|
type: zodSchema,
|
|
201
|
+
partialType: partialZodSchema,
|
|
202
|
+
serializers,
|
|
203
|
+
nullable: false,
|
|
204
|
+
objectSchema: schema,
|
|
145
205
|
...restProps
|
|
146
206
|
});
|
|
147
207
|
});
|
|
@@ -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 } from "./types";
|
|
13
|
+
export type { ObjectSchema, InferObjectSchema, FieldDef, PrimitiveFieldDef, ObjectFieldDef, ArrayFieldDef, EnumFieldDef, DateFieldDef } 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,EACb,MAAM,SAAS,CAAC"}
|
|
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,EACb,MAAM,SAAS,CAAC"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { NativeAttributeValue } from "@aws-sdk/util-dynamodb";
|
|
2
|
+
import type { ObjectSchema, FieldDef } from "./types";
|
|
3
|
+
import type { Serializers } from "../../metadata/types";
|
|
2
4
|
/**
|
|
3
5
|
* Provides serialization and deserialization functions for date attributes when interfacing with a DynamoDB table, enabling the conversion between the table's string-based date representation and JavaScript's `Date` object. DynamoDb dos not support Date types naturally, this utility allows for Date attributes to be serialized to an entity and stored as ISO strings in Dynamo.
|
|
4
6
|
*
|
|
@@ -10,4 +12,51 @@ export declare const dateSerializer: {
|
|
|
10
12
|
toEntityAttribute: (val: NativeAttributeValue) => any;
|
|
11
13
|
toTableAttribute: (val?: Date) => string | undefined;
|
|
12
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* Recursively walks an {@link ObjectSchema} and converts the entity value to its
|
|
17
|
+
* DynamoDB representation.
|
|
18
|
+
*
|
|
19
|
+
* - `"date"` fields are converted from `Date` objects to ISO 8601 strings.
|
|
20
|
+
* - `"object"` fields recurse into their nested schema.
|
|
21
|
+
* - `"array"` fields map each item through the same conversion.
|
|
22
|
+
* - `null` and `undefined` values are stripped from the result so that nullable
|
|
23
|
+
* fields set to `null` are removed from the stored object rather than persisted
|
|
24
|
+
* as `null` in DynamoDB.
|
|
25
|
+
* - All other field types pass through unchanged.
|
|
26
|
+
*
|
|
27
|
+
* @param schema The {@link ObjectSchema} describing the object shape
|
|
28
|
+
* @param value The entity-level object value to convert
|
|
29
|
+
* @returns A new object suitable for DynamoDB storage
|
|
30
|
+
*/
|
|
31
|
+
export declare function objectToTableItem(schema: ObjectSchema, value: Record<string, unknown>): Record<string, unknown>;
|
|
32
|
+
export declare function convertFieldToTableItem(fieldDef: FieldDef, val: unknown): unknown;
|
|
33
|
+
/**
|
|
34
|
+
* Recursively walks an {@link ObjectSchema} and converts a DynamoDB table item
|
|
35
|
+
* back to its entity representation.
|
|
36
|
+
*
|
|
37
|
+
* - `"date"` fields are converted from ISO 8601 strings to `Date` objects.
|
|
38
|
+
* - `"object"` fields recurse into their nested schema.
|
|
39
|
+
* - `"array"` fields map each item through the same conversion.
|
|
40
|
+
* - `null` and `undefined` values are stripped from the result so that absent
|
|
41
|
+
* fields are represented as `undefined` (omitted) on the entity, consistent
|
|
42
|
+
* with root-level nullable attribute behaviour.
|
|
43
|
+
* - All other field types pass through unchanged.
|
|
44
|
+
*
|
|
45
|
+
* @param schema The {@link ObjectSchema} describing the object shape
|
|
46
|
+
* @param value The DynamoDB table item to convert
|
|
47
|
+
* @returns A new object with entity-level types (e.g. `Date` instead of string)
|
|
48
|
+
*/
|
|
49
|
+
export declare function tableItemToObject(schema: ObjectSchema, value: Record<string, unknown>): Record<string, unknown>;
|
|
50
|
+
/**
|
|
51
|
+
* Creates a {@link Serializers} pair for an {@link ObjectSchema}.
|
|
52
|
+
*
|
|
53
|
+
* The returned serializers handle:
|
|
54
|
+
* - Converting `Date` fields to/from ISO 8601 strings for DynamoDB storage.
|
|
55
|
+
* - Stripping `null` and `undefined` values so that nullable fields set to
|
|
56
|
+
* `null` during updates are removed from the stored object.
|
|
57
|
+
*
|
|
58
|
+
* @param schema The {@link ObjectSchema} describing the object shape
|
|
59
|
+
* @returns A `Serializers` object with `toTableAttribute` and `toEntityAttribute` functions
|
|
60
|
+
*/
|
|
61
|
+
export declare function createObjectSerializer(schema: ObjectSchema): Serializers;
|
|
13
62
|
//# sourceMappingURL=serializers.d.ts.map
|
|
@@ -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;
|
|
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;6BAMpB,IAAI;CAC9B,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;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;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,OAAO,GACX,OAAO,CAaT;AAED;;;;;;;;;;;;;;;GAeG;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;AAiBD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW,CAOxE"}
|