dyna-record 0.4.10 → 0.4.11

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 CHANGED
@@ -183,6 +183,7 @@ const addressSchema = {
183
183
  zip: { type: "number", nullable: true },
184
184
  tags: { type: "array", items: { type: "string" } },
185
185
  category: { type: "enum", values: ["home", "work", "other"] },
186
+ createdDate: { type: "date" },
186
187
  geo: {
187
188
  type: "object",
188
189
  fields: {
@@ -202,8 +203,8 @@ class Store extends MyTable {
202
203
  }
203
204
  ```
204
205
 
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 allow `null` values
206
+ - **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
207
208
  - **Nullable object attributes:** Set `nullable: true` on the decorator options to make the entire object optional
208
209
  - **Alias support:** Use the `alias` option to map to a different DynamoDB attribute name
209
210
  - **Storage:** Objects are stored as native DynamoDB Map types
@@ -221,7 +222,7 @@ const schema = {
221
222
  // Top-level enum: inferred as "active" | "inactive"
222
223
  status: { type: "enum", values: ["active", "inactive"] },
223
224
 
224
- // Nullable enum: inferred as "home" | "work" | "other" | null | undefined
225
+ // Nullable enum: inferred as "home" | "work" | "other" | undefined
225
226
  category: { type: "enum", values: ["home", "work", "other"], nullable: true },
226
227
 
227
228
  // Enum inside a nested object
@@ -40,7 +40,7 @@ export interface ObjectAttributeOptions<S extends ObjectSchema> extends Attribut
40
40
  * - `"object"` — nested objects (arbitrarily deep)
41
41
  * - `"array"` — lists of any field type
42
42
  *
43
- * All field types support `nullable: true` to allow `null` values.
43
+ * All field types support `nullable: true` to remove them
44
44
  *
45
45
  * @template T The class type that the decorator is applied to
46
46
  * @template S The ObjectSchema type used for validation and type inference
@@ -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;AAEzE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,sBAAsB,CAAC,CAAC,SAAS,YAAY,CAC5D,SAAQ,gBAAgB;IACxB;;;;OAIG;IACH,MAAM,EAAE,CAAC,CAAC;CACX;AAsED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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,UAgBjE;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,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"}
@@ -5,6 +5,7 @@ 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");
8
9
  /**
9
10
  * Converts an {@link ObjectSchema} to a Zod schema for runtime validation.
10
11
  *
@@ -29,7 +30,7 @@ function objectSchemaToZod(schema) {
29
30
  * - `"boolean"` → `z.boolean()`
30
31
  * - `"enum"` → `z.enum(values)` for string literal validation
31
32
  *
32
- * When `nullable` is `true`, wraps the type with `.nullable().optional()`.
33
+ * When `nullable` is `true`, wraps the type with `.optional().nullable()`.
33
34
  *
34
35
  * @param fieldDef The field definition to convert
35
36
  * @returns A ZodType that validates values matching the field definition
@@ -52,6 +53,9 @@ function fieldDefToZod(fieldDef) {
52
53
  case "boolean":
53
54
  zodType = zod_1.z.boolean();
54
55
  break;
56
+ case "date":
57
+ zodType = zod_1.z.date();
58
+ break;
55
59
  case "enum":
56
60
  zodType = zod_1.z.enum(fieldDef.values);
57
61
  break;
@@ -62,7 +66,7 @@ function fieldDefToZod(fieldDef) {
62
66
  }
63
67
  }
64
68
  if (fieldDef.nullable === true) {
65
- zodType = zodType.nullable().optional();
69
+ zodType = zodType.optional().nullable();
66
70
  }
67
71
  return zodType;
68
72
  }
@@ -80,7 +84,7 @@ function fieldDefToZod(fieldDef) {
80
84
  * - `"object"` — nested objects (arbitrarily deep)
81
85
  * - `"array"` — lists of any field type
82
86
  *
83
- * All field types support `nullable: true` to allow `null` values.
87
+ * All field types support `nullable: true` to remove them
84
88
  *
85
89
  * @template T The class type that the decorator is applied to
86
90
  * @template S The ObjectSchema type used for validation and type inference
@@ -138,10 +142,12 @@ function ObjectAttribute(props) {
138
142
  context.addInitializer(function () {
139
143
  const { schema, ...restProps } = props;
140
144
  const zodSchema = objectSchemaToZod(schema);
145
+ const serializers = (0, serializers_1.createObjectSerializer)(schema);
141
146
  metadata_1.default.addEntityAttribute(this.constructor.name, {
142
147
  attributeName: context.name.toString(),
143
148
  nullable: props?.nullable,
144
149
  type: zodSchema,
150
+ serializers,
145
151
  ...restProps
146
152
  });
147
153
  });
@@ -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 } 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,50 @@ 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
+ /**
33
+ * Recursively walks an {@link ObjectSchema} and converts a DynamoDB table item
34
+ * back to its entity representation.
35
+ *
36
+ * - `"date"` fields are converted from ISO 8601 strings to `Date` objects.
37
+ * - `"object"` fields recurse into their nested schema.
38
+ * - `"array"` fields map each item through the same conversion.
39
+ * - `null` and `undefined` values are stripped from the result so that absent
40
+ * fields are represented as `undefined` (omitted) on the entity, consistent
41
+ * with root-level nullable attribute behaviour.
42
+ * - All other field types pass through unchanged.
43
+ *
44
+ * @param schema The {@link ObjectSchema} describing the object shape
45
+ * @param value The DynamoDB table item to convert
46
+ * @returns A new object with entity-level types (e.g. `Date` instead of string)
47
+ */
48
+ export declare function tableItemToObject(schema: ObjectSchema, value: Record<string, unknown>): Record<string, unknown>;
49
+ /**
50
+ * Creates a {@link Serializers} pair for an {@link ObjectSchema}.
51
+ *
52
+ * The returned serializers handle:
53
+ * - Converting `Date` fields to/from ISO 8601 strings for DynamoDB storage.
54
+ * - Stripping `null` and `undefined` values so that nullable fields set to
55
+ * `null` during updates are removed from the stored object.
56
+ *
57
+ * @param schema The {@link ObjectSchema} describing the object shape
58
+ * @returns A `Serializers` object with `toTableAttribute` and `toEntityAttribute` functions
59
+ */
60
+ export declare function createObjectSerializer(schema: ObjectSchema): Serializers;
13
61
  //# 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;AAEnE;;;;;;GAMG;AACH,eAAO,MAAM,cAAc;6BACA,oBAAoB;6BAMpB,IAAI;CAC9B,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,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,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dateSerializer = void 0;
4
+ exports.objectToTableItem = objectToTableItem;
5
+ exports.tableItemToObject = tableItemToObject;
6
+ exports.createObjectSerializer = createObjectSerializer;
4
7
  /**
5
8
  * 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.
6
9
  *
@@ -17,3 +20,98 @@ exports.dateSerializer = {
17
20
  },
18
21
  toTableAttribute: (val) => val?.toISOString() ?? undefined
19
22
  };
23
+ /**
24
+ * Recursively walks an {@link ObjectSchema} and converts the entity value to its
25
+ * DynamoDB representation.
26
+ *
27
+ * - `"date"` fields are converted from `Date` objects to ISO 8601 strings.
28
+ * - `"object"` fields recurse into their nested schema.
29
+ * - `"array"` fields map each item through the same conversion.
30
+ * - `null` and `undefined` values are stripped from the result so that nullable
31
+ * fields set to `null` are removed from the stored object rather than persisted
32
+ * as `null` in DynamoDB.
33
+ * - All other field types pass through unchanged.
34
+ *
35
+ * @param schema The {@link ObjectSchema} describing the object shape
36
+ * @param value The entity-level object value to convert
37
+ * @returns A new object suitable for DynamoDB storage
38
+ */
39
+ function objectToTableItem(schema, value) {
40
+ const result = {};
41
+ for (const [key, fieldDef] of Object.entries(schema)) {
42
+ const val = value[key];
43
+ if (val === undefined || val === null) {
44
+ continue;
45
+ }
46
+ result[key] = convertFieldToTableItem(fieldDef, val);
47
+ }
48
+ return result;
49
+ }
50
+ function convertFieldToTableItem(fieldDef, val) {
51
+ switch (fieldDef.type) {
52
+ case "date":
53
+ return val.toISOString();
54
+ case "object":
55
+ return objectToTableItem(fieldDef.fields, val);
56
+ case "array":
57
+ return val.map(item => convertFieldToTableItem(fieldDef.items, item));
58
+ default:
59
+ return val;
60
+ }
61
+ }
62
+ /**
63
+ * Recursively walks an {@link ObjectSchema} and converts a DynamoDB table item
64
+ * back to its entity representation.
65
+ *
66
+ * - `"date"` fields are converted from ISO 8601 strings to `Date` objects.
67
+ * - `"object"` fields recurse into their nested schema.
68
+ * - `"array"` fields map each item through the same conversion.
69
+ * - `null` and `undefined` values are stripped from the result so that absent
70
+ * fields are represented as `undefined` (omitted) on the entity, consistent
71
+ * with root-level nullable attribute behaviour.
72
+ * - All other field types pass through unchanged.
73
+ *
74
+ * @param schema The {@link ObjectSchema} describing the object shape
75
+ * @param value The DynamoDB table item to convert
76
+ * @returns A new object with entity-level types (e.g. `Date` instead of string)
77
+ */
78
+ function tableItemToObject(schema, value) {
79
+ const result = {};
80
+ for (const [key, fieldDef] of Object.entries(schema)) {
81
+ const val = value[key];
82
+ if (val === undefined || val === null) {
83
+ continue;
84
+ }
85
+ result[key] = convertFieldToEntityValue(fieldDef, val);
86
+ }
87
+ return result;
88
+ }
89
+ function convertFieldToEntityValue(fieldDef, val) {
90
+ switch (fieldDef.type) {
91
+ case "date":
92
+ return new Date(val);
93
+ case "object":
94
+ return tableItemToObject(fieldDef.fields, val);
95
+ case "array":
96
+ return val.map(item => convertFieldToEntityValue(fieldDef.items, item));
97
+ default:
98
+ return val;
99
+ }
100
+ }
101
+ /**
102
+ * Creates a {@link Serializers} pair for an {@link ObjectSchema}.
103
+ *
104
+ * The returned serializers handle:
105
+ * - Converting `Date` fields to/from ISO 8601 strings for DynamoDB storage.
106
+ * - Stripping `null` and `undefined` values so that nullable fields set to
107
+ * `null` during updates are removed from the stored object.
108
+ *
109
+ * @param schema The {@link ObjectSchema} describing the object shape
110
+ * @returns A `Serializers` object with `toTableAttribute` and `toEntityAttribute` functions
111
+ */
112
+ function createObjectSerializer(schema) {
113
+ return {
114
+ toTableAttribute: (val) => objectToTableItem(schema, val),
115
+ toEntityAttribute: (val) => tableItemToObject(schema, val)
116
+ };
117
+ }
@@ -8,16 +8,18 @@
8
8
  * | `"string"` | `string` |
9
9
  * | `"number"` | `number` |
10
10
  * | `"boolean"` | `boolean` |
11
+ * | `"date"` | `Date` |
11
12
  */
12
13
  export interface PrimitiveTypeMap {
13
14
  string: string;
14
15
  number: number;
15
16
  boolean: boolean;
17
+ date: Date;
16
18
  }
17
19
  /**
18
20
  * The allowed primitive type strings for object schema fields.
19
21
  *
20
- * Derived from the keys of {@link PrimitiveTypeMap}: `"string" | "number" | "boolean"`.
22
+ * Derived from the keys of {@link PrimitiveTypeMap}: `"string" | "number" | "boolean" | "date"`.
21
23
  */
22
24
  export type PrimitiveFieldType = keyof PrimitiveTypeMap;
23
25
  /**
@@ -35,7 +37,7 @@ export type PrimitiveFieldType = keyof PrimitiveTypeMap;
35
37
  export interface PrimitiveFieldDef {
36
38
  /** The primitive type — `"string"`, `"number"`, or `"boolean"`. */
37
39
  type: PrimitiveFieldType;
38
- /** When `true`, the field accepts `null` and becomes optional (`T | null | undefined`). */
40
+ /** When `true`, the field becomes optional (`T | undefined`). */
39
41
  nullable?: boolean;
40
42
  }
41
43
  /**
@@ -61,7 +63,7 @@ export interface ObjectFieldDef {
61
63
  type: "object";
62
64
  /** The nested {@link ObjectSchema} describing the object's shape. */
63
65
  fields: ObjectSchema;
64
- /** When `true`, the field accepts `null` and becomes optional. */
66
+ /** When `true`, the field becomes optional. */
65
67
  nullable?: boolean;
66
68
  }
67
69
  /**
@@ -83,7 +85,7 @@ export interface ArrayFieldDef {
83
85
  type: "array";
84
86
  /** A {@link FieldDef} describing the type of each array element. */
85
87
  items: FieldDef;
86
- /** When `true`, the field accepts `null` and becomes optional. */
88
+ /** When `true`, the field becomes optional. */
87
89
  nullable?: boolean;
88
90
  }
89
91
  /**
@@ -120,7 +122,7 @@ export interface ArrayFieldDef {
120
122
  * type T = InferObjectSchema<typeof schema>;
121
123
  * // {
122
124
  * // status: "active" | "inactive";
123
- * // category?: "home" | "work" | "other" | null;
125
+ * // category?: "home" | "work" | "other";
124
126
  * // geo: { accuracy: "precise" | "approximate" };
125
127
  * // roles: ("admin" | "user" | "guest")[];
126
128
  * // }
@@ -138,7 +140,27 @@ export interface EnumFieldDef {
138
140
  * Must contain at least one value (enforced by the `[string, ...string[]]` tuple type).
139
141
  */
140
142
  values: readonly [string, ...string[]];
141
- /** When `true`, the field accepts `null` and becomes optional. */
143
+ /** When `true`, the field becomes optional. */
144
+ nullable?: boolean;
145
+ }
146
+ /**
147
+ * A schema field definition for a date type.
148
+ *
149
+ * Date fields are stored as ISO 8601 strings in DynamoDB and exposed as
150
+ * JavaScript `Date` objects on entities, mirroring `@DateAttribute` behavior.
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * const schema = {
155
+ * createdDate: { type: "date" },
156
+ * deletedAt: { type: "date", nullable: true }
157
+ * } as const satisfies ObjectSchema;
158
+ * ```
159
+ */
160
+ export interface DateFieldDef {
161
+ /** Must be `"date"` to indicate a date field. */
162
+ type: "date";
163
+ /** When `true`, the field becomes optional (`Date | undefined`). */
142
164
  nullable?: boolean;
143
165
  }
144
166
  /**
@@ -146,13 +168,14 @@ export interface EnumFieldDef {
146
168
  *
147
169
  * This is the union of all supported field types:
148
170
  * - {@link PrimitiveFieldDef} — `"string"`, `"number"`, `"boolean"`
171
+ * - {@link DateFieldDef} — dates stored as ISO strings, exposed as `Date` objects
149
172
  * - {@link ObjectFieldDef} — nested objects via `fields`
150
173
  * - {@link ArrayFieldDef} — arrays/lists via `items`
151
174
  * - {@link EnumFieldDef} — string literal enums via `values`
152
175
  *
153
176
  * Each variant is discriminated by the `type` property.
154
177
  */
155
- export type FieldDef = PrimitiveFieldDef | ObjectFieldDef | ArrayFieldDef | EnumFieldDef;
178
+ export type FieldDef = PrimitiveFieldDef | DateFieldDef | ObjectFieldDef | ArrayFieldDef | EnumFieldDef;
156
179
  /**
157
180
  * Declarative schema for describing the shape of an object attribute.
158
181
  *
@@ -193,7 +216,7 @@ export type InferFieldDef<F extends FieldDef> = F extends ArrayFieldDef ? Array<
193
216
  * - Enum fields become a union of their `values` (`values[number]`)
194
217
  * - Nested object fields recurse through `InferObjectSchema`
195
218
  * - Array fields become `T[]` where `T` is inferred from `items`
196
- * - Fields with `nullable: true` become optional and accept `null` (`T | null | undefined`)
219
+ * - Fields with `nullable: true` become optional (`T | undefined`)
197
220
  *
198
221
  * @example
199
222
  * ```typescript
@@ -211,13 +234,13 @@ export type InferFieldDef<F extends FieldDef> = F extends ArrayFieldDef ? Array<
211
234
  * // status: "active" | "inactive";
212
235
  * // tags: string[];
213
236
  * // geo: { lat: number; lng: number };
214
- * // age?: number | null;
237
+ * // age?: number;
215
238
  * // }
216
239
  * ```
217
240
  */
218
241
  export type InferObjectSchema<S extends ObjectSchema> = {
219
242
  [K in keyof S as S[K]["nullable"] extends true ? never : K]: InferFieldDef<S[K]>;
220
243
  } & {
221
- [K in keyof S as S[K]["nullable"] extends true ? K : never]?: InferFieldDef<S[K]> | null;
244
+ [K in keyof S as S[K]["nullable"] extends true ? K : never]?: InferFieldDef<S[K]>;
222
245
  };
223
246
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/decorators/attributes/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,gBAAgB,CAAC;AAExD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAChC,mEAAmE;IACnE,IAAI,EAAE,kBAAkB,CAAC;IACzB,2FAA2F;IAC3F,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,kEAAkE;IAClE,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,kEAAkE;IAClE,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,kEAAkE;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,QAAQ,GAChB,iBAAiB,GACjB,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,GAAG,IAAI;CACT,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;;;;;;;;;;;;;;;;;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"}
@@ -9,14 +9,28 @@ import type { EntityDefinedAttributes } from "../types";
9
9
  type NullableProperties<T> = {
10
10
  [K in keyof T]: undefined extends T[K] ? K : never;
11
11
  }[keyof T];
12
+ /**
13
+ * Recursively resolves the value type for `AllowNullForNullable`.
14
+ *
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.
18
+ *
19
+ * Primitives, `Date`, arrays, and functions pass through unchanged.
20
+ */
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;
12
22
  /**
13
23
  * Transforms a type `T` by allowing `null` as an additional type for its nullable properties.
14
24
  *
25
+ * Recurses into plain object values (e.g. object schema attributes) so that
26
+ * nullable fields at any depth receive `| null`, matching root-level nullable
27
+ * attribute behavior during updates.
28
+ *
15
29
  * @typeParam T - The type whose properties are to be transformed.
16
30
  * @returns A new type with properties of `T` where each nullable property is also allowed to be `null`.
17
31
  */
18
32
  type AllowNullForNullable<T> = {
19
- [K in keyof T]: K extends NullableProperties<T> ? T[K] | null : T[K];
33
+ [K in keyof T]: K extends NullableProperties<T> ? AllowNullForNullableValue<NonNullable<T[K]>> | null | undefined : AllowNullForNullableValue<T[K]>;
20
34
  };
21
35
  /**
22
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
@@ -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;;;;;GAKG;AACH,KAAK,oBAAoB,CAAC,CAAC,IAAI;KAC5B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;CACrE,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;;;;;;;;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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dyna-record",
3
- "version": "0.4.10",
3
+ "version": "0.4.11",
4
4
  "description": "Typescript Data Modeler and ORM for Dynamo",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",