@ftschopp/dynatable-core 1.0.0 → 1.2.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 (85) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +528 -2
  3. package/dist/builders/delete/types.d.ts +6 -1
  4. package/dist/builders/delete/types.d.ts.map +1 -1
  5. package/dist/builders/get/types.d.ts +6 -1
  6. package/dist/builders/get/types.d.ts.map +1 -1
  7. package/dist/builders/put/types.d.ts +6 -1
  8. package/dist/builders/put/types.d.ts.map +1 -1
  9. package/dist/builders/query/create-query-builder.d.ts +1 -1
  10. package/dist/builders/query/create-query-builder.d.ts.map +1 -1
  11. package/dist/builders/query/types.d.ts +9 -10
  12. package/dist/builders/query/types.d.ts.map +1 -1
  13. package/dist/builders/transact-write/create-transact-write-builder.d.ts.map +1 -1
  14. package/dist/builders/transact-write/create-transact-write-builder.js +1 -1
  15. package/dist/builders/transact-write/types.d.ts +33 -6
  16. package/dist/builders/transact-write/types.d.ts.map +1 -1
  17. package/dist/builders/update/create-update-builder.d.ts.map +1 -1
  18. package/dist/builders/update/create-update-builder.js +30 -9
  19. package/dist/builders/update/types.d.ts +8 -2
  20. package/dist/builders/update/types.d.ts.map +1 -1
  21. package/dist/core/types.d.ts +96 -11
  22. package/dist/core/types.d.ts.map +1 -1
  23. package/dist/entity/create-entity-api.d.ts +15 -0
  24. package/dist/entity/create-entity-api.d.ts.map +1 -0
  25. package/dist/entity/create-entity-api.js +124 -0
  26. package/dist/entity/index.d.ts +12 -0
  27. package/dist/entity/index.d.ts.map +1 -0
  28. package/dist/entity/index.js +18 -0
  29. package/dist/entity/middleware/factories.d.ts +6 -0
  30. package/dist/entity/middleware/factories.d.ts.map +1 -0
  31. package/dist/entity/middleware/factories.js +15 -0
  32. package/dist/entity/middleware/types.d.ts +8 -0
  33. package/dist/entity/middleware/types.d.ts.map +1 -0
  34. package/dist/entity/middleware/types.js +2 -0
  35. package/dist/entity/middleware/with-middleware.d.ts +8 -0
  36. package/dist/entity/middleware/with-middleware.d.ts.map +1 -0
  37. package/dist/entity/middleware/with-middleware.js +29 -0
  38. package/dist/{entity.d.ts → entity/types.d.ts} +6 -17
  39. package/dist/entity/types.d.ts.map +1 -0
  40. package/dist/entity/types.js +2 -0
  41. package/dist/entity/validation/key-validation.d.ts +7 -0
  42. package/dist/entity/validation/key-validation.d.ts.map +1 -0
  43. package/dist/entity/validation/key-validation.js +25 -0
  44. package/dist/index.d.ts +1 -1
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/table.d.ts +8 -1
  47. package/dist/table.d.ts.map +1 -1
  48. package/dist/table.js +1 -0
  49. package/dist/utils/model-utils.d.ts +7 -1
  50. package/dist/utils/model-utils.d.ts.map +1 -1
  51. package/dist/utils/model-utils.js +32 -3
  52. package/dist/utils/zod-utils.d.ts +3 -2
  53. package/dist/utils/zod-utils.d.ts.map +1 -1
  54. package/dist/utils/zod-utils.js +33 -11
  55. package/package.json +3 -2
  56. package/src/builders/README.md +68 -1
  57. package/src/builders/delete/types.ts +7 -1
  58. package/src/builders/get/types.ts +7 -1
  59. package/src/builders/put/types.ts +7 -1
  60. package/src/builders/query/create-query-builder.ts +4 -6
  61. package/src/builders/query/types.ts +9 -12
  62. package/src/builders/transact-write/README.md +37 -1
  63. package/src/builders/transact-write/create-transact-write-builder.ts +20 -14
  64. package/src/builders/transact-write/types.ts +44 -6
  65. package/src/builders/update/create-update-builder.test.ts +43 -0
  66. package/src/builders/update/create-update-builder.ts +47 -9
  67. package/src/builders/update/types.ts +9 -2
  68. package/src/core/types.test.ts +137 -0
  69. package/src/core/types.ts +97 -20
  70. package/src/entity/create-entity-api.ts +212 -0
  71. package/src/entity/index.ts +19 -0
  72. package/src/entity/middleware/factories.ts +15 -0
  73. package/src/entity/middleware/types.ts +7 -0
  74. package/src/entity/middleware/with-middleware.ts +37 -0
  75. package/src/entity/types.ts +79 -0
  76. package/src/entity/validation/key-validation.ts +34 -0
  77. package/src/index.ts +1 -0
  78. package/src/table.ts +10 -3
  79. package/src/utils/model-utils.test.ts +131 -1
  80. package/src/utils/model-utils.ts +35 -2
  81. package/src/utils/zod-utils.test.ts +97 -2
  82. package/src/utils/zod-utils.ts +31 -12
  83. package/dist/entity.d.ts.map +0 -1
  84. package/dist/entity.js +0 -161
  85. package/src/entity.ts +0 -337
