@ftschopp/dynatable-core 1.4.2 → 1.4.3
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 +7 -0
- package/dist/builders/query/create-query-builder.d.ts.map +1 -1
- package/dist/builders/query/create-query-builder.js +19 -2
- package/dist/core/types.d.ts +5 -0
- package/dist/core/types.d.ts.map +1 -1
- package/package.json +11 -2
- package/eslint.config.mjs +0 -4
- package/jest.config.js +0 -11
- package/src/builders/README.md +0 -339
- package/src/builders/batch-get/README.md +0 -43
- package/src/builders/batch-get/create-batch-get-builder.test.ts +0 -193
- package/src/builders/batch-get/create-batch-get-builder.ts +0 -108
- package/src/builders/batch-get/index.ts +0 -2
- package/src/builders/batch-get/types.ts +0 -28
- package/src/builders/batch-write/README.md +0 -204
- package/src/builders/batch-write/create-batch-write-builder.test.ts +0 -173
- package/src/builders/batch-write/create-batch-write-builder.ts +0 -49
- package/src/builders/batch-write/index.ts +0 -2
- package/src/builders/batch-write/types.ts +0 -33
- package/src/builders/delete/create-delete-builder.test.ts +0 -294
- package/src/builders/delete/create-delete-builder.ts +0 -100
- package/src/builders/delete/index.ts +0 -2
- package/src/builders/delete/types.ts +0 -17
- package/src/builders/get/create-get-builder.test.ts +0 -272
- package/src/builders/get/create-get-builder.ts +0 -117
- package/src/builders/get/index.ts +0 -2
- package/src/builders/get/types.ts +0 -39
- package/src/builders/index.ts +0 -14
- package/src/builders/put/create-put-builder.test.ts +0 -213
- package/src/builders/put/create-put-builder.ts +0 -160
- package/src/builders/put/index.ts +0 -2
- package/src/builders/put/types.ts +0 -24
- package/src/builders/query/create-query-builder.test.ts +0 -770
- package/src/builders/query/create-query-builder.ts +0 -455
- package/src/builders/query/index.ts +0 -2
- package/src/builders/query/types.ts +0 -109
- package/src/builders/scan/create-scan-builder.test.ts +0 -416
- package/src/builders/scan/create-scan-builder.ts +0 -265
- package/src/builders/scan/index.ts +0 -2
- package/src/builders/scan/types.ts +0 -88
- package/src/builders/shared/conditions.ts +0 -58
- package/src/builders/shared/index.ts +0 -4
- package/src/builders/shared/operators.test.ts +0 -270
- package/src/builders/shared/operators.ts +0 -208
- package/src/builders/shared/projection.ts +0 -28
- package/src/builders/shared/types.ts +0 -101
- package/src/builders/transact-get/README.md +0 -167
- package/src/builders/transact-get/create-transact-get-builder.test.ts +0 -239
- package/src/builders/transact-get/create-transact-get-builder.ts +0 -67
- package/src/builders/transact-get/index.ts +0 -2
- package/src/builders/transact-get/types.ts +0 -31
- package/src/builders/transact-write/README.md +0 -202
- package/src/builders/transact-write/create-transact-write-builder.test.ts +0 -288
- package/src/builders/transact-write/create-transact-write-builder.ts +0 -124
- package/src/builders/transact-write/index.ts +0 -2
- package/src/builders/transact-write/types.ts +0 -71
- package/src/builders/update/create-update-builder.test.ts +0 -573
- package/src/builders/update/create-update-builder.ts +0 -375
- package/src/builders/update/index.ts +0 -2
- package/src/builders/update/types.ts +0 -63
- package/src/core/types.test.ts +0 -641
- package/src/core/types.ts +0 -366
- package/src/entity/create-entity-api.ts +0 -224
- package/src/entity/index.ts +0 -19
- package/src/entity/middleware/factories.ts +0 -15
- package/src/entity/middleware/types.ts +0 -7
- package/src/entity/middleware/with-middleware.ts +0 -37
- package/src/entity/types.ts +0 -79
- package/src/entity/validation/key-validation.ts +0 -34
- package/src/index.ts +0 -23
- package/src/table.ts +0 -116
- package/src/utils/dynamodb-logger.test.ts +0 -246
- package/src/utils/dynamodb-logger.ts +0 -175
- package/src/utils/model-utils.test.ts +0 -452
- package/src/utils/model-utils.ts +0 -188
- package/src/utils/zod-utils.test.ts +0 -363
- package/src/utils/zod-utils.ts +0 -56
- package/tests/integration/instagram-clone.integration.test.ts +0 -1019
- package/tests/integration/pagination-timestamps.integration.test.ts +0 -374
- package/tests/integration/transactions.integration.test.ts +0 -528
- package/tsconfig.json +0 -12
package/src/core/types.ts
DELETED
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Type definitions for DynamoDB schema and model inference
|
|
5
|
-
*
|
|
6
|
-
* Provides comprehensive type utilities for:
|
|
7
|
-
* - Defining DynamoDB table schemas with primary and secondary indexes
|
|
8
|
-
* - Inferring strongly-typed input and output models from schema definitions
|
|
9
|
-
* - Automatic key generation and template variable extraction
|
|
10
|
-
* - Type-safe attribute handling with support for defaults and auto-generation
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```typescript
|
|
14
|
-
* const schema: SchemaDefinition = {
|
|
15
|
-
* format: 'dynatable:1.0.0',
|
|
16
|
-
* version: '1.0.0',
|
|
17
|
-
* indexes: { primary: { hash: "PK", sort: "SK" } },
|
|
18
|
-
* models: {
|
|
19
|
-
* User: {
|
|
20
|
-
* key: { PK: { type: String, value: "USER#${id}" }, SK: { type: String, value: "PROFILE" } },
|
|
21
|
-
* attributes: { id: { type: String, required: true }, name: { type: String } }
|
|
22
|
-
* }
|
|
23
|
-
* }
|
|
24
|
-
* };
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
// -------------------- Type Definitions --------------------
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Scalar attribute definition (String, Number, Boolean, Date)
|
|
32
|
-
*/
|
|
33
|
-
export type ScalarAttributeDefinition = {
|
|
34
|
-
type: StringConstructor | NumberConstructor | BooleanConstructor | DateConstructor;
|
|
35
|
-
required?: boolean;
|
|
36
|
-
generate?: 'ulid' | 'uuid';
|
|
37
|
-
default?: any;
|
|
38
|
-
nulls?: boolean;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Object attribute definition with a nested schema
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* address: {
|
|
46
|
-
* type: Object,
|
|
47
|
-
* schema: {
|
|
48
|
-
* street: { type: String },
|
|
49
|
-
* city: { type: String, required: true },
|
|
50
|
-
* }
|
|
51
|
-
* }
|
|
52
|
-
*/
|
|
53
|
-
export type ObjectAttributeDefinition = {
|
|
54
|
-
type: ObjectConstructor;
|
|
55
|
-
schema: Record<string, AttributeDefinition>;
|
|
56
|
-
required?: boolean;
|
|
57
|
-
default?: any;
|
|
58
|
-
nulls?: boolean;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Array attribute definition with a typed items schema
|
|
63
|
-
*
|
|
64
|
-
* @example
|
|
65
|
-
* history: {
|
|
66
|
-
* type: Array,
|
|
67
|
-
* default: [],
|
|
68
|
-
* items: {
|
|
69
|
-
* type: Object,
|
|
70
|
-
* schema: {
|
|
71
|
-
* date: { type: String },
|
|
72
|
-
* status: { type: String },
|
|
73
|
-
* }
|
|
74
|
-
* }
|
|
75
|
-
* }
|
|
76
|
-
*/
|
|
77
|
-
export type ArrayAttributeDefinition = {
|
|
78
|
-
type: ArrayConstructor;
|
|
79
|
-
items: AttributeDefinition;
|
|
80
|
-
required?: boolean;
|
|
81
|
-
default?: any;
|
|
82
|
-
nulls?: boolean;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Attribute definition for model attributes — supports scalars, nested objects, and arrays
|
|
87
|
-
*/
|
|
88
|
-
export type AttributeDefinition =
|
|
89
|
-
| ScalarAttributeDefinition
|
|
90
|
-
| ObjectAttributeDefinition
|
|
91
|
-
| ArrayAttributeDefinition;
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Key definition for primary and secondary indexes
|
|
95
|
-
*
|
|
96
|
-
* @property type - Always String for DynamoDB keys
|
|
97
|
-
* @property value - Template string for key generation
|
|
98
|
-
*/
|
|
99
|
-
export type KeyDefinition = {
|
|
100
|
-
type: StringConstructor;
|
|
101
|
-
value: string;
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Primary key definition - requires both PK and SK (uppercase)
|
|
106
|
-
*/
|
|
107
|
-
export type PrimaryKeyDefinition = {
|
|
108
|
-
PK: KeyDefinition;
|
|
109
|
-
SK: KeyDefinition;
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Index definition with hash and optional sort key
|
|
114
|
-
*/
|
|
115
|
-
export type IndexDefinition = {
|
|
116
|
-
hash: string;
|
|
117
|
-
sort?: string;
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Indexes configuration - requires at least a primary index
|
|
122
|
-
*/
|
|
123
|
-
export type IndexesDefinition = {
|
|
124
|
-
primary: IndexDefinition;
|
|
125
|
-
[indexName: string]: IndexDefinition;
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Model definition containing keys, indexes, and attributes
|
|
130
|
-
* - key: REQUIRED, must have pk and sk
|
|
131
|
-
* - attributes: REQUIRED, model attributes
|
|
132
|
-
* - index: OPTIONAL, secondary index keys
|
|
133
|
-
*/
|
|
134
|
-
export type ModelDefinition = {
|
|
135
|
-
key: PrimaryKeyDefinition;
|
|
136
|
-
index?: Record<string, KeyDefinition>;
|
|
137
|
-
attributes: Record<string, AttributeDefinition>;
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Schema parameters configuration
|
|
142
|
-
*/
|
|
143
|
-
export type SchemaParams = {
|
|
144
|
-
timestamps?: boolean;
|
|
145
|
-
cleanInternalKeys?: boolean;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Complete schema definition for a DynamoDB table
|
|
150
|
-
* - format: Table schema format version (e.g., "dynatable:1.0.0")
|
|
151
|
-
* - version: Schema version (e.g., "1.0.0")
|
|
152
|
-
* - indexes: Index definitions (requires at least 'primary')
|
|
153
|
-
* - models: Model definitions (each requires 'key' and 'attributes')
|
|
154
|
-
* - params: Optional schema parameters
|
|
155
|
-
*/
|
|
156
|
-
export type SchemaDefinition = {
|
|
157
|
-
format: string;
|
|
158
|
-
version: string;
|
|
159
|
-
indexes: IndexesDefinition;
|
|
160
|
-
models: Record<string, ModelDefinition>;
|
|
161
|
-
params?: SchemaParams;
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Recursively infers the TypeScript type from an AttributeDefinition.
|
|
166
|
-
* - Object → infers the nested schema shape
|
|
167
|
-
* - Array → infers an array of the items type
|
|
168
|
-
* - Scalars → maps to the corresponding primitive
|
|
169
|
-
*/
|
|
170
|
-
type InferAttr<A> = A extends { type: ObjectConstructor; schema: infer S }
|
|
171
|
-
? InferObjectSchema<S>
|
|
172
|
-
: A extends { type: ArrayConstructor; items: infer I }
|
|
173
|
-
? Array<InferAttr<I>>
|
|
174
|
-
: A extends { type: StringConstructor }
|
|
175
|
-
? string
|
|
176
|
-
: A extends { type: NumberConstructor }
|
|
177
|
-
? number
|
|
178
|
-
: A extends { type: BooleanConstructor }
|
|
179
|
-
? boolean
|
|
180
|
-
: A extends { type: DateConstructor }
|
|
181
|
-
? Date
|
|
182
|
-
: unknown;
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Infers the shape of a nested object schema, respecting required/optional fields.
|
|
186
|
-
*/
|
|
187
|
-
type InferObjectSchema<S> = {
|
|
188
|
-
[K in keyof S as S[K] extends { required: true } ? K : never]: InferAttr<S[K]>;
|
|
189
|
-
} & {
|
|
190
|
-
[K in keyof S as S[K] extends { required: true } ? never : K]?: InferAttr<S[K]>;
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Non-generated attributes for input
|
|
195
|
-
* Splits into required and optional based on the 'required' field
|
|
196
|
-
*/
|
|
197
|
-
type NonGeneratedAttributes<M extends ModelDefinition> = {
|
|
198
|
-
[K in keyof M['attributes'] as M['attributes'][K] extends { generate: string }
|
|
199
|
-
? never
|
|
200
|
-
: M['attributes'][K] extends { required: true }
|
|
201
|
-
? K
|
|
202
|
-
: never]: InferAttr<M['attributes'][K]>;
|
|
203
|
-
} & {
|
|
204
|
-
[K in keyof M['attributes'] as M['attributes'][K] extends { generate: string }
|
|
205
|
-
? never
|
|
206
|
-
: M['attributes'][K] extends { required: false }
|
|
207
|
-
? K
|
|
208
|
-
: M['attributes'][K] extends { required: true }
|
|
209
|
-
? never
|
|
210
|
-
: K]?: InferAttr<M['attributes'][K]>;
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Generated-only attributes for internal use
|
|
215
|
-
*/
|
|
216
|
-
type GeneratedAttributes<M extends ModelDefinition> = {
|
|
217
|
-
[K in keyof M['attributes'] as M['attributes'][K] extends { generate: string }
|
|
218
|
-
? K
|
|
219
|
-
: never]: InferAttr<M['attributes'][K]>;
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Template string variable extraction
|
|
224
|
-
*/
|
|
225
|
-
type ExtractTemplateVars<S extends string> = S extends `${string}\${${infer Var}}${infer Rest}`
|
|
226
|
-
? Var | ExtractTemplateVars<Rest>
|
|
227
|
-
: never;
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Extract template variables from primary keys (PK and SK)
|
|
231
|
-
*/
|
|
232
|
-
type PrimaryKeyVars<M extends ModelDefinition> =
|
|
233
|
-
| ExtractTemplateVars<M['key']['PK']['value']>
|
|
234
|
-
| ExtractTemplateVars<M['key']['SK']['value']>;
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Extract template variables from index keys (if they exist)
|
|
238
|
-
*/
|
|
239
|
-
type IndexKeyVars<M extends ModelDefinition> =
|
|
240
|
-
M['index'] extends Record<string, KeyDefinition>
|
|
241
|
-
? {
|
|
242
|
-
[K in keyof M['index']]: ExtractTemplateVars<M['index'][K]['value']>;
|
|
243
|
-
}[keyof M['index']]
|
|
244
|
-
: never;
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Extract all template variables from primary and index keys
|
|
248
|
-
*/
|
|
249
|
-
type KeyVars<M extends ModelDefinition> = PrimaryKeyVars<M> | IndexKeyVars<M>;
|
|
250
|
-
|
|
251
|
-
type IsGenerated<M extends ModelDefinition, K extends string> = K extends keyof M['attributes']
|
|
252
|
-
? M['attributes'][K] extends { generate: string }
|
|
253
|
-
? true
|
|
254
|
-
: false
|
|
255
|
-
: false;
|
|
256
|
-
|
|
257
|
-
type FilterNonGeneratedKeyVars<
|
|
258
|
-
M extends ModelDefinition,
|
|
259
|
-
K extends string = KeyVars<M>,
|
|
260
|
-
> = K extends string ? (IsGenerated<M, K> extends true ? never : K) : never;
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Keys required in input
|
|
264
|
-
*/
|
|
265
|
-
type RequiredKeys<M extends ModelDefinition> = {
|
|
266
|
-
[K in keyof NonGeneratedAttributes<M>]: M['attributes'][K] extends {
|
|
267
|
-
required: true;
|
|
268
|
-
}
|
|
269
|
-
? K
|
|
270
|
-
: never;
|
|
271
|
-
}[keyof NonGeneratedAttributes<M>];
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Input type used for put/update
|
|
275
|
-
*
|
|
276
|
-
* @deprecated Use InferInputFromSchema when possible to get timestamp inference
|
|
277
|
-
*/
|
|
278
|
-
export type InferInput<M extends ModelDefinition> = {
|
|
279
|
-
[K in keyof NonGeneratedAttributes<M> as K extends RequiredKeys<M>
|
|
280
|
-
? K
|
|
281
|
-
: never]: NonGeneratedAttributes<M>[K];
|
|
282
|
-
} & {
|
|
283
|
-
[K in keyof NonGeneratedAttributes<M> as K extends RequiredKeys<M>
|
|
284
|
-
? never
|
|
285
|
-
: K]?: NonGeneratedAttributes<M>[K];
|
|
286
|
-
} & {
|
|
287
|
-
[K in FilterNonGeneratedKeyVars<M>]: string;
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Infers the input type from a complete schema definition
|
|
292
|
-
* When timestamps are enabled, createdAt and updatedAt are NOT included (auto-generated)
|
|
293
|
-
*/
|
|
294
|
-
export type InferInputFromSchema<
|
|
295
|
-
S extends SchemaDefinition,
|
|
296
|
-
ModelName extends keyof S['models'],
|
|
297
|
-
> = InferInput<S['models'][ModelName]>;
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Full model type after applying defaults and keys
|
|
301
|
-
*/
|
|
302
|
-
type ModelAttributes<M extends ModelDefinition> = NonGeneratedAttributes<M> &
|
|
303
|
-
GeneratedAttributes<M>;
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Timestamp fields that are automatically added when timestamps are enabled
|
|
307
|
-
*/
|
|
308
|
-
export type TimestampFields = {
|
|
309
|
-
createdAt: string;
|
|
310
|
-
updatedAt: string;
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* Infers the model type without exposing internal DynamoDB keys (PK, SK, GSI1PK, etc.)
|
|
315
|
-
* Only includes business attributes and generated fields
|
|
316
|
-
*
|
|
317
|
-
* @deprecated Use InferModelFromSchema when possible to get timestamp inference
|
|
318
|
-
*/
|
|
319
|
-
export type InferModel<M extends ModelDefinition> = ModelAttributes<M>;
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* Infers the model type from a complete schema definition
|
|
323
|
-
* Automatically includes timestamp fields (createdAt, updatedAt) when params.timestamps is true
|
|
324
|
-
*/
|
|
325
|
-
export type InferModelFromSchema<
|
|
326
|
-
S extends SchemaDefinition,
|
|
327
|
-
ModelName extends keyof S['models'],
|
|
328
|
-
> = S['params'] extends { timestamps: true }
|
|
329
|
-
? ModelAttributes<S['models'][ModelName]> & TimestampFields
|
|
330
|
-
: ModelAttributes<S['models'][ModelName]>;
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Internal type that includes DynamoDB keys - used internally by builders
|
|
334
|
-
* Includes pk, sk, and any index keys
|
|
335
|
-
* @internal
|
|
336
|
-
*/
|
|
337
|
-
export type InferModelWithKeys<M extends ModelDefinition> = ModelAttributes<M> & {
|
|
338
|
-
[K in keyof M['key']]: string;
|
|
339
|
-
} & (M['index'] extends Record<string, KeyDefinition>
|
|
340
|
-
? {
|
|
341
|
-
[K in keyof M['index']]: string;
|
|
342
|
-
}
|
|
343
|
-
: Record<string, never>);
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Extract template variables from primary keys only
|
|
347
|
-
*/
|
|
348
|
-
type KeyTemplateVars<M extends ModelDefinition> = PrimaryKeyVars<M>;
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Input for get/delete operations (only key template vars)
|
|
352
|
-
*/
|
|
353
|
-
export type InferKeyInput<M extends ModelDefinition> = {
|
|
354
|
-
[K in KeyTemplateVars<M>]: string;
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* Extracts the item type from an array attribute.
|
|
359
|
-
*
|
|
360
|
-
* @example
|
|
361
|
-
* type StoryFrame = ArrayItem<StoryEntity['frames']>;
|
|
362
|
-
* // → { url: string; duration?: number; mediaType?: string }
|
|
363
|
-
*
|
|
364
|
-
* type HistoryEntry = ArrayItem<TransactionEntity['history']>;
|
|
365
|
-
*/
|
|
366
|
-
export type ArrayItem<T extends readonly unknown[] | undefined> = NonNullable<T>[number];
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
3
|
-
import { InferInput, InferKeyInput, InferModel, ModelDefinition } from '@/core/types';
|
|
4
|
-
import { applyPostDefaults, resolveKeys } from '@/utils/model-utils';
|
|
5
|
-
import { modelToZod } from '@/utils/zod-utils';
|
|
6
|
-
import {
|
|
7
|
-
createGetBuilder,
|
|
8
|
-
createPutBuilder,
|
|
9
|
-
createQueryBuilder,
|
|
10
|
-
createUpdateBuilder,
|
|
11
|
-
createDeleteBuilder,
|
|
12
|
-
createScanBuilder,
|
|
13
|
-
createBatchGetBuilder,
|
|
14
|
-
createBatchWriteBuilder,
|
|
15
|
-
WriteRequest,
|
|
16
|
-
} from '@/builders';
|
|
17
|
-
import { EntityAPI, EntityAPIOptions } from './types';
|
|
18
|
-
import { withMiddleware } from './middleware/with-middleware';
|
|
19
|
-
import { createCleanKeysMiddleware } from './middleware/factories';
|
|
20
|
-
import { validateKeyFields } from './validation/key-validation';
|
|
21
|
-
import { Condition } from '@/builders/shared/types';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Creates an entity API instance with validation, key resolution, and builder creation.
|
|
25
|
-
*
|
|
26
|
-
* @param tableName - The name of the DynamoDB table
|
|
27
|
-
* @param modelName - The name of the model/entity
|
|
28
|
-
* @param model - The model definition
|
|
29
|
-
* @param client - DynamoDB client instance
|
|
30
|
-
* @param options - Optional configuration (logger, timestamps, cleanInternalKeys)
|
|
31
|
-
* @returns EntityAPI with get, put, query, scan, update, delete, batchGet, and batchWrite methods
|
|
32
|
-
*/
|
|
33
|
-
export const createEntityAPI = <Model extends ModelDefinition>(
|
|
34
|
-
tableName: string,
|
|
35
|
-
modelName: string,
|
|
36
|
-
model: Model,
|
|
37
|
-
client: DynamoDBClient,
|
|
38
|
-
options: EntityAPIOptions = {}
|
|
39
|
-
): EntityAPI<InferModel<Model>, InferInput<Model>, InferKeyInput<Model>> => {
|
|
40
|
-
const { logger, timestamps = false, cleanInternalKeys = false } = options;
|
|
41
|
-
|
|
42
|
-
// Build a Zod schema from the model
|
|
43
|
-
const zodSchema = modelToZod(model);
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
get(key) {
|
|
47
|
-
// Validate key fields
|
|
48
|
-
validateKeyFields(modelName, model, key as Record<string, unknown>, 'get()');
|
|
49
|
-
|
|
50
|
-
// Resolve any key defaults or computed keys
|
|
51
|
-
const fullKey = resolveKeys(model, key);
|
|
52
|
-
|
|
53
|
-
const builder = createGetBuilder<InferKeyInput<Model>, InferModel<Model>>(
|
|
54
|
-
tableName,
|
|
55
|
-
fullKey,
|
|
56
|
-
client,
|
|
57
|
-
undefined,
|
|
58
|
-
logger
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
return withMiddleware(builder, createCleanKeysMiddleware(cleanInternalKeys));
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
put(item) {
|
|
65
|
-
// Validate full input data
|
|
66
|
-
const parsed = zodSchema.parse(item);
|
|
67
|
-
|
|
68
|
-
// Apply post-processing defaults from the model (including timestamps for new items)
|
|
69
|
-
const withDefaults = applyPostDefaults(model, parsed, {
|
|
70
|
-
isUpdate: false,
|
|
71
|
-
timestamps,
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// Resolve keys again with defaults (including GSI index keys)
|
|
75
|
-
const fullKey = resolveKeys(model, withDefaults, 'both');
|
|
76
|
-
|
|
77
|
-
// Combine keys and data into full item, adding _type field
|
|
78
|
-
const fullItem = {
|
|
79
|
-
...withDefaults,
|
|
80
|
-
...fullKey,
|
|
81
|
-
_type: modelName, // Add entity type identifier
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
return createPutBuilder(tableName, fullItem, client, [], false, 'NONE', false, logger);
|
|
85
|
-
},
|
|
86
|
-
|
|
87
|
-
query() {
|
|
88
|
-
// Auto-filter by entity type so query() only returns items for this
|
|
89
|
-
// entity. Without this, queries on shared GSIs return items from other
|
|
90
|
-
// entities that share the same partition key.
|
|
91
|
-
return createQueryBuilder<InferModel<Model>>(tableName, client, model, logger, modelName);
|
|
92
|
-
},
|
|
93
|
-
|
|
94
|
-
scan() {
|
|
95
|
-
// Auto-filter by entity type so scan only returns items for this entity
|
|
96
|
-
const typeFilter: Condition = {
|
|
97
|
-
expression: '#_type = :_type',
|
|
98
|
-
names: { '#_type': '_type' },
|
|
99
|
-
values: { ':_type': modelName },
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const builder = createScanBuilder<InferModel<Model>>(
|
|
103
|
-
tableName,
|
|
104
|
-
client,
|
|
105
|
-
[typeFilter],
|
|
106
|
-
[],
|
|
107
|
-
undefined,
|
|
108
|
-
false,
|
|
109
|
-
undefined,
|
|
110
|
-
undefined,
|
|
111
|
-
undefined,
|
|
112
|
-
logger
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
return withMiddleware(builder, createCleanKeysMiddleware(cleanInternalKeys));
|
|
116
|
-
},
|
|
117
|
-
|
|
118
|
-
update(key) {
|
|
119
|
-
// Validate key fields
|
|
120
|
-
validateKeyFields(modelName, model, key as Record<string, unknown>, 'update()');
|
|
121
|
-
|
|
122
|
-
// Resolve any key defaults or computed keys
|
|
123
|
-
const fullKey = resolveKeys(model, key);
|
|
124
|
-
|
|
125
|
-
const builder = createUpdateBuilder<InferModel<Model>>(
|
|
126
|
-
tableName,
|
|
127
|
-
fullKey as Partial<InferModel<Model>>,
|
|
128
|
-
client,
|
|
129
|
-
[],
|
|
130
|
-
{ set: [], remove: [], add: [], delete: [] },
|
|
131
|
-
'NONE',
|
|
132
|
-
0,
|
|
133
|
-
timestamps,
|
|
134
|
-
logger,
|
|
135
|
-
// Carry the original template-vars-bearing key (e.g. { username: 'jane' })
|
|
136
|
-
// so the builder can recompute index keys when .set() touches their template fields.
|
|
137
|
-
{ model, keyVars: key as Record<string, unknown> }
|
|
138
|
-
);
|
|
139
|
-
|
|
140
|
-
return withMiddleware(builder, createCleanKeysMiddleware(cleanInternalKeys));
|
|
141
|
-
},
|
|
142
|
-
|
|
143
|
-
delete(key) {
|
|
144
|
-
// Validate key fields
|
|
145
|
-
validateKeyFields(modelName, model, key as Record<string, unknown>, 'delete()');
|
|
146
|
-
|
|
147
|
-
// Resolve any key defaults or computed keys
|
|
148
|
-
const fullKey = resolveKeys(model, key);
|
|
149
|
-
|
|
150
|
-
const builder = createDeleteBuilder<InferModel<Model>>(
|
|
151
|
-
tableName,
|
|
152
|
-
fullKey as Partial<InferModel<Model>>,
|
|
153
|
-
client,
|
|
154
|
-
[],
|
|
155
|
-
'NONE',
|
|
156
|
-
logger
|
|
157
|
-
);
|
|
158
|
-
|
|
159
|
-
return withMiddleware(builder, createCleanKeysMiddleware(cleanInternalKeys));
|
|
160
|
-
},
|
|
161
|
-
|
|
162
|
-
batchGet(keys) {
|
|
163
|
-
// Process all keys and validate them
|
|
164
|
-
const resolvedKeys = keys.map((key) => {
|
|
165
|
-
// Validate key fields
|
|
166
|
-
validateKeyFields(modelName, model, key as Record<string, unknown>, 'batchGet()');
|
|
167
|
-
|
|
168
|
-
// Resolve any key defaults or computed keys
|
|
169
|
-
return resolveKeys(model, key);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
// Create the request items in the format expected by BatchGetItem
|
|
173
|
-
const requestItems = {
|
|
174
|
-
[tableName]: {
|
|
175
|
-
Keys: resolvedKeys,
|
|
176
|
-
},
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
const builder = createBatchGetBuilder<InferModel<Model>>(
|
|
180
|
-
requestItems,
|
|
181
|
-
client,
|
|
182
|
-
undefined,
|
|
183
|
-
logger
|
|
184
|
-
);
|
|
185
|
-
|
|
186
|
-
return withMiddleware(builder, createCleanKeysMiddleware(cleanInternalKeys));
|
|
187
|
-
},
|
|
188
|
-
|
|
189
|
-
batchWrite(items) {
|
|
190
|
-
// Validate and process all items
|
|
191
|
-
const processedItems = items.map((item) => {
|
|
192
|
-
// Validate full input data
|
|
193
|
-
const parsed = zodSchema.parse(item);
|
|
194
|
-
|
|
195
|
-
// Apply post-processing defaults from the model (including timestamps for new items)
|
|
196
|
-
const withDefaults = applyPostDefaults(model, parsed, {
|
|
197
|
-
isUpdate: false,
|
|
198
|
-
timestamps,
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
// Resolve keys again with defaults (including GSI index keys)
|
|
202
|
-
const fullKey = resolveKeys(model, withDefaults, 'both');
|
|
203
|
-
|
|
204
|
-
// Combine keys and data into full item, adding _type field
|
|
205
|
-
return {
|
|
206
|
-
...withDefaults,
|
|
207
|
-
...fullKey,
|
|
208
|
-
_type: modelName, // Add entity type identifier
|
|
209
|
-
};
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
// Create the request items in the format expected by BatchWriteItem
|
|
213
|
-
const requestItems: Record<string, WriteRequest[]> = {
|
|
214
|
-
[tableName]: processedItems.map((item) => ({
|
|
215
|
-
PutRequest: {
|
|
216
|
-
Item: item,
|
|
217
|
-
},
|
|
218
|
-
})),
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
return createBatchWriteBuilder(requestItems, client, logger);
|
|
222
|
-
},
|
|
223
|
-
};
|
|
224
|
-
};
|
package/src/entity/index.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Entity API module
|
|
3
|
-
*
|
|
4
|
-
* Provides high-level entity management with validation, key resolution, and builder creation.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// Core types
|
|
8
|
-
export type { EntityAPI, EntityAPIOptions } from './types';
|
|
9
|
-
|
|
10
|
-
// Middleware types and utilities
|
|
11
|
-
export type { ExecutionMiddleware } from './middleware/types';
|
|
12
|
-
export { withMiddleware } from './middleware/with-middleware';
|
|
13
|
-
export { createCleanKeysMiddleware } from './middleware/factories';
|
|
14
|
-
|
|
15
|
-
// Validation utilities
|
|
16
|
-
export { validateKeyFields } from './validation/key-validation';
|
|
17
|
-
|
|
18
|
-
// Main entity API factory
|
|
19
|
-
export { createEntityAPI } from './create-entity-api';
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { stripInternalKeys } from '@/utils/model-utils';
|
|
2
|
-
import { ExecutionMiddleware } from './types';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Creates middleware configuration for cleaning internal keys
|
|
6
|
-
*/
|
|
7
|
-
export function createCleanKeysMiddleware(shouldClean: boolean): ExecutionMiddleware {
|
|
8
|
-
if (!shouldClean) {
|
|
9
|
-
return {};
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return {
|
|
13
|
-
after: (result) => stripInternalKeys(result),
|
|
14
|
-
};
|
|
15
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { ExecutionMiddleware } from './types';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Applies middleware hooks to a builder's execute method
|
|
6
|
-
*/
|
|
7
|
-
export function withMiddleware<B extends { execute: () => Promise<any> }>(
|
|
8
|
-
builder: B,
|
|
9
|
-
middleware: ExecutionMiddleware
|
|
10
|
-
): B {
|
|
11
|
-
const { before, after } = middleware;
|
|
12
|
-
|
|
13
|
-
// If no middleware hooks provided, return builder as-is
|
|
14
|
-
if (!before && !after) {
|
|
15
|
-
return builder;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return {
|
|
19
|
-
...builder,
|
|
20
|
-
execute: async () => {
|
|
21
|
-
// Before execution hook
|
|
22
|
-
if (before) {
|
|
23
|
-
await before();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Execute original builder
|
|
27
|
-
const result = await builder.execute();
|
|
28
|
-
|
|
29
|
-
// After execution hook
|
|
30
|
-
if (after) {
|
|
31
|
-
return await after(result);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return result;
|
|
35
|
-
},
|
|
36
|
-
};
|
|
37
|
-
}
|