dyno-table 1.6.0 → 1.8.0-next.1

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 (74) hide show
  1. package/README.md +53 -140
  2. package/dist/batch-builder-BOBwOIUE.d.ts +398 -0
  3. package/dist/batch-builder-CKYnMRyz.d.cts +398 -0
  4. package/dist/{builder-types-DlaUSc-b.d.cts → builder-types-BTVhQSHI.d.cts} +55 -5
  5. package/dist/{builder-types-B_tCpn9F.d.ts → builder-types-CzuLR4Th.d.ts} +55 -5
  6. package/dist/builders/condition-check-builder.cjs +0 -13
  7. package/dist/builders/condition-check-builder.cjs.map +1 -1
  8. package/dist/builders/condition-check-builder.d.cts +1 -14
  9. package/dist/builders/condition-check-builder.d.ts +1 -14
  10. package/dist/builders/condition-check-builder.js +0 -13
  11. package/dist/builders/condition-check-builder.js.map +1 -1
  12. package/dist/builders/delete-builder.cjs +38 -0
  13. package/dist/builders/delete-builder.cjs.map +1 -1
  14. package/dist/builders/delete-builder.d.cts +37 -1
  15. package/dist/builders/delete-builder.d.ts +37 -1
  16. package/dist/builders/delete-builder.js +38 -0
  17. package/dist/builders/delete-builder.js.map +1 -1
  18. package/dist/builders/paginator.cjs +21 -27
  19. package/dist/builders/paginator.cjs.map +1 -1
  20. package/dist/builders/paginator.d.cts +3 -27
  21. package/dist/builders/paginator.d.ts +3 -27
  22. package/dist/builders/paginator.js +21 -27
  23. package/dist/builders/paginator.js.map +1 -1
  24. package/dist/builders/put-builder.cjs +39 -8
  25. package/dist/builders/put-builder.cjs.map +1 -1
  26. package/dist/builders/put-builder.d.cts +38 -9
  27. package/dist/builders/put-builder.d.ts +38 -9
  28. package/dist/builders/put-builder.js +39 -8
  29. package/dist/builders/put-builder.js.map +1 -1
  30. package/dist/builders/query-builder.cjs +115 -75
  31. package/dist/builders/query-builder.cjs.map +1 -1
  32. package/dist/builders/query-builder.d.cts +2 -2
  33. package/dist/builders/query-builder.d.ts +2 -2
  34. package/dist/builders/query-builder.js +115 -75
  35. package/dist/builders/query-builder.js.map +1 -1
  36. package/dist/builders/transaction-builder.cjs +0 -47
  37. package/dist/builders/transaction-builder.cjs.map +1 -1
  38. package/dist/builders/transaction-builder.d.cts +1 -48
  39. package/dist/builders/transaction-builder.d.ts +1 -48
  40. package/dist/builders/transaction-builder.js +0 -47
  41. package/dist/builders/transaction-builder.js.map +1 -1
  42. package/dist/builders/update-builder.cjs +2 -2
  43. package/dist/builders/update-builder.cjs.map +1 -1
  44. package/dist/builders/update-builder.d.cts +3 -3
  45. package/dist/builders/update-builder.d.ts +3 -3
  46. package/dist/builders/update-builder.js +2 -2
  47. package/dist/builders/update-builder.js.map +1 -1
  48. package/dist/conditions.cjs.map +1 -1
  49. package/dist/conditions.js.map +1 -1
  50. package/dist/entity.cjs +69 -37
  51. package/dist/entity.cjs.map +1 -1
  52. package/dist/entity.d.cts +30 -10
  53. package/dist/entity.d.ts +30 -10
  54. package/dist/entity.js +69 -37
  55. package/dist/entity.js.map +1 -1
  56. package/dist/index.cjs +661 -218
  57. package/dist/index.cjs.map +1 -1
  58. package/dist/index.d.cts +4 -3
  59. package/dist/index.d.ts +4 -3
  60. package/dist/index.js +660 -219
  61. package/dist/index.js.map +1 -1
  62. package/dist/{query-builder-BhrR31oO.d.ts → query-builder-CaHzZmDf.d.ts} +31 -63
  63. package/dist/{query-builder-CbHvimBk.d.cts → query-builder-DFkxojBM.d.cts} +31 -63
  64. package/dist/{table-CY9byPEg.d.cts → table-CHitMHXE.d.cts} +55 -169
  65. package/dist/{table-Des8C2od.d.ts → table-m7DQk5dK.d.ts} +55 -169
  66. package/dist/table.cjs +590 -181
  67. package/dist/table.cjs.map +1 -1
  68. package/dist/table.d.cts +4 -3
  69. package/dist/table.d.ts +4 -3
  70. package/dist/table.js +590 -181
  71. package/dist/table.js.map +1 -1
  72. package/dist/utils.cjs.map +1 -1
  73. package/dist/utils.js.map +1 -1
  74. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <div align="center">