package/src/entity.ts DELETED
@@ -1,337 +0,0 @@
1
- import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
2
- import { InferInput, InferKeyInput, InferModel, ModelDefinition } from './core/types';
3
- import { applyPostDefaults, resolveKeys, extractTemplateVars } from './utils/model-utils';
4
- import { modelToZod } from './utils/zod-utils';
5
- import {
6
- createGetBuilder,
7
- createPutBuilder,
8
- createQueryBuilder,
9
- createUpdateBuilder,
10
- createDeleteBuilder,
11
- createScanBuilder,
12
- createBatchGetBuilder,
13
- createBatchWriteBuilder,
14
- GetBuilder,
15
- PutBuilder,
16
- QueryBuilder,
17
- UpdateBuilder,
18
- DeleteBuilder,
19
- ScanBuilder,
20
- BatchGetBuilder,
21
- BatchWriteBuilder,
22
- WriteRequest,
23
- } from './builders';
24
- import { DynamoDBLogger } from './utils/dynamodb-logger';
25
-
26
- /**
27
- * Options for creating the Entity API
28
- */
29
- export type EntityAPIOptions = {
30
- logger?: DynamoDBLogger;
31
- timestamps?: boolean;
32
- };
33
-
34
- /**
35
- * Entity API interface for a model
36
- */
37
- export type EntityAPI<Model, Input, KeyInput, ModelDef extends ModelDefinition = any> = {
38
- /**
39
- * Retrieves an item by its key.
40
- * @param key - Partial or full key object to identify the item
41
- * @returns GetBuilder configured for the item
42
- */
43
- get: (key: KeyInput) => GetBuilder<KeyInput, Model>;
44
-
45
- /**
46
- * Puts an item into the table after validation and applying defaults.
47
- * @param item - The input data to put
48
- * @returns PutBuilder configured for the item
49
- */
50
- put: (item: Input) => PutBuilder<Model>;
51
-
52
- /**
53
- * Queries items using key conditions.
54
- * @returns QueryBuilder for building and executing the query
55
- */
56
- query: () => QueryBuilder<Model, ModelDef>;
57
-
58
- /**
59
- * Scans the entire table or index without key conditions.
60
- * @returns ScanBuilder for building and executing the scan
61
- */
62
- scan: () => ScanBuilder<Model>;
63
-
64
- /**
65
- * Updates an item by its key.
66
- * @param key - Partial or full key object to identify the item
67
- * @returns UpdateBuilder configured for the item
68
- */
69
- update: (key: KeyInput) => UpdateBuilder<Model>;
70
-
71
- /**
72
- * Deletes an item by its key.
73
- * @param key - Partial or full key object to identify the item
74
- * @returns DeleteBuilder configured for the item
75
- */
76
- delete: (key: KeyInput) => DeleteBuilder<Model>;
77
-
78
- /**
79
- * Retrieves multiple items by their keys in a single batch operation.
80
- * @param keys - Array of key objects to retrieve
81
- * @returns BatchGetBuilder configured for the items
82
- */
83
- batchGet: (keys: KeyInput[]) => BatchGetBuilder<Model>;
84
-
85
- /**
86
- * Writes multiple items in a single batch operation (puts or deletes).
87
- * @param items - Array of items to put
88
- * @returns BatchWriteBuilder configured for the items
89
- */
90
- batchWrite: (items: Input[]) => BatchWriteBuilder;
91
- };
92
-
93
- /**
94
- * Creates an entity API instance with validation, key resolution, and builder creation.
95
- *
96
- * @param modelName - The name of the model/entity
97
- * @param model - The model definition
98
- * @param client - DynamoDB client instance
99
- * @param options - Optional configuration (logger, timestamps)
100
- * @returns EntityAPI with get and put methods
101
- */
102
- export const createEntityAPI = <Model extends ModelDefinition>(
103
- tableName: string,
104
- modelName: string,
105
- model: Model,
106
- client: DynamoDBClient,
107
- options: EntityAPIOptions = {}
108
- ): EntityAPI<InferModel<Model>, InferInput<Model>, InferKeyInput<Model>, Model> => {
109
- const { logger, timestamps = false } = options;
110
-
111
- // Build a Zod schema from the model
112
- const zodSchema = modelToZod(model);
113
-
114
- return {
115
- get(key) {
116
- // Extract required fields from key templates
117
- const requiredFields = new Set<string>();
118
- if (model.key) {
119
- for (const keyDef of Object.values(model.key)) {
120
- extractTemplateVars(keyDef.value).forEach((field) => requiredFields.add(field));
121
- }
122
- }
123
-
124
- // Check if all required fields are present
125
- const keyRecord = key as Record<string, unknown>;
126
- const missingFields = Array.from(requiredFields).filter(
127
- (field) => keyRecord[field] === undefined
128
- );
129
-
130
- if (missingFields.length > 0) {
131
- throw new Error(
132
- `[${modelName}] Missing required key field(s) for get(): ${missingFields.join(', ')}. ` +
133
- `Required fields: ${Array.from(requiredFields).join(', ')}`
134
- );
135
- }
136
-
137
- // Resolve any key defaults or computed keys
138
- const fullKey = resolveKeys(model, key);
139
-
140
- return createGetBuilder<InferKeyInput<Model>, InferModel<Model>>(
141
- tableName,
142
- fullKey,
143
- client,
144
- undefined,
145
- logger
146
- );
147
- },
148
-
149
- put(item) {
150
- // Validate full input data
151
- const parsed = zodSchema.parse(item);
152
-
153
- // Apply post-processing defaults from the model (including timestamps for new items)
154
- const withDefaults = applyPostDefaults(model, parsed, {
155
- isUpdate: false,
156
- timestamps,
157
- });
158
-
159
- // Resolve keys again with defaults
160
- const fullKey = resolveKeys(model, withDefaults);
161
-
162
- // Combine keys and data into full item, adding _type field
163
- const fullItem = {
164
- ...withDefaults,
165
- ...fullKey,
166
- _type: modelName, // Add entity type identifier
167
- };
168
-
169
- return createPutBuilder(tableName, fullItem, client, [], false, 'NONE', false, logger);
170
- },
171
-
172
- query() {
173
- return createQueryBuilder<InferModel<Model>, Model>(tableName, client, model, logger);
174
- },
175
-
176
- scan() {
177
- return createScanBuilder<InferModel<Model>>(
178
- tableName,
179
- client,
180
- [],
181
- [],
182
- undefined,
183
- false,
184
- undefined,
185
- undefined,
186
- undefined,
187
- logger
188
- );
189
- },
190
-
191
- update(key) {
192
- // Extract required fields from key templates
193
- const requiredFields = new Set<string>();
194
- if (model.key) {
195
- for (const keyDef of Object.values(model.key)) {
196
- extractTemplateVars(keyDef.value).forEach((field) => requiredFields.add(field));
197
- }
198
- }
199
-
200
- // Check if all required fields are present
201
- const keyRecord = key as Record<string, unknown>;
202
- const missingFields = Array.from(requiredFields).filter(
203
- (field) => keyRecord[field] === undefined
204
- );
205
-
206
- if (missingFields.length > 0) {
207
- throw new Error(
208
- `[${modelName}] Missing required key field(s) for update(): ${missingFields.join(', ')}. ` +
209
- `Required fields: ${Array.from(requiredFields).join(', ')}`
210
- );
211
- }
212
-
213
- // Resolve any key defaults or computed keys
214
- const fullKey = resolveKeys(model, key);
215
-
216
- return createUpdateBuilder<InferModel<Model>>(
217
- tableName,
218
- fullKey as Partial<InferModel<Model>>,
219
- client,
220
- [],
221
- { set: [], remove: [], add: [], delete: [] },
222
- 'NONE',
223
- 0,
224
- timestamps,
225
- logger
226
- );
227
- },
228
-
229
- delete(key) {
230
- // Extract required fields from key templates
231
- const requiredFields = new Set<string>();
232
- if (model.key) {
233
- for (const keyDef of Object.values(model.key)) {
234
- extractTemplateVars(keyDef.value).forEach((field) => requiredFields.add(field));
235
- }
236
- }
237
-
238
- // Check if all required fields are present
239
- const keyRecord = key as Record<string, unknown>;
240
- const missingFields = Array.from(requiredFields).filter(
241
- (field) => keyRecord[field] === undefined
242
- );
243
-
244
- if (missingFields.length > 0) {
245
- throw new Error(
246
- `[${modelName}] Missing required key field(s) for delete(): ${missingFields.join(', ')}. ` +
247
- `Required fields: ${Array.from(requiredFields).join(', ')}`
248
- );
249
- }
250
-
251
- // Resolve any key defaults or computed keys
252
- const fullKey = resolveKeys(model, key);
253
-
254
- return createDeleteBuilder<InferModel<Model>>(
255
- tableName,
256
- fullKey as Partial<InferModel<Model>>,
257
- client,
258
- [],
259
- 'NONE',
260
- logger
261
- );
262
- },
263
-
264
- batchGet(keys) {
265
- // Extract required fields from key templates
266
- const requiredFields = new Set<string>();
267
- if (model.key) {
268
- for (const keyDef of Object.values(model.key)) {
269
- extractTemplateVars(keyDef.value).forEach((field) => requiredFields.add(field));
270
- }
271
- }
272
-
273
- // Process all keys and validate them
274
- const resolvedKeys = keys.map((key) => {
275
- // Check if all required fields are present
276
- const keyRecord = key as Record<string, unknown>;
277
- const missingFields = Array.from(requiredFields).filter(
278
- (field) => keyRecord[field] === undefined
279
- );
280
-
281
- if (missingFields.length > 0) {
282
- throw new Error(
283
- `[${modelName}] Missing required key field(s) for batchGet(): ${missingFields.join(', ')}. ` +
284
- `Required fields: ${Array.from(requiredFields).join(', ')}`
285
- );
286
- }
287
-
288
- // Resolve any key defaults or computed keys
289
- return resolveKeys(model, key);
290
- });
291
-
292
- // Create the request items in the format expected by BatchGetItem
293
- const requestItems = {
294
- [tableName]: {
295
- Keys: resolvedKeys,
296
- },
297
- };
298
-
299
- return createBatchGetBuilder<InferModel<Model>>(requestItems, client, undefined, logger);
300
- },
301
-
302
- batchWrite(items) {
303
- // Validate and process all items
304
- const processedItems = items.map((item) => {
305
- // Validate full input data
306
- const parsed = zodSchema.parse(item);
307
-
308
- // Apply post-processing defaults from the model (including timestamps for new items)
309
- const withDefaults = applyPostDefaults(model, parsed, {
310
- isUpdate: false,
311
- timestamps,
312
- });
313
-
314
- // Resolve keys again with defaults
315
- const fullKey = resolveKeys(model, withDefaults);
316
-
317
- // Combine keys and data into full item, adding _type field
318
- return {
319
- ...withDefaults,
320
- ...fullKey,
321
- _type: modelName, // Add entity type identifier
322
- };
323
- });
324
-
325
- // Create the request items in the format expected by BatchWriteItem
326
- const requestItems: Record<string, WriteRequest[]> = {
327
- [tableName]: processedItems.map((item) => ({
328
- PutRequest: {
329
- Item: item,
330
- },
331
- })),
332
- };
333
-
334
- return createBatchWriteBuilder(requestItems, client, logger);
335
- },
336
- };
337
- };