dyna-record 0.4.11 → 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.
Files changed (39) hide show
  1. package/README.md +53 -6
  2. package/dist/src/DynaRecord.d.ts +17 -1
  3. package/dist/src/DynaRecord.d.ts.map +1 -1
  4. package/dist/src/DynaRecord.js +24 -6
  5. package/dist/src/decorators/attributes/ObjectAttribute.d.ts +40 -17
  6. package/dist/src/decorators/attributes/ObjectAttribute.d.ts.map +1 -1
  7. package/dist/src/decorators/attributes/ObjectAttribute.js +70 -16
  8. package/dist/src/decorators/attributes/serializers.d.ts +2 -1
  9. package/dist/src/decorators/attributes/serializers.d.ts.map +1 -1
  10. package/dist/src/decorators/attributes/serializers.js +1 -0
  11. package/dist/src/decorators/attributes/types.d.ts +20 -6
  12. package/dist/src/decorators/attributes/types.d.ts.map +1 -1
  13. package/dist/src/metadata/AttributeMetadata.d.ts +3 -0
  14. package/dist/src/metadata/AttributeMetadata.d.ts.map +1 -1
  15. package/dist/src/metadata/AttributeMetadata.js +5 -0
  16. package/dist/src/metadata/EntityMetadata.d.ts.map +1 -1
  17. package/dist/src/metadata/EntityMetadata.js +8 -1
  18. package/dist/src/metadata/types.d.ts +11 -0
  19. package/dist/src/metadata/types.d.ts.map +1 -1
  20. package/dist/src/operations/Update/Update.d.ts +6 -1
  21. package/dist/src/operations/Update/Update.d.ts.map +1 -1
  22. package/dist/src/operations/Update/Update.js +25 -3
  23. package/dist/src/operations/Update/types.d.ts +14 -4
  24. package/dist/src/operations/Update/types.d.ts.map +1 -1
  25. package/dist/src/operations/utils/expressionBuilder.d.ts +4 -3
  26. package/dist/src/operations/utils/expressionBuilder.d.ts.map +1 -1
  27. package/dist/src/operations/utils/expressionBuilder.js +63 -2
  28. package/dist/src/operations/utils/flattenObjectForUpdate.d.ts +19 -0
  29. package/dist/src/operations/utils/flattenObjectForUpdate.d.ts.map +1 -0
  30. package/dist/src/operations/utils/flattenObjectForUpdate.js +45 -0
  31. package/dist/src/operations/utils/index.d.ts +2 -0
  32. package/dist/src/operations/utils/index.d.ts.map +1 -1
  33. package/dist/src/operations/utils/index.js +2 -0
  34. package/dist/src/operations/utils/mergePartialObjectAttributes.d.ts +8 -0
  35. package/dist/src/operations/utils/mergePartialObjectAttributes.d.ts.map +1 -0
  36. package/dist/src/operations/utils/mergePartialObjectAttributes.js +52 -0
  37. package/dist/src/operations/utils/types.d.ts +16 -0
  38. package/dist/src/operations/utils/types.d.ts.map +1 -1
  39. 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)
@@ -197,18 +198,15 @@ const addressSchema = {
197
198
  class Store extends MyTable {
198
199
  @ObjectAttribute({ alias: "Address", schema: addressSchema })
199
200
  public readonly address: InferObjectSchema<typeof addressSchema>;
200
-
201
- @ObjectAttribute({ alias: "Metadata", schema: metaSchema, nullable: true })
202
- public readonly metadata?: InferObjectSchema<typeof metaSchema>;
203
201
  }
204
202
  ```
205
203
 
206
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`)
207
- - **Nullable fields:** Set `nullable: true` on individual fields within the schema to remove them
208
- - **Nullable object attributes:** Set `nullable: true` on the decorator options to make the entire object optional
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.
209
207
  - **Alias support:** Use the `alias` option to map to a different DynamoDB attribute name
210
208
  - **Storage:** Objects are stored as native DynamoDB Map types
211
- - **Updates:** Updates replace the entire object (not a partial merge)
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)
212
210
  - **Filtering:** Object attributes support dot-path filtering in queries — see [Filtering on Object Attributes](#filtering-on-object-attributes)
213
211
 
214
212
  ##### Enum fields
@@ -696,6 +694,55 @@ await Pet.update("123", {
696
694
  });
697
695
  ```
698
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
+
699
746
  #### Instance Method
700
747
 
701
748
  There is an instance `update` method that has the same rules above, but returns the full updated instance.
@@ -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":"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"}
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;AAEtB,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGtE,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,uBAAe,UAAW,YAAW,cAAc;IACjD;;OAEG;IACH,SACgB,EAAE,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,SACgB,IAAI,EAAE,MAAM,CAAC;IAE7B;;OAEG;IACH,SACgB,SAAS,EAAE,IAAI,CAAC;IAEhC;;OAEG;IACH,SACgB,SAAS,EAAE,IAAI,CAAC;IAEhC;;;;;;;;;;;;;;;;;;;;;;OAsBG;WAEiB,QAAQ,CAAC,CAAC,SAAS,UAAU,EAC/C,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EACpB,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE,SAAS,GAClB,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;WAG7B,QAAQ,CAC1B,CAAC,SAAS,UAAU,EACpB,GAAG,SAAS,oBAAoB,CAAC,CAAC,CAAC,GAAG,EAAE,EAExC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EACpB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,eAAe,CAAC,CAAC,EAAE,GAAG,CAAC,GAC/B,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAgBjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;WACiB,KAAK,CAAC,CAAC,SAAS,UAAU,EAC5C,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EACpB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAE3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqDG;WACiB,KAAK,CAAC,CAAC,SAAS,UAAU,EAC5C,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EACpB,GAAG,EAAE,mBAAmB,CAAC,CAAC,CAAC,EAC3B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAE3B;;;;;;;;;;;;;;;OAeG;WACiB,KAAK,CAAC,CAAC,SAAS,UAAU,EAC5C,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EACpB,GAAG,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAC1B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAW3B;;;;;;;;;;;;;;;;;;OAkBG;WACiB,MAAM,CAAC,CAAC,SAAS,UAAU,EAC7C,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EACpB,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,EAC5B,OAAO,CAAC,EAAE;QAAE,yBAAyB,CAAC,EAAE,OAAO,CAAA;KAAE,GAChD,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IAKxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;WACiB,MAAM,CAAC,CAAC,SAAS,UAAU,EAC7C,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EACpB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,EAC5B,OAAO,CAAC,EAAE;QAAE,yBAAyB,CAAC,EAAE,OAAO,CAAA;KAAE,GAChD,OAAO,CAAC,IAAI,CAAC;IAKhB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACU,MAAM,CAAC,CAAC,SAAS,IAAI,EAChC,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,EAC5B,OAAO,CAAC,EAAE;QAAE,yBAAyB,CAAC,EAAE,OAAO,CAAA;KAAE,GAChD,OAAO,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC;IAuBvC;;;;;;;;;;OAUG;WACiB,MAAM,CAAC,CAAC,SAAS,UAAU,EAC7C,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EACpB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,IAAI,CAAC;IAKhB;;;;;;;;;OASG;WACW,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAKnD;;OAEG;WACW,iBAAiB,CAAC,CAAC,SAAS,UAAU,EAClD,IAAI,EAAE,UAAU,CAAC,EACjB,SAAS,EAAE,eAAe,GACzB,wBAAwB,CAAC,CAAC,CAAC;IAW9B;;;OAGG;IACI,iBAAiB,IAAI,MAAM;IAIlC;;;;;;;;;;;;OAYG;WACW,QAAQ,IAAI,UAAU,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;CAK9D;AAED,eAAe,UAAU,CAAC"}
@@ -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
- // Update the current instance with new attributes
230
- Object.assign(clone, updatedAttributes);
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, utils_1.createInstance)(InstanceClass, updatedInstance);
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, utils_1.tableItemToEntity)(this, tableItem);
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, AttributeOptions } from "../types";
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 AttributeOptions} with a required `schema` field describing the object shape.
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 AttributeOptions {
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
- * Can be set to nullable via decorator props.
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, validated at runtime via `z.enum()`
40
- * - `"object"` — nested objects (arbitrarily deep)
41
- * - `"array"` — lists of any field type
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
- * All field types support `nullable: true` to remove them
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` and `nullable` configuration.
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, P extends ObjectAttributeOptions<S>>(props: P): (_value: undefined, context: AttributeDecoratorContext<T, InferObjectSchema<S>, P>) => void;
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,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAY,MAAM,SAAS,CAAC;AAGzE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,sBAAsB,CAAC,CAAC,SAAS,YAAY,CAC5D,SAAQ,gBAAgB;IACxB;;;;OAIG;IACH,MAAM,EAAE,CAAC,CAAC;CACX;AAyED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,iBAAS,eAAe,CACtB,CAAC,SAAS,UAAU,EACpB,KAAK,CAAC,CAAC,SAAS,YAAY,EAC5B,CAAC,SAAS,sBAAsB,CAAC,CAAC,CAAC,EACnC,KAAK,EAAE,CAAC,YAEE,SAAS,WACR,yBAAyB,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAkBjE;AAED,eAAe,eAAe,CAAC"}
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"}
@@ -6,6 +6,35 @@ 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
+ * 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
+ }
9
38
  /**
10
39
  * Converts an {@link ObjectSchema} to a Zod schema for runtime validation.
11
40
  *
@@ -23,24 +52,26 @@ function objectSchemaToZod(schema) {
23
52
  * Converts a single {@link FieldDef} to the corresponding Zod type for runtime validation.
24
53
  *
25
54
  * Handles all field types:
26
- * - `"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.
27
57
  * - `"array"` → `z.array()` wrapping a recursive call for the `items` type
28
58
  * - `"string"` → `z.string()`
29
59
  * - `"number"` → `z.number()`
30
60
  * - `"boolean"` → `z.boolean()`
31
61
  * - `"enum"` → `z.enum(values)` for string literal validation
32
62
  *
33
- * When `nullable` is `true`, wraps the type with `.optional().nullable()`.
63
+ * When `nullable` is `true` (non-object fields only), wraps the type with `.optional().nullable()`.
34
64
  *
35
65
  * @param fieldDef The field definition to convert
36
66
  * @returns A ZodType that validates values matching the field definition
37
67
  */