2
2
 
3
- # 🦖 dyno-table
3
+ # 🦖 dyno-table ALPHA
4
4
 
5
5
  ### **Tame Your DynamoDB Data with Type-Safe Precision**
6
6
 
@@ -101,8 +101,8 @@ await dinoTable
101
101
  - [Nested Object Support](#nested-object-support)
102
102
  - [Type-Safe Conditions](#type-safe-conditions)
103
103
  - [🔄 Batch Operations](#-batch-operations)
104
- - [Batch Get](#batch-get)
105
- - [Batch Write](#batch-write)
104
+ - [Entity-Based Batch Operations](#-entity-based-batch-operations)
105
+ - [Table-Direct Batch Operations](#-table-direct-batch-operations)
106
106
  - [🔒 Transaction Operations](#-transaction-operations)
107
107
  - [Transaction Builder](#transaction-builder)
108
108
  - [Transaction Options](#transaction-options)
@@ -947,16 +947,6 @@ async function main() {
947
947
  }
948
948
  ```
949
949
 
950
- **Key benefits:**
951
- - 🎯 **Semantic Data Access**: Method names like `getDinosaursBySpecies()` clearly express business intent
952
- - 🚫 **Prevents Accidental Cross-Type Access**: Type-safe operations prevent data corruption
953
- - 🔍 **Self-Documenting Code**: No need to remember what `gsi1` or `gsi2` does
954
- - 🛡️ **Consistent Key Structure**: Ensures uniform key patterns across entities
955
- - 📦 **Encapsulated Domain Logic**: Business rules are contained within entity definitions
956
- - 🧪 **Schema Validation**: Automatic data validation with your preferred schema library
957
- - 🔄 **Full Type Inference**: Complete TypeScript support from schema to queries
958
- - 👥 **Team Collaboration**: New developers understand the codebase immediately
959
-
960
950
  ## 🧩 Advanced Features
961
951
 
962
952
  ### Transactional Operations
@@ -1060,108 +1050,6 @@ await dinoTable.transaction(
1060
1050
  );
1061
1051
  ```
1062
1052
 
1063
- **Benefits of this transaction approach:**
1064
- - 🔄 Uses the same familiar API as non-transactional operations
1065
- - 🧠 Maintains consistent mental model for developers
1066
- - 🔒 All operations within the callback are executed as a single transaction
1067
- - 🛡️ Prevents race conditions and data inconsistencies
1068
- - 📊 Supports up to 100 actions per transaction
1069
-
1070
- ### Batch Processing
1071
-
1072
- **Efficient dinosaur park management with bulk operations**
1073
- ```ts
1074
- // SCENARIO 1: Morning health check for multiple dinosaurs across enclosures
1075
- // Retrieve health status for multiple dinosaurs in a single operation
1076
- const healthCheckKeys = [
1077
- { pk: "ENCLOSURE#A", sk: "DINO#001" }, // T-Rex in Paddock A
1078
- { pk: "ENCLOSURE#B", sk: "DINO#002" }, // Velociraptor in Paddock B
1079
- { pk: "ENCLOSURE#C", sk: "DINO#003" } // Stegosaurus in Paddock C
1080
- ];
1081
-
1082
- // Perform batch get operation to retrieve all dinosaurs at once
1083
- // This is much more efficient than individual gets
1084
- const { items: dinosaurs, unprocessedKeys } = await dinoTable.batchGet<Dinosaur>(healthCheckKeys);
1085
- console.log(`Health check completed for ${dinosaurs.length} dinosaurs`);
1086
-
1087
- // Process health check results and identify any dinosaurs needing attention
1088
- dinosaurs.forEach(dino => {
1089
- if (dino.health < 80) {
1090
- console.log(`Health alert for ${dino.name} in Enclosure ${dino.enclosureId}`);
1091
- // In a real application, you might trigger alerts or schedule veterinary visits
1092
- }
1093
- });
1094
-
1095
- // SCENARIO 2: Adding new herbivores to the park after quarantine
1096
- // Prepare data for multiple new herbivores joining the collection
1097
- const newHerbivores = [
1098
- {
1099
- pk: "ENCLOSURE#D", sk: "DINO#004",
1100
- name: "Triceratops Alpha", // Three-horned herbivore
1101
- species: "Triceratops",
1102
- diet: "Herbivore",
1103
- status: "HEALTHY",
1104
- health: 95, // Excellent health after quarantine
1105
- lastFed: new Date().toISOString() // Just fed before joining main enclosure
1106
- },
1107
- {
1108
- pk: "ENCLOSURE#D", sk: "DINO#005",
1109
- name: "Brachy", // Long-necked herbivore
1110
- species: "Brachiosaurus",
1111
- diet: "Herbivore",
1112
- status: "HEALTHY",
1113
- health: 90,
1114
- lastFed: new Date().toISOString()
1115
- }
1116
- ];
1117
-
1118
- // Add all new herbivores to the enclosure in a single batch operation
1119
- // More efficient than individual writes and ensures consistent state
1120
- await dinoTable.batchWrite(
1121
- newHerbivores.map(dino => ({
1122
- type: "put", // Create or replace operation
1123
- item: dino // Full dinosaur record
1124
- }))
1125
- );
1126
-
1127
- // SCENARIO 3: Releasing a dinosaur from quarantine to general population
1128
- // Multiple related operations performed as a batch
1129
- await dinoTable.batchWrite([
1130
- // Step 1: Remove dinosaur from quarantine enclosure
1131
- {
1132
- type: "delete",
1133
- key: { pk: "ENCLOSURE#QUARANTINE", sk: "DINO#006" }
1134
- },
1135
-
1136
- // Step 2: Add recovered dinosaur to main raptor enclosure
1137
- {
1138
- type: "put",
1139
- item: {
1140
- pk: "ENCLOSURE#E", sk: "DINO#006",
1141
- name: "Raptor Beta", // Juvenile Velociraptor
1142
- species: "Velociraptor",
1143
- diet: "Carnivore",
1144
- status: "HEALTHY", // Now healthy after treatment
1145
- health: 100,
1146
- lastFed: new Date().toISOString()
1147
- }
1148
- },
1149
-
1150
- // Step 3: Clear quarantine status record
1151
- {
1152
- type: "delete",
1153
- key: { pk: "ENCLOSURE#QUARANTINE", sk: "STATUS#DINO#006" }
1154
- }
1155
- ]);
1156
-
1157
- // SCENARIO 4: Daily park-wide health monitoring
1158
- // Handle large-scale operations across all dinosaurs
1159
- // The library automatically handles chunking for large batches:
1160
- // - 25 items per batch write
1161
- // - 100 items per batch get
1162
- const dailyHealthUpdates = generateDinosaurHealthUpdates(); // Hundreds of updates
1163
- await dinoTable.batchWrite(dailyHealthUpdates); // Automatically chunked into multiple requests
1164
- ```
1165
1053
 
1166
1054
  ### Pagination Made Simple
1167
1055
 
@@ -1244,11 +1132,11 @@ Dyno-table provides comprehensive query methods that match DynamoDB's capabiliti
1244
1132
  | **Greater Than or Equal** | `.filter(op => op.gte("rating", 4))` | `rating >= :v1` |
1245
1133
  | **Between** | `.filter(op => op.between("age", 18, 65))` | `age BETWEEN :v1 AND :v2` |
1246
1134
  | **In Array** | `.filter(op => op.inArray("status", ["ACTIVE", "PENDING"]))` | `status IN (:v1, :v2)` |
1247
- | **Begins With** | `.filter(op => op.beginsWith("email", "@example.com"))` | `begins_with(email, :v1)` |
1248
- | **Contains** | `.filter(op => op.contains("tags", "important"))` | `contains(tags, :v1)` |
1249
- | **Attribute Exists** | `.filter(op => op.attributeExists("email"))` | `attribute_exists(email)` |
1250
- | **Attribute Not Exists** | `.filter(op => op.attributeNotExists("deletedAt"))` | `attribute_not_exists(deletedAt)` |
1251
- | **Nested Attributes** | `.filter(op => op.eq("address.city", "London"))` | `address.city = :v1` |
1135
+ | **Begins With** | `.filter(op => op.beginsWith("email", "@example.com"))` | `begins_with(email, :v1)` |
1136
+ | **Contains** | `.filter(op => op.contains("tags", "important"))` | `contains(tags, :v1)` |
1137
+ | **Attribute Exists** | `.filter(op => op.attributeExists("email"))` | `attribute_exists(email)` |
1138
+ | **Attribute Not Exists** | `.filter(op => op.attributeNotExists("deletedAt"))` | `attribute_not_exists(deletedAt)` |
1139
+ | **Nested Attributes** | `.filter(op => op.eq("address.city", "London"))` | `address.city = :v1` |
1252
1140
 
1253
1141
  ### Logical Operators
1254
1142
 
@@ -1449,24 +1337,58 @@ await table.query<DinosaurMonitoring>({
1449
1337
 
1450
1338
  ## 🔄 Batch Operations
1451
1339
 
1452
- The library supports efficient batch operations for both reading and writing multiple items:
1340
+ Efficiently handle multiple items in a single request with automatic chunking and type safety.
1341
+
1342
+ ### 🏗️ Entity-Based Batch Operations
1343
+
1344
+ **Type-safe batch operations with automatic entity type inference**
1453
1345
 
1454
- ### Batch Get
1455
1346
  ```ts
1456
- const { items, unprocessedKeys } = await table.batchGet<User>([
1457
- { pk: "USER#1", sk: "PROFILE" },
1458
- { pk: "USER#2", sk: "PROFILE" }
1459
- ]);
1347
+ // Create a typed batch builder
1348
+ const batch = table.batchBuilder<{
1349
+ Dinosaur: DinosaurEntity;
1350
+ Fossil: FossilEntity;
1351
+ }>();
1352
+
1353
+ // Add operations - entity type is automatically inferred
1354
+ dinosaurRepo.create(newDinosaur).withBatch(batch);
1355
+ dinosaurRepo.get({ id: 'dino-123', diet: 'carnivore', species: 'Tyrannosaurus Rex' }).withBatch(batch);
1356
+ fossilRepo.create(newFossil).withBatch(batch);
1357
+
1358
+ // Execute and get typed results
1359
+ const result = await batch.execute();
1360
+ const dinosaurs: DinosaurEntity[] = result.reads.itemsByType.Dinosaur;
1361
+ const fossils: FossilEntity[] = result.reads.itemsByType.Fossil;
1460
1362
  ```
1461
1363
 
1462
- ### Batch Write
1364
+ ### 📋 Table-Direct Batch Operations
1365
+
1366
+ **Direct table access for maximum control**
1367
+
1463
1368
  ```ts
1464
- const { unprocessedItems } = await table.batchWrite<User>([
1465
- { type: "put", item: newUser },
1466
- { type: "delete", key: { pk: "USER#123", sk: "PROFILE" } }
1467
- ]);
1369
+ // Batch get - retrieve multiple items
1370
+ const keys = [
1371
+ { pk: "DIET#carnivore", sk: "SPECIES#Tyrannosaurus Rex#ID#dino-123" },
1372
+ { pk: "FOSSIL#456", sk: "DISCOVERY#2024" }
1373
+ ];
1374
+
1375
+ const { items, unprocessedKeys } = await table.batchGet<DynamoItem>(keys);
1376
+
1377
+ // Batch write - mix of operations
1378
+ const operations = [
1379
+ { type: "put" as const, item: { pk: "DIET#herbivore", sk: "SPECIES#Triceratops#ID#dino-789", name: "Spike", dangerLevel: 3 } },
1380
+ { type: "delete" as const, key: { pk: "FOSSIL#OLD", sk: "DISCOVERY#1990" } }
1381
+ ];
1382
+
1383
+ const { unprocessedItems } = await table.batchWrite(operations);
1384
+
1385
+ // Handle unprocessed items (retry if needed)
1386
+ if (unprocessedItems.length > 0) {
1387
+ await table.batchWrite(unprocessedItems);
1388
+ }
1468
1389
  ```
1469
1390
 
1391
+
1470
1392
  ## 🔒 Transaction Operations
1471
1393
 
1472
1394
  Perform multiple operations atomically with transaction support:
@@ -1666,15 +1588,6 @@ const quarantinedDinos = await dinoTable
1666
1588
  .execute();
1667
1589
  ```
1668
1590
 
1669
- Available key conditions for dinosaur queries:
1670
- - `eq(value)` - Exact match (e.g., specific enclosure)
1671
- - `lt(value)` - Earlier than date/time
1672
- - `lte(value)` - Up to and including date/time
1673
- - `gt(value)` - Later than date/time
1674
- - `gte(value)` - From date/time onwards
1675
- - `between(lower, upper)` - Range (e.g., weight range, date range)
1676
- - `beginsWith(value)` - Prefix match (e.g., all health checks today)
1677
-
1678
1591
  ## 🔮 Future Roadmap
1679
1592
 
1680
1593
  - [ ] Enhanced query plan visualization
@@ -0,0 +1,398 @@
1
+ import { DynamoItem } from './types.js';
2
+ import { r as PrimaryKeyWithoutExpression } from './conditions-BtynAviC.js';
3
+ import { a as PutCommandParams, D as DeleteCommandParams } from './builder-types-CzuLR4Th.js';
4
+
5
+ type BatchWriteOperation<T extends Record<string, unknown>> = {
6
+ type: "put";
7
+ item: T;
8
+ } | {
9
+ type: "delete";
10
+ key: PrimaryKeyWithoutExpression;
11
+ };
12
+
13
+ /**
14
+ * Parameters for the DynamoDB get command.
15
+ */
16
+ interface GetCommandParams {
17
+ /** The name of the DynamoDB table */
18
+ tableName: string;
19
+ /** The primary key of the item to get */
20
+ key: PrimaryKeyWithoutExpression;
21
+ /** Comma-separated list of attributes to return */
22
+ projectionExpression?: string;
23
+ /** Map of expression attribute name placeholders to actual names */
24
+ expressionAttributeNames?: Record<string, string>;
25
+ /** Whether to use strongly consistent reads */
26
+ consistentRead?: boolean;
27
+ }
28
+ /**
29
+ * Function type for executing DynamoDB get operations.
30
+ * @typeParam T - The type of item being retrieved
31
+ */
32
+ type GetExecutor<T extends DynamoItem> = (params: GetCommandParams) => Promise<{
33
+ item: T | undefined;
34
+ }>;
35
+ /**
36
+ * Builder for creating DynamoDB get operations.
37
+ * Use this builder when you need to:
38
+ * - Retrieve a single dinosaur by its primary key
39
+ * - Project specific dinosaur attributes
40
+ * - Use consistent reads for critical dinosaur data
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * // Simple get
45
+ * const result = await new GetBuilder(executor, { pk: 'dinosaur#123', sk: 'profile' })
46
+ * .execute();
47
+ *
48
+ * // Get with projection and consistent read
49
+ * const result = await new GetBuilder(executor, { pk: 'dinosaur#123', sk: 'profile' })
50
+ * .select(['species', 'name', 'diet'])
51
+ * .consistentRead()
52
+ * .execute();
53
+ * ```
54
+ *
55
+ * @typeParam T - The type of item being retrieved
56
+ */
57
+ declare class GetBuilder<T extends DynamoItem> {
58
+ private readonly executor;
59
+ private readonly params;
60
+ private options;
61
+ private selectedFields;
62
+ /**
63
+ * Creates a new GetBuilder instance.
64
+ *
65
+ * @param executor - Function that executes the get operation
66
+ * @param key - Primary key of the item to retrieve
67
+ * @param tableName - Name of the DynamoDB table
68
+ */
69
+ constructor(executor: GetExecutor<T>, key: PrimaryKeyWithoutExpression, tableName: string);
70
+ /**
71
+ * Specifies which attributes to return in the get results.
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * // Select single attribute
76
+ * builder.select('species')
77
+ *
78
+ * // Select multiple attributes
79
+ * builder.select(['id', 'species', 'diet'])
80
+ *
81
+ * // Chain multiple select calls
82
+ * builder
83
+ * .select('id')
84
+ * .select(['species', 'diet'])
85
+ * ```
86
+ *
87
+ * @param fields - A single field name or an array of field names to return
88
+ * @returns The builder instance for method chaining
89
+ */
90
+ select(fields: string | string[]): GetBuilder<T>;
91
+ /**
92
+ * Sets whether to use strongly consistent reads for the get operation.
93
+ * Use this method when you need:
94
+ * - The most up-to-date dinosaur data
95
+ * - To ensure you're reading the latest dinosaur status
96
+ * - Critical safety information about dangerous species
97
+ *
98
+ * Note: Consistent reads consume twice the throughput
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * // Get the latest T-Rex data
103
+ * const result = await new GetBuilder(executor, { pk: 'dinosaur#123', sk: 'profile' })
104
+ * .consistentRead()
105
+ * .execute();
106
+ * ```
107
+ *
108
+ * @param consistentRead - Whether to use consistent reads (defaults to true)
109
+ * @returns The builder instance for method chaining
110
+ */
111
+ consistentRead(consistentRead?: boolean): GetBuilder<T>;
112
+ /**
113
+ * Adds this get operation to a batch with optional entity type information.
114
+ *
115
+ * @example Basic Usage
116
+ * ```ts
117
+ * const batch = table.batchBuilder();
118
+ *
119
+ * // Add multiple get operations to batch
120
+ * dinosaurRepo.get({ id: 'dino-1' }).withBatch(batch);
121
+ * dinosaurRepo.get({ id: 'dino-2' }).withBatch(batch);
122
+ * dinosaurRepo.get({ id: 'dino-3' }).withBatch(batch);
123
+ *
124
+ * // Execute all gets efficiently
125
+ * const results = await batch.execute();
126
+ * ```
127
+ *
128
+ * @example Typed Usage
129
+ * ```ts
130
+ * const batch = table.batchBuilder<{
131
+ * User: UserEntity;
132
+ * Order: OrderEntity;
133
+ * }>();
134
+ *
135
+ * // Add operations with type information
136
+ * userRepo.get({ id: 'user-1' }).withBatch(batch, 'User');
137
+ * orderRepo.get({ id: 'order-1' }).withBatch(batch, 'Order');
138
+ *
139
+ * // Execute and get typed results
140
+ * const result = await batch.execute();
141
+ * const users: UserEntity[] = result.reads.itemsByType.User;
142
+ * const orders: OrderEntity[] = result.reads.itemsByType.Order;
143
+ * ```
144
+ *
145
+ * @param batch - The batch builder to add this operation to
146
+ * @param entityType - Optional entity type key for type tracking
147
+ */
148
+ withBatch<TEntities extends Record<string, DynamoItem> = Record<string, DynamoItem>, K extends keyof TEntities = keyof TEntities>(batch: BatchBuilder<TEntities>, entityType?: K): void;
149
+ /**
150
+ * Converts the builder configuration to a DynamoDB command
151
+ */
152
+ private toDynamoCommand;
153
+ /**
154
+ * Executes the get operation against DynamoDB.
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * try {
159
+ * const result = await new GetBuilder(executor, { pk: 'dinosaur#123', sk: 'profile' })
160
+ * .select(['species', 'name', 'diet'])
161
+ * .consistentRead()
162
+ * .execute();
163
+ *
164
+ * if (result.item) {
165
+ * console.log('Dinosaur found:', result.item);
166
+ * } else {
167
+ * console.log('Dinosaur not found');
168
+ * }
169
+ * } catch (error) {
170
+ * console.error('Error getting dinosaur:', error);
171
+ * }
172
+ * ```
173
+ *
174
+ * @returns A promise that resolves to an object containing:
175
+ * - item: The retrieved dinosaur or undefined if not found
176
+ */
177
+ execute(): Promise<{
178
+ item: T | undefined;
179
+ }>;
180
+ }
181
+
182
+ /**
183
+ * Configuration for batch operations
184
+ */
185
+ interface BatchConfig {
186
+ partitionKey: string;
187
+ sortKey?: string;
188
+ }
189
+ /**
190
+ * Executor function for batch write operations
191
+ */
192
+ type BatchWriteExecutor = (operations: Array<BatchWriteOperation<DynamoItem>>) => Promise<{
193
+ unprocessedItems: Array<BatchWriteOperation<DynamoItem>>;
194
+ }>;
195
+ /**
196
+ * Executor function for batch get operations
197
+ */
198
+ type BatchGetExecutor = (keys: Array<PrimaryKeyWithoutExpression>) => Promise<{
199
+ items: DynamoItem[];
200
+ unprocessedKeys: PrimaryKeyWithoutExpression[];
201
+ }>;
202
+ /**
203
+ * Error class for batch operation failures
204
+ */
205
+ declare class BatchError extends Error {
206
+ readonly operation: "write" | "read";
207
+ readonly cause?: Error;
208
+ constructor(message: string, operation: "write" | "read", cause?: Error);
209
+ }
210
+ /**
211
+ * Result structure for batch operations
212
+ */
213
+ interface BatchResult {
214
+ /** Whether the batch operation completed successfully */
215
+ success: boolean;
216
+ /** Write operation results */
217
+ writes: {
218
+ /** Number of write operations processed successfully */
219
+ processed: number;
220
+ /** Write operations that were not processed and may need retry */
221
+ unprocessed: Array<BatchWriteOperation<DynamoItem>>;
222
+ };
223
+ /** Read operation results */
224
+ reads: {
225
+ /** Items retrieved from the batch get operations */
226
+ items: DynamoItem[];
227
+ /** Number of items found and returned */
228
+ found: number;
229
+ /** Keys that were not processed and may need retry */
230
+ unprocessed: PrimaryKeyWithoutExpression[];
231
+ };
232
+ /** Total number of operations in the batch */
233
+ totalOperations: number;
234
+ /** Any errors that occurred during batch processing */
235
+ errors?: BatchError[];
236
+ }
237
+ /**
238
+ * Typed result structure for batch operations with entity type information
239
+ */
240
+ interface TypedBatchResult<TEntities extends Record<string, DynamoItem> = Record<string, DynamoItem>> {
241
+ /** Whether the batch operation completed successfully */
242
+ success: boolean;
243
+ /** Write operation results */
244
+ writes: {
245
+ /** Number of write operations processed successfully */
246
+ processed: number;
247
+ /** Write operations that were not processed and may need retry */
248
+ unprocessed: Array<BatchWriteOperation<DynamoItem>>;
249
+ };
250
+ /** Read operation results with typed items */
251
+ reads: {
252
+ /** Items retrieved from the batch get operations, grouped by entity type */
253
+ itemsByType: {
254
+ [K in keyof TEntities]: TEntities[K][];
255
+ };
256
+ /** All items retrieved (typed as union of all entity types) */
257
+ items: TEntities[keyof TEntities][];
258
+ /** Number of items found and returned */
259
+ found: number;
260
+ /** Keys that were not processed and may need retry */
261
+ unprocessed: PrimaryKeyWithoutExpression[];
262
+ };
263
+ /** Total number of operations in the batch */
264
+ totalOperations: number;
265
+ /** Any errors that occurred during batch execution */
266
+ errors?: BatchError[];
267
+ }
268
+ /**
269
+ * Builder for creating and executing DynamoDB batch operations with full entity support and type inference.
270
+ *
271
+ * Use BatchBuilder when you need to:
272
+ * - Perform multiple operations efficiently (up to 25 writes, 100 reads per batch)
273
+ * - Maintain entity validation, key generation, and type safety
274
+ * - Mix read and write operations in a single batch
275
+ * - Get typed results grouped by entity type
276
+ *
277
+ * @example Basic Usage
278
+ * ```typescript
279
+ * // Define entity types for the batch
280
+ * const batch = table.batchBuilder<{
281
+ * User: UserEntity;
282
+ * Order: OrderEntity;
283
+ * }>();
284
+ *
285
+ * // Add operations using entity repositories
286
+ * userRepo.create(newUser).withBatch(batch, 'User')
287
+ * userRepo.delete({ id: 'old-user' }).withBatch(batch, 'User')
288
+ * orderRepo.get({ id: 'existing-order' }).withBatch(batch, 'Order')
289
+ *
290
+ * // Execute all operations and get typed results
291
+ * const result = await batch.execute()
292
+ * const users: UserEntity[] = result.reads.itemsByType.User
293
+ * const orders: OrderEntity[] = result.reads.itemsByType.Order
294
+ * ```
295
+ *
296
+ * @example Error Handling
297
+ * ```typescript
298
+ * try {
299
+ * const result = await batch.execute()
300
+ *
301
+ * if (result.writes.unprocessed.length > 0) {
302
+ * console.warn('Some writes were not processed:', result.writes.unprocessed)
303
+ * }
304
+ * } catch (error) {
305
+ * if (error instanceof BatchError) {
306
+ * console.error('Batch operation failed:', error.message)
307
+ * }
308
+ * }
309
+ * ```
310
+ */
311
+ declare class BatchBuilder<TEntities extends Record<string, DynamoItem> = Record<string, DynamoItem>> {
312
+ private batchWriteExecutor;
313
+ private batchGetExecutor;
314
+ private config;
315
+ private writeItems;
316
+ private getItems;
317
+ constructor(batchWriteExecutor: BatchWriteExecutor, batchGetExecutor: BatchGetExecutor, config: BatchConfig);
318
+ /**
319
+ * Checks if the batch is empty (contains no operations)
320
+ *
321
+ * @returns true if the batch contains no operations
322
+ */
323
+ isEmpty(): boolean;
324
+ /**
325
+ * Gets the count of operations in the batch
326
+ *
327
+ * @returns Object containing the count of write and read operations
328
+ */
329
+ getOperationCount(): {
330
+ writes: number;
331
+ reads: number;
332
+ };
333
+ /**
334
+ * Validates that the batch is not empty before execution
335
+ *
336
+ * @throws {BatchError} If the batch is empty
337
+ */
338
+ private validateNotEmpty;
339
+ /**
340
+ * Adds a put operation to the batch with entity type information.
341
+ * This method is used internally by entity builders.
342
+ *
343
+ * @param command - The complete put command configuration
344
+ * @param entityType - The entity type name for type tracking
345
+ * @returns The batch builder for method chaining
346
+ * @internal
347
+ */
348
+ putWithCommand<K extends keyof TEntities>(command: PutCommandParams, entityType?: K): this;
349
+ /**
350
+ * Adds a delete operation to the batch with entity type information.
351
+ * This method is used internally by entity builders.
352
+ *
353
+ * @param command - The complete delete command configuration
354
+ * @param entityType - The entity type name for type tracking
355
+ * @returns The batch builder for method chaining
356
+ * @internal
357
+ */
358
+ deleteWithCommand<K extends keyof TEntities>(command: DeleteCommandParams, entityType?: K): this;
359
+ /**
360
+ * Adds a get operation to the batch with entity type information.
361
+ * This method is used internally by entity builders.
362
+ *
363
+ * @param command - The complete get command configuration
364
+ * @param entityType - The entity type name for type tracking
365
+ * @returns The batch builder for method chaining
366
+ * @internal
367
+ */
368
+ getWithCommand<K extends keyof TEntities>(command: GetCommandParams, entityType?: K): this;
369
+ /**
370
+ * Executes all write operations in the batch.
371
+ *
372
+ * @returns A promise that resolves to any unprocessed operations
373
+ * @private
374
+ */
375
+ private executeWrites;
376
+ /**
377
+ * Executes all get operations in the batch.
378
+ *
379
+ * @returns A promise that resolves to the retrieved items
380
+ * @private
381
+ */
382
+ private executeGets;
383
+ /**
384
+ * Groups retrieved items by their entity type.
385
+ * @private
386
+ */
387
+ private groupItemsByType;
388
+ /**
389
+ * Executes all operations in the batch with typed results.
390
+ * Performs write operations first, then get operations.
391
+ *
392
+ * @returns A promise that resolves to a TypedBatchResult with entity type information
393
+ * @throws {BatchError} If the batch is empty or if operations fail
394
+ */
395
+ execute(): Promise<TypedBatchResult<TEntities>>;
396
+ }
397
+
398
+ export { BatchBuilder as B, GetBuilder as G, BatchError as a, type BatchResult as b, type BatchWriteOperation as c };