@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.
- package/CHANGELOG.md +19 -0
- package/README.md +528 -2
- package/dist/builders/delete/types.d.ts +6 -1
- package/dist/builders/delete/types.d.ts.map +1 -1
- package/dist/builders/get/types.d.ts +6 -1
- package/dist/builders/get/types.d.ts.map +1 -1
- package/dist/builders/put/types.d.ts +6 -1
- package/dist/builders/put/types.d.ts.map +1 -1
- package/dist/builders/query/create-query-builder.d.ts +1 -1
- package/dist/builders/query/create-query-builder.d.ts.map +1 -1
- package/dist/builders/query/types.d.ts +9 -10
- package/dist/builders/query/types.d.ts.map +1 -1
- package/dist/builders/transact-write/create-transact-write-builder.d.ts.map +1 -1
- package/dist/builders/transact-write/create-transact-write-builder.js +1 -1
- package/dist/builders/transact-write/types.d.ts +33 -6
- package/dist/builders/transact-write/types.d.ts.map +1 -1
- package/dist/builders/update/create-update-builder.d.ts.map +1 -1
- package/dist/builders/update/create-update-builder.js +30 -9
- package/dist/builders/update/types.d.ts +8 -2
- package/dist/builders/update/types.d.ts.map +1 -1
- package/dist/core/types.d.ts +96 -11
- package/dist/core/types.d.ts.map +1 -1
- package/dist/entity/create-entity-api.d.ts +15 -0
- package/dist/entity/create-entity-api.d.ts.map +1 -0
- package/dist/entity/create-entity-api.js +124 -0
- package/dist/entity/index.d.ts +12 -0
- package/dist/entity/index.d.ts.map +1 -0
- package/dist/entity/index.js +18 -0
- package/dist/entity/middleware/factories.d.ts +6 -0
- package/dist/entity/middleware/factories.d.ts.map +1 -0
- package/dist/entity/middleware/factories.js +15 -0
- package/dist/entity/middleware/types.d.ts +8 -0
- package/dist/entity/middleware/types.d.ts.map +1 -0
- package/dist/entity/middleware/types.js +2 -0
- package/dist/entity/middleware/with-middleware.d.ts +8 -0
- package/dist/entity/middleware/with-middleware.d.ts.map +1 -0
- package/dist/entity/middleware/with-middleware.js +29 -0
- package/dist/{entity.d.ts → entity/types.d.ts} +6 -17
- package/dist/entity/types.d.ts.map +1 -0
- package/dist/entity/types.js +2 -0
- package/dist/entity/validation/key-validation.d.ts +7 -0
- package/dist/entity/validation/key-validation.d.ts.map +1 -0
- package/dist/entity/validation/key-validation.js +25 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/table.d.ts +8 -1
- package/dist/table.d.ts.map +1 -1
- package/dist/table.js +1 -0
- package/dist/utils/model-utils.d.ts +7 -1
- package/dist/utils/model-utils.d.ts.map +1 -1
- package/dist/utils/model-utils.js +32 -3
- package/dist/utils/zod-utils.d.ts +3 -2
- package/dist/utils/zod-utils.d.ts.map +1 -1
- package/dist/utils/zod-utils.js +33 -11
- package/package.json +3 -2
- package/src/builders/README.md +68 -1
- package/src/builders/delete/types.ts +7 -1
- package/src/builders/get/types.ts +7 -1
- package/src/builders/put/types.ts +7 -1
- package/src/builders/query/create-query-builder.ts +4 -6
- package/src/builders/query/types.ts +9 -12
- package/src/builders/transact-write/README.md +37 -1
- package/src/builders/transact-write/create-transact-write-builder.ts +20 -14
- package/src/builders/transact-write/types.ts +44 -6
- package/src/builders/update/create-update-builder.test.ts +43 -0
- package/src/builders/update/create-update-builder.ts +47 -9
- package/src/builders/update/types.ts +9 -2
- package/src/core/types.test.ts +137 -0
- package/src/core/types.ts +97 -20
- package/src/entity/create-entity-api.ts +212 -0
- package/src/entity/index.ts +19 -0
- package/src/entity/middleware/factories.ts +15 -0
- package/src/entity/middleware/types.ts +7 -0
- package/src/entity/middleware/with-middleware.ts +37 -0
- package/src/entity/types.ts +79 -0
- package/src/entity/validation/key-validation.ts +34 -0
- package/src/index.ts +1 -0
- package/src/table.ts +10 -3
- package/src/utils/model-utils.test.ts +131 -1
- package/src/utils/model-utils.ts +35 -2
- package/src/utils/zod-utils.test.ts +97 -2
- package/src/utils/zod-utils.ts +31 -12
- package/dist/entity.d.ts.map +0 -1
- package/dist/entity.js +0 -161
- package/src/entity.ts +0 -337
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { applyPostDefaults } from './model-utils';
|
|
2
|
+
import { applyPostDefaults, stripInternalKeys } from './model-utils';
|
|
3
3
|
import { ModelDefinition } from '../core/types';
|
|
4
4
|
|
|
5
5
|
describe('applyPostDefaults - Timestamps', () => {
|
|
@@ -230,3 +230,133 @@ describe('applyPostDefaults - Timestamps', () => {
|
|
|
230
230
|
});
|
|
231
231
|
});
|
|
232
232
|
});
|
|
233
|
+
|
|
234
|
+
describe('stripInternalKeys', () => {
|
|
235
|
+
test('should remove PK, SK, and _type from object', () => {
|
|
236
|
+
const input = {
|
|
237
|
+
PK: 'USER#alice',
|
|
238
|
+
SK: 'USER#alice',
|
|
239
|
+
_type: 'User',
|
|
240
|
+
username: 'alice',
|
|
241
|
+
name: 'Alice',
|
|
242
|
+
email: 'alice@example.com',
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
const result = stripInternalKeys(input);
|
|
246
|
+
|
|
247
|
+
expect(result).toEqual({
|
|
248
|
+
username: 'alice',
|
|
249
|
+
name: 'Alice',
|
|
250
|
+
email: 'alice@example.com',
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test('should handle object without internal keys', () => {
|
|
255
|
+
const input = {
|
|
256
|
+
username: 'alice',
|
|
257
|
+
name: 'Alice',
|
|
258
|
+
email: 'alice@example.com',
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const result = stripInternalKeys(input);
|
|
262
|
+
|
|
263
|
+
expect(result).toEqual(input);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test('should handle array of objects', () => {
|
|
267
|
+
const input = [
|
|
268
|
+
{
|
|
269
|
+
PK: 'USER#alice',
|
|
270
|
+
SK: 'USER#alice',
|
|
271
|
+
_type: 'User',
|
|
272
|
+
username: 'alice',
|
|
273
|
+
name: 'Alice',
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
PK: 'USER#bob',
|
|
277
|
+
SK: 'USER#bob',
|
|
278
|
+
_type: 'User',
|
|
279
|
+
username: 'bob',
|
|
280
|
+
name: 'Bob',
|
|
281
|
+
},
|
|
282
|
+
];
|
|
283
|
+
|
|
284
|
+
const result = stripInternalKeys(input);
|
|
285
|
+
|
|
286
|
+
expect(result).toEqual([
|
|
287
|
+
{ username: 'alice', name: 'Alice' },
|
|
288
|
+
{ username: 'bob', name: 'Bob' },
|
|
289
|
+
]);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test('should handle undefined', () => {
|
|
293
|
+
const result = stripInternalKeys(undefined);
|
|
294
|
+
expect(result).toBeUndefined();
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test('should handle null', () => {
|
|
298
|
+
const result = stripInternalKeys(null);
|
|
299
|
+
expect(result).toBeNull();
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
test('should handle empty object', () => {
|
|
303
|
+
const input = {};
|
|
304
|
+
const result = stripInternalKeys(input);
|
|
305
|
+
expect(result).toEqual({});
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test('should handle empty array', () => {
|
|
309
|
+
const input: any[] = [];
|
|
310
|
+
const result = stripInternalKeys(input);
|
|
311
|
+
expect(result).toEqual([]);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
test('should preserve other fields with similar names', () => {
|
|
315
|
+
const input = {
|
|
316
|
+
PK: 'USER#alice',
|
|
317
|
+
SK: 'USER#alice',
|
|
318
|
+
_type: 'User',
|
|
319
|
+
PKG: 'package-name',
|
|
320
|
+
SKIP: 'skip-value',
|
|
321
|
+
type: 'customer',
|
|
322
|
+
username: 'alice',
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const result = stripInternalKeys(input);
|
|
326
|
+
|
|
327
|
+
expect(result).toEqual({
|
|
328
|
+
PKG: 'package-name',
|
|
329
|
+
SKIP: 'skip-value',
|
|
330
|
+
type: 'customer',
|
|
331
|
+
username: 'alice',
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
test('should handle nested objects (does not recurse)', () => {
|
|
336
|
+
const input = {
|
|
337
|
+
PK: 'USER#alice',
|
|
338
|
+
SK: 'USER#alice',
|
|
339
|
+
_type: 'User',
|
|
340
|
+
username: 'alice',
|
|
341
|
+
metadata: {
|
|
342
|
+
PK: 'METADATA#1',
|
|
343
|
+
SK: 'METADATA#1',
|
|
344
|
+
_type: 'Metadata',
|
|
345
|
+
value: 'test',
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
const result = stripInternalKeys(input);
|
|
350
|
+
|
|
351
|
+
// stripInternalKeys does not recurse into nested objects
|
|
352
|
+
expect(result).toEqual({
|
|
353
|
+
username: 'alice',
|
|
354
|
+
metadata: {
|
|
355
|
+
PK: 'METADATA#1',
|
|
356
|
+
SK: 'METADATA#1',
|
|
357
|
+
_type: 'Metadata',
|
|
358
|
+
value: 'test',
|
|
359
|
+
},
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
});
|
package/src/utils/model-utils.ts
CHANGED
|
@@ -71,9 +71,10 @@ export const applyPostDefaults = <M extends ModelDefinition>(
|
|
|
71
71
|
|
|
72
72
|
for (const [key, attr] of Object.entries(model.attributes)) {
|
|
73
73
|
if (result[key] === undefined) {
|
|
74
|
-
|
|
74
|
+
const generate = 'generate' in attr ? attr.generate : undefined;
|
|
75
|
+
if (generate === 'ulid') {
|
|
75
76
|
result[key] = ulid();
|
|
76
|
-
} else if (
|
|
77
|
+
} else if (generate === 'uuid') {
|
|
77
78
|
result[key] = crypto.randomUUID();
|
|
78
79
|
} else if (attr.default !== undefined) {
|
|
79
80
|
result[key] = typeof attr.default === 'function' ? attr.default() : attr.default;
|
|
@@ -99,3 +100,35 @@ export const applyPostDefaults = <M extends ModelDefinition>(
|
|
|
99
100
|
|
|
100
101
|
return result as InferModel<M>;
|
|
101
102
|
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Internal DynamoDB keys that should be stripped when cleanInternalKeys is enabled
|
|
106
|
+
*/
|
|
107
|
+
const INTERNAL_KEYS = ['PK', 'SK', '_type'] as const;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Removes internal DynamoDB keys from an item or array of items
|
|
111
|
+
* @param data - Single item or array of items from DynamoDB
|
|
112
|
+
* @returns Data with internal keys removed
|
|
113
|
+
*/
|
|
114
|
+
export const stripInternalKeys = <T>(data: T | T[] | undefined): T | T[] | undefined => {
|
|
115
|
+
if (data === undefined || data === null) {
|
|
116
|
+
return data;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (Array.isArray(data)) {
|
|
120
|
+
return data.map((item) => stripInternalKeys(item)) as T[];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (typeof data === 'object') {
|
|
124
|
+
const cleaned: any = {};
|
|
125
|
+
for (const [key, value] of Object.entries(data)) {
|
|
126
|
+
if (!INTERNAL_KEYS.includes(key as any)) {
|
|
127
|
+
cleaned[key] = value;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return cleaned as T;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return data;
|
|
134
|
+
};
|
|
@@ -71,9 +71,9 @@ describe('zod-utils', () => {
|
|
|
71
71
|
expect(() => zodType.parse(undefined)).toThrow();
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
-
it('should return z.unknown() for
|
|
74
|
+
it('should return z.unknown() for unrecognized types', () => {
|
|
75
75
|
const attr: AttributeDefinition = {
|
|
76
|
-
type:
|
|
76
|
+
type: Map as any,
|
|
77
77
|
required: true,
|
|
78
78
|
};
|
|
79
79
|
const zodType = typeToZod(attr);
|
|
@@ -83,6 +83,101 @@ describe('zod-utils', () => {
|
|
|
83
83
|
expect(() => zodType.parse(123)).not.toThrow();
|
|
84
84
|
expect(() => zodType.parse([])).not.toThrow();
|
|
85
85
|
});
|
|
86
|
+
|
|
87
|
+
it('should convert Object type with schema to z.looseObject()', () => {
|
|
88
|
+
const attr: AttributeDefinition = {
|
|
89
|
+
type: Object,
|
|
90
|
+
schema: {
|
|
91
|
+
city: { type: String, required: true },
|
|
92
|
+
zip: { type: String },
|
|
93
|
+
},
|
|
94
|
+
required: true,
|
|
95
|
+
};
|
|
96
|
+
const zodType = typeToZod(attr);
|
|
97
|
+
|
|
98
|
+
expect(() => zodType.parse({ city: 'BA' })).not.toThrow();
|
|
99
|
+
expect(() => zodType.parse({ city: 'BA', zip: '1000' })).not.toThrow();
|
|
100
|
+
expect(() => zodType.parse({ zip: '1000' })).toThrow(); // city required
|
|
101
|
+
expect(() => zodType.parse({})).toThrow();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should convert Object type without schema to z.record()', () => {
|
|
105
|
+
const attr: AttributeDefinition = {
|
|
106
|
+
type: Object,
|
|
107
|
+
schema: {},
|
|
108
|
+
};
|
|
109
|
+
const zodType = typeToZod(attr);
|
|
110
|
+
expect(() => zodType.parse({})).not.toThrow();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should convert Array type with scalar items', () => {
|
|
114
|
+
const attr: AttributeDefinition = {
|
|
115
|
+
type: Array,
|
|
116
|
+
items: { type: String },
|
|
117
|
+
required: true,
|
|
118
|
+
};
|
|
119
|
+
const zodType = typeToZod(attr);
|
|
120
|
+
|
|
121
|
+
expect(() => zodType.parse(['a', 'b'])).not.toThrow();
|
|
122
|
+
expect(() => zodType.parse([])).not.toThrow();
|
|
123
|
+
expect(() => zodType.parse([1, 2])).toThrow(); // numbers, not strings
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('should convert Array type with object items (like history)', () => {
|
|
127
|
+
const attr: AttributeDefinition = {
|
|
128
|
+
type: Array,
|
|
129
|
+
items: {
|
|
130
|
+
type: Object,
|
|
131
|
+
schema: {
|
|
132
|
+
date: { type: String },
|
|
133
|
+
status: { type: String, required: true },
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
required: true,
|
|
137
|
+
};
|
|
138
|
+
const zodType = typeToZod(attr);
|
|
139
|
+
|
|
140
|
+
expect(() => zodType.parse([{ status: 'PENDING' }])).not.toThrow();
|
|
141
|
+
expect(() =>
|
|
142
|
+
zodType.parse([{ date: '2024-01-01', status: 'DONE' }])
|
|
143
|
+
).not.toThrow();
|
|
144
|
+
expect(() => zodType.parse([{ date: '2024-01-01' }])).toThrow(); // missing status
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should handle optional Object attribute', () => {
|
|
148
|
+
const attr: AttributeDefinition = {
|
|
149
|
+
type: Object,
|
|
150
|
+
schema: { name: { type: String, required: true } },
|
|
151
|
+
};
|
|
152
|
+
const zodType = typeToZod(attr);
|
|
153
|
+
|
|
154
|
+
expect(() => zodType.parse(undefined)).not.toThrow();
|
|
155
|
+
expect(() => zodType.parse({ name: 'test' })).not.toThrow();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should handle deeply nested objects', () => {
|
|
159
|
+
const attr: AttributeDefinition = {
|
|
160
|
+
type: Object,
|
|
161
|
+
required: true,
|
|
162
|
+
schema: {
|
|
163
|
+
value: { type: Number, required: true },
|
|
164
|
+
breakdown: {
|
|
165
|
+
type: Object,
|
|
166
|
+
schema: {
|
|
167
|
+
base: { type: Number, required: true },
|
|
168
|
+
fees: { type: Number, required: true },
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
const zodType = typeToZod(attr);
|
|
174
|
+
|
|
175
|
+
expect(() =>
|
|
176
|
+
zodType.parse({ value: 100, breakdown: { base: 90, fees: 10 } })
|
|
177
|
+
).not.toThrow();
|
|
178
|
+
expect(() => zodType.parse({ value: 100 })).not.toThrow(); // breakdown optional
|
|
179
|
+
expect(() => zodType.parse({})).toThrow(); // value required
|
|
180
|
+
});
|
|
86
181
|
});
|
|
87
182
|
|
|
88
183
|
describe('modelToZod', () => {
|
package/src/utils/zod-utils.ts
CHANGED
|
@@ -5,19 +5,38 @@ import { AttributeDefinition, ModelDefinition } from '@/core/types';
|
|
|
5
5
|
import { z, ZodObject, ZodType } from 'zod';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Converts an attribute definition to a Zod schema type
|
|
8
|
+
* Converts an attribute definition to a Zod schema type.
|
|
9
|
+
* Supports scalars, nested objects (with schema), and arrays (with items).
|
|
9
10
|
*/
|
|
10
11
|
export const typeToZod = (attr: AttributeDefinition): ZodType => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
12
|
+
let zodType: ZodType;
|
|
13
|
+
|
|
14
|
+
if (attr.type === Object) {
|
|
15
|
+
const schema = (attr as { schema?: Record<string, AttributeDefinition> }).schema;
|
|
16
|
+
if (schema) {
|
|
17
|
+
const shape: Record<string, ZodType> = {};
|
|
18
|
+
for (const [key, nestedAttr] of Object.entries(schema)) {
|
|
19
|
+
shape[key] = typeToZod(nestedAttr);
|
|
20
|
+
}
|
|
21
|
+
zodType = z.looseObject(shape);
|
|
22
|
+
} else {
|
|
23
|
+
zodType = z.record(z.string(), z.unknown());
|
|
24
|
+
}
|
|
25
|
+
} else if (attr.type === Array) {
|
|
26
|
+
const items = (attr as { items?: AttributeDefinition }).items;
|
|
27
|
+
zodType = items ? z.array(typeToZod(items)) : z.array(z.unknown());
|
|
28
|
+
} else {
|
|
29
|
+
zodType =
|
|
30
|
+
attr.type === String
|
|
31
|
+
? z.string()
|
|
32
|
+
: attr.type === Number
|
|
33
|
+
? z.number()
|
|
34
|
+
: attr.type === Boolean
|
|
35
|
+
? z.boolean()
|
|
36
|
+
: attr.type === Date
|
|
37
|
+
? z.date()
|
|
38
|
+
: z.unknown();
|
|
39
|
+
}
|
|
21
40
|
|
|
22
41
|
return attr.required ? zodType : zodType.optional();
|
|
23
42
|
};
|
|
@@ -32,5 +51,5 @@ export const modelToZod = (model: ModelDefinition): ZodObject<any> => {
|
|
|
32
51
|
for (const [key, attr] of Object.entries(model.attributes)) {
|
|
33
52
|
shape[key] = typeToZod(attr);
|
|
34
53
|
}
|
|
35
|
-
return z.
|
|
54
|
+
return z.looseObject(shape);
|
|
36
55
|
};
|
package/dist/entity.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../src/entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGtF,OAAO,EASL,UAAU,EACV,UAAU,EACV,YAAY,EACZ,aAAa,EACb,aAAa,EACb,WAAW,EACX,eAAe,EACf,iBAAiB,EAElB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,SAAS,eAAe,GAAG,GAAG,IAAI;IACtF;;;;OAIG;IACH,GAAG,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAEpD;;;;OAIG;IACH,GAAG,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,UAAU,CAAC,KAAK,CAAC,CAAC;IAExC;;;OAGG;IACH,KAAK,EAAE,MAAM,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAE3C;;;OAGG;IACH,IAAI,EAAE,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;IAE/B;;;;OAIG;IACH,MAAM,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,aAAa,CAAC,KAAK,CAAC,CAAC;IAEhD;;;;OAIG;IACH,MAAM,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,aAAa,CAAC,KAAK,CAAC,CAAC;IAEhD;;;;OAIG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,eAAe,CAAC,KAAK,CAAC,CAAC;IAEvD;;;;OAIG;IACH,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,iBAAiB,CAAC;CACnD,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,GAAI,KAAK,SAAS,eAAe,EAC3D,WAAW,MAAM,EACjB,WAAW,MAAM,EACjB,OAAO,KAAK,EACZ,QAAQ,cAAc,EACtB,UAAS,gBAAqB,KAC7B,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,KAAK,CAqO7E,CAAC"}
|
package/dist/entity.js
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createEntityAPI = void 0;
|
|
4
|
-
const model_utils_1 = require("./utils/model-utils");
|
|
5
|
-
const zod_utils_1 = require("./utils/zod-utils");
|
|
6
|
-
const builders_1 = require("./builders");
|
|
7
|
-
/**
|
|
8
|
-
* Creates an entity API instance with validation, key resolution, and builder creation.
|
|
9
|
-
*
|
|
10
|
-
* @param modelName - The name of the model/entity
|
|
11
|
-
* @param model - The model definition
|
|
12
|
-
* @param client - DynamoDB client instance
|
|
13
|
-
* @param options - Optional configuration (logger, timestamps)
|
|
14
|
-
* @returns EntityAPI with get and put methods
|
|
15
|
-
*/
|
|
16
|
-
const createEntityAPI = (tableName, modelName, model, client, options = {}) => {
|
|
17
|
-
const { logger, timestamps = false } = options;
|
|
18
|
-
// Build a Zod schema from the model
|
|
19
|
-
const zodSchema = (0, zod_utils_1.modelToZod)(model);
|
|
20
|
-
return {
|
|
21
|
-
get(key) {
|
|
22
|
-
// Extract required fields from key templates
|
|
23
|
-
const requiredFields = new Set();
|
|
24
|
-
if (model.key) {
|
|
25
|
-
for (const keyDef of Object.values(model.key)) {
|
|
26
|
-
(0, model_utils_1.extractTemplateVars)(keyDef.value).forEach((field) => requiredFields.add(field));
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
// Check if all required fields are present
|
|
30
|
-
const keyRecord = key;
|
|
31
|
-
const missingFields = Array.from(requiredFields).filter((field) => keyRecord[field] === undefined);
|
|
32
|
-
if (missingFields.length > 0) {
|
|
33
|
-
throw new Error(`[${modelName}] Missing required key field(s) for get(): ${missingFields.join(', ')}. ` +
|
|
34
|
-
`Required fields: ${Array.from(requiredFields).join(', ')}`);
|
|
35
|
-
}
|
|
36
|
-
// Resolve any key defaults or computed keys
|
|
37
|
-
const fullKey = (0, model_utils_1.resolveKeys)(model, key);
|
|
38
|
-
return (0, builders_1.createGetBuilder)(tableName, fullKey, client, undefined, logger);
|
|
39
|
-
},
|
|
40
|
-
put(item) {
|
|
41
|
-
// Validate full input data
|
|
42
|
-
const parsed = zodSchema.parse(item);
|
|
43
|
-
// Apply post-processing defaults from the model (including timestamps for new items)
|
|
44
|
-
const withDefaults = (0, model_utils_1.applyPostDefaults)(model, parsed, {
|
|
45
|
-
isUpdate: false,
|
|
46
|
-
timestamps,
|
|
47
|
-
});
|
|
48
|
-
// Resolve keys again with defaults
|
|
49
|
-
const fullKey = (0, model_utils_1.resolveKeys)(model, withDefaults);
|
|
50
|
-
// Combine keys and data into full item, adding _type field
|
|
51
|
-
const fullItem = {
|
|
52
|
-
...withDefaults,
|
|
53
|
-
...fullKey,
|
|
54
|
-
_type: modelName, // Add entity type identifier
|
|
55
|
-
};
|
|
56
|
-
return (0, builders_1.createPutBuilder)(tableName, fullItem, client, [], false, 'NONE', false, logger);
|
|
57
|
-
},
|
|
58
|
-
query() {
|
|
59
|
-
return (0, builders_1.createQueryBuilder)(tableName, client, model, logger);
|
|
60
|
-
},
|
|
61
|
-
scan() {
|
|
62
|
-
return (0, builders_1.createScanBuilder)(tableName, client, [], [], undefined, false, undefined, undefined, undefined, logger);
|
|
63
|
-
},
|
|
64
|
-
update(key) {
|
|
65
|
-
// Extract required fields from key templates
|
|
66
|
-
const requiredFields = new Set();
|
|
67
|
-
if (model.key) {
|
|
68
|
-
for (const keyDef of Object.values(model.key)) {
|
|
69
|
-
(0, model_utils_1.extractTemplateVars)(keyDef.value).forEach((field) => requiredFields.add(field));
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
// Check if all required fields are present
|
|
73
|
-
const keyRecord = key;
|
|
74
|
-
const missingFields = Array.from(requiredFields).filter((field) => keyRecord[field] === undefined);
|
|
75
|
-
if (missingFields.length > 0) {
|
|
76
|
-
throw new Error(`[${modelName}] Missing required key field(s) for update(): ${missingFields.join(', ')}. ` +
|
|
77
|
-
`Required fields: ${Array.from(requiredFields).join(', ')}`);
|
|
78
|
-
}
|
|
79
|
-
// Resolve any key defaults or computed keys
|
|
80
|
-
const fullKey = (0, model_utils_1.resolveKeys)(model, key);
|
|
81
|
-
return (0, builders_1.createUpdateBuilder)(tableName, fullKey, client, [], { set: [], remove: [], add: [], delete: [] }, 'NONE', 0, timestamps, logger);
|
|
82
|
-
},
|
|
83
|
-
delete(key) {
|
|
84
|
-
// Extract required fields from key templates
|
|
85
|
-
const requiredFields = new Set();
|
|
86
|
-
if (model.key) {
|
|
87
|
-
for (const keyDef of Object.values(model.key)) {
|
|
88
|
-
(0, model_utils_1.extractTemplateVars)(keyDef.value).forEach((field) => requiredFields.add(field));
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
// Check if all required fields are present
|
|
92
|
-
const keyRecord = key;
|
|
93
|
-
const missingFields = Array.from(requiredFields).filter((field) => keyRecord[field] === undefined);
|
|
94
|
-
if (missingFields.length > 0) {
|
|
95
|
-
throw new Error(`[${modelName}] Missing required key field(s) for delete(): ${missingFields.join(', ')}. ` +
|
|
96
|
-
`Required fields: ${Array.from(requiredFields).join(', ')}`);
|
|
97
|
-
}
|
|
98
|
-
// Resolve any key defaults or computed keys
|
|
99
|
-
const fullKey = (0, model_utils_1.resolveKeys)(model, key);
|
|
100
|
-
return (0, builders_1.createDeleteBuilder)(tableName, fullKey, client, [], 'NONE', logger);
|
|
101
|
-
},
|
|
102
|
-
batchGet(keys) {
|
|
103
|
-
// Extract required fields from key templates
|
|
104
|
-
const requiredFields = new Set();
|
|
105
|
-
if (model.key) {
|
|
106
|
-
for (const keyDef of Object.values(model.key)) {
|
|
107
|
-
(0, model_utils_1.extractTemplateVars)(keyDef.value).forEach((field) => requiredFields.add(field));
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
// Process all keys and validate them
|
|
111
|
-
const resolvedKeys = keys.map((key) => {
|
|
112
|
-
// Check if all required fields are present
|
|
113
|
-
const keyRecord = key;
|
|
114
|
-
const missingFields = Array.from(requiredFields).filter((field) => keyRecord[field] === undefined);
|
|
115
|
-
if (missingFields.length > 0) {
|
|
116
|
-
throw new Error(`[${modelName}] Missing required key field(s) for batchGet(): ${missingFields.join(', ')}. ` +
|
|
117
|
-
`Required fields: ${Array.from(requiredFields).join(', ')}`);
|
|
118
|
-
}
|
|
119
|
-
// Resolve any key defaults or computed keys
|
|
120
|
-
return (0, model_utils_1.resolveKeys)(model, key);
|
|
121
|
-
});
|
|
122
|
-
// Create the request items in the format expected by BatchGetItem
|
|
123
|
-
const requestItems = {
|
|
124
|
-
[tableName]: {
|
|
125
|
-
Keys: resolvedKeys,
|
|
126
|
-
},
|
|
127
|
-
};
|
|
128
|
-
return (0, builders_1.createBatchGetBuilder)(requestItems, client, undefined, logger);
|
|
129
|
-
},
|
|
130
|
-
batchWrite(items) {
|
|
131
|
-
// Validate and process all items
|
|
132
|
-
const processedItems = items.map((item) => {
|
|
133
|
-
// Validate full input data
|
|
134
|
-
const parsed = zodSchema.parse(item);
|
|
135
|
-
// Apply post-processing defaults from the model (including timestamps for new items)
|
|
136
|
-
const withDefaults = (0, model_utils_1.applyPostDefaults)(model, parsed, {
|
|
137
|
-
isUpdate: false,
|
|
138
|
-
timestamps,
|
|
139
|
-
});
|
|
140
|
-
// Resolve keys again with defaults
|
|
141
|
-
const fullKey = (0, model_utils_1.resolveKeys)(model, withDefaults);
|
|
142
|
-
// Combine keys and data into full item, adding _type field
|
|
143
|
-
return {
|
|
144
|
-
...withDefaults,
|
|
145
|
-
...fullKey,
|
|
146
|
-
_type: modelName, // Add entity type identifier
|
|
147
|
-
};
|
|
148
|
-
});
|
|
149
|
-
// Create the request items in the format expected by BatchWriteItem
|
|
150
|
-
const requestItems = {
|
|
151
|
-
[tableName]: processedItems.map((item) => ({
|
|
152
|
-
PutRequest: {
|
|
153
|
-
Item: item,
|
|
154
|
-
},
|
|
155
|
-
})),
|
|
156
|
-
};
|
|
157
|
-
return (0, builders_1.createBatchWriteBuilder)(requestItems, client, logger);
|
|
158
|
-
},
|
|
159
|
-
};
|
|
160
|
-
};
|
|
161
|
-
exports.createEntityAPI = createEntityAPI;
|