@ftschopp/dynatable-core 1.0.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 (197) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +17 -0
  3. package/dist/builders/batch-get/create-batch-get-builder.d.ts +18 -0
  4. package/dist/builders/batch-get/create-batch-get-builder.d.ts.map +1 -0
  5. package/dist/builders/batch-get/create-batch-get-builder.js +71 -0
  6. package/dist/builders/batch-get/index.d.ts +3 -0
  7. package/dist/builders/batch-get/index.d.ts.map +1 -0
  8. package/dist/builders/batch-get/index.js +18 -0
  9. package/dist/builders/batch-get/types.d.ts +25 -0
  10. package/dist/builders/batch-get/types.d.ts.map +1 -0
  11. package/dist/builders/batch-get/types.js +2 -0
  12. package/dist/builders/batch-write/create-batch-write-builder.d.ts +12 -0
  13. package/dist/builders/batch-write/create-batch-write-builder.d.ts.map +1 -0
  14. package/dist/builders/batch-write/create-batch-write-builder.js +35 -0
  15. package/dist/builders/batch-write/index.d.ts +3 -0
  16. package/dist/builders/batch-write/index.d.ts.map +1 -0
  17. package/dist/builders/batch-write/index.js +18 -0
  18. package/dist/builders/batch-write/types.d.ts +30 -0
  19. package/dist/builders/batch-write/types.d.ts.map +1 -0
  20. package/dist/builders/batch-write/types.js +2 -0
  21. package/dist/builders/delete/create-delete-builder.d.ts +9 -0
  22. package/dist/builders/delete/create-delete-builder.d.ts.map +1 -0
  23. package/dist/builders/delete/create-delete-builder.js +72 -0
  24. package/dist/builders/delete/index.d.ts +3 -0
  25. package/dist/builders/delete/index.d.ts.map +1 -0
  26. package/dist/builders/delete/index.js +18 -0
  27. package/dist/builders/delete/types.d.ts +11 -0
  28. package/dist/builders/delete/types.d.ts.map +1 -0
  29. package/dist/builders/delete/types.js +2 -0
  30. package/dist/builders/get/create-get-builder.d.ts +12 -0
  31. package/dist/builders/get/create-get-builder.d.ts.map +1 -0
  32. package/dist/builders/get/create-get-builder.js +95 -0
  33. package/dist/builders/get/index.d.ts +3 -0
  34. package/dist/builders/get/index.d.ts.map +1 -0
  35. package/dist/builders/get/index.js +18 -0
  36. package/dist/builders/get/types.d.ts +28 -0
  37. package/dist/builders/get/types.d.ts.map +1 -0
  38. package/dist/builders/get/types.js +2 -0
  39. package/dist/builders/index.d.ts +12 -0
  40. package/dist/builders/index.d.ts.map +1 -0
  41. package/dist/builders/index.js +29 -0
  42. package/dist/builders/put/create-put-builder.d.ts +9 -0
  43. package/dist/builders/put/create-put-builder.d.ts.map +1 -0
  44. package/dist/builders/put/create-put-builder.js +104 -0
  45. package/dist/builders/put/index.d.ts +3 -0
  46. package/dist/builders/put/index.d.ts.map +1 -0
  47. package/dist/builders/put/index.js +18 -0
  48. package/dist/builders/put/types.d.ts +17 -0
  49. package/dist/builders/put/types.d.ts.map +1 -0
  50. package/dist/builders/put/types.js +2 -0
  51. package/dist/builders/query/create-query-builder.d.ts +9 -0
  52. package/dist/builders/query/create-query-builder.d.ts.map +1 -0
  53. package/dist/builders/query/create-query-builder.js +283 -0
  54. package/dist/builders/query/index.d.ts +3 -0
  55. package/dist/builders/query/index.d.ts.map +1 -0
  56. package/dist/builders/query/index.js +18 -0
  57. package/dist/builders/query/types.d.ts +79 -0
  58. package/dist/builders/query/types.d.ts.map +1 -0
  59. package/dist/builders/query/types.js +2 -0
  60. package/dist/builders/scan/create-scan-builder.d.ts +12 -0
  61. package/dist/builders/scan/create-scan-builder.d.ts.map +1 -0
  62. package/dist/builders/scan/create-scan-builder.js +103 -0
  63. package/dist/builders/scan/index.d.ts +3 -0
  64. package/dist/builders/scan/index.d.ts.map +1 -0
  65. package/dist/builders/scan/index.js +18 -0
  66. package/dist/builders/scan/types.d.ts +43 -0
  67. package/dist/builders/scan/types.d.ts.map +1 -0
  68. package/dist/builders/scan/types.js +2 -0
  69. package/dist/builders/shared/conditions.d.ts +18 -0
  70. package/dist/builders/shared/conditions.d.ts.map +1 -0
  71. package/dist/builders/shared/conditions.js +48 -0
  72. package/dist/builders/shared/index.d.ts +4 -0
  73. package/dist/builders/shared/index.d.ts.map +1 -0
  74. package/dist/builders/shared/index.js +19 -0
  75. package/dist/builders/shared/operators.d.ts +12 -0
  76. package/dist/builders/shared/operators.d.ts.map +1 -0
  77. package/dist/builders/shared/operators.js +197 -0
  78. package/dist/builders/shared/types.d.ts +77 -0
  79. package/dist/builders/shared/types.d.ts.map +1 -0
  80. package/dist/builders/shared/types.js +6 -0
  81. package/dist/builders/transact-get/create-transact-get-builder.d.ts +18 -0
  82. package/dist/builders/transact-get/create-transact-get-builder.d.ts.map +1 -0
  83. package/dist/builders/transact-get/create-transact-get-builder.js +60 -0
  84. package/dist/builders/transact-get/index.d.ts +3 -0
  85. package/dist/builders/transact-get/index.d.ts.map +1 -0
  86. package/dist/builders/transact-get/index.js +18 -0
  87. package/dist/builders/transact-get/types.d.ts +28 -0
  88. package/dist/builders/transact-get/types.d.ts.map +1 -0
  89. package/dist/builders/transact-get/types.js +2 -0
  90. package/dist/builders/transact-write/create-transact-write-builder.d.ts +18 -0
  91. package/dist/builders/transact-write/create-transact-write-builder.d.ts.map +1 -0
  92. package/dist/builders/transact-write/create-transact-write-builder.js +97 -0
  93. package/dist/builders/transact-write/index.d.ts +3 -0
  94. package/dist/builders/transact-write/index.d.ts.map +1 -0
  95. package/dist/builders/transact-write/index.js +18 -0
  96. package/dist/builders/transact-write/types.d.ts +34 -0
  97. package/dist/builders/transact-write/types.d.ts.map +1 -0
  98. package/dist/builders/transact-write/types.js +2 -0
  99. package/dist/builders/update/create-update-builder.d.ts +14 -0
  100. package/dist/builders/update/create-update-builder.d.ts.map +1 -0
  101. package/dist/builders/update/create-update-builder.js +180 -0
  102. package/dist/builders/update/index.d.ts +3 -0
  103. package/dist/builders/update/index.d.ts.map +1 -0
  104. package/dist/builders/update/index.js +18 -0
  105. package/dist/builders/update/types.d.ts +35 -0
  106. package/dist/builders/update/types.d.ts.map +1 -0
  107. package/dist/builders/update/types.js +2 -0
  108. package/dist/core/types.d.ts +224 -0
  109. package/dist/core/types.d.ts.map +1 -0
  110. package/dist/core/types.js +3 -0
  111. package/dist/entity.d.ts +73 -0
  112. package/dist/entity.d.ts.map +1 -0
  113. package/dist/entity.js +161 -0
  114. package/dist/index.d.ts +4 -0
  115. package/dist/index.d.ts.map +1 -0
  116. package/dist/index.js +20 -0
  117. package/dist/table.d.ts +70 -0
  118. package/dist/table.d.ts.map +1 -0
  119. package/dist/table.js +69 -0
  120. package/dist/utils/dynamodb-logger.d.ts +118 -0
  121. package/dist/utils/dynamodb-logger.d.ts.map +1 -0
  122. package/dist/utils/dynamodb-logger.js +125 -0
  123. package/dist/utils/model-utils.d.ts +24 -0
  124. package/dist/utils/model-utils.d.ts.map +1 -0
  125. package/dist/utils/model-utils.js +88 -0
  126. package/dist/utils/zod-utils.d.ts +13 -0
  127. package/dist/utils/zod-utils.d.ts.map +1 -0
  128. package/dist/utils/zod-utils.js +35 -0
  129. package/eslint.config.mjs +4 -0
  130. package/jest.config.js +11 -0
  131. package/package.json +36 -0
  132. package/src/builders/README.md +272 -0
  133. package/src/builders/batch-get/README.md +98 -0
  134. package/src/builders/batch-get/create-batch-get-builder.test.ts +165 -0
  135. package/src/builders/batch-get/create-batch-get-builder.ts +106 -0
  136. package/src/builders/batch-get/index.ts +2 -0
  137. package/src/builders/batch-get/types.ts +29 -0
  138. package/src/builders/batch-write/README.md +204 -0
  139. package/src/builders/batch-write/create-batch-write-builder.test.ts +173 -0
  140. package/src/builders/batch-write/create-batch-write-builder.ts +49 -0
  141. package/src/builders/batch-write/index.ts +2 -0
  142. package/src/builders/batch-write/types.ts +33 -0
  143. package/src/builders/delete/create-delete-builder.test.ts +294 -0
  144. package/src/builders/delete/create-delete-builder.ts +100 -0
  145. package/src/builders/delete/index.ts +2 -0
  146. package/src/builders/delete/types.ts +11 -0
  147. package/src/builders/get/create-get-builder.test.ts +272 -0
  148. package/src/builders/get/create-get-builder.ts +140 -0
  149. package/src/builders/get/index.ts +2 -0
  150. package/src/builders/get/types.ts +30 -0
  151. package/src/builders/index.ts +14 -0
  152. package/src/builders/put/create-put-builder.test.ts +213 -0
  153. package/src/builders/put/create-put-builder.ts +151 -0
  154. package/src/builders/put/index.ts +2 -0
  155. package/src/builders/put/types.ts +18 -0
  156. package/src/builders/query/create-query-builder.test.ts +230 -0
  157. package/src/builders/query/create-query-builder.ts +353 -0
  158. package/src/builders/query/index.ts +2 -0
  159. package/src/builders/query/types.ts +95 -0
  160. package/src/builders/scan/create-scan-builder.test.ts +260 -0
  161. package/src/builders/scan/create-scan-builder.ts +217 -0
  162. package/src/builders/scan/index.ts +2 -0
  163. package/src/builders/scan/types.ts +49 -0
  164. package/src/builders/shared/conditions.ts +58 -0
  165. package/src/builders/shared/index.ts +3 -0
  166. package/src/builders/shared/operators.test.ts +270 -0
  167. package/src/builders/shared/operators.ts +200 -0
  168. package/src/builders/shared/types.ts +100 -0
  169. package/src/builders/transact-get/README.md +167 -0
  170. package/src/builders/transact-get/create-transact-get-builder.test.ts +239 -0
  171. package/src/builders/transact-get/create-transact-get-builder.ts +67 -0
  172. package/src/builders/transact-get/index.ts +2 -0
  173. package/src/builders/transact-get/types.ts +31 -0
  174. package/src/builders/transact-write/README.md +166 -0
  175. package/src/builders/transact-write/create-transact-write-builder.test.ts +288 -0
  176. package/src/builders/transact-write/create-transact-write-builder.ts +118 -0
  177. package/src/builders/transact-write/index.ts +2 -0
  178. package/src/builders/transact-write/types.ts +33 -0
  179. package/src/builders/update/create-update-builder.test.ts +333 -0
  180. package/src/builders/update/create-update-builder.ts +284 -0
  181. package/src/builders/update/index.ts +2 -0
  182. package/src/builders/update/types.ts +42 -0
  183. package/src/core/types.test.ts +506 -0
  184. package/src/core/types.ts +290 -0
  185. package/src/entity.ts +337 -0
  186. package/src/index.ts +22 -0
  187. package/src/table.ts +109 -0
  188. package/src/utils/dynamodb-logger.test.ts +246 -0
  189. package/src/utils/dynamodb-logger.ts +175 -0
  190. package/src/utils/model-utils.test.ts +232 -0
  191. package/src/utils/model-utils.ts +101 -0
  192. package/src/utils/zod-utils.test.ts +272 -0
  193. package/src/utils/zod-utils.ts +36 -0
  194. package/tests/integration/instagram-clone.integration.test.ts +966 -0
  195. package/tests/integration/pagination-timestamps.integration.test.ts +375 -0
  196. package/tests/integration/transactions.integration.test.ts +529 -0
  197. package/tsconfig.json +12 -0
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Configuration for DynamoDB operation logging
3
+ */
4
+ export interface DynamoDBLoggerConfig {
5
+ /**
6
+ * Enable/disable logging. Default: false
7
+ */
8
+ enabled: boolean;
9
+ /**
10
+ * Log the request parameters. Default: true
11
+ */
12
+ logParams?: boolean;
13
+ /**
14
+ * Log the response data. Default: false
15
+ */
16
+ logResponse?: boolean;
17
+ /**
18
+ * Custom logger function. Default: console.log
19
+ */
20
+ loggerFn?: (message: string) => void;
21
+ }
22
+ /**
23
+ * DynamoDB Logger interface
24
+ */
25
+ export type DynamoDBLogger = {
26
+ /**
27
+ * Log a DynamoDB operation with its parameters and optionally the response
28
+ */
29
+ log: <TParams, TResponse>(operationName: string, params: TParams, response?: TResponse) => void;
30
+ };
31
+ /**
32
+ * Creates a DynamoDB logger instance with the given configuration
33
+ * This is the main factory function for creating loggers
34
+ *
35
+ * @example Basic logger with request parameters only
36
+ * ```typescript
37
+ * const logger = createDynamoDBLogger({
38
+ * enabled: true,
39
+ * logParams: true,
40
+ * logResponse: false,
41
+ * });
42
+ * ```
43
+ *
44
+ * @example Full logging (params + response)
45
+ * ```typescript
46
+ * const logger = createDynamoDBLogger({
47
+ * enabled: true,
48
+ * logParams: true,
49
+ * logResponse: true,
50
+ * });
51
+ * ```
52
+ *
53
+ * @example Using with a table
54
+ * ```typescript
55
+ * const logger = createDynamoDBLogger({
56
+ * enabled: true,
57
+ * logParams: true,
58
+ * logResponse: true,
59
+ * });
60
+ *
61
+ * const userTable = createTable({
62
+ * tableName: 'Users',
63
+ * client: dynamoDBClient,
64
+ * schema: userSchema,
65
+ * logger, // Pass logger to table
66
+ * });
67
+ *
68
+ * // Operations will be logged automatically
69
+ * const user = await userTable.get({ username: 'johndoe' }).execute();
70
+ * ```
71
+ *
72
+ * @example Custom logger function (Winston, Pino, etc.)
73
+ * ```typescript
74
+ * import winston from 'winston';
75
+ *
76
+ * const winstonLogger = winston.createLogger({
77
+ * level: 'info',
78
+ * format: winston.format.json(),
79
+ * transports: [new winston.transports.Console()],
80
+ * });
81
+ *
82
+ * const logger = createDynamoDBLogger({
83
+ * enabled: true,
84
+ * logParams: true,
85
+ * logResponse: true,
86
+ * loggerFn: (message) => winstonLogger.info(message),
87
+ * });
88
+ * ```
89
+ *
90
+ * @example Output format
91
+ * ```
92
+ * ================================================================================
93
+ * [DynamoDB] GetCommand - 2025-12-29T10:30:45.123Z
94
+ * ================================================================================
95
+ *
96
+ * 📤 Request Parameters:
97
+ * {
98
+ * "TableName": "Users",
99
+ * "Key": {
100
+ * "PK": "USER#johndoe",
101
+ * "SK": "PROFILE"
102
+ * }
103
+ * }
104
+ *
105
+ * 📥 Response:
106
+ * {
107
+ * "Item": {
108
+ * "PK": "USER#johndoe",
109
+ * "SK": "PROFILE",
110
+ * "username": "johndoe",
111
+ * "email": "john@example.com"
112
+ * }
113
+ * }
114
+ * ================================================================================
115
+ * ```
116
+ */
117
+ export declare const createDynamoDBLogger: (config: DynamoDBLoggerConfig) => DynamoDBLogger;
118
+ //# sourceMappingURL=dynamodb-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dynamodb-logger.d.ts","sourceRoot":"","sources":["../../src/utils/dynamodb-logger.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B;;OAEG;IACH,GAAG,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;CACjG,CAAC;AAkCF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqFG;AACH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,oBAAoB,KAAG,cAmBnE,CAAC"}
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.createDynamoDBLogger = void 0;
5
+ /**
6
+ * Pure function to format log message
7
+ * This function has no side effects and is easily testable
8
+ */
9
+ const formatLogMessage = (operationName, timestamp, params, response, config) => {
10
+ const parts = [
11
+ '\n' + '='.repeat(80),
12
+ `[DynamoDB] ${operationName} - ${timestamp}`,
13
+ '='.repeat(80),
14
+ ];
15
+ if (config.logParams && params) {
16
+ parts.push('\n📤 Request Parameters:');
17
+ parts.push(JSON.stringify(params, null, 2));
18
+ }
19
+ if (config.logResponse && response) {
20
+ parts.push('\n📥 Response:');
21
+ parts.push(JSON.stringify(response, null, 2));
22
+ }
23
+ parts.push('='.repeat(80) + '\n');
24
+ return parts.join('\n');
25
+ };
26
+ /**
27
+ * Creates a DynamoDB logger instance with the given configuration
28
+ * This is the main factory function for creating loggers
29
+ *
30
+ * @example Basic logger with request parameters only
31
+ * ```typescript
32
+ * const logger = createDynamoDBLogger({
33
+ * enabled: true,
34
+ * logParams: true,
35
+ * logResponse: false,
36
+ * });
37
+ * ```
38
+ *
39
+ * @example Full logging (params + response)
40
+ * ```typescript
41
+ * const logger = createDynamoDBLogger({
42
+ * enabled: true,
43
+ * logParams: true,
44
+ * logResponse: true,
45
+ * });
46
+ * ```
47
+ *
48
+ * @example Using with a table
49
+ * ```typescript
50
+ * const logger = createDynamoDBLogger({
51
+ * enabled: true,
52
+ * logParams: true,
53
+ * logResponse: true,
54
+ * });
55
+ *
56
+ * const userTable = createTable({
57
+ * tableName: 'Users',
58
+ * client: dynamoDBClient,
59
+ * schema: userSchema,
60
+ * logger, // Pass logger to table
61
+ * });
62
+ *
63
+ * // Operations will be logged automatically
64
+ * const user = await userTable.get({ username: 'johndoe' }).execute();
65
+ * ```
66
+ *
67
+ * @example Custom logger function (Winston, Pino, etc.)
68
+ * ```typescript
69
+ * import winston from 'winston';
70
+ *
71
+ * const winstonLogger = winston.createLogger({
72
+ * level: 'info',
73
+ * format: winston.format.json(),
74
+ * transports: [new winston.transports.Console()],
75
+ * });
76
+ *
77
+ * const logger = createDynamoDBLogger({
78
+ * enabled: true,
79
+ * logParams: true,
80
+ * logResponse: true,
81
+ * loggerFn: (message) => winstonLogger.info(message),
82
+ * });
83
+ * ```
84
+ *
85
+ * @example Output format
86
+ * ```
87
+ * ================================================================================
88
+ * [DynamoDB] GetCommand - 2025-12-29T10:30:45.123Z
89
+ * ================================================================================
90
+ *
91
+ * 📤 Request Parameters:
92
+ * {
93
+ * "TableName": "Users",
94
+ * "Key": {
95
+ * "PK": "USER#johndoe",
96
+ * "SK": "PROFILE"
97
+ * }
98
+ * }
99
+ *
100
+ * 📥 Response:
101
+ * {
102
+ * "Item": {
103
+ * "PK": "USER#johndoe",
104
+ * "SK": "PROFILE",
105
+ * "username": "johndoe",
106
+ * "email": "john@example.com"
107
+ * }
108
+ * }
109
+ * ================================================================================
110
+ * ```
111
+ */
112
+ const createDynamoDBLogger = (config) => {
113
+ const logFn = config.loggerFn || console.log;
114
+ return {
115
+ log: (operationName, params, response) => {
116
+ if (!config.enabled) {
117
+ return;
118
+ }
119
+ const timestamp = new Date().toISOString();
120
+ const message = formatLogMessage(operationName, timestamp, params, response, config);
121
+ logFn(message);
122
+ },
123
+ };
124
+ };
125
+ exports.createDynamoDBLogger = createDynamoDBLogger;
@@ -0,0 +1,24 @@
1
+ import { InferModel, ModelDefinition } from '@/core/types';
2
+ /**
3
+ * Extracts all variable names from a template string
4
+ * @param template - Template string with ${variable} syntax
5
+ * @returns Array of variable names found in the template
6
+ */
7
+ export declare const extractTemplateVars: (template: string) => string[];
8
+ /**
9
+ * Resolves a string template with provided data
10
+ * @throws Error if any required template variable is missing from data
11
+ */
12
+ export declare const resolveTemplate: (template: string, data: Record<string, any>) => string;
13
+ /**
14
+ * Resolves all keys or indexes for a model
15
+ */
16
+ export declare const resolveKeys: <M extends ModelDefinition>(model: M, input: Record<string, any>, type?: "key" | "index" | "both") => Record<string, string>;
17
+ /**
18
+ * Applies default and generated values to validated input
19
+ */
20
+ export declare const applyPostDefaults: <M extends ModelDefinition>(model: M, validatedItem: Record<string, any>, options?: {
21
+ isUpdate?: boolean;
22
+ timestamps?: boolean;
23
+ }) => InferModel<M>;
24
+ //# sourceMappingURL=model-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-utils.d.ts","sourceRoot":"","sources":["../../src/utils/model-utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAiB,eAAe,EAAE,MAAM,cAAc,CAAC;AAG1E;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAAI,UAAU,MAAM,KAAG,MAAM,EAG5D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,UAAU,MAAM,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAG,MAoB7E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,eAAe,EACnD,OAAO,CAAC,EACR,OAAO,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC1B,OAAM,KAAK,GAAG,OAAO,GAAG,MAAc,KACrC,MAAM,CAAC,MAAM,EAAE,MAAM,CAWvB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,eAAe,EACzD,OAAO,CAAC,EACR,eAAe,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAClC,UAAU;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,KACrD,UAAU,CAAC,CAAC,CAgCd,CAAC"}
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.applyPostDefaults = exports.resolveKeys = exports.resolveTemplate = exports.extractTemplateVars = void 0;
5
+ const ulid_1 = require("ulid");
6
+ /**
7
+ * Extracts all variable names from a template string
8
+ * @param template - Template string with ${variable} syntax
9
+ * @returns Array of variable names found in the template
10
+ */
11
+ const extractTemplateVars = (template) => {
12
+ const matches = template.matchAll(/\${(.*?)}/g);
13
+ return Array.from(matches, (m) => m[1]).filter((v) => v !== undefined);
14
+ };
15
+ exports.extractTemplateVars = extractTemplateVars;
16
+ /**
17
+ * Resolves a string template with provided data
18
+ * @throws Error if any required template variable is missing from data
19
+ */
20
+ const resolveTemplate = (template, data) => {
21
+ const missing = [];
22
+ const result = template.replace(/\${(.*?)}/g, (_, key) => {
23
+ const value = data[key];
24
+ if (value === undefined) {
25
+ missing.push(key);
26
+ return `\${${key}}`; // Keep placeholder for error message
27
+ }
28
+ return String(value);
29
+ });
30
+ if (missing.length > 0) {
31
+ throw new Error(`Missing required field(s) for key template: ${missing.join(', ')}. ` +
32
+ `Template: "${template}"`);
33
+ }
34
+ return result;
35
+ };
36
+ exports.resolveTemplate = resolveTemplate;
37
+ /**
38
+ * Resolves all keys or indexes for a model
39
+ */
40
+ const resolveKeys = (model, input, type = 'key') => {
41
+ const out = {};
42
+ const process = (keys) => {
43
+ if (!keys)
44
+ return;
45
+ for (const [k, def] of Object.entries(keys)) {
46
+ out[k] = (0, exports.resolveTemplate)(def.value, input);
47
+ }
48
+ };
49
+ if (type === 'key' || type === 'both')
50
+ process(model.key);
51
+ if (type === 'index' || type === 'both')
52
+ process(model.index);
53
+ return out;
54
+ };
55
+ exports.resolveKeys = resolveKeys;
56
+ /**
57
+ * Applies default and generated values to validated input
58
+ */
59
+ const applyPostDefaults = (model, validatedItem, options) => {
60
+ const result = { ...validatedItem };
61
+ for (const [key, attr] of Object.entries(model.attributes)) {
62
+ if (result[key] === undefined) {
63
+ if (attr.generate === 'ulid') {
64
+ result[key] = (0, ulid_1.ulid)();
65
+ }
66
+ else if (attr.generate === 'uuid') {
67
+ result[key] = crypto.randomUUID();
68
+ }
69
+ else if (attr.default !== undefined) {
70
+ result[key] = typeof attr.default === 'function' ? attr.default() : attr.default;
71
+ }
72
+ }
73
+ }
74
+ // Apply timestamps if enabled
75
+ const enableTimestamps = options?.timestamps ?? false;
76
+ const isUpdate = options?.isUpdate ?? false;
77
+ if (enableTimestamps) {
78
+ const now = new Date().toISOString();
79
+ // Only set createdAt on new items (not updates)
80
+ if (!isUpdate && result.createdAt === undefined) {
81
+ result.createdAt = now;
82
+ }
83
+ // Always set updatedAt
84
+ result.updatedAt = now;
85
+ }
86
+ return result;
87
+ };
88
+ exports.applyPostDefaults = applyPostDefaults;
@@ -0,0 +1,13 @@
1
+ import { AttributeDefinition, ModelDefinition } from '@/core/types';
2
+ import { ZodObject, ZodType } from 'zod';
3
+ /**
4
+ * Converts an attribute definition to a Zod schema type
5
+ */
6
+ export declare const typeToZod: (attr: AttributeDefinition) => ZodType;
7
+ /**
8
+ * Converts a model definition to a Zod object schema
9
+ * Uses passthrough mode to allow additional fields like createdAt/updatedAt
10
+ * that are added by applyPostDefaults when timestamps are enabled
11
+ */
12
+ export declare const modelToZod: (model: ModelDefinition) => ZodObject<any>;
13
+ //# sourceMappingURL=zod-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zod-utils.d.ts","sourceRoot":"","sources":["../../src/utils/zod-utils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAK,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAE5C;;GAEG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,mBAAmB,KAAG,OAarD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAI,OAAO,eAAe,KAAG,SAAS,CAAC,GAAG,CAMhE,CAAC"}
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ // -------------------- Zod Conversion --------------------
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.modelToZod = exports.typeToZod = void 0;
6
+ const zod_1 = require("zod");
7
+ /**
8
+ * Converts an attribute definition to a Zod schema type
9
+ */
10
+ const typeToZod = (attr) => {
11
+ const zodType = attr.type === String
12
+ ? zod_1.z.string()
13
+ : attr.type === Number
14
+ ? zod_1.z.number()
15
+ : attr.type === Boolean
16
+ ? zod_1.z.boolean()
17
+ : attr.type === Date
18
+ ? zod_1.z.date()
19
+ : zod_1.z.unknown();
20
+ return attr.required ? zodType : zodType.optional();
21
+ };
22
+ exports.typeToZod = typeToZod;
23
+ /**
24
+ * Converts a model definition to a Zod object schema
25
+ * Uses passthrough mode to allow additional fields like createdAt/updatedAt
26
+ * that are added by applyPostDefaults when timestamps are enabled
27
+ */
28
+ const modelToZod = (model) => {
29
+ const shape = {};
30
+ for (const [key, attr] of Object.entries(model.attributes)) {
31
+ shape[key] = (0, exports.typeToZod)(attr);
32
+ }
33
+ return zod_1.z.object(shape).passthrough();
34
+ };
35
+ exports.modelToZod = modelToZod;
@@ -0,0 +1,4 @@
1
+ import { config } from "@repo/eslint-config/react-internal";
2
+
3
+ /** @type {import("eslint").Linter.Config} */
4
+ export default config;
package/jest.config.js ADDED
@@ -0,0 +1,11 @@
1
+ /** @type {import('jest').Config} */
2
+ module.exports = {
3
+ preset: 'ts-jest',
4
+ testEnvironment: 'node',
5
+ testMatch: ['**/?(*.)+(test).[tj]s'],
6
+ testPathIgnorePatterns: ['/node_modules/', '/dist/'],
7
+ roots: ['<rootDir>/src', '<rootDir>/tests'],
8
+ moduleNameMapper: {
9
+ '^@/(.*)$': '<rootDir>/src/$1',
10
+ },
11
+ };
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@ftschopp/dynatable-core",
3
+ "version": "1.0.0",
4
+ "description": "Core library for DynamoDB single table design",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
13
+ "test": "jest"
14
+ },
15
+ "devDependencies": {
16
+ "@repo/eslint-config": "*",
17
+ "@repo/typescript-config": "*",
18
+ "@types/jest": "^30.0.0",
19
+ "@types/node": "^25.0.3",
20
+ "aws-sdk-client-mock": "^4.1.0",
21
+ "eslint": "^9.39.2",
22
+ "jest": "^30.2.0",
23
+ "ts-jest": "^29.4.6",
24
+ "ts-node": "^10.9.2",
25
+ "typescript": "5.9.3"
26
+ },
27
+ "dependencies": {
28
+ "@aws-sdk/client-dynamodb": "^3.965.0",
29
+ "@aws-sdk/lib-dynamodb": "^3.965.0",
30
+ "@aws-sdk/util-dynamodb": "^3.965.0",
31
+ "@types/ramda": "^0.31.1",
32
+ "ramda": "^0.32.0",
33
+ "ulid": "^3.0.2",
34
+ "zod": "^4.3.5"
35
+ }
36
+ }