38
68
  function fieldDefToZod(fieldDef) {
69
+ // Object fields return early — they are never nullable
70
+ if (fieldDef.type === "object") {
71
+ return objectSchemaToZod(fieldDef.fields);
72
+ }
39
73
  let zodType;
40
74
  switch (fieldDef.type) {
41
- case "object":
42
- zodType = objectSchemaToZod(fieldDef.fields);
43
- break;
44
75
  case "array":
45
76
  zodType = zod_1.z.array(fieldDefToZod(fieldDef.items));
46
77
  break;
@@ -76,21 +107,28 @@ function fieldDefToZod(fieldDef) {
76
107
  * Objects are stored as native DynamoDB Map types and validated at runtime against the provided schema.
77
108
  * The TypeScript type is inferred from the schema using {@link InferObjectSchema}.
78
109
  *
79
- * Can be set to nullable via decorator props.
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.
80
115
  *
81
116
  * **Supported field types within the schema:**
82
- * - `"string"`, `"number"`, `"boolean"` — primitives
83
- * - `"enum"` — string literal unions, validated at runtime via `z.enum()`
84
- * - `"object"` — nested objects (arbitrarily deep)
85
- * - `"array"` — lists of any field type
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)
86
122
  *
87
- * All field types support `nullable: true` to remove them
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.
88
126
  *
89
127
  * @template T The class type that the decorator is applied to
90
128
  * @template S The ObjectSchema type used for validation and type inference
91
129
  * @template K The inferred TypeScript type from the schema
92
130
  * @template P The decorator options type
93
- * @param props An {@link ObjectAttributeOptions} object providing the `schema` and optional `alias` and `nullable` configuration.
131
+ * @param props An {@link ObjectAttributeOptions} object providing the `schema` and optional `alias`.
94
132
  * @returns A class field decorator function
95
133
  *
96
134
  * Usage example:
@@ -113,9 +151,6 @@ function fieldDefToZod(fieldDef) {
113
151
  * class MyEntity extends MyTable {
114
152
  * @ObjectAttribute({ alias: 'Address', schema: addressSchema })
115
153
  * public address: InferObjectSchema<typeof addressSchema>;
116
- *
117
- * @ObjectAttribute({ alias: 'Meta', schema: metaSchema, nullable: true })
118
- * public meta?: InferObjectSchema<typeof metaSchema>;
119
154
  * }
120
155
  *
121
156
  * // TypeScript infers:
@@ -123,6 +158,22 @@ function fieldDefToZod(fieldDef) {
123
158
  * // address.geo.accuracy → "precise" | "approximate"
124
159
  * ```
125
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
+ *
126
177
  * Object attributes support filtering in queries using dot-path notation for nested fields
127
178
  * and the {@link ContainsFilter | $contains} operator for List membership checks.
128
179
  *
@@ -142,12 +193,15 @@ function ObjectAttribute(props) {
142
193
  context.addInitializer(function () {
143
194
  const { schema, ...restProps } = props;
144
195
  const zodSchema = objectSchemaToZod(schema);
196
+ const partialZodSchema = objectSchemaToZodPartial(schema);
145
197
  const serializers = (0, serializers_1.createObjectSerializer)(schema);
146
198
  metadata_1.default.addEntityAttribute(this.constructor.name, {
147
199
  attributeName: context.name.toString(),
148
- nullable: props?.nullable,
149
200
  type: zodSchema,
201
+ partialType: partialZodSchema,
150
202
  serializers,
203
+ nullable: false,
204
+ objectSchema: schema,
151
205
  ...restProps
152
206
  });
153
207
  });
@@ -1,5 +1,5 @@
1
1
  import type { NativeAttributeValue } from "@aws-sdk/util-dynamodb";
2
- import type { ObjectSchema } from "./types";
2
+ import type { ObjectSchema, FieldDef } from "./types";
3
3
  import type { Serializers } from "../../metadata/types";
4
4
  /**
5
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.
@@ -29,6 +29,7 @@ export declare const dateSerializer: {
29
29
  * @returns A new object suitable for DynamoDB storage
30
30
  */
31
31
  export declare function objectToTableItem(schema: ObjectSchema, value: Record<string, unknown>): Record<string, unknown>;
32
+ export declare function convertFieldToTableItem(fieldDef: FieldDef, val: unknown): unknown;
32
33
  /**
33
34
  * Recursively walks an {@link ObjectSchema} and converts a DynamoDB table item
34
35
  * back to its entity representation.
@@ -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,EAAY,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;AAiBD;;;;;;;;;;;;;;;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"}
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"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dateSerializer = void 0;
4
4
  exports.objectToTableItem = objectToTableItem;
5
+ exports.convertFieldToTableItem = convertFieldToTableItem;
5
6
  exports.tableItemToObject = tableItemToObject;
6
7
  exports.createObjectSerializer = createObjectSerializer;
7
8
  /**
@@ -45,6 +45,15 @@ export interface PrimitiveFieldDef {
45
45
  *
46
46
  * The `fields` property is itself an {@link ObjectSchema}, enabling arbitrarily deep nesting.
47
47
  *
48
+ * **Object fields are never nullable.** DynamoDB cannot update nested document paths
49
+ * (e.g. `address.geo.lat`) if an intermediate object does not exist, which causes:
50
+ * `ValidationException: The document path provided in the update expression is invalid for update`.
51
+ * To avoid this, object-type fields always exist as at least an empty object `{}`.
52
+ * Non-object fields within the object may still be nullable.
53
+ *
54
+ * Objects within arrays are not subject to this limitation because arrays use full
55
+ * replacement on update rather than document path expressions.
56
+ *
48
57
  * @example
49
58
  * ```typescript
50
59
  * const schema = {
@@ -52,7 +61,8 @@ export interface PrimitiveFieldDef {
52
61
  * type: "object",
53
62
  * fields: {
54
63
  * lat: { type: "number" },
55
- * lng: { type: "number" }
64
+ * lng: { type: "number" },
65
+ * notes: { type: "string", nullable: true }
56
66
  * }
57
67
  * }
58
68
  * } as const satisfies ObjectSchema;
@@ -63,8 +73,6 @@ export interface ObjectFieldDef {
63
73
  type: "object";
64
74
  /** The nested {@link ObjectSchema} describing the object's shape. */
65
75
  fields: ObjectSchema;
66
- /** When `true`, the field becomes optional. */
67
- nullable?: boolean;
68
76
  }
69
77
  /**
70
78
  * A schema field definition for an array/list type.
@@ -214,9 +222,11 @@ export type InferFieldDef<F extends FieldDef> = F extends ArrayFieldDef ? Array<
214
222
  *
215
223
  * - Primitive fields map to their TS equivalents via {@link PrimitiveTypeMap}
216
224
  * - Enum fields become a union of their `values` (`values[number]`)
217
- * - Nested object fields recurse through `InferObjectSchema`
225
+ * - Nested object fields recurse through `InferObjectSchema` — always required (never nullable)
218
226
  * - Array fields become `T[]` where `T` is inferred from `items`
219
227
  * - Fields with `nullable: true` become optional (`T | undefined`)
228
+ * - Object fields are always required because DynamoDB cannot update nested document paths
229
+ * if an intermediate object does not exist
220
230
  *
221
231
  * @example
222
232
  * ```typescript
@@ -239,8 +249,12 @@ export type InferFieldDef<F extends FieldDef> = F extends ArrayFieldDef ? Array<
239
249
  * ```
240
250
  */
241
251
  export type InferObjectSchema<S extends ObjectSchema> = {
242
- [K in keyof S as S[K]["nullable"] extends true ? never : K]: InferFieldDef<S[K]>;
252
+ [K in keyof S as S[K] extends {
253
+ nullable: true;
254
+ } ? never : K]: InferFieldDef<S[K]>;
243
255
  } & {
244
- [K in keyof S as S[K]["nullable"] extends true ? K : never]?: InferFieldDef<S[K]>;
256
+ [K in keyof S as S[K] extends {
257
+ nullable: true;
258
+ } ? K : never]?: InferFieldDef<S[K]>;
245
259
  };
246
260
  //# sourceMappingURL=types.d.ts.map
@@ -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;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,cAAc;IAC7B,4DAA4D;IAC5D,IAAI,EAAE,QAAQ,CAAC;IACf,qEAAqE;IACrE,MAAM,EAAE,YAAY,CAAC;IACrB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,IAAI,EAAE,OAAO,CAAC;IACd,oEAAoE;IACpE,KAAK,EAAE,QAAQ,CAAC;IAChB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IACvC,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,QAAQ,GAChB,iBAAiB,GACjB,YAAY,GACZ,cAAc,GACd,aAAa,GACb,YAAY,CAAC;AAEjB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,QAAQ,IAAI,CAAC,SAAS,aAAa,GACnE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAChC,CAAC,SAAS,cAAc,GACtB,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAC9B,CAAC,SAAS,YAAY,GACpB,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GACnB,CAAC,SAAS,iBAAiB,GACzB,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAC3B,KAAK,CAAC;AAEhB;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,YAAY,IAAI;KACrD,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,IAAI,GAAG,KAAK,GAAG,CAAC,GAAG,aAAa,CACxE,CAAC,CAAC,CAAC,CAAC,CACL;CACF,GAAG;KACD,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,aAAa,CACzE,CAAC,CAAC,CAAC,CAAC,CACL;CACF,CAAC"}
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,oEAAoE;IACpE,KAAK,EAAE,QAAQ,CAAC;IAChB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IACvC,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,QAAQ,GAChB,iBAAiB,GACjB,YAAY,GACZ,cAAc,GACd,aAAa,GACb,YAAY,CAAC;AAEjB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,QAAQ,IAAI,CAAC,SAAS,aAAa,GACnE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAChC,CAAC,SAAS,cAAc,GACtB,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAC9B,CAAC,SAAS,YAAY,GACpB,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GACnB,CAAC,SAAS,iBAAiB,GACzB,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAC3B,KAAK,CAAC;AAEhB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,YAAY,IAAI;KACrD,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,GAAG,KAAK,GAAG,CAAC,GAAG,aAAa,CAC1E,CAAC,CAAC,CAAC,CAAC,CACL;CACF,GAAG;KACD,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,aAAa,CAC3E,CAAC,CAAC,CAAC,CAAC,CACL;CACF,CAAC"}
@@ -2,6 +2,7 @@ import { type ZodType } from "zod";
2
2
  import type DynaRecord from "../DynaRecord";
3
3
  import type { AttributeMetadataOptions, Serializers } from "./types";
4
4
  import type { EntityClass } from "../types";
5
+ import type { ObjectSchema } from "../decorators/attributes/types";
5
6
  /**
6
7
  * Represents the metadata for an attribute of an entity, including its name, alias (if any), nullability, and serialization strategies.
7
8
  *
@@ -23,6 +24,8 @@ declare class AttributeMetadata {
23
24
  readonly serializers?: Serializers;
24
25
  readonly type: ZodType;
25
26
  readonly foreignKeyTarget?: EntityClass<DynaRecord>;
27
+ readonly objectSchema?: ObjectSchema;
28
+ readonly partialType?: ZodType;
26
29
  constructor(options: AttributeMetadataOptions);
27
30
  }
28
31
  export default AttributeMetadata;
@@ -1 +1 @@
1
- {"version":3,"file":"AttributeMetadata.d.ts","sourceRoot":"","sources":["../../../src/metadata/AttributeMetadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,KAAK,CAAC;AACnC,OAAO,KAAK,UAAU,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,wBAAwB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C;;;;;;;;;;;;;GAaG;AACH,cAAM,iBAAiB;IACrB,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,KAAK,EAAE,MAAM,CAAC;IAC9B,SAAgB,QAAQ,EAAE,OAAO,CAAC;IAClC,SAAgB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1C,SAAgB,IAAI,EAAE,OAAO,CAAC;IAC9B,SAAgB,gBAAgB,CAAC,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;gBAE/C,OAAO,EAAE,wBAAwB;CAa9C;AAED,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"AttributeMetadata.d.ts","sourceRoot":"","sources":["../../../src/metadata/AttributeMetadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,KAAK,CAAC;AACnC,OAAO,KAAK,UAAU,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,wBAAwB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAEnE;;;;;;;;;;;;;GAaG;AACH,cAAM,iBAAiB;IACrB,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,KAAK,EAAE,MAAM,CAAC;IAC9B,SAAgB,QAAQ,EAAE,OAAO,CAAC;IAClC,SAAgB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1C,SAAgB,IAAI,EAAE,OAAO,CAAC;IAC9B,SAAgB,gBAAgB,CAAC,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;IAC3D,SAAgB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5C,SAAgB,WAAW,CAAC,EAAE,OAAO,CAAC;gBAE1B,OAAO,EAAE,wBAAwB;CAe9C;AAED,eAAe,iBAAiB,CAAC"}
@@ -21,17 +21,22 @@ class AttributeMetadata {
21
21
  serializers;
22
22
  type;
23
23
  foreignKeyTarget;
24
+ objectSchema;
25
+ partialType;
24
26
  constructor(options) {
25
27
  this.name = options.attributeName;
26
28
  this.alias = options.alias ?? options.attributeName;
27
29
  this.nullable = options.nullable ?? false;
28
30
  this.serializers = options.serializers;
29
31
  this.foreignKeyTarget = options.foreignKeyTarget;
32
+ this.objectSchema = options.objectSchema;
30
33
  if (options.nullable === true) {
31
34
  this.type = options.type.optional().nullable();
35
+ this.partialType = options.partialType?.optional().nullable();
32
36
  }
33
37
  else {
34
38
  this.type = options.type;
39
+ this.partialType = options.partialType;
35
40
  }
36
41
  }
37
42
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EntityMetadata.d.ts","sourceRoot":"","sources":["../../../src/metadata/EntityMetadata.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,EACjB,wBAAwB,EACxB,2BAA2B,EAC3B,oBAAoB,EACpB,mBAAmB,EACnB,8BAA8B,EAC9B,2BAA2B,EAC5B,MAAM,GAAG,CAAC;AACX,OAAO,KAAK,UAAU,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAY7D,KAAK,WAAW,GAAG,KAAK,GAAG,IAAI,EAAE,GAAG,KAAK,UAAU,CAAC;AAEpD;;;;;;;;;;;GAWG;AACH,cAAM,cAAc;;IAClB;;OAEG;IACH,SAAgB,cAAc,EAAE,MAAM,CAAC;IACvC;;OAEG;IACH,SAAgB,UAAU,EAAE,wBAAwB,CAAC;IACrD;;OAEG;IACH,SAAgB,eAAe,EAAE,wBAAwB,CAAC;IAE1D;;OAEG;IACH,SAAgB,aAAa,EAAE,2BAA2B,CAAC;IAE3D,SAAgB,WAAW,EAAE,WAAW,CAAC;IAEzC;;OAEG;IACI,OAAO,EAAE,MAAM,CAAC;gBAiBX,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM;IAS5D;;;OAGG;IACI,YAAY,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAOtD;;;;;OAKG;IACI,+BAA+B,CACpC,UAAU,EAAE,uBAAuB,CAAC,UAAU,CAAC,GAC9C,uBAAuB,CAAC,UAAU,CAAC;IAatC;;;;;;OAMG;IACI,sCAAsC,CAC3C,UAAU,EAAE,OAAO,CAAC,uBAAuB,CAAC,UAAU,CAAC,CAAC,GACvD,OAAO,CAAC,uBAAuB,CAAC,UAAU,CAAC,CAAC;IA0B/C;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAM5B;;OAEG;IACH,IAAW,gBAAgB,IAAI,oBAAoB,EAAE,CAEpD;IAED;;OAEG;IACH,IAAW,sBAAsB,IAAI,qBAAqB,EAAE,CAI3D;IAED;;OAEG;IACH,IAAW,oBAAoB,IAAI,mBAAmB,EAAE,CAIvD;IAED;;OAEG;IACH,IAAW,+BAA+B,IAAI,8BAA8B,EAAE,CAE7E;IAED;;OAEG;IACH,IAAW,gBAAgB,IAAI,gBAAgB,CAO9C;IAED;;;OAGG;IACH,IAAW,oBAAoB,IAAI,2BAA2B,EAAE,CAE/D;IAED;;;OAGG;IACH,IAAW,8BAA8B,IAAI,2BAA2B,EAAE,CAUzE;CACF;AAED,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"EntityMetadata.d.ts","sourceRoot":"","sources":["../../../src/metadata/EntityMetadata.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,EACjB,wBAAwB,EACxB,2BAA2B,EAC3B,oBAAoB,EACpB,mBAAmB,EACnB,8BAA8B,EAC9B,2BAA2B,EAC5B,MAAM,GAAG,CAAC;AACX,OAAO,KAAK,UAAU,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAY7D,KAAK,WAAW,GAAG,KAAK,GAAG,IAAI,EAAE,GAAG,KAAK,UAAU,CAAC;AAEpD;;;;;;;;;;;GAWG;AACH,cAAM,cAAc;;IAClB;;OAEG;IACH,SAAgB,cAAc,EAAE,MAAM,CAAC;IACvC;;OAEG;IACH,SAAgB,UAAU,EAAE,wBAAwB,CAAC;IACrD;;OAEG;IACH,SAAgB,eAAe,EAAE,wBAAwB,CAAC;IAE1D;;OAEG;IACH,SAAgB,aAAa,EAAE,2BAA2B,CAAC;IAE3D,SAAgB,WAAW,EAAE,WAAW,CAAC;IAEzC;;OAEG;IACI,OAAO,EAAE,MAAM,CAAC;gBAuBX,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM;IAS5D;;;OAGG;IACI,YAAY,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAStD;;;;;OAKG;IACI,+BAA+B,CACpC,UAAU,EAAE,uBAAuB,CAAC,UAAU,CAAC,GAC9C,uBAAuB,CAAC,UAAU,CAAC;IAatC;;;;;;OAMG;IACI,sCAAsC,CAC3C,UAAU,EAAE,OAAO,CAAC,uBAAuB,CAAC,UAAU,CAAC,CAAC,GACvD,OAAO,CAAC,uBAAuB,CAAC,UAAU,CAAC,CAAC;IA0B/C;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAM5B;;OAEG;IACH,IAAW,gBAAgB,IAAI,oBAAoB,EAAE,CAEpD;IAED;;OAEG;IACH,IAAW,sBAAsB,IAAI,qBAAqB,EAAE,CAI3D;IAED;;OAEG;IACH,IAAW,oBAAoB,IAAI,mBAAmB,EAAE,CAIvD;IAED;;OAEG;IACH,IAAW,+BAA+B,IAAI,8BAA8B,EAAE,CAE7E;IAED;;OAEG;IACH,IAAW,gBAAgB,IAAI,gBAAgB,CAO9C;IAED;;;OAGG;IACH,IAAW,oBAAoB,IAAI,2BAA2B,EAAE,CAE/D;IAED;;;OAGG;IACH,IAAW,8BAA8B,IAAI,2BAA2B,EAAE,CAUzE;CACF;AAED,eAAe,cAAc,CAAC"}
@@ -53,6 +53,11 @@ class EntityMetadata {
53
53
  * Object containing zod attributes. Built programmatically via decorators and used to create schemas
54
54
  */
55
55
  #zodAttributes = {};
56
+ /**
57
+ * Object containing zod attributes for partial (update) validation.
58
+ * ObjectAttributes use their partialType; others use the standard type.
59
+ */
60
+ #zodPartialAttributes = {};
56
61
  constructor(entityClass, tableClassName) {
57
62
  this.EntityClass = entityClass;
58
63
  this.tableClassName = tableClassName;
@@ -68,6 +73,8 @@ class EntityMetadata {
68
73
  this.attributes[attrMeta.name] = attrMeta;
69
74
  this.tableAttributes[attrMeta.alias] = attrMeta;
70
75
  this.#zodAttributes[attrMeta.name] = attrMeta.type;
76
+ this.#zodPartialAttributes[attrMeta.name] =
77
+ attrMeta.partialType ?? attrMeta.type;
71
78
  }
72
79
  /**
73
80
  * Parse raw entity defined attributes (not reserved/relationship attributes) from input and ensure they are entity defined attributes.
@@ -98,7 +105,7 @@ class EntityMetadata {
98
105
  if (this.#schemaPartial === undefined) {
99
106
  const tableMeta = _1.default.getTable(this.tableClassName);
100
107
  this.#schemaPartial = zod_1.z
101
- .object(this.#zodAttributes)
108
+ .object(this.#zodPartialAttributes)
102
109
  .omit(tableMeta.reservedKeys)
103
110
  .partial()
104
111
  .transform((data) => {
@@ -3,6 +3,7 @@ import type { AttributeMetadata, BelongsToRelationship, EntityMetadata, JoinTabl
3
3
  import type DynaRecord from "../DynaRecord";
4
4
  import type { EntityClass, MakeOptional } from "../types";
5
5
  import type { ZodType } from "zod";
6
+ import type { ObjectSchema } from "../decorators/attributes/types";
6
7
  /**
7
8
  * Represents relationship metadata that includes a foreign key reference to another entity.
8
9
  */
@@ -99,6 +100,16 @@ export interface AttributeMetadataOptions {
99
100
  * Used to enforce referential integrity even when a relationship decorator is not present.
100
101
  */
101
102
  foreignKeyTarget?: EntityClass<DynaRecord>;
103
+ /**
104
+ * When the attribute is an ObjectAttribute, stores the original ObjectSchema
105
+ * for use in partial update operations (document path expressions).
106
+ */
107
+ objectSchema?: ObjectSchema;
108
+ /**
109
+ * When present, an alternative Zod type used for partial (update) validation.
110
+ * ObjectAttributes use this to allow partial field updates.
111
+ */
112
+ partialType?: ZodType;
102
113
  }
103
114
  /**
104
115
  * A relationship that is either BelongsTo (bi-directional to parent) or OwnedBy (uni directional to parent)
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/metadata/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/metadata/types.ts"],"names":[],"mappings":"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"}
@@ -85,7 +85,12 @@ declare class Update<T extends DynaRecord> extends OperationBase<T> {
85
85
  *
86
86
  * **What it does:**
87
87
  * - Merges the provided attributes with `updatedAt` (automatically set to the current time).
88
- * - Converts the updated attributes into a DynamoDB update expression.
88
+ * - For `@ObjectAttribute` fields with non-null values, flattens the partial object into
89
+ * {@link DocumentPathOperation | document path operations} (e.g., `SET #address.#street = :address_street`)
90
+ * instead of replacing the entire map. Nested objects are recursively flattened.
91
+ * - For regular attributes and `@ObjectAttribute` fields set to `null`, uses the standard
92
+ * expression builder (existing full-replacement / REMOVE behavior).
93
+ * - Combines both regular and document path expressions into a single DynamoDB update expression.
89
94
  *
90
95
  * @param attributes - The partial attributes to be updated on the entity.
91
96
  * @returns An object containing:
@@ -1 +1 @@
1
- {"version":3,"file":"Update.d.ts","sourceRoot":"","sources":["../../../../src/operations/Update/Update.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAGL,oBAAoB,EACrB,MAAM,oBAAoB,CAAC;AAmB5B,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,sBAAsB,EACvB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAmB,WAAW,EAAgB,MAAM,aAAa,CAAC;AA4D9E;;;;;;;;;;;;;;;;;GAiBG;AACH,cAAM,MAAM,CAAC,CAAC,SAAS,UAAU,CAAE,SAAQ,aAAa,CAAC,CAAC,CAAC;IACzD,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAE,oBAAoB,CAAC;gBAG1D,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,kBAAkB,CAAC,EAAE,oBAAoB;IAO3C;;;;;;;;;;;;;;OAcG;IACU,GAAG,CACd,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,aAAa,CAAC,UAAU,CAAC,EACrC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;cAoDhB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIlD;;;;OAIG;IACH,OAAO,CAAC,uCAAuC;IAY/C;;;;;;OAMG;IACH,OAAO,CAAC,sCAAsC;IAoC9C;;;;;;;;;;;;;;;OAeG;YACW,QAAQ;IAsDtB;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;IA4B7B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,mBAAmB;IAY3B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,0BAA0B;IAyBlC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,0BAA0B;IA0DlC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,iCAAiC;IAuBzC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,8BAA8B;IAkCtC;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAkBlC;;;;;OAKG;IACH,OAAO,CAAC,mCAAmC;IAsB3C;;;;;;;;OAQG;IACH,OAAO,CAAC,sCAAsC;IAqC9C;;;;;;;;;;OAUG;IACH,OAAO,CAAC,6BAA6B;IAuCrC;;;;;;;;;OASG;IACH,OAAO,CAAC,4BAA4B;IAgCpC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,6BAA6B;IAwBrC;;;;;;OAMG;IACH,OAAO,CAAC,gCAAgC;IAgBxC;;;OAGG;IACH,OAAO,CAAC,iCAAiC;CAU1C;AAED,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"Update.d.ts","sourceRoot":"","sources":["../../../../src/operations/Update/Update.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAGL,oBAAoB,EACrB,MAAM,oBAAoB,CAAC;AAqB5B,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,sBAAsB,EACvB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAmB,WAAW,EAAgB,MAAM,aAAa,CAAC;AA4D9E;;;;;;;;;;;;;;;;;GAiBG;AACH,cAAM,MAAM,CAAC,CAAC,SAAS,UAAU,CAAE,SAAQ,aAAa,CAAC,CAAC,CAAC;IACzD,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAE,oBAAoB,CAAC;gBAG1D,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,kBAAkB,CAAC,EAAE,oBAAoB;IAO3C;;;;;;;;;;;;;;OAcG;IACU,GAAG,CACd,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,aAAa,CAAC,UAAU,CAAC,EACrC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;cAoDhB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIlD;;;;OAIG;IACH,OAAO,CAAC,uCAAuC;IAY/C;;;;;;OAMG;IACH,OAAO,CAAC,sCAAsC;IAoC9C;;;;;;;;;;;;;;;OAeG;YACW,QAAQ;IAsDtB;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;IA4B7B;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,mBAAmB;IAuC3B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,0BAA0B;IAyBlC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,0BAA0B;IA0DlC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,iCAAiC;IAuBzC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,8BAA8B;IAkCtC;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAkBlC;;;;;OAKG;IACH,OAAO,CAAC,mCAAmC;IAsB3C;;;;;;;;OAQG;IACH,OAAO,CAAC,sCAAsC;IAqC9C;;;;;;;;;;OAUG;IACH,OAAO,CAAC,6BAA6B;IAuCrC;;;;;;;;;OASG;IACH,OAAO,CAAC,4BAA4B;IAgCpC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,6BAA6B;IAwBrC;;;;;;OAMG;IACH,OAAO,CAAC,gCAAgC;IAgBxC;;;OAGG;IACH,OAAO,CAAC,iCAAiC;CAU1C;AAED,eAAe,MAAM,CAAC"}
@@ -210,7 +210,12 @@ class Update extends OperationBase_1.default {
210
210
  *
211
211
  * **What it does:**
212
212
  * - Merges the provided attributes with `updatedAt` (automatically set to the current time).
213
- * - Converts the updated attributes into a DynamoDB update expression.
213
+ * - For `@ObjectAttribute` fields with non-null values, flattens the partial object into
214
+ * {@link DocumentPathOperation | document path operations} (e.g., `SET #address.#street = :address_street`)
215
+ * instead of replacing the entire map. Nested objects are recursively flattened.
216
+ * - For regular attributes and `@ObjectAttribute` fields set to `null`, uses the standard
217
+ * expression builder (existing full-replacement / REMOVE behavior).
218
+ * - Combines both regular and document path expressions into a single DynamoDB update expression.
214
219
  *
215
220
  * @param attributes - The partial attributes to be updated on the entity.
216
221
  * @returns An object containing:
@@ -223,8 +228,25 @@ class Update extends OperationBase_1.default {
223
228
  ...attributes,
224
229
  updatedAt: new Date()
225
230
  };
226
- const tableAttrs = (0, utils_1.entityToTableItem)(this.EntityClass, updatedAttrs);
227
- const expression = (0, utils_2.expressionBuilder)(tableAttrs);
231
+ const entityAttrs = metadata_1.default.getEntityAttributes(this.EntityClass.name);
232
+ // Separate ObjectAttribute fields (non-null) for document path handling
233
+ const regularAttrs = {};
234
+ const allDocumentPathOps = [];
235
+ for (const [key, val] of Object.entries(updatedAttrs)) {
236
+ const attrMeta = entityAttrs[key];
237
+ if (attrMeta?.objectSchema !== undefined) {
238
+ // ObjectAttribute → flatten for document path updates (objects are never nullable)
239
+ const alias = attrMeta.alias;
240
+ const ops = (0, utils_2.flattenObjectForUpdate)([alias], attrMeta.objectSchema, val);
241
+ allDocumentPathOps.push(...ops);
242
+ }
243
+ else {
244
+ // Regular attribute → existing behavior
245
+ regularAttrs[key] = val;
246
+ }
247
+ }
248
+ const tableAttrs = (0, utils_1.entityToTableItem)(this.EntityClass, regularAttrs);
249
+ const expression = (0, utils_2.expressionBuilder)(tableAttrs, allDocumentPathOps);
228
250
  return { updatedAttrs, expression };
229
251
  }
230
252
  /**
@@ -13,12 +13,14 @@ type NullableProperties<T> = {
13
13
  * Recursively resolves the value type for `AllowNullForNullable`.
14
14
  *
15
15
  * For plain object types (not `Date`, arrays, primitives, or functions),
16
- * recurses via {@link AllowNullForNullable} so that nullable fields within
17
- * object schemas (e.g. `@ObjectAttribute`) also receive `| null` during updates.
16
+ * wraps with `Partial<>` and recurses via {@link AllowNullForNullable} so that:
17
+ * - All fields within `@ObjectAttribute` objects are optional in update payloads,
18
+ * matching the partial update semantics (only provided fields are modified).
19
+ * - Nullable fields at any nesting depth receive `| null` during updates.
18
20
  *
19
21
  * Primitives, `Date`, arrays, and functions pass through unchanged.
20
22
  */
21
- type AllowNullForNullableValue<T> = T extends Date | readonly unknown[] | string | number | boolean | null | undefined | ((...args: unknown[]) => unknown) ? T : T extends Record<string, unknown> ? AllowNullForNullable<T> : T;
23
+ type AllowNullForNullableValue<T> = T extends Date | readonly unknown[] | string | number | boolean | null | undefined | ((...args: unknown[]) => unknown) ? T : T extends Record<string, unknown> ? Partial<AllowNullForNullable<T>> : T;
22
24
  /**
23
25
  * Transforms a type `T` by allowing `null` as an additional type for its nullable properties.
24
26
  *
@@ -33,13 +35,21 @@ type AllowNullForNullable<T> = {
33
35
  [K in keyof T]: K extends NullableProperties<T> ? AllowNullForNullableValue<NonNullable<T[K]>> | null | undefined : AllowNullForNullableValue<T[K]>;
34
36
  };
35
37
  /**
36
- * Attributes of an entity to update. Not all properties are required. Setting a nullable property to null will remove the attribute from the item
38
+ * Attributes of an entity to update. Not all properties are required. Setting a nullable property to null will remove the attribute from the item.
39
+ *
40
+ * For `@ObjectAttribute` fields, all nested fields are `Partial` — you only need to provide the
41
+ * fields you want to change. Omitted fields are preserved in DynamoDB via document path expressions.
37
42
  *
38
43
  * @example
39
44
  * await MockModel.update("123", {
40
45
  * nonNullableAttr: "new val", // Sets new value
41
46
  * nullableAttr: null // Remove the value. This will throw a compile time error if the property is not nullable
42
47
  * })
48
+ *
49
+ * @example Partial ObjectAttribute update
50
+ * await MockModel.update("123", {
51
+ * address: { street: "456 Oak Ave" } // Only updates street, preserves other fields
52
+ * })
43
53
  */
44
54
  export type UpdateOptions<T extends DynaRecord> = Partial<AllowNullForNullable<EntityDefinedAttributes<T>>>;
45
55
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/operations/Update/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAExD;;;;;GAKG;AACH,KAAK,kBAAkB,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,GAAG,SAAS,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;CACnD,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX;;;;;;;;GAQG;AACH,KAAK,yBAAyB,CAAC,CAAC,IAAI,CAAC,SACjC,IAAI,GACJ,SAAS,OAAO,EAAE,GAClB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,GACT,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,GACjC,CAAC,GACD,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,oBAAoB,CAAC,CAAC,CAAC,GACvB,CAAC,CAAC;AAER;;;;;;;;;GASG;AACH,KAAK,oBAAoB,CAAC,CAAC,IAAI;KAC5B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,kBAAkB,CAAC,CAAC,CAAC,GAC3C,yBAAyB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,GAC/D,yBAAyB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACpC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,UAAU,IAAI,OAAO,CACvD,oBAAoB,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CACjD,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,UAAU,IAAI,IAAI,CACxD,OAAO,CAAC,CAAC,CAAC,EACV,WAAW,CACZ,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/operations/Update/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAExD;;;;;GAKG;AACH,KAAK,kBAAkB,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,GAAG,SAAS,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;CACnD,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX;;;;;;;;;;GAUG;AACH,KAAK,yBAAyB,CAAC,CAAC,IAAI,CAAC,SACjC,IAAI,GACJ,SAAS,OAAO,EAAE,GAClB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,GACT,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,GACjC,CAAC,GACD,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,GAChC,CAAC,CAAC;AAER;;;;;;;;;GASG;AACH,KAAK,oBAAoB,CAAC,CAAC,IAAI;KAC5B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,kBAAkB,CAAC,CAAC,CAAC,GAC3C,yBAAyB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,GAC/D,yBAAyB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACpC,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,UAAU,IAAI,OAAO,CACvD,oBAAoB,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CACjD,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,UAAU,IAAI,IAAI,CACxD,OAAO,CAAC,CAAC,CAAC,EACV,WAAW,CACZ,CAAC"}
@@ -1,9 +1,10 @@
1
1
  import type { DynamoTableItem } from "../../types";
2
- import type { UpdateExpression } from "./types";
2
+ import type { UpdateExpression, DocumentPathOperation } from "./types";
3
3
  /**
4
- * Builds a dynamo expression given the table attributes
4
+ * Builds a dynamo expression given the table attributes and optional document path operations
5
5
  * @param tableAttrs The table aliases of the entity attributes
6
+ * @param documentPathOps Optional document path operations for partial ObjectAttribute updates
6
7
  * @returns
7
8
  */
8
- export declare const expressionBuilder: (tableAttrs: DynamoTableItem) => UpdateExpression;
9
+ export declare const expressionBuilder: (tableAttrs: DynamoTableItem, documentPathOps?: DocumentPathOperation[]) => UpdateExpression;
9
10
  //# sourceMappingURL=expressionBuilder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"expressionBuilder.d.ts","sourceRoot":"","sources":["../../../../src/operations/utils/expressionBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EACV,gBAAgB,EAGjB,MAAM,SAAS,CAAC;AAUjB;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,eAChB,eAAe,KAC1B,gBAoBF,CAAC"}
1
+ {"version":3,"file":"expressionBuilder.d.ts","sourceRoot":"","sources":["../../../../src/operations/utils/expressionBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EACV,gBAAgB,EAGhB,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAyBjB;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,eAChB,eAAe,oBACT,qBAAqB,EAAE,KACxC,gBAiEF,CAAC"}
@@ -2,14 +2,46 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.expressionBuilder = void 0;
4
4
  /**
5
- * Builds a dynamo expression given the table attributes
5
+ * Builds a dynamo expression given the table attributes and optional document path operations
6
6
  * @param tableAttrs The table aliases of the entity attributes
7
+ * @param documentPathOps Optional document path operations for partial ObjectAttribute updates
7
8
  * @returns
8
9
  */
9
- const expressionBuilder = (tableAttrs) => {
10
+ const expressionBuilder = (tableAttrs, documentPathOps) => {
10
11
  const sorted = sortAttributesByOperand(tableAttrs);
11
12
  const setExpression = buildUpdateSetExpression(sorted.set);
12
13
  const removeExpression = buildUpdateRemoveExpression(sorted.remove);
14
+ // Merge document path operations into the expressions
15
+ if (documentPathOps !== undefined && documentPathOps.length > 0) {
16
+ const docPathResult = buildDocumentPathExpressions(documentPathOps);
17
+ // Merge SET items
18
+ if (docPathResult.setItems.length > 0) {
19
+ Object.assign(setExpression.ExpressionAttributeNames, docPathResult.expressionAttributeNames);
20
+ Object.assign(setExpression.ExpressionAttributeValues, docPathResult.expressionAttributeValues);
21
+ const existingSet = setExpression.UpdateExpression;
22
+ const docSetClause = docPathResult.setItems.join(", ");
23
+ if (existingSet !== "") {
24
+ // Append to existing SET clause
25
+ setExpression.UpdateExpression = `${existingSet}, ${docSetClause}`;
26
+ }
27
+ else {
28
+ setExpression.UpdateExpression = `SET ${docSetClause}`;
29
+ }
30
+ }
31
+ // Merge REMOVE items
32
+ if (docPathResult.removeItems.length > 0) {
33
+ // Add names used in REMOVE paths
34
+ Object.assign(removeExpression.ExpressionAttributeNames, docPathResult.expressionAttributeNames);
35
+ const existingRemove = removeExpression.UpdateExpression;
36
+ const docRemoveClause = docPathResult.removeItems.join(", ");
37
+ if (existingRemove !== "") {
38
+ removeExpression.UpdateExpression = `${existingRemove}, ${docRemoveClause}`;
39
+ }
40
+ else {
41
+ removeExpression.UpdateExpression = `REMOVE ${docRemoveClause}`;
42
+ }
43
+ }
44
+ }
13
45
  return {
14
46
  // If the operation has only REMOVE actions, it will not have expression attribute values
15
47
  ExpressionAttributeValues: setExpression.ExpressionAttributeValues,
@@ -26,6 +58,35 @@ const expressionBuilder = (tableAttrs) => {
26
58
  };
27
59
  };
28
60
  exports.expressionBuilder = expressionBuilder;
61
+ /**
62
+ * Build document path expressions from DocumentPathOperations
63
+ */
64
+ const buildDocumentPathExpressions = (ops) => {
65
+ const result = {
66
+ setItems: [],
67
+ removeItems: [],
68
+ expressionAttributeNames: {},
69
+ expressionAttributeValues: {}
70
+ };
71
+ for (const op of ops) {
72
+ // Build the document path expression: #segment1.#segment2.#segment3
73
+ const pathExpr = op.path.map(seg => `#${seg}`).join(".");
74
+ // Build the value placeholder: :segment1_segment2_segment3
75
+ const valuePlaceholder = `:${op.path.join("_")}`;
76
+ // Register all path segment names
77
+ for (const seg of op.path) {
78
+ result.expressionAttributeNames[`#${seg}`] = seg;
79
+ }
80
+ if (op.type === "set") {
81
+ result.setItems.push(`${pathExpr} = ${valuePlaceholder}`);
82
+ result.expressionAttributeValues[valuePlaceholder] = op.value;
83
+ }
84
+ else {
85
+ result.removeItems.push(pathExpr);
86
+ }
87
+ }
88
+ return result;
89
+ };
29
90
  /**
30
91
  * Sort attributes based on their operand
31
92
  * @param tableAttrs
@@ -0,0 +1,19 @@
1
+ import type { ObjectSchema } from "../../decorators/attributes/types";
2
+ import type { DocumentPathOperation } from "./types";
3
+ /**
4
+ * Flattens a partial object value into document path operations for DynamoDB
5
+ * update expressions.
6
+ *
7
+ * For each field in the partial value:
8
+ * - `undefined` → skip (not being updated)
9
+ * - `null` → REMOVE operation
10
+ * - Nested object (`fieldDef.type === "object"`) → recurse, prepending parent path
11
+ * - Everything else (primitives, arrays, dates, enums) → serialize and SET
12
+ *
13
+ * @param parentPath Path segments leading to this object (e.g. ["address"] or ["address", "geo"])
14
+ * @param schema The ObjectSchema describing the object shape
15
+ * @param partialValue The partial object value to flatten
16
+ * @returns Array of DocumentPathOperation for use in expressionBuilder
17
+ */
18
+ export declare function flattenObjectForUpdate(parentPath: string[], schema: ObjectSchema, partialValue: Record<string, unknown>): DocumentPathOperation[];
19
+ //# sourceMappingURL=flattenObjectForUpdate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flattenObjectForUpdate.d.ts","sourceRoot":"","sources":["../../../../src/operations/utils/flattenObjectForUpdate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,mCAAmC,CAAC;AAEhF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAErD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAAE,EACpB,MAAM,EAAE,YAAY,EACpB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACpC,qBAAqB,EAAE,CAmCzB"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.flattenObjectForUpdate = flattenObjectForUpdate;
4
+ const serializers_1 = require("../../decorators/attributes/serializers");
5
+ /**
6
+ * Flattens a partial object value into document path operations for DynamoDB
7
+ * update expressions.
8
+ *
9
+ * For each field in the partial value:
10
+ * - `undefined` → skip (not being updated)
11
+ * - `null` → REMOVE operation
12
+ * - Nested object (`fieldDef.type === "object"`) → recurse, prepending parent path
13
+ * - Everything else (primitives, arrays, dates, enums) → serialize and SET
14
+ *
15
+ * @param parentPath Path segments leading to this object (e.g. ["address"] or ["address", "geo"])
16
+ * @param schema The ObjectSchema describing the object shape
17
+ * @param partialValue The partial object value to flatten
18
+ * @returns Array of DocumentPathOperation for use in expressionBuilder
19
+ */
20
+ function flattenObjectForUpdate(parentPath, schema, partialValue) {
21
+ const ops = [];
22
+ for (const [key, val] of Object.entries(partialValue)) {
23
+ const fieldDef = schema[key];
24
+ if (fieldDef === undefined)
25
+ continue;
26
+ const fieldPath = [...parentPath, key];
27
+ if (val === undefined) {
28
+ continue;
29
+ }
30
+ if (val === null) {
31
+ ops.push({ type: "remove", path: fieldPath });
32
+ continue;
33
+ }
34
+ if (fieldDef.type === "object") {
35
+ // Recurse into nested objects
36
+ const nestedOps = flattenObjectForUpdate(fieldPath, fieldDef.fields, val);
37
+ ops.push(...nestedOps);
38
+ continue;
39
+ }
40
+ // Primitives, arrays, dates, enums → serialize and SET
41
+ const serialized = (0, serializers_1.convertFieldToTableItem)(fieldDef, val);
42
+ ops.push({ type: "set", path: fieldPath, value: serialized });
43
+ }
44
+ return ops;
45
+ }
@@ -1,4 +1,6 @@
1
1
  export * from "./expressionBuilder";
2
+ export * from "./flattenObjectForUpdate";
3
+ export * from "./mergePartialObjectAttributes";
2
4
  export * from "./types";
3
5
  export * from "./utils";
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/operations/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/operations/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC"}
@@ -15,5 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./expressionBuilder"), exports);
18
+ __exportStar(require("./flattenObjectForUpdate"), exports);
19
+ __exportStar(require("./mergePartialObjectAttributes"), exports);
18
20
  __exportStar(require("./types"), exports);
19
21
  __exportStar(require("./utils"), exports);
@@ -0,0 +1,8 @@
1
+ import type { AttributeMetadataStorage } from "../../metadata";
2
+ /**
3
+ * Deep merges partial ObjectAttribute updates into the target object.
4
+ * For ObjectAttribute fields: recursively merges using the schema, removing null fields.
5
+ * For regular fields: shallow assigns (existing behavior).
6
+ */
7
+ export declare function mergePartialObjectAttributes(target: Record<string, unknown>, partial: Record<string, unknown>, entityAttrs: AttributeMetadataStorage): void;
8
+ //# sourceMappingURL=mergePartialObjectAttributes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mergePartialObjectAttributes.d.ts","sourceRoot":"","sources":["../../../../src/operations/utils/mergePartialObjectAttributes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAG/D;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,WAAW,EAAE,wBAAwB,GACpC,IAAI,CAiBN"}
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mergePartialObjectAttributes = mergePartialObjectAttributes;
4
+ /**
5
+ * Deep merges partial ObjectAttribute updates into the target object.
6
+ * For ObjectAttribute fields: recursively merges using the schema, removing null fields.
7
+ * For regular fields: shallow assigns (existing behavior).
8
+ */
9
+ function mergePartialObjectAttributes(target, partial, entityAttrs) {
10
+ for (const [key, val] of Object.entries(partial)) {
11
+ const attrMeta = entityAttrs[key];
12
+ if (attrMeta?.objectSchema !== undefined) {
13
+ // Deep merge for ObjectAttribute (objects are never nullable)
14
+ const existing = target[key] ?? {};
15
+ target[key] = deepMergeObject(existing, val, attrMeta.objectSchema);
16
+ }
17
+ else {
18
+ target[key] = val;
19
+ }
20
+ }
21
+ }
22
+ /**
23
+ * Recursively deep merges a partial object into an existing object using the schema
24
+ * to determine which fields are nested objects (and should be recursed) vs leaf values
25
+ * (which should be overwritten).
26
+ * - null values cause the key to be deleted
27
+ * - object-type fields per the schema are recursed
28
+ * - everything else (primitives, arrays, dates, enums) is overwritten
29
+ */
30
+ function deepMergeObject(existing, partial, schema) {
31
+ const result = {};
32
+ // Copy existing keys, skipping those being nulled
33
+ for (const [key, val] of Object.entries(existing)) {
34
+ if (partial[key] !== null) {
35
+ result[key] = val;
36
+ }
37
+ }
38
+ // Apply updates in a single pass
39
+ for (const [key, val] of Object.entries(partial)) {
40
+ if (val === null || val === undefined) {
41
+ continue;
42
+ }
43
+ const fieldDef = schema[key];
44
+ if (fieldDef?.type === "object" && typeof existing[key] === "object") {
45
+ result[key] = deepMergeObject(existing[key] ?? {}, val, fieldDef.fields);
46
+ }
47
+ else {
48
+ result[key] = val;
49
+ }
50
+ }
51
+ return result;
52
+ }
@@ -18,4 +18,20 @@ export interface UpdateRemoveExpression {
18
18
  * Represents either an update expression for setting new or modifying existing attributes of an item (UpdateSetExpression) or an update expression for removing attributes from an item (UpdateRemoveExpression) in DynamoDB.
19
19
  */
20
20
  export type UpdateExpression = UpdateSetExpression | UpdateRemoveExpression;
21
+ /**
22
+ * Represents a single document path operation for partial ObjectAttribute updates.
23
+ * Used to build DynamoDB document path expressions like `SET #addr.#street = :addr_street`
24
+ * or `REMOVE #addr.#zip`.
25
+ */
26
+ export type DocumentPathOperation = {
27
+ type: "set";
28
+ /** Path segments, e.g. ["address", "street"] or ["address", "geo", "lat"] */
29
+ path: string[];
30
+ /** The serialized value */
31
+ value: unknown;
32
+ } | {
33
+ type: "remove";
34
+ /** Path segments, e.g. ["address", "zip"] */
35
+ path: string[];
36
+ };
21
37
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/operations/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,gBAAgB,EAAE,WAAW,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACtE,wBAAwB,EAAE,WAAW,CACnC,kBAAkB,CAAC,0BAA0B,CAAC,CAC/C,CAAC;IACF,yBAAyB,EAAE,WAAW,CACpC,kBAAkB,CAAC,2BAA2B,CAAC,CAChD,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,gBAAgB,EAAE,WAAW,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACtE,wBAAwB,EAAE,WAAW,CACnC,kBAAkB,CAAC,0BAA0B,CAAC,CAC/C,CAAC;CACH;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,GAAG,sBAAsB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/operations/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,gBAAgB,EAAE,WAAW,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACtE,wBAAwB,EAAE,WAAW,CACnC,kBAAkB,CAAC,0BAA0B,CAAC,CAC/C,CAAC;IACF,yBAAyB,EAAE,WAAW,CACpC,kBAAkB,CAAC,2BAA2B,CAAC,CAChD,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,gBAAgB,EAAE,WAAW,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACtE,wBAAwB,EAAE,WAAW,CACnC,kBAAkB,CAAC,0BAA0B,CAAC,CAC/C,CAAC;CACH;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,GAAG,sBAAsB,CAAC;AAE5E;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IACE,IAAI,EAAE,KAAK,CAAC;IACZ,6EAA6E;IAC7E,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,2BAA2B;IAC3B,KAAK,EAAE,OAAO,CAAC;CAChB,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,6CAA6C;IAC7C,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dyna-record",
3
- "version": "0.4.11",
3
+ "version": "0.5.0",
4
4
  "description": "Typescript Data Modeler and ORM for Dynamo",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",