dyno-table 2.2.1 → 2.3.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 (102) hide show
  1. package/README.md +187 -1865
  2. package/dist/builders.cjs +55 -0
  3. package/dist/builders.d.cts +4 -0
  4. package/dist/builders.d.ts +4 -0
  5. package/dist/builders.js +2 -0
  6. package/dist/chunk-2EWNZOUK.js +618 -0
  7. package/dist/chunk-2WIBY7PZ.js +46 -0
  8. package/dist/chunk-7UJJ7JXM.cjs +63 -0
  9. package/dist/chunk-DTFJJASK.js +3200 -0
  10. package/dist/chunk-EODPMYPE.js +558 -0
  11. package/dist/chunk-KA3VPIPS.cjs +560 -0
  12. package/dist/chunk-NTA6GDPP.cjs +622 -0
  13. package/dist/chunk-PB7BBCZO.cjs +32 -0
  14. package/dist/chunk-QVRMYGC4.js +29 -0
  15. package/dist/chunk-XYL43FDX.cjs +3217 -0
  16. package/dist/conditions.cjs +67 -62
  17. package/dist/conditions.js +1 -48
  18. package/dist/entity.cjs +14 -625
  19. package/dist/entity.d.cts +2 -10
  20. package/dist/entity.d.ts +2 -10
  21. package/dist/entity.js +2 -626
  22. package/dist/index-2cbm07Bi.d.ts +2797 -0
  23. package/dist/index-DlN8G9hd.d.cts +2797 -0
  24. package/dist/index.cjs +111 -4460
  25. package/dist/index.d.cts +2 -10
  26. package/dist/index.d.ts +2 -10
  27. package/dist/index.js +5 -4442
  28. package/dist/standard-schema.cjs +0 -2
  29. package/dist/standard-schema.js +0 -2
  30. package/dist/table.cjs +7 -3796
  31. package/dist/table.d.cts +163 -12
  32. package/dist/table.d.ts +163 -12
  33. package/dist/table.js +3 -3799
  34. package/dist/types.cjs +0 -2
  35. package/dist/types.js +0 -2
  36. package/dist/utils.cjs +10 -30
  37. package/dist/utils.js +1 -31
  38. package/package.json +6 -66
  39. package/dist/batch-builder-BiQDIZ7p.d.cts +0 -398
  40. package/dist/batch-builder-CNsLS6sR.d.ts +0 -398
  41. package/dist/builder-types-BTVhQSHI.d.cts +0 -169
  42. package/dist/builder-types-CzuLR4Th.d.ts +0 -169
  43. package/dist/builders/condition-check-builder.cjs +0 -422
  44. package/dist/builders/condition-check-builder.cjs.map +0 -1
  45. package/dist/builders/condition-check-builder.d.cts +0 -153
  46. package/dist/builders/condition-check-builder.d.ts +0 -153
  47. package/dist/builders/condition-check-builder.js +0 -420
  48. package/dist/builders/condition-check-builder.js.map +0 -1
  49. package/dist/builders/delete-builder.cjs +0 -484
  50. package/dist/builders/delete-builder.cjs.map +0 -1
  51. package/dist/builders/delete-builder.d.cts +0 -211
  52. package/dist/builders/delete-builder.d.ts +0 -211
  53. package/dist/builders/delete-builder.js +0 -482
  54. package/dist/builders/delete-builder.js.map +0 -1
  55. package/dist/builders/paginator.cjs +0 -193
  56. package/dist/builders/paginator.cjs.map +0 -1
  57. package/dist/builders/paginator.d.cts +0 -155
  58. package/dist/builders/paginator.d.ts +0 -155
  59. package/dist/builders/paginator.js +0 -191
  60. package/dist/builders/paginator.js.map +0 -1
  61. package/dist/builders/put-builder.cjs +0 -554
  62. package/dist/builders/put-builder.cjs.map +0 -1
  63. package/dist/builders/put-builder.d.cts +0 -319
  64. package/dist/builders/put-builder.d.ts +0 -319
  65. package/dist/builders/put-builder.js +0 -552
  66. package/dist/builders/put-builder.js.map +0 -1
  67. package/dist/builders/query-builder.cjs +0 -757
  68. package/dist/builders/query-builder.cjs.map +0 -1
  69. package/dist/builders/query-builder.d.cts +0 -6
  70. package/dist/builders/query-builder.d.ts +0 -6
  71. package/dist/builders/query-builder.js +0 -755
  72. package/dist/builders/query-builder.js.map +0 -1
  73. package/dist/builders/transaction-builder.cjs +0 -906
  74. package/dist/builders/transaction-builder.cjs.map +0 -1
  75. package/dist/builders/transaction-builder.d.cts +0 -464
  76. package/dist/builders/transaction-builder.d.ts +0 -464
  77. package/dist/builders/transaction-builder.js +0 -904
  78. package/dist/builders/transaction-builder.js.map +0 -1
  79. package/dist/builders/update-builder.cjs +0 -668
  80. package/dist/builders/update-builder.cjs.map +0 -1
  81. package/dist/builders/update-builder.d.cts +0 -374
  82. package/dist/builders/update-builder.d.ts +0 -374
  83. package/dist/builders/update-builder.js +0 -666
  84. package/dist/builders/update-builder.js.map +0 -1
  85. package/dist/conditions.cjs.map +0 -1
  86. package/dist/conditions.js.map +0 -1
  87. package/dist/entity.cjs.map +0 -1
  88. package/dist/entity.js.map +0 -1
  89. package/dist/index.cjs.map +0 -1
  90. package/dist/index.js.map +0 -1
  91. package/dist/query-builder-D3URwK9k.d.cts +0 -477
  92. package/dist/query-builder-cfEkU0_w.d.ts +0 -477
  93. package/dist/standard-schema.cjs.map +0 -1
  94. package/dist/standard-schema.js.map +0 -1
  95. package/dist/table-ClST8nkR.d.cts +0 -276
  96. package/dist/table-vE3cGoDy.d.ts +0 -276
  97. package/dist/table.cjs.map +0 -1
  98. package/dist/table.js.map +0 -1
  99. package/dist/types.cjs.map +0 -1
  100. package/dist/types.js.map +0 -1
  101. package/dist/utils.cjs.map +0 -1
  102. package/dist/utils.js.map +0 -1
@@ -0,0 +1,3217 @@
1
+ 'use strict';
2
+
3
+ var chunk7UJJ7JXM_cjs = require('./chunk-7UJJ7JXM.cjs');
4
+
5
+ // src/builders/batch-builder.ts
6
+ var BatchError = class extends Error {
7
+ operation;
8
+ cause;
9
+ constructor(message, operation, cause) {
10
+ super(message);
11
+ this.name = "BatchError";
12
+ this.operation = operation;
13
+ this.cause = cause;
14
+ }
15
+ };
16
+ var BatchBuilder = class {
17
+ constructor(batchWriteExecutor, batchGetExecutor, config) {
18
+ this.batchWriteExecutor = batchWriteExecutor;
19
+ this.batchGetExecutor = batchGetExecutor;
20
+ this.config = config;
21
+ }
22
+ writeItems = [];
23
+ getItems = [];
24
+ /**
25
+ * Checks if the batch is empty (contains no operations)
26
+ *
27
+ * @returns true if the batch contains no operations
28
+ */
29
+ isEmpty() {
30
+ return this.writeItems.length === 0 && this.getItems.length === 0;
31
+ }
32
+ /**
33
+ * Gets the count of operations in the batch
34
+ *
35
+ * @returns Object containing the count of write and read operations
36
+ */
37
+ getOperationCount() {
38
+ return {
39
+ writes: this.writeItems.length,
40
+ reads: this.getItems.length
41
+ };
42
+ }
43
+ /**
44
+ * Validates that the batch is not empty before execution
45
+ *
46
+ * @throws {BatchError} If the batch is empty
47
+ */
48
+ validateNotEmpty() {
49
+ if (this.isEmpty()) {
50
+ throw new BatchError(
51
+ "Cannot execute empty batch. Add operations using entity builders with .withBatch()",
52
+ "write"
53
+ );
54
+ }
55
+ }
56
+ /**
57
+ * Adds a put operation to the batch with entity type information.
58
+ * This method is used internally by entity builders.
59
+ *
60
+ * @param command - The complete put command configuration
61
+ * @param entityType - The entity type name for type tracking
62
+ * @returns The batch builder for method chaining
63
+ * @internal
64
+ */
65
+ putWithCommand(command, entityType) {
66
+ const batchItem = {
67
+ type: "Put",
68
+ params: command,
69
+ entityType
70
+ };
71
+ this.writeItems.push(batchItem);
72
+ return this;
73
+ }
74
+ /**
75
+ * Adds a delete operation to the batch with entity type information.
76
+ * This method is used internally by entity builders.
77
+ *
78
+ * @param command - The complete delete command configuration
79
+ * @param entityType - The entity type name for type tracking
80
+ * @returns The batch builder for method chaining
81
+ * @internal
82
+ */
83
+ deleteWithCommand(command, entityType) {
84
+ const batchItem = {
85
+ type: "Delete",
86
+ params: command,
87
+ entityType
88
+ };
89
+ this.writeItems.push(batchItem);
90
+ return this;
91
+ }
92
+ /**
93
+ * Adds a get operation to the batch with entity type information.
94
+ * This method is used internally by entity builders.
95
+ *
96
+ * @param command - The complete get command configuration
97
+ * @param entityType - The entity type name for type tracking
98
+ * @returns The batch builder for method chaining
99
+ * @internal
100
+ */
101
+ getWithCommand(command, entityType) {
102
+ const batchItem = {
103
+ type: "Get",
104
+ params: command,
105
+ entityType
106
+ };
107
+ this.getItems.push(batchItem);
108
+ return this;
109
+ }
110
+ /**
111
+ * Executes all write operations in the batch.
112
+ *
113
+ * @returns A promise that resolves to any unprocessed operations
114
+ * @private
115
+ */
116
+ async executeWrites() {
117
+ if (this.writeItems.length === 0) {
118
+ return { unprocessedItems: [] };
119
+ }
120
+ try {
121
+ const operations = this.writeItems.map((item) => {
122
+ if (item.type === "Put") {
123
+ return {
124
+ type: "put",
125
+ item: item.params.item
126
+ };
127
+ }
128
+ if (item.type === "Delete") {
129
+ let key;
130
+ if (typeof item.params.key === "object" && item.params.key !== null && "pk" in item.params.key) {
131
+ key = item.params.key;
132
+ } else {
133
+ const tableKey = item.params.key;
134
+ key = {
135
+ pk: tableKey[this.config.partitionKey],
136
+ sk: this.config.sortKey ? tableKey[this.config.sortKey] : void 0
137
+ };
138
+ }
139
+ return {
140
+ type: "delete",
141
+ key
142
+ };
143
+ }
144
+ throw new BatchError(`Unsupported batch item type for write operation: ${item.type}`, "write");
145
+ });
146
+ return await this.batchWriteExecutor(operations);
147
+ } catch (error) {
148
+ throw new BatchError(
149
+ `Failed to execute batch write operations: ${error instanceof Error ? error.message : "Unknown error"}`,
150
+ "write",
151
+ error instanceof Error ? error : void 0
152
+ );
153
+ }
154
+ }
155
+ /**
156
+ * Executes all get operations in the batch.
157
+ *
158
+ * @returns A promise that resolves to the retrieved items
159
+ * @private
160
+ */
161
+ async executeGets() {
162
+ if (this.getItems.length === 0) {
163
+ return { items: [], unprocessedKeys: [] };
164
+ }
165
+ try {
166
+ const keys = this.getItems.map((item) => {
167
+ if (item.type === "Get") {
168
+ if (typeof item.params.key === "object" && item.params.key !== null && "pk" in item.params.key) {
169
+ return item.params.key;
170
+ }
171
+ const tableKey = item.params.key;
172
+ return {
173
+ pk: tableKey[this.config.partitionKey],
174
+ sk: this.config.sortKey ? tableKey[this.config.sortKey] : void 0
175
+ };
176
+ }
177
+ throw new BatchError(`Unsupported batch item type for get operation: ${item.type}`, "read");
178
+ });
179
+ return await this.batchGetExecutor(keys);
180
+ } catch (error) {
181
+ throw new BatchError(
182
+ `Failed to execute batch get operations: ${error instanceof Error ? error.message : "Unknown error"}`,
183
+ "read",
184
+ error instanceof Error ? error : void 0
185
+ );
186
+ }
187
+ }
188
+ /**
189
+ * Groups retrieved items by their entity type.
190
+ * @private
191
+ */
192
+ groupItemsByType(items) {
193
+ const grouped = {};
194
+ for (const item of this.getItems) {
195
+ if (item.entityType) {
196
+ const entityType = item.entityType;
197
+ if (!grouped[entityType]) {
198
+ grouped[entityType] = [];
199
+ }
200
+ }
201
+ }
202
+ for (const item of items) {
203
+ const entityType = item.entityType;
204
+ if (entityType && grouped[entityType]) {
205
+ grouped[entityType].push(item);
206
+ }
207
+ }
208
+ return grouped;
209
+ }
210
+ /**
211
+ * Executes all operations in the batch with typed results.
212
+ * Performs write operations first, then get operations.
213
+ *
214
+ * @returns A promise that resolves to a TypedBatchResult with entity type information
215
+ * @throws {BatchError} If the batch is empty or if operations fail
216
+ */
217
+ async execute() {
218
+ this.validateNotEmpty();
219
+ const errors = [];
220
+ let writeResults = { unprocessedItems: [] };
221
+ let getResults = {
222
+ items: [],
223
+ unprocessedKeys: []
224
+ };
225
+ if (this.writeItems.length > 0) {
226
+ try {
227
+ writeResults = await this.executeWrites();
228
+ } catch (error) {
229
+ if (error instanceof BatchError) {
230
+ errors.push(error);
231
+ } else {
232
+ errors.push(
233
+ new BatchError(
234
+ "Unexpected error during write operations",
235
+ "write",
236
+ error instanceof Error ? error : void 0
237
+ )
238
+ );
239
+ }
240
+ }
241
+ }
242
+ if (this.getItems.length > 0) {
243
+ try {
244
+ getResults = await this.executeGets();
245
+ } catch (error) {
246
+ if (error instanceof BatchError) {
247
+ errors.push(error);
248
+ } else {
249
+ errors.push(
250
+ new BatchError(
251
+ "Unexpected error during read operations",
252
+ "read",
253
+ error instanceof Error ? error : void 0
254
+ )
255
+ );
256
+ }
257
+ }
258
+ }
259
+ if (errors.length > 0 && (writeResults.unprocessedItems.length === this.writeItems.length || getResults.unprocessedKeys.length === this.getItems.length)) {
260
+ throw errors[0];
261
+ }
262
+ const totalOperations = this.writeItems.length + this.getItems.length;
263
+ const success = errors.length === 0 && writeResults.unprocessedItems.length === 0 && getResults.unprocessedKeys.length === 0;
264
+ return {
265
+ success,
266
+ writes: {
267
+ processed: this.writeItems.length - writeResults.unprocessedItems.length,
268
+ unprocessed: writeResults.unprocessedItems
269
+ },
270
+ reads: {
271
+ itemsByType: this.groupItemsByType(getResults.items),
272
+ items: getResults.items,
273
+ found: getResults.items.length,
274
+ unprocessed: getResults.unprocessedKeys
275
+ },
276
+ totalOperations,
277
+ errors: errors.length > 0 ? errors : void 0
278
+ };
279
+ }
280
+ };
281
+
282
+ // src/expression.ts
283
+ var generateAttributeName = (params, attr) => {
284
+ if (attr.includes(".")) {
285
+ const pathSegments = attr.split(".");
286
+ const segmentNames = [];
287
+ for (const segment of pathSegments) {
288
+ let segmentName;
289
+ for (const [existingName, existingAttr] of Object.entries(params.expressionAttributeNames)) {
290
+ if (existingAttr === segment) {
291
+ segmentName = existingName;
292
+ break;
293
+ }
294
+ }
295
+ if (!segmentName) {
296
+ segmentName = `#${Object.keys(params.expressionAttributeNames).length}`;
297
+ params.expressionAttributeNames[segmentName] = segment;
298
+ }
299
+ segmentNames.push(segmentName);
300
+ }
301
+ return segmentNames.join(".");
302
+ }
303
+ for (const [existingName, existingAttr] of Object.entries(params.expressionAttributeNames)) {
304
+ if (existingAttr === attr) {
305
+ return existingName;
306
+ }
307
+ }
308
+ const attrName = `#${Object.keys(params.expressionAttributeNames).length}`;
309
+ params.expressionAttributeNames[attrName] = attr;
310
+ return attrName;
311
+ };
312
+ var generateValueName = (params, value) => {
313
+ const valueName = `:${params.valueCounter.count++}`;
314
+ params.expressionAttributeValues[valueName] = value;
315
+ return valueName;
316
+ };
317
+ var validateCondition = (condition, requiresAttr = true, requiresValue = true) => {
318
+ if (requiresAttr && !condition.attr) {
319
+ throw new Error(`Attribute is required for ${condition.type} condition`);
320
+ }
321
+ if (requiresValue && condition.value === void 0) {
322
+ throw new Error(`Value is required for ${condition.type} condition`);
323
+ }
324
+ };
325
+ var buildComparisonExpression = (condition, operator, params) => {
326
+ validateCondition(condition);
327
+ if (!condition.attr) {
328
+ throw new Error(`Attribute is required for ${condition.type} condition`);
329
+ }
330
+ const attrName = generateAttributeName(params, condition.attr);
331
+ const valueName = generateValueName(params, condition.value);
332
+ return `${attrName} ${operator} ${valueName}`;
333
+ };
334
+ var buildBetweenExpression = (condition, params) => {
335
+ validateCondition(condition);
336
+ if (!condition.attr) {
337
+ throw new Error(`Attribute is required for ${condition.type} condition`);
338
+ }
339
+ if (!Array.isArray(condition.value) || condition.value.length !== 2) {
340
+ throw new Error("Between condition requires an array of two values");
341
+ }
342
+ const attrName = generateAttributeName(params, condition.attr);
343
+ const lowerName = generateValueName(params, condition.value[0]);
344
+ const upperName = generateValueName(params, condition.value[1]);
345
+ return `${attrName} BETWEEN ${lowerName} AND ${upperName}`;
346
+ };
347
+ var buildInExpression = (condition, params) => {
348
+ validateCondition(condition);
349
+ if (!condition.attr) {
350
+ throw new Error(`Attribute is required for ${condition.type} condition`);
351
+ }
352
+ if (!Array.isArray(condition.value) || condition.value.length === 0) {
353
+ throw new Error("In condition requires a non-empty array of values");
354
+ }
355
+ if (condition.value.length > 100) {
356
+ throw new Error("In condition supports a maximum of 100 values");
357
+ }
358
+ const attrName = generateAttributeName(params, condition.attr);
359
+ const valueNames = condition.value.map((value) => generateValueName(params, value));
360
+ return `${attrName} IN (${valueNames.join(", ")})`;
361
+ };
362
+ var buildFunctionExpression = (functionName, condition, params) => {
363
+ validateCondition(condition);
364
+ if (!condition.attr) {
365
+ throw new Error(`Attribute is required for ${condition.type} condition`);
366
+ }
367
+ const attrName = generateAttributeName(params, condition.attr);
368
+ const valueName = generateValueName(params, condition.value);
369
+ return `${functionName}(${attrName}, ${valueName})`;
370
+ };
371
+ var buildAttributeFunction = (functionName, condition, params) => {
372
+ validateCondition(condition, true, false);
373
+ if (!condition.attr) {
374
+ throw new Error(`Attribute is required for ${condition.type} condition`);
375
+ }
376
+ const attrName = generateAttributeName(params, condition.attr);
377
+ return `${functionName}(${attrName})`;
378
+ };
379
+ var buildLogicalExpression = (operator, conditions, params) => {
380
+ if (!conditions || conditions.length === 0) {
381
+ throw new Error(`At least one condition is required for ${operator} expression`);
382
+ }
383
+ const expressions = conditions.map((c) => buildExpression(c, params));
384
+ return `(${expressions.join(` ${operator} `)})`;
385
+ };
386
+ var buildExpression = (condition, params) => {
387
+ if (!condition) return "";
388
+ try {
389
+ const expressionBuilders = {
390
+ eq: () => buildComparisonExpression(condition, "=", params),
391
+ ne: () => buildComparisonExpression(condition, "<>", params),
392
+ lt: () => buildComparisonExpression(condition, "<", params),
393
+ lte: () => buildComparisonExpression(condition, "<=", params),
394
+ gt: () => buildComparisonExpression(condition, ">", params),
395
+ gte: () => buildComparisonExpression(condition, ">=", params),
396
+ between: () => buildBetweenExpression(condition, params),
397
+ in: () => buildInExpression(condition, params),
398
+ beginsWith: () => buildFunctionExpression("begins_with", condition, params),
399
+ contains: () => buildFunctionExpression("contains", condition, params),
400
+ attributeExists: () => buildAttributeFunction("attribute_exists", condition, params),
401
+ attributeNotExists: () => buildAttributeFunction("attribute_not_exists", condition, params),
402
+ and: () => {
403
+ if (!condition.conditions) {
404
+ throw new Error("Conditions array is required for AND operator");
405
+ }
406
+ return buildLogicalExpression("AND", condition.conditions, params);
407
+ },
408
+ or: () => {
409
+ if (!condition.conditions) {
410
+ throw new Error("Conditions array is required for OR operator");
411
+ }
412
+ return buildLogicalExpression("OR", condition.conditions, params);
413
+ },
414
+ not: () => {
415
+ if (!condition.condition) {
416
+ throw new Error("Condition is required for NOT operator");
417
+ }
418
+ return `NOT (${buildExpression(condition.condition, params)})`;
419
+ }
420
+ };
421
+ const builder = expressionBuilders[condition.type];
422
+ if (!builder) {
423
+ throw new Error(`Unknown condition type: ${condition.type}`);
424
+ }
425
+ return builder();
426
+ } catch (error) {
427
+ if (error instanceof Error) {
428
+ console.error(`Error building expression for condition type ${condition.type}:`, error.message);
429
+ } else {
430
+ console.error(`Error building expression for condition type ${condition.type}:`, error);
431
+ }
432
+ throw error;
433
+ }
434
+ };
435
+ var prepareExpressionParams = (condition) => {
436
+ if (!condition) return {};
437
+ const params = {
438
+ expressionAttributeNames: {},
439
+ expressionAttributeValues: {},
440
+ valueCounter: { count: 0 }
441
+ };
442
+ const expression = buildExpression(condition, params);
443
+ return {
444
+ expression,
445
+ names: Object.keys(params.expressionAttributeNames).length > 0 ? params.expressionAttributeNames : void 0,
446
+ values: Object.keys(params.expressionAttributeValues).length > 0 ? params.expressionAttributeValues : void 0
447
+ };
448
+ };
449
+
450
+ // src/utils/debug-expression.ts
451
+ function debugCommand(command) {
452
+ const result = {};
453
+ function replaceAliases(expressionString) {
454
+ if (!expressionString) {
455
+ return expressionString;
456
+ }
457
+ let replacedString = expressionString;
458
+ for (const alias in command.expressionAttributeNames) {
459
+ const attributeName = command.expressionAttributeNames[alias];
460
+ const regex = new RegExp(alias, "g");
461
+ replacedString = replacedString.replace(regex, attributeName);
462
+ }
463
+ for (const alias in command.expressionAttributeValues) {
464
+ let attributeValue = command.expressionAttributeValues[alias];
465
+ if (attributeValue instanceof Set) {
466
+ const array = Array.from(attributeValue);
467
+ attributeValue = `Set(${array.length}){${array.map((v) => JSON.stringify(v)).join(", ")}}`;
468
+ } else {
469
+ attributeValue = JSON.stringify(attributeValue);
470
+ }
471
+ const regex = new RegExp(alias, "g");
472
+ replacedString = replacedString.replace(regex, attributeValue);
473
+ }
474
+ return replacedString;
475
+ }
476
+ if (command.updateExpression) {
477
+ result.updateExpression = replaceAliases(command.updateExpression);
478
+ }
479
+ if (command.conditionExpression) {
480
+ result.conditionExpression = replaceAliases(command.conditionExpression);
481
+ }
482
+ if (command.filterExpression) {
483
+ result.filterExpression = replaceAliases(command.filterExpression);
484
+ }
485
+ if (command.keyConditionExpression) {
486
+ result.keyConditionExpression = replaceAliases(command.keyConditionExpression);
487
+ }
488
+ if (command.projectionExpression) {
489
+ result.projectionExpression = replaceAliases(command.projectionExpression);
490
+ }
491
+ return {
492
+ raw: command,
493
+ readable: result
494
+ };
495
+ }
496
+
497
+ // src/builders/delete-builder.ts
498
+ var DeleteBuilder = class {
499
+ options = {
500
+ returnValues: "ALL_OLD"
501
+ };
502
+ executor;
503
+ tableName;
504
+ key;
505
+ constructor(executor, tableName, key) {
506
+ this.executor = executor;
507
+ this.tableName = tableName;
508
+ this.key = key;
509
+ }
510
+ /**
511
+ * Adds a condition that must be satisfied for the delete operation to succeed.
512
+ *
513
+ * @example
514
+ * ```typescript
515
+ * // Ensure dinosaur can be safely removed
516
+ * builder.condition(op =>
517
+ * op.and([
518
+ * op.eq('status', 'SEDATED'),
519
+ * op.eq('location', 'MEDICAL_BAY'),
520
+ * op.attributeExists('lastCheckup')
521
+ * ])
522
+ * );
523
+ *
524
+ * // Verify habitat is empty
525
+ * builder.condition(op =>
526
+ * op.and([
527
+ * op.eq('occupants', 0),
528
+ * op.eq('maintenanceStatus', 'COMPLETE'),
529
+ * op.not(op.attributeExists('activeAlerts'))
530
+ * ])
531
+ * );
532
+ * ```
533
+ *
534
+ * @param condition - Either a Condition object or a callback function that builds the condition
535
+ * @returns The builder instance for method chaining
536
+ */
537
+ condition(condition) {
538
+ if (typeof condition === "function") {
539
+ const conditionOperator = {
540
+ eq: chunk7UJJ7JXM_cjs.eq,
541
+ ne: chunk7UJJ7JXM_cjs.ne,
542
+ lt: chunk7UJJ7JXM_cjs.lt,
543
+ lte: chunk7UJJ7JXM_cjs.lte,
544
+ gt: chunk7UJJ7JXM_cjs.gt,
545
+ gte: chunk7UJJ7JXM_cjs.gte,
546
+ between: chunk7UJJ7JXM_cjs.between,
547
+ inArray: chunk7UJJ7JXM_cjs.inArray,
548
+ beginsWith: chunk7UJJ7JXM_cjs.beginsWith,
549
+ contains: chunk7UJJ7JXM_cjs.contains,
550
+ attributeExists: chunk7UJJ7JXM_cjs.attributeExists,
551
+ attributeNotExists: chunk7UJJ7JXM_cjs.attributeNotExists,
552
+ and: chunk7UJJ7JXM_cjs.and,
553
+ or: chunk7UJJ7JXM_cjs.or,
554
+ not: chunk7UJJ7JXM_cjs.not
555
+ };
556
+ this.options.condition = condition(conditionOperator);
557
+ } else {
558
+ this.options.condition = condition;
559
+ }
560
+ return this;
561
+ }
562
+ /**
563
+ * Sets whether to return the item's attribute values before deletion.
564
+ *
565
+ * @example
566
+ * ```ts
567
+ * // Archive dinosaur data before removal
568
+ * const result = await builder
569
+ * .returnValues('ALL_OLD')
570
+ * .execute();
571
+ *
572
+ * if (result.item) {
573
+ * console.log('Removed dinosaur data:', {
574
+ * species: result.item.species,
575
+ * age: result.item.age,
576
+ * lastLocation: result.item.location
577
+ * });
578
+ * }
579
+ * ```
580
+ *
581
+ * @param returnValues - Use 'ALL_OLD' to return all attributes of the deleted item
582
+ * @returns The builder instance for method chaining
583
+ */
584
+ returnValues(returnValues) {
585
+ this.options.returnValues = returnValues;
586
+ return this;
587
+ }
588
+ /**
589
+ * Generate the DynamoDB command parameters
590
+ */
591
+ toDynamoCommand() {
592
+ const { expression, names, values } = prepareExpressionParams(this.options.condition);
593
+ return {
594
+ tableName: this.tableName,
595
+ key: this.key,
596
+ conditionExpression: expression,
597
+ expressionAttributeNames: names,
598
+ expressionAttributeValues: values,
599
+ returnValues: this.options.returnValues
600
+ };
601
+ }
602
+ /**
603
+ * Adds this delete operation to a transaction.
604
+ *
605
+ * @example
606
+ * ```ts
607
+ * const transaction = new TransactionBuilder();
608
+ *
609
+ * // Remove dinosaur from old habitat
610
+ * new DeleteBuilder(executor, 'dinosaurs', { id: 'RAPTOR-001' })
611
+ * .condition(op => op.eq('status', 'SEDATED'))
612
+ * .withTransaction(transaction);
613
+ *
614
+ * // Update old habitat occupancy
615
+ * new UpdateBuilder(executor, 'habitats', { id: 'PADDOCK-A' })
616
+ * .add('occupants', -1)
617
+ * .withTransaction(transaction);
618
+ *
619
+ * // Execute transfer atomically
620
+ * await transaction.execute();
621
+ * ```
622
+ *
623
+ * @param transaction - The transaction builder to add this operation to
624
+ */
625
+ withTransaction(transaction) {
626
+ const command = this.toDynamoCommand();
627
+ transaction.deleteWithCommand(command);
628
+ }
629
+ /**
630
+ * Adds this delete operation to a batch with optional entity type information.
631
+ *
632
+ * @example Basic Usage
633
+ * ```ts
634
+ * const batch = table.batchBuilder();
635
+ *
636
+ * // Remove multiple dinosaurs in batch
637
+ * dinosaurRepo.delete({ id: 'old-dino-1' }).withBatch(batch);
638
+ * dinosaurRepo.delete({ id: 'old-dino-2' }).withBatch(batch);
639
+ * dinosaurRepo.delete({ id: 'old-dino-3' }).withBatch(batch);
640
+ *
641
+ * // Execute all deletions efficiently
642
+ * await batch.execute();
643
+ * ```
644
+ *
645
+ * @example Typed Usage
646
+ * ```ts
647
+ * const batch = table.batchBuilder<{
648
+ * User: UserEntity;
649
+ * Order: OrderEntity;
650
+ * }>();
651
+ *
652
+ * // Add operations with type information
653
+ * userRepo.delete({ id: 'user-1' }).withBatch(batch, 'User');
654
+ * orderRepo.delete({ id: 'order-1' }).withBatch(batch, 'Order');
655
+ *
656
+ * // Execute batch operations
657
+ * await batch.execute();
658
+ * ```
659
+ *
660
+ * @param batch - The batch builder to add this operation to
661
+ * @param entityType - Optional entity type key for type tracking
662
+ */
663
+ withBatch(batch, entityType) {
664
+ const command = this.toDynamoCommand();
665
+ batch.deleteWithCommand(command, entityType);
666
+ }
667
+ /**
668
+ * Executes the delete operation against DynamoDB.
669
+ *
670
+ * @example
671
+ * ```ts
672
+ * // Delete with condition and retrieve old values
673
+ * const result = await new DeleteBuilder(executor, 'myTable', { id: '123' })
674
+ * .condition(op => op.eq('status', 'INACTIVE'))
675
+ * .returnValues('ALL_OLD')
676
+ * .execute();
677
+ *
678
+ * if (result.item) {
679
+ * console.log('Deleted item:', result.item);
680
+ * }
681
+ * ```
682
+ *
683
+ * @returns A promise that resolves to an object containing the deleted item's attributes (if returnValues is 'ALL_OLD')
684
+ */
685
+ async execute() {
686
+ const params = this.toDynamoCommand();
687
+ return this.executor(params);
688
+ }
689
+ /**
690
+ * Gets a human-readable representation of the delete command
691
+ * with all expression placeholders replaced by their actual values.
692
+ *
693
+ * @example
694
+ * ```ts
695
+ * const debugInfo = new DeleteBuilder(executor, 'dinosaurs', { id: 'TREX-001' })
696
+ * .condition(op => op.and([
697
+ * op.eq('status', 'SEDATED'),
698
+ * op.eq('location', 'MEDICAL_BAY'),
699
+ * op.gt('sedationLevel', 8)
700
+ * op.eq('version', 1),
701
+ * op.attributeExists('status')
702
+ * ]))
703
+ * .debug();
704
+ *
705
+ * console.log('Delete command:', debugInfo);
706
+ * ```
707
+ *
708
+ * @returns A readable representation of the delete command with resolved expressions
709
+ */
710
+ debug() {
711
+ const command = this.toDynamoCommand();
712
+ return debugCommand(command);
713
+ }
714
+ };
715
+
716
+ // src/builders/put-builder.ts
717
+ var PutBuilder = class {
718
+ item;
719
+ options;
720
+ executor;
721
+ tableName;
722
+ constructor(executor, item, tableName) {
723
+ this.executor = executor;
724
+ this.item = item;
725
+ this.tableName = tableName;
726
+ this.options = {
727
+ returnValues: "NONE"
728
+ };
729
+ }
730
+ set(valuesOrPath, value) {
731
+ if (typeof valuesOrPath === "object") {
732
+ Object.assign(this.item, valuesOrPath);
733
+ } else {
734
+ this.item[valuesOrPath] = value;
735
+ }
736
+ return this;
737
+ }
738
+ /**
739
+ * Adds a condition that must be satisfied for the put operation to succeed.
740
+ *
741
+ * @example
742
+ * ```ts
743
+ * // Ensure item doesn't exist (insert only)
744
+ * builder.condition(op => op.attributeNotExists('id'))
745
+ *
746
+ * // Complex condition with version check
747
+ * builder.condition(op =>
748
+ * op.and([
749
+ * op.attributeExists('id'),
750
+ * op.eq('version', currentVersion),
751
+ * op.eq('status', 'ACTIVE')
752
+ * ])
753
+ * )
754
+ * ```
755
+ *
756
+ * @param condition - Either a Condition object or a callback function that builds the condition
757
+ * @returns The builder instance for method chaining
758
+ */
759
+ /**
760
+ * Adds a condition that must be satisfied for the put operation to succeed.
761
+ *
762
+ * @example
763
+ * ```typescript
764
+ * // Ensure unique dinosaur ID
765
+ * builder.condition(op =>
766
+ * op.attributeNotExists('id')
767
+ * );
768
+ *
769
+ * // Verify habitat requirements
770
+ * builder.condition(op =>
771
+ * op.and([
772
+ * op.eq('securityStatus', 'READY'),
773
+ * op.attributeExists('lastInspection'),
774
+ * op.gt('securityLevel', 5)
775
+ * ])
776
+ * );
777
+ *
778
+ * // Check breeding facility conditions
779
+ * builder.condition(op =>
780
+ * op.and([
781
+ * op.between('temperature', 25, 30),
782
+ * op.between('humidity', 60, 80),
783
+ * op.eq('quarantineStatus', 'CLEAR')
784
+ * ])
785
+ * );
786
+ * ```
787
+ *
788
+ * @param condition - Either a Condition object or a callback function that builds the condition
789
+ * @returns The builder instance for method chaining
790
+ */
791
+ condition(condition) {
792
+ if (typeof condition === "function") {
793
+ const conditionOperator = {
794
+ eq: chunk7UJJ7JXM_cjs.eq,
795
+ ne: chunk7UJJ7JXM_cjs.ne,
796
+ lt: chunk7UJJ7JXM_cjs.lt,
797
+ lte: chunk7UJJ7JXM_cjs.lte,
798
+ gt: chunk7UJJ7JXM_cjs.gt,
799
+ gte: chunk7UJJ7JXM_cjs.gte,
800
+ between: chunk7UJJ7JXM_cjs.between,
801
+ inArray: chunk7UJJ7JXM_cjs.inArray,
802
+ beginsWith: chunk7UJJ7JXM_cjs.beginsWith,
803
+ contains: chunk7UJJ7JXM_cjs.contains,
804
+ attributeExists: chunk7UJJ7JXM_cjs.attributeExists,
805
+ attributeNotExists: chunk7UJJ7JXM_cjs.attributeNotExists,
806
+ and: chunk7UJJ7JXM_cjs.and,
807
+ or: chunk7UJJ7JXM_cjs.or,
808
+ not: chunk7UJJ7JXM_cjs.not
809
+ };
810
+ this.options.condition = condition(conditionOperator);
811
+ } else {
812
+ this.options.condition = condition;
813
+ }
814
+ return this;
815
+ }
816
+ /**
817
+ * Sets whether to return the item's previous values (if it existed).
818
+ *
819
+ * @options
820
+ * - NONE: No return value
821
+ * - ALL_OLD: Returns the item's previous state if it existed, no read capacity units are consumed
822
+ * - CONSISTENT: Performs a GET operation after the put to retrieve the item's new state
823
+ * - INPUT: Returns the input values that were passed to the operation
824
+ *
825
+ * @example
826
+ * ```ts
827
+ * // Get previous dinosaur state
828
+ * const result = await builder
829
+ * .returnValues('ALL_OLD')
830
+ * .execute();
831
+ *
832
+ * if (result) {
833
+ * console.log('Previous profile:', {
834
+ * species: result.species,
835
+ * status: result.status,
836
+ * stats: {
837
+ * health: result.stats.health,
838
+ * threatLevel: result.stats.threatLevel
839
+ * }
840
+ * });
841
+ * }
842
+ *
843
+ * // Return input values for create operations
844
+ * const createResult = await builder
845
+ * .returnValues('INPUT')
846
+ * .execute();
847
+ * ```
848
+ *
849
+ * @param returnValues - Use 'ALL_OLD' to return previous values, 'INPUT' to return input values, 'CONSISTENT' for fresh data, or 'NONE' (default).
850
+ * @returns The builder instance for method chaining
851
+ */
852
+ returnValues(returnValues) {
853
+ this.options.returnValues = returnValues;
854
+ return this;
855
+ }
856
+ /**
857
+ * Generate the DynamoDB command parameters
858
+ */
859
+ toDynamoCommand() {
860
+ const { expression, names, values } = prepareExpressionParams(this.options.condition);
861
+ return {
862
+ tableName: this.tableName,
863
+ item: this.item,
864
+ conditionExpression: expression,
865
+ expressionAttributeNames: names,
866
+ expressionAttributeValues: values,
867
+ returnValues: this.options.returnValues
868
+ };
869
+ }
870
+ /**
871
+ * Adds this put operation to a transaction.
872
+ *
873
+ * @example
874
+ * ```ts
875
+ * const transaction = new TransactionBuilder();
876
+ *
877
+ * // Add dinosaur to new habitat
878
+ * new PutBuilder(executor, {
879
+ * id: 'TREX-002',
880
+ * location: 'PADDOCK-B',
881
+ * status: 'ACTIVE',
882
+ * transferDate: new Date().toISOString()
883
+ * }, 'dinosaurs')
884
+ * .withTransaction(transaction);
885
+ *
886
+ * // Update habitat records
887
+ * new UpdateBuilder(executor, 'habitats', { id: 'PADDOCK-B' })
888
+ * .add('occupants', 1)
889
+ * .set('lastTransfer', new Date().toISOString())
890
+ * .withTransaction(transaction);
891
+ *
892
+ * // Execute transfer atomically
893
+ * await transaction.execute();
894
+ * ```
895
+ *
896
+ * @param transaction - The transaction builder to add this operation to
897
+ * @returns The builder instance for method chaining
898
+ */
899
+ withTransaction(transaction) {
900
+ const command = this.toDynamoCommand();
901
+ transaction.putWithCommand(command);
902
+ return this;
903
+ }
904
+ /**
905
+ * Adds this put operation to a batch with optional entity type information.
906
+ *
907
+ * @example Basic Usage
908
+ * ```ts
909
+ * const batch = table.batchBuilder();
910
+ *
911
+ * // Add multiple dinosaurs to batch
912
+ * dinosaurRepo.create(newDino1).withBatch(batch);
913
+ * dinosaurRepo.create(newDino2).withBatch(batch);
914
+ * dinosaurRepo.create(newDino3).withBatch(batch);
915
+ *
916
+ * // Execute all operations efficiently
917
+ * await batch.execute();
918
+ * ```
919
+ *
920
+ * @example Typed Usage
921
+ * ```ts
922
+ * const batch = table.batchBuilder<{
923
+ * User: UserEntity;
924
+ * Order: OrderEntity;
925
+ * }>();
926
+ *
927
+ * // Add operations with type information
928
+ * userRepo.create(newUser).withBatch(batch, 'User');
929
+ * orderRepo.create(newOrder).withBatch(batch, 'Order');
930
+ *
931
+ * // Execute and get typed results
932
+ * const result = await batch.execute();
933
+ * const users: UserEntity[] = result.reads.itemsByType.User;
934
+ * ```
935
+ *
936
+ * @param batch - The batch builder to add this operation to
937
+ * @param entityType - Optional entity type key for type tracking
938
+ */
939
+ withBatch(batch, entityType) {
940
+ const command = this.toDynamoCommand();
941
+ batch.putWithCommand(command, entityType);
942
+ }
943
+ /**
944
+ * Executes the put operation against DynamoDB.
945
+ *
946
+ * @example
947
+ * ```ts
948
+ * try {
949
+ * // Put with condition and return old values
950
+ * const result = await new PutBuilder(executor, newItem, 'myTable')
951
+ * .condition(op => op.eq('version', 1))
952
+ * .returnValues('ALL_OLD')
953
+ * .execute();
954
+ *
955
+ * console.log('Put successful, old item:', result);
956
+ * } catch (error) {
957
+ * // Handle condition check failure or other errors
958
+ * console.error('Put failed:', error);
959
+ * }
960
+ * ```
961
+ *
962
+ * @returns A promise that resolves to the operation result (type depends on returnValues setting)
963
+ * @throws Will throw an error if the condition check fails or other DynamoDB errors occur
964
+ */
965
+ async execute() {
966
+ const params = this.toDynamoCommand();
967
+ return this.executor(params);
968
+ }
969
+ /**
970
+ * Gets a human-readable representation of the put command
971
+ * with all expression placeholders replaced by their actual values.
972
+ *
973
+ * @example
974
+ * ```ts
975
+ * const debugInfo = new PutBuilder(executor, {
976
+ * id: 'RAPTOR-003',
977
+ * species: 'Velociraptor',
978
+ * status: 'QUARANTINE',
979
+ * stats: {
980
+ * health: 100,
981
+ * aggressionLevel: 7,
982
+ * age: 2
983
+ * }
984
+ * }, 'dinosaurs')
985
+ * .condition(op =>
986
+ * op.and([
987
+ * op.attributeNotExists('id'),
988
+ * op.eq('quarantineStatus', 'READY'),
989
+ * op.gt('securityLevel', 8)
990
+ * ])
991
+ * )
992
+ * .debug();
993
+ *
994
+ * console.log('Dinosaur transfer command:', debugInfo);
995
+ * ```
996
+ *
997
+ * @returns A readable representation of the put command with resolved expressions
998
+ */
999
+ debug() {
1000
+ const command = this.toDynamoCommand();
1001
+ return debugCommand(command);
1002
+ }
1003
+ };
1004
+
1005
+ // src/builders/paginator.ts
1006
+ var Paginator = class {
1007
+ queryBuilder;
1008
+ pageSize;
1009
+ currentPage = 0;
1010
+ lastEvaluatedKey;
1011
+ hasMorePages = true;
1012
+ totalItemsRetrieved = 0;
1013
+ overallLimit;
1014
+ constructor(queryBuilder, pageSize) {
1015
+ this.queryBuilder = queryBuilder;
1016
+ this.pageSize = pageSize;
1017
+ this.overallLimit = queryBuilder.getLimit();
1018
+ }
1019
+ /**
1020
+ * Gets the current page number (1-indexed).
1021
+ *
1022
+ * @example
1023
+ * ```ts
1024
+ * const paginator = new QueryBuilder(executor, eq('species', 'Tyrannosaurus'))
1025
+ * .paginate(5);
1026
+ *
1027
+ * await paginator.getNextPage();
1028
+ * console.log(`Reviewing T-Rex group ${paginator.getCurrentPage()}`);
1029
+ * ```
1030
+ *
1031
+ * @returns The current page number, starting from 1
1032
+ */
1033
+ getCurrentPage() {
1034
+ return this.currentPage;
1035
+ }
1036
+ /**
1037
+ * Checks if there are more pages of dinosaurs or habitats to process.
1038
+ *
1039
+ * This method takes into account both:
1040
+ * - DynamoDB's lastEvaluatedKey mechanism
1041
+ * - Any overall limit set on the query
1042
+ *
1043
+ * @example
1044
+ * ```ts
1045
+ * // Process all security incidents
1046
+ * const paginator = new QueryBuilder(executor, eq('type', 'SECURITY_BREACH'))
1047
+ * .sortDescending()
1048
+ * .paginate(10);
1049
+ *
1050
+ * while (paginator.hasNextPage()) {
1051
+ * const page = await paginator.getNextPage();
1052
+ * for (const incident of page.items) {
1053
+ * await processSecurityBreach(incident);
1054
+ * }
1055
+ * console.log(`Processed incidents page ${page.page}`);
1056
+ * }
1057
+ * ```
1058
+ *
1059
+ * @returns true if there are more pages available, false otherwise
1060
+ */
1061
+ hasNextPage() {
1062
+ if (this.overallLimit !== void 0 && this.totalItemsRetrieved >= this.overallLimit) {
1063
+ return false;
1064
+ }
1065
+ return this.hasMorePages;
1066
+ }
1067
+ /**
1068
+ * Retrieves the next page of dinosaurs or habitats from DynamoDB.
1069
+ *
1070
+ * This method handles:
1071
+ * - Automatic continuation between groups
1072
+ * - Respect for park capacity limits
1073
+ * - Group size adjustments for safety
1074
+ *
1075
+ * @example
1076
+ * ```ts
1077
+ * const paginator = new QueryBuilder(executor, eq('species', 'Velociraptor'))
1078
+ * .filter(op => op.eq('status', 'ACTIVE'))
1079
+ * .paginate(5);
1080
+ *
1081
+ * // Check first raptor group
1082
+ * const page1 = await paginator.getNextPage();
1083
+ * console.log(`Found ${page1.items.length} active raptors`);
1084
+ *
1085
+ * // Continue inspection if more groups exist
1086
+ * if (page1.hasNextPage) {
1087
+ * const page2 = await paginator.getNextPage();
1088
+ * console.log(`Inspecting raptor group ${page2.page}`);
1089
+ *
1090
+ * for (const raptor of page2.items) {
1091
+ * await performHealthCheck(raptor);
1092
+ * }
1093
+ * }
1094
+ * ```
1095
+ *
1096
+ * @returns A promise that resolves to a PaginationResult containing:
1097
+ * - items: The dinosaurs/habitats for this page
1098
+ * - hasNextPage: Whether more groups exist
1099
+ * - page: The current group number
1100
+ * - lastEvaluatedKey: DynamoDB's continuation token
1101
+ */
1102
+ async getNextPage() {
1103
+ if (!this.hasNextPage()) {
1104
+ return {
1105
+ items: [],
1106
+ hasNextPage: false,
1107
+ page: this.currentPage
1108
+ };
1109
+ }
1110
+ let effectivePageSize = this.pageSize;
1111
+ if (this.overallLimit !== void 0) {
1112
+ const remainingItems = this.overallLimit - this.totalItemsRetrieved;
1113
+ if (remainingItems <= 0) {
1114
+ return {
1115
+ items: [],
1116
+ hasNextPage: false,
1117
+ page: this.currentPage
1118
+ };
1119
+ }
1120
+ if (effectivePageSize !== void 0) {
1121
+ effectivePageSize = Math.min(effectivePageSize, remainingItems);
1122
+ } else {
1123
+ effectivePageSize = remainingItems;
1124
+ }
1125
+ }
1126
+ const query = this.queryBuilder.clone();
1127
+ if (effectivePageSize !== void 0) {
1128
+ query.limit(effectivePageSize);
1129
+ }
1130
+ if (this.lastEvaluatedKey) {
1131
+ query.startFrom(this.lastEvaluatedKey);
1132
+ }
1133
+ const generator = await query.execute();
1134
+ const items = [];
1135
+ let itemCount = 0;
1136
+ for await (const item of generator) {
1137
+ if (effectivePageSize !== void 0 && itemCount >= effectivePageSize) {
1138
+ break;
1139
+ }
1140
+ items.push(item);
1141
+ itemCount++;
1142
+ }
1143
+ const lastEvaluatedKey = generator.getLastEvaluatedKey();
1144
+ const result = { items, lastEvaluatedKey };
1145
+ this.currentPage += 1;
1146
+ this.lastEvaluatedKey = result.lastEvaluatedKey;
1147
+ this.totalItemsRetrieved += result.items.length;
1148
+ this.hasMorePages = !!result.lastEvaluatedKey && (this.overallLimit === void 0 || this.totalItemsRetrieved < this.overallLimit);
1149
+ return {
1150
+ items: result.items,
1151
+ lastEvaluatedKey: result.lastEvaluatedKey,
1152
+ hasNextPage: this.hasNextPage(),
1153
+ page: this.currentPage
1154
+ };
1155
+ }
1156
+ /**
1157
+ * Gets all remaining dinosaurs or habitats and combines them into a single array.
1158
+ *
1159
+ * @example
1160
+ * ```ts
1161
+ * // Get complete carnivore inventory
1162
+ * const paginator = new QueryBuilder(executor, eq('diet', 'CARNIVORE'))
1163
+ * .filter(op => op.eq('status', 'ACTIVE'))
1164
+ * .paginate(10);
1165
+ *
1166
+ * try {
1167
+ * const allCarnivores = await paginator.getAllPages();
1168
+ * console.log(`Park contains ${allCarnivores.length} active carnivores`);
1169
+ *
1170
+ * // Calculate total threat level
1171
+ * const totalThreat = allCarnivores.reduce(
1172
+ * (sum, dino) => sum + dino.stats.threatLevel,
1173
+ * 0
1174
+ * );
1175
+ * console.log(`Total threat level: ${totalThreat}`);
1176
+ * } catch (error) {
1177
+ * console.error('Failed to complete carnivore census:', error);
1178
+ * }
1179
+ * ```
1180
+ *
1181
+ * @returns A promise that resolves to an array containing all remaining items
1182
+ */
1183
+ async getAllPages() {
1184
+ const allItems = [];
1185
+ while (this.hasNextPage()) {
1186
+ const result = await this.getNextPage();
1187
+ allItems.push(...result.items);
1188
+ }
1189
+ return allItems;
1190
+ }
1191
+ };
1192
+
1193
+ // src/builders/filter-builder.ts
1194
+ var FilterBuilder = class {
1195
+ options = {};
1196
+ selectedFields = /* @__PURE__ */ new Set();
1197
+ /**
1198
+ * Sets the maximum number of items to return.
1199
+ *
1200
+ * Note: This limit applies to the items that match the key condition
1201
+ * before any filter expressions are applied.
1202
+ *
1203
+ * @example
1204
+ * ```typescript
1205
+ * // Get first 10 dinosaurs
1206
+ * const result = await builder
1207
+ * .limit(10)
1208
+ * .execute();
1209
+ * ```
1210
+ *
1211
+ * @param limit - Maximum number of items to return
1212
+ * @returns The builder instance for method chaining
1213
+ */
1214
+ limit(limit) {
1215
+ this.options.limit = limit;
1216
+ return this;
1217
+ }
1218
+ /**
1219
+ * Gets the current limit set on the operation.
1220
+ * This is used internally by the paginator to manage result sets.
1221
+ *
1222
+ * @returns The current limit or undefined if no limit is set
1223
+ */
1224
+ getLimit() {
1225
+ return this.options.limit;
1226
+ }
1227
+ /**
1228
+ * Specifies a Global Secondary Index (GSI) to use for the operation.
1229
+ *
1230
+ * @example
1231
+ * ```typescript
1232
+ * // Find all dinosaurs of a specific species
1233
+ * builder
1234
+ * .useIndex('species-status-index')
1235
+ * .filter(op => op.eq('status', 'ACTIVE'));
1236
+ *
1237
+ * // Search high-security habitats
1238
+ * builder
1239
+ * .useIndex('security-level-index')
1240
+ * .filter(op =>
1241
+ * op.and([
1242
+ * op.gt('securityLevel', 8),
1243
+ * op.eq('status', 'OPERATIONAL')
1244
+ * ])
1245
+ * );
1246
+ * ```
1247
+ *
1248
+ * @param indexName - The name of the GSI to use (type-safe based on table configuration)
1249
+ * @returns The builder instance for method chaining
1250
+ */
1251
+ useIndex(indexName) {
1252
+ this.options.indexName = indexName;
1253
+ return this;
1254
+ }
1255
+ /**
1256
+ * Sets whether to use strongly consistent reads for the operation.
1257
+ *
1258
+ * Note:
1259
+ * - Consistent reads are not available on GSIs
1260
+ * - Consistent reads consume twice the throughput
1261
+ * - Default is eventually consistent reads
1262
+ *
1263
+ * @example
1264
+ * ```typescript
1265
+ * // Check immediate dinosaur status
1266
+ * const result = await builder
1267
+ * .filter(op => op.eq('status', 'ACTIVE'))
1268
+ * .consistentRead()
1269
+ * .execute();
1270
+ *
1271
+ * // Monitor security breaches
1272
+ * const result = await builder
1273
+ * .useIndex('primary-index')
1274
+ * .consistentRead(isEmergencyMode)
1275
+ * .execute();
1276
+ * ```
1277
+ *
1278
+ * @param consistentRead - Whether to use consistent reads (defaults to true)
1279
+ * @returns The builder instance for method chaining
1280
+ */
1281
+ consistentRead(consistentRead = true) {
1282
+ this.options.consistentRead = consistentRead;
1283
+ return this;
1284
+ }
1285
+ /**
1286
+ * Adds a filter expression to refine the operation results.
1287
+ *
1288
+ * @example
1289
+ * ```typescript
1290
+ * // Find aggressive carnivores
1291
+ * builder.filter(op =>
1292
+ * op.and([
1293
+ * op.eq('diet', 'CARNIVORE'),
1294
+ * op.gt('aggressionLevel', 7),
1295
+ * op.eq('status', 'ACTIVE')
1296
+ * ])
1297
+ * );
1298
+ *
1299
+ * // Search suitable breeding habitats
1300
+ * builder.filter(op =>
1301
+ * op.and([
1302
+ * op.between('temperature', 25, 30),
1303
+ * op.lt('currentOccupants', 3),
1304
+ * op.eq('quarantineStatus', 'CLEAR')
1305
+ * ])
1306
+ * );
1307
+ * ```
1308
+ *
1309
+ * @param condition - Either a Condition object or a callback function that builds the condition
1310
+ * @returns The builder instance for method chaining
1311
+ */
1312
+ filter(condition) {
1313
+ const newCondition = typeof condition === "function" ? condition(this.getConditionOperator()) : condition;
1314
+ if (this.options.filter) {
1315
+ if (this.options.filter.type === "and" && this.options.filter.conditions) {
1316
+ if (newCondition.type === "and" && newCondition.conditions) {
1317
+ this.options.filter = {
1318
+ type: "and",
1319
+ conditions: [...this.options.filter.conditions, ...newCondition.conditions]
1320
+ };
1321
+ } else {
1322
+ this.options.filter = {
1323
+ type: "and",
1324
+ conditions: [...this.options.filter.conditions, newCondition]
1325
+ };
1326
+ }
1327
+ } else {
1328
+ if (newCondition.type === "and" && newCondition.conditions) {
1329
+ this.options.filter = {
1330
+ type: "and",
1331
+ conditions: [this.options.filter, ...newCondition.conditions]
1332
+ };
1333
+ } else {
1334
+ this.options.filter = chunk7UJJ7JXM_cjs.and(this.options.filter, newCondition);
1335
+ }
1336
+ }
1337
+ } else {
1338
+ this.options.filter = newCondition;
1339
+ }
1340
+ return this;
1341
+ }
1342
+ getConditionOperator() {
1343
+ return {
1344
+ eq: chunk7UJJ7JXM_cjs.eq,
1345
+ ne: chunk7UJJ7JXM_cjs.ne,
1346
+ lt: chunk7UJJ7JXM_cjs.lt,
1347
+ lte: chunk7UJJ7JXM_cjs.lte,
1348
+ gt: chunk7UJJ7JXM_cjs.gt,
1349
+ gte: chunk7UJJ7JXM_cjs.gte,
1350
+ between: chunk7UJJ7JXM_cjs.between,
1351
+ inArray: chunk7UJJ7JXM_cjs.inArray,
1352
+ beginsWith: chunk7UJJ7JXM_cjs.beginsWith,
1353
+ contains: chunk7UJJ7JXM_cjs.contains,
1354
+ attributeExists: chunk7UJJ7JXM_cjs.attributeExists,
1355
+ attributeNotExists: chunk7UJJ7JXM_cjs.attributeNotExists,
1356
+ and: chunk7UJJ7JXM_cjs.and,
1357
+ or: chunk7UJJ7JXM_cjs.or,
1358
+ not: chunk7UJJ7JXM_cjs.not
1359
+ };
1360
+ }
1361
+ /**
1362
+ * Specifies which attributes to return in the results.
1363
+ *
1364
+ * @example
1365
+ * ```typescript
1366
+ * // Get basic dinosaur info
1367
+ * builder.select([
1368
+ * 'species',
1369
+ * 'status',
1370
+ * 'stats.health',
1371
+ * 'stats.aggressionLevel'
1372
+ * ]);
1373
+ *
1374
+ * // Monitor habitat conditions
1375
+ * builder
1376
+ * .select('securityStatus')
1377
+ * .select([
1378
+ * 'currentOccupants',
1379
+ * 'temperature',
1380
+ * 'lastInspectionDate'
1381
+ * ]);
1382
+ * ```
1383
+ *
1384
+ * @param fields - A single field name or an array of field names to return
1385
+ * @returns The builder instance for method chaining
1386
+ */
1387
+ select(fields) {
1388
+ if (typeof fields === "string") {
1389
+ this.selectedFields.add(fields);
1390
+ } else if (Array.isArray(fields)) {
1391
+ for (const field of fields) {
1392
+ this.selectedFields.add(field);
1393
+ }
1394
+ }
1395
+ this.options.projection = Array.from(this.selectedFields);
1396
+ return this;
1397
+ }
1398
+ /**
1399
+ * Creates a paginator that handles DynamoDB pagination automatically.
1400
+ * The paginator handles:
1401
+ * - Tracking the last evaluated key
1402
+ * - Managing page boundaries
1403
+ * - Respecting overall query limits
1404
+ *
1405
+ * @example
1406
+ * ```typescript
1407
+ * // Create a paginator for dinosaur records with specific page size
1408
+ * const paginator = builder
1409
+ * .filter(op => op.eq('status', 'ACTIVE'))
1410
+ * .paginate(10);
1411
+ *
1412
+ * // Create a paginator with automatic DynamoDB paging (no page size limit)
1413
+ * const autoPaginator = builder
1414
+ * .filter(op => op.eq('status', 'ACTIVE'))
1415
+ * .paginate();
1416
+ *
1417
+ * // Process pages of dinosaur results
1418
+ * while (paginator.hasNextPage()) {
1419
+ * const page = await paginator.getNextPage();
1420
+ * console.log(`Processing page ${page.page}, count: ${page.items.length}`);
1421
+ * // Process dinosaur data
1422
+ * }
1423
+ * ```
1424
+ *
1425
+ * @param pageSize - The number of items to return per page. If not provided, DynamoDB will automatically determine page sizes.
1426
+ * @returns A Paginator instance that manages the pagination state
1427
+ * @see Paginator for more pagination control options
1428
+ */
1429
+ paginate(pageSize) {
1430
+ return new Paginator(this, pageSize);
1431
+ }
1432
+ /**
1433
+ * Sets the starting point using a previous lastEvaluatedKey.
1434
+ *
1435
+ * Note: This method is typically used for manual pagination.
1436
+ * For automatic pagination, use the paginate() method instead.
1437
+ *
1438
+ * @example
1439
+ * ```typescript
1440
+ * // First batch of dinosaurs
1441
+ * const result1 = await builder
1442
+ * .filter(op => op.eq('status', 'ACTIVE'))
1443
+ * .limit(5)
1444
+ * .execute();
1445
+ *
1446
+ * const lastKey = result1.getLastEvaluatedKey();
1447
+ * if (lastKey) {
1448
+ * // Continue listing dinosaurs
1449
+ * const result2 = await builder
1450
+ * .filter(op => op.eq('status', 'ACTIVE'))
1451
+ * .startFrom(lastKey)
1452
+ * .limit(5)
1453
+ * .execute();
1454
+ *
1455
+ * const items = await result2.toArray();
1456
+ * console.log('Additional dinosaurs:', items);
1457
+ * }
1458
+ * ```
1459
+ *
1460
+ * @param lastEvaluatedKey - The exclusive start key from a previous result
1461
+ * @returns The builder instance for method chaining
1462
+ */
1463
+ startFrom(lastEvaluatedKey) {
1464
+ this.options.lastEvaluatedKey = lastEvaluatedKey;
1465
+ return this;
1466
+ }
1467
+ };
1468
+
1469
+ // src/builders/result-iterator.ts
1470
+ var ResultIterator = class {
1471
+ constructor(queryBuilder, directExecutor) {
1472
+ this.queryBuilder = queryBuilder;
1473
+ this.directExecutor = directExecutor;
1474
+ this.overallLimit = queryBuilder.getLimit();
1475
+ }
1476
+ lastEvaluatedKey;
1477
+ itemsYielded = 0;
1478
+ overallLimit;
1479
+ /**
1480
+ * Async iterator with automatic pagination
1481
+ */
1482
+ async *[Symbol.asyncIterator]() {
1483
+ let hasMorePages = true;
1484
+ while (hasMorePages) {
1485
+ const result = await this.directExecutor();
1486
+ for (const item of result.items) {
1487
+ if (this.overallLimit !== void 0 && this.itemsYielded >= this.overallLimit) {
1488
+ return;
1489
+ }
1490
+ yield item;
1491
+ this.itemsYielded++;
1492
+ }
1493
+ if (result.lastEvaluatedKey !== null && result.lastEvaluatedKey !== void 0) {
1494
+ this.lastEvaluatedKey = result.lastEvaluatedKey;
1495
+ this.queryBuilder.startFrom(result.lastEvaluatedKey);
1496
+ } else if (result.lastEvaluatedKey === null) {
1497
+ if (this.lastEvaluatedKey === void 0) {
1498
+ this.lastEvaluatedKey = null;
1499
+ }
1500
+ }
1501
+ hasMorePages = !!result.lastEvaluatedKey && (this.overallLimit === void 0 || this.itemsYielded < this.overallLimit);
1502
+ }
1503
+ }
1504
+ /**
1505
+ * Convert to array (loads all pages).
1506
+ *
1507
+ * ```ts
1508
+ * const result = await table.query({ pk: "foo" }).execute();
1509
+ * const allItemsFromDynamo = await result.toArray();
1510
+ * ```
1511
+ *
1512
+ * Note: This will load all pages into memory. For large datasets, consider using async iteration instead.
1513
+ *```ts
1514
+ * const result = await table.query({ pk: "foo" }).execute();
1515
+ * for await (const item of result) {
1516
+ * // Process each item
1517
+ * }
1518
+ * ```
1519
+ */
1520
+ async toArray() {
1521
+ const items = [];
1522
+ for await (const item of this) {
1523
+ items.push(item);
1524
+ }
1525
+ return items;
1526
+ }
1527
+ /**
1528
+ * Get the last evaluated key
1529
+ */
1530
+ getLastEvaluatedKey() {
1531
+ return this.lastEvaluatedKey === null ? void 0 : this.lastEvaluatedKey;
1532
+ }
1533
+ };
1534
+
1535
+ // src/builders/query-builder.ts
1536
+ var QueryBuilder = class _QueryBuilder extends FilterBuilder {
1537
+ keyCondition;
1538
+ options = {};
1539
+ executor;
1540
+ constructor(executor, keyCondition) {
1541
+ super();
1542
+ this.executor = executor;
1543
+ this.keyCondition = keyCondition;
1544
+ }
1545
+ /**
1546
+ * Sets the maximum number of items to return from the query.
1547
+ *
1548
+ * Note: This is the default behavior if no sort order is specified.
1549
+ *
1550
+ * @example
1551
+ * ```typescript
1552
+ * // Get orders in chronological order
1553
+ * const result = await new QueryBuilder(executor, eq('userId', '123'))
1554
+ * .sortAscending()
1555
+ * .execute();
1556
+ *
1557
+ * // Get events from oldest to newest
1558
+ * const result = await new QueryBuilder(executor, eq('entityId', 'order-123'))
1559
+ * .useIndex('entity-timestamp-index')
1560
+ * .sortAscending()
1561
+ * .execute();
1562
+ * ```
1563
+ *
1564
+ * @returns The builder instance for method chaining
1565
+ */
1566
+ /**
1567
+ * Sets the query to return items in ascending order by sort key.
1568
+ *
1569
+ * @example
1570
+ * ```typescript
1571
+ * // List dinosaurs by age
1572
+ * const result = await new QueryBuilder(executor, eq('species', 'Velociraptor'))
1573
+ * .useIndex('age-index')
1574
+ * .sortAscending()
1575
+ * .execute();
1576
+ *
1577
+ * // View incidents chronologically
1578
+ * const result = await new QueryBuilder(executor, eq('type', 'SECURITY_BREACH'))
1579
+ * .useIndex('date-index')
1580
+ * .sortAscending()
1581
+ * .execute();
1582
+ * ```
1583
+ *
1584
+ * @returns The builder instance for method chaining
1585
+ */
1586
+ sortAscending() {
1587
+ this.options.scanIndexForward = true;
1588
+ return this;
1589
+ }
1590
+ /**
1591
+ * Sets the query to return items in descending order by sort key.
1592
+ *
1593
+ * @example
1594
+ * ```typescript
1595
+ * // Get most recent security incidents
1596
+ * const result = await new QueryBuilder(executor, eq('type', 'SECURITY_BREACH'))
1597
+ * .useIndex('date-index')
1598
+ * .sortDescending()
1599
+ * .limit(10)
1600
+ * .execute();
1601
+ *
1602
+ * // Check latest dinosaur activities
1603
+ * const result = await new QueryBuilder(executor, eq('species', 'Velociraptor'))
1604
+ * .useIndex('activity-time-index')
1605
+ * .filter(op => op.eq('status', 'ACTIVE'))
1606
+ * .sortDescending()
1607
+ * .execute();
1608
+ * ```
1609
+ *
1610
+ * @returns The builder instance for method chaining
1611
+ */
1612
+ sortDescending() {
1613
+ this.options.scanIndexForward = false;
1614
+ return this;
1615
+ }
1616
+ /**
1617
+ * Creates a deep clone of this QueryBuilder instance.
1618
+ *
1619
+ * This is particularly useful when:
1620
+ * - Implementing pagination (used internally by paginate())
1621
+ * - Creating query templates
1622
+ * - Running multiple variations of a query
1623
+ *
1624
+ * @example
1625
+ * ```typescript
1626
+ * // Create base dinosaur query
1627
+ * const baseQuery = new QueryBuilder(executor, eq('species', 'Velociraptor'))
1628
+ * .useIndex('status-index')
1629
+ * .select(['id', 'status', 'location']);
1630
+ *
1631
+ * // Check active dinosaurs
1632
+ * const activeRaptors = baseQuery.clone()
1633
+ * .filter(op => op.eq('status', 'HUNTING'))
1634
+ * .execute();
1635
+ *
1636
+ * // Check contained dinosaurs
1637
+ * const containedRaptors = baseQuery.clone()
1638
+ * .filter(op => op.eq('status', 'CONTAINED'))
1639
+ * .execute();
1640
+ *
1641
+ * // Check sedated dinosaurs
1642
+ * const sedatedRaptors = baseQuery.clone()
1643
+ * .filter(op => op.eq('status', 'SEDATED'))
1644
+ * .execute();
1645
+ * ```
1646
+ *
1647
+ * @returns A new QueryBuilder instance with the same configuration
1648
+ */
1649
+ clone() {
1650
+ const clone = new _QueryBuilder(this.executor, this.keyCondition);
1651
+ clone.options = {
1652
+ ...this.options,
1653
+ filter: this.deepCloneFilter(this.options.filter)
1654
+ };
1655
+ clone.selectedFields = new Set(this.selectedFields);
1656
+ return clone;
1657
+ }
1658
+ deepCloneFilter(filter) {
1659
+ if (!filter) return filter;
1660
+ if (filter.type === "and" || filter.type === "or") {
1661
+ return {
1662
+ ...filter,
1663
+ conditions: filter.conditions?.map((condition) => this.deepCloneFilter(condition)).filter((c) => c !== void 0)
1664
+ };
1665
+ }
1666
+ return { ...filter };
1667
+ }
1668
+ /**
1669
+ * Executes the query against DynamoDB and returns a generator that behaves like an array.
1670
+ *
1671
+ * The generator automatically handles pagination and provides array-like methods
1672
+ * for processing results efficiently without loading everything into memory at once.
1673
+ *
1674
+ * @example
1675
+ * ```typescript
1676
+ * try {
1677
+ * // Find active carnivores with automatic pagination
1678
+ * const results = await new QueryBuilder(executor, eq('habitatId', 'PADDOCK-A'))
1679
+ * .useIndex('species-status-index')
1680
+ * .filter(op =>
1681
+ * op.and([
1682
+ * op.eq('diet', 'CARNIVORE'),
1683
+ * op.eq('status', 'ACTIVE'),
1684
+ * op.gt('aggressionLevel', 7)
1685
+ * ])
1686
+ * )
1687
+ * .sortDescending()
1688
+ * .execute();
1689
+ *
1690
+ * // Use like an array with automatic pagination
1691
+ * for await (const dinosaur of results) {
1692
+ * console.log(`Processing ${dinosaur.name}`);
1693
+ * }
1694
+ *
1695
+ * // Or convert to array and use array methods
1696
+ * const allItems = await results.toArray();
1697
+ * const dangerousOnes = allItems.filter(dino => dino.aggressionLevel > 9);
1698
+ * const totalCount = allItems.length;
1699
+ * } catch (error) {
1700
+ * console.error('Security scan failed:', error);
1701
+ * }
1702
+ * ```
1703
+ *
1704
+ * @returns A promise that resolves to a ResultGenerator that behaves like an array
1705
+ */
1706
+ async execute() {
1707
+ const directExecutor = () => this.executor(this.keyCondition, this.options);
1708
+ return new ResultIterator(this, directExecutor);
1709
+ }
1710
+ };
1711
+
1712
+ // src/utils/debug-transaction.ts
1713
+ function debugTransactionItem(item) {
1714
+ const result = {
1715
+ type: item.type,
1716
+ tableName: item.params.tableName
1717
+ };
1718
+ if ("key" in item.params) {
1719
+ result.key = item.params.key;
1720
+ }
1721
+ if (item.type === "Put") {
1722
+ result.item = item.params.item;
1723
+ }
1724
+ switch (item.type) {
1725
+ case "Put":
1726
+ case "Delete":
1727
+ case "ConditionCheck":
1728
+ result.readable = debugCommand(item.params).readable;
1729
+ break;
1730
+ case "Update":
1731
+ result.readable = debugCommand(item.params).readable;
1732
+ break;
1733
+ }
1734
+ return result;
1735
+ }
1736
+ function debugTransaction(items) {
1737
+ return items.map((item) => debugTransactionItem(item));
1738
+ }
1739
+
1740
+ // src/builders/transaction-builder.ts
1741
+ var TransactionBuilder = class {
1742
+ items = [];
1743
+ options = {};
1744
+ indexConfig;
1745
+ executor;
1746
+ constructor(executor, indexConfig) {
1747
+ this.executor = executor;
1748
+ this.indexConfig = indexConfig;
1749
+ }
1750
+ /**
1751
+ * Checks if an item with the same primary key already exists in the transaction
1752
+ * @private
1753
+ */
1754
+ checkForDuplicateItem(tableName, newItem) {
1755
+ const pkName = this.indexConfig.partitionKey;
1756
+ const skName = this.indexConfig.sortKey ?? "";
1757
+ const pkValue = newItem[pkName];
1758
+ const skValue = skName ? newItem[skName] : void 0;
1759
+ if (!pkValue) {
1760
+ throw new Error(`Primary key value for '${pkName}' is missing`);
1761
+ }
1762
+ const duplicateItem = this.items.find((item) => {
1763
+ let itemKey;
1764
+ let itemTableName;
1765
+ switch (item.type) {
1766
+ case "Put":
1767
+ itemTableName = item.params.tableName;
1768
+ itemKey = item.params.item;
1769
+ break;
1770
+ case "Update":
1771
+ case "Delete":
1772
+ case "ConditionCheck":
1773
+ itemTableName = item.params.tableName;
1774
+ itemKey = item.params.key;
1775
+ break;
1776
+ }
1777
+ if (itemTableName === tableName && itemKey) {
1778
+ const itemPkValue = itemKey[pkName];
1779
+ const itemSkValue = skName ? itemKey[skName] : void 0;
1780
+ if (itemPkValue === pkValue) {
1781
+ if (skValue === void 0 && itemSkValue === void 0) {
1782
+ return true;
1783
+ }
1784
+ if (skValue !== void 0 && itemSkValue !== void 0 && skValue === itemSkValue) {
1785
+ return true;
1786
+ }
1787
+ }
1788
+ }
1789
+ return false;
1790
+ });
1791
+ if (duplicateItem) {
1792
+ throw new Error(
1793
+ `Duplicate item detected in transaction: Table=${tableName}, ${pkName}=${String(pkValue)}, ${skName}=${skValue !== void 0 ? String(skValue) : "undefined"}. DynamoDB transactions do not allow multiple operations on the same item.`
1794
+ );
1795
+ }
1796
+ }
1797
+ createKeyForPrimaryIndex(key) {
1798
+ const keyCondition = {
1799
+ [this.indexConfig.partitionKey]: key.pk
1800
+ };
1801
+ if (this.indexConfig.sortKey) {
1802
+ if (key.sk === void 0) {
1803
+ throw new Error("Sort key is required for delete operation");
1804
+ }
1805
+ keyCondition[this.indexConfig.sortKey] = key.sk;
1806
+ }
1807
+ return keyCondition;
1808
+ }
1809
+ /**
1810
+ * Adds a put operation to the transaction.
1811
+ *
1812
+ * The method automatically checks for duplicate items within the transaction
1813
+ * to prevent multiple operations on the same item.
1814
+ *
1815
+ * @example
1816
+ * ```typescript
1817
+ * // Simple put operation
1818
+ * transaction.put('orders', {
1819
+ * orderId: '123',
1820
+ * status: 'PENDING',
1821
+ * amount: 100
1822
+ * });
1823
+ *
1824
+ * // Conditional put operation
1825
+ * transaction.put(
1826
+ * 'inventory',
1827
+ * { productId: 'ABC', quantity: 50 },
1828
+ * op => op.attributeNotExists('productId')
1829
+ * );
1830
+ *
1831
+ * // Put with complex condition
1832
+ * transaction.put(
1833
+ * 'users',
1834
+ * { userId: '123', status: 'ACTIVE' },
1835
+ * op => op.and([
1836
+ * op.attributeNotExists('userId'),
1837
+ * op.beginsWith('status', 'ACTIVE')
1838
+ * ])
1839
+ * );
1840
+ * ```
1841
+ *
1842
+ * @param tableName - The name of the DynamoDB table
1843
+ * @param item - The item to put into the table
1844
+ * @param condition - Optional condition that must be satisfied
1845
+ * @returns The transaction builder for method chaining
1846
+ * @throws {Error} If a duplicate item is detected in the transaction
1847
+ */
1848
+ put(tableName, item, condition) {
1849
+ this.checkForDuplicateItem(tableName, item);
1850
+ const transactionItem = {
1851
+ type: "Put",
1852
+ params: {
1853
+ tableName,
1854
+ item
1855
+ }
1856
+ };
1857
+ if (condition) {
1858
+ const { expression, names, values } = prepareExpressionParams(condition);
1859
+ transactionItem.params.conditionExpression = expression;
1860
+ transactionItem.params.expressionAttributeNames = names;
1861
+ transactionItem.params.expressionAttributeValues = values;
1862
+ }
1863
+ this.items.push(transactionItem);
1864
+ return this;
1865
+ }
1866
+ /**
1867
+ * Adds a pre-configured put operation to the transaction.
1868
+ *
1869
+ * This method is particularly useful when working with PutBuilder
1870
+ * to maintain consistency in put operations across your application.
1871
+ *
1872
+ * @example
1873
+ * ```typescript
1874
+ * // Create a put command with PutBuilder
1875
+ * const putCommand = new PutBuilder(executor, newItem, 'users')
1876
+ * .condition(op => op.attributeNotExists('userId'))
1877
+ * .toDynamoCommand();
1878
+ *
1879
+ * // Add the command to the transaction
1880
+ * transaction.putWithCommand(putCommand);
1881
+ * ```
1882
+ *
1883
+ * @param command - The complete put command configuration
1884
+ * @returns The transaction builder for method chaining
1885
+ * @throws {Error} If a duplicate item is detected in the transaction
1886
+ * @see PutBuilder for creating put commands
1887
+ */
1888
+ putWithCommand(command) {
1889
+ this.checkForDuplicateItem(command.tableName, command.item);
1890
+ const transactionItem = {
1891
+ type: "Put",
1892
+ params: command
1893
+ };
1894
+ this.items.push(transactionItem);
1895
+ return this;
1896
+ }
1897
+ /**
1898
+ * Adds a delete operation to the transaction.
1899
+ *
1900
+ * The method automatically checks for duplicate items within the transaction
1901
+ * to prevent multiple operations on the same item.
1902
+ *
1903
+ * @example
1904
+ * ```typescript
1905
+ * // Simple delete operation
1906
+ * transaction.delete('orders', {
1907
+ * pk: 'ORDER#123',
1908
+ * sk: 'METADATA'
1909
+ * });
1910
+ *
1911
+ * // Conditional delete operation
1912
+ * transaction.delete(
1913
+ * 'users',
1914
+ * { pk: 'USER#123' },
1915
+ * op => op.eq('status', 'INACTIVE')
1916
+ * );
1917
+ *
1918
+ * // Delete with complex condition
1919
+ * transaction.delete(
1920
+ * 'products',
1921
+ * { pk: 'PROD#ABC' },
1922
+ * op => op.and([
1923
+ * op.eq('status', 'DRAFT'),
1924
+ * op.lt('version', 5)
1925
+ * ])
1926
+ * );
1927
+ * ```
1928
+ *
1929
+ * @param tableName - The name of the DynamoDB table
1930
+ * @param key - The primary key of the item to delete
1931
+ * @param condition - Optional condition that must be satisfied
1932
+ * @returns The transaction builder for method chaining
1933
+ * @throws {Error} If a duplicate item is detected in the transaction
1934
+ */
1935
+ delete(tableName, key, condition) {
1936
+ const keyCondition = this.createKeyForPrimaryIndex(key);
1937
+ this.checkForDuplicateItem(tableName, keyCondition);
1938
+ const transactionItem = {
1939
+ type: "Delete",
1940
+ params: {
1941
+ tableName,
1942
+ key: keyCondition
1943
+ }
1944
+ };
1945
+ if (condition) {
1946
+ const { expression, names, values } = prepareExpressionParams(condition);
1947
+ transactionItem.params.conditionExpression = expression;
1948
+ transactionItem.params.expressionAttributeNames = names;
1949
+ transactionItem.params.expressionAttributeValues = values;
1950
+ }
1951
+ this.items.push(transactionItem);
1952
+ return this;
1953
+ }
1954
+ /**
1955
+ * Adds a pre-configured delete operation to the transaction.
1956
+ *
1957
+ * This method is particularly useful when working with DeleteBuilder
1958
+ * to maintain consistency in delete operations across your application.
1959
+ *
1960
+ * @example
1961
+ * ```typescript
1962
+ * // Create a delete command with DeleteBuilder
1963
+ * const deleteCommand = new DeleteBuilder(executor, 'users', { pk: 'USER#123' })
1964
+ * .condition(op => op.and([
1965
+ * op.attributeExists('pk'),
1966
+ * op.eq('status', 'INACTIVE')
1967
+ * ]))
1968
+ * .toDynamoCommand();
1969
+ *
1970
+ * // Add the command to the transaction
1971
+ * transaction.deleteWithCommand(deleteCommand);
1972
+ * ```
1973
+ *
1974
+ * @param command - The complete delete command configuration
1975
+ * @returns The transaction builder for method chaining
1976
+ * @throws {Error} If a duplicate item is detected in the transaction
1977
+ * @see DeleteBuilder for creating delete commands
1978
+ */
1979
+ deleteWithCommand(command) {
1980
+ let keyForDuplicateCheck;
1981
+ let keyForTransaction;
1982
+ if (typeof command.key === "object" && command.key !== null && "pk" in command.key) {
1983
+ keyForTransaction = this.createKeyForPrimaryIndex(command.key);
1984
+ keyForDuplicateCheck = keyForTransaction;
1985
+ } else {
1986
+ keyForTransaction = command.key;
1987
+ keyForDuplicateCheck = command.key;
1988
+ }
1989
+ this.checkForDuplicateItem(command.tableName, keyForDuplicateCheck);
1990
+ const transactionItem = {
1991
+ type: "Delete",
1992
+ params: {
1993
+ ...command,
1994
+ key: keyForTransaction
1995
+ }
1996
+ };
1997
+ this.items.push(transactionItem);
1998
+ return this;
1999
+ }
2000
+ /**
2001
+ * Adds an update operation to the transaction.
2002
+ *
2003
+ * The method supports all DynamoDB update expressions:
2004
+ * - SET: Modify or add attributes
2005
+ * - REMOVE: Delete attributes
2006
+ * - ADD: Update numbers and sets
2007
+ * - DELETE: Remove elements from a set
2008
+ *
2009
+ * @example
2010
+ * ```typescript
2011
+ * // Simple update
2012
+ * transaction.update(
2013
+ * 'orders',
2014
+ * { pk: 'ORDER#123' },
2015
+ * 'SET #status = :status',
2016
+ * { '#status': 'status' },
2017
+ * { ':status': 'PROCESSING' }
2018
+ * );
2019
+ *
2020
+ * // Complex update with multiple operations
2021
+ * transaction.update(
2022
+ * 'products',
2023
+ * { pk: 'PROD#ABC' },
2024
+ * 'SET #qty = #qty - :amount, #status = :status REMOVE #oldAttr',
2025
+ * { '#qty': 'quantity', '#status': 'status', '#oldAttr': 'deprecated_field' },
2026
+ * { ':amount': 1, ':status': 'LOW_STOCK' }
2027
+ * );
2028
+ *
2029
+ * // Conditional update
2030
+ * transaction.update(
2031
+ * 'users',
2032
+ * { pk: 'USER#123' },
2033
+ * 'SET #lastLogin = :now',
2034
+ * { '#lastLogin': 'lastLoginDate' },
2035
+ * { ':now': new Date().toISOString() },
2036
+ * op => op.attributeExists('pk')
2037
+ * );
2038
+ * ```
2039
+ *
2040
+ * @param tableName - The name of the DynamoDB table
2041
+ * @param key - The primary key of the item to update
2042
+ * @param updateExpression - The update expression (SET, REMOVE, ADD, DELETE)
2043
+ * @param expressionAttributeNames - Map of attribute name placeholders to actual names
2044
+ * @param expressionAttributeValues - Map of value placeholders to actual values
2045
+ * @param condition - Optional condition that must be satisfied
2046
+ * @returns The transaction builder for method chaining
2047
+ * @throws {Error} If a duplicate item is detected in the transaction
2048
+ */
2049
+ update(tableName, key, updateExpression, expressionAttributeNames, expressionAttributeValues, condition) {
2050
+ const keyCondition = this.createKeyForPrimaryIndex(key);
2051
+ this.checkForDuplicateItem(tableName, keyCondition);
2052
+ const transactionItem = {
2053
+ type: "Update",
2054
+ params: {
2055
+ tableName,
2056
+ key: keyCondition,
2057
+ updateExpression,
2058
+ expressionAttributeNames,
2059
+ expressionAttributeValues
2060
+ }
2061
+ };
2062
+ if (condition) {
2063
+ const { expression, names, values } = prepareExpressionParams(condition);
2064
+ transactionItem.params.conditionExpression = expression;
2065
+ transactionItem.params.expressionAttributeNames = {
2066
+ ...transactionItem.params.expressionAttributeNames,
2067
+ ...names
2068
+ };
2069
+ transactionItem.params.expressionAttributeValues = {
2070
+ ...transactionItem.params.expressionAttributeValues,
2071
+ ...values
2072
+ };
2073
+ }
2074
+ this.items.push(transactionItem);
2075
+ return this;
2076
+ }
2077
+ /**
2078
+ * Adds a pre-configured update operation to the transaction.
2079
+ *
2080
+ * This method is particularly useful when working with UpdateBuilder
2081
+ * to maintain consistency in update operations across your application.
2082
+ *
2083
+ * @example
2084
+ * ```typescript
2085
+ * // Create an update command with UpdateBuilder
2086
+ * const updateCommand = new UpdateBuilder(executor, 'inventory', { pk: 'PROD#ABC' })
2087
+ * .set('quantity', ':qty')
2088
+ * .set('lastUpdated', ':now')
2089
+ * .values({
2090
+ * ':qty': 100,
2091
+ * ':now': new Date().toISOString()
2092
+ * })
2093
+ * .condition(op => op.gt('quantity', 0))
2094
+ * .toDynamoCommand();
2095
+ *
2096
+ * // Add the command to the transaction
2097
+ * transaction.updateWithCommand(updateCommand);
2098
+ * ```
2099
+ *
2100
+ * @param command - The complete update command configuration
2101
+ * @returns The transaction builder for method chaining
2102
+ * @throws {Error} If a duplicate item is detected in the transaction
2103
+ * @see UpdateBuilder for creating update commands
2104
+ */
2105
+ updateWithCommand(command) {
2106
+ let keyForDuplicateCheck;
2107
+ let keyForTransaction;
2108
+ if (typeof command.key === "object" && command.key !== null && "pk" in command.key) {
2109
+ keyForTransaction = this.createKeyForPrimaryIndex(command.key);
2110
+ keyForDuplicateCheck = keyForTransaction;
2111
+ } else {
2112
+ keyForTransaction = command.key;
2113
+ keyForDuplicateCheck = command.key;
2114
+ }
2115
+ this.checkForDuplicateItem(command.tableName, keyForDuplicateCheck);
2116
+ const transactionItem = {
2117
+ type: "Update",
2118
+ params: {
2119
+ ...command,
2120
+ key: keyForTransaction
2121
+ }
2122
+ };
2123
+ this.items.push(transactionItem);
2124
+ return this;
2125
+ }
2126
+ /**
2127
+ * Adds a condition check operation to the transaction.
2128
+ *
2129
+ * Condition checks are particularly useful for:
2130
+ * - Implementing optimistic locking
2131
+ * - Ensuring referential integrity
2132
+ * - Validating business rules atomically
2133
+ *
2134
+ * @example
2135
+ * ```typescript
2136
+ * // Check if order is in correct state
2137
+ * transaction.conditionCheck(
2138
+ * 'orders',
2139
+ * { pk: 'ORDER#123' },
2140
+ * op => op.eq('status', 'PENDING')
2141
+ * );
2142
+ *
2143
+ * // Complex condition check
2144
+ * transaction.conditionCheck(
2145
+ * 'inventory',
2146
+ * { pk: 'PROD#ABC' },
2147
+ * op => op.and([
2148
+ * op.gt('quantity', 0),
2149
+ * op.eq('status', 'ACTIVE'),
2150
+ * op.attributeExists('lastRestockDate')
2151
+ * ])
2152
+ * );
2153
+ *
2154
+ * // Check with multiple attributes
2155
+ * transaction.conditionCheck(
2156
+ * 'users',
2157
+ * { pk: 'USER#123' },
2158
+ * op => op.or([
2159
+ * op.eq('status', 'PREMIUM'),
2160
+ * op.gte('credits', 100)
2161
+ * ])
2162
+ * );
2163
+ * ```
2164
+ *
2165
+ * @param tableName - The name of the DynamoDB table
2166
+ * @param key - The primary key of the item to check
2167
+ * @param condition - The condition that must be satisfied
2168
+ * @returns The transaction builder for method chaining
2169
+ * @throws {Error} If a duplicate item is detected in the transaction
2170
+ * @throws {Error} If condition expression generation fails
2171
+ */
2172
+ conditionCheck(tableName, key, condition) {
2173
+ const keyCondition = this.createKeyForPrimaryIndex(key);
2174
+ this.checkForDuplicateItem(tableName, keyCondition);
2175
+ const { expression, names, values } = prepareExpressionParams(condition);
2176
+ if (!expression) {
2177
+ throw new Error("Failed to generate condition expression");
2178
+ }
2179
+ const transactionItem = {
2180
+ type: "ConditionCheck",
2181
+ params: {
2182
+ tableName,
2183
+ key: keyCondition,
2184
+ conditionExpression: expression,
2185
+ expressionAttributeNames: names,
2186
+ expressionAttributeValues: values
2187
+ }
2188
+ };
2189
+ this.items.push(transactionItem);
2190
+ return this;
2191
+ }
2192
+ /**
2193
+ * Adds a pre-configured condition check operation to the transaction.
2194
+ *
2195
+ * This method is particularly useful when working with ConditionCheckBuilder
2196
+ * to maintain consistency in condition checks across your application.
2197
+ *
2198
+ * @example
2199
+ * ```typescript
2200
+ * // Create a condition check with ConditionCheckBuilder
2201
+ * const checkCommand = new ConditionCheckBuilder('inventory', { pk: 'PROD#ABC' })
2202
+ * .condition(op => op.and([
2203
+ * op.between('quantity', 10, 100),
2204
+ * op.beginsWith('category', 'ELECTRONICS'),
2205
+ * op.attributeExists('lastAuditDate')
2206
+ * ]))
2207
+ * .toDynamoCommand();
2208
+ *
2209
+ * // Add the command to the transaction
2210
+ * transaction.conditionCheckWithCommand(checkCommand);
2211
+ * ```
2212
+ *
2213
+ * @param command - The complete condition check command configuration
2214
+ * @returns The transaction builder for method chaining
2215
+ * @throws {Error} If a duplicate item is detected in the transaction
2216
+ * @see ConditionCheckBuilder for creating condition check commands
2217
+ */
2218
+ conditionCheckWithCommand(command) {
2219
+ let keyForDuplicateCheck;
2220
+ let keyForTransaction;
2221
+ if (typeof command.key === "object" && command.key !== null && "pk" in command.key) {
2222
+ keyForTransaction = this.createKeyForPrimaryIndex(command.key);
2223
+ keyForDuplicateCheck = keyForTransaction;
2224
+ } else {
2225
+ keyForTransaction = command.key;
2226
+ keyForDuplicateCheck = command.key;
2227
+ }
2228
+ this.checkForDuplicateItem(command.tableName, keyForDuplicateCheck);
2229
+ const transactionItem = {
2230
+ type: "ConditionCheck",
2231
+ params: {
2232
+ ...command,
2233
+ key: keyForTransaction
2234
+ }
2235
+ };
2236
+ this.items.push(transactionItem);
2237
+ return this;
2238
+ }
2239
+ /**
2240
+ * Sets options for the transaction execution.
2241
+ *
2242
+ * @example
2243
+ * ```typescript
2244
+ * // Enable idempotency and capacity tracking
2245
+ * transaction.withOptions({
2246
+ * clientRequestToken: 'unique-request-id-123',
2247
+ * returnConsumedCapacity: 'TOTAL'
2248
+ * });
2249
+ *
2250
+ * // Track item collection metrics
2251
+ * transaction.withOptions({
2252
+ * returnItemCollectionMetrics: 'SIZE'
2253
+ * });
2254
+ * ```
2255
+ *
2256
+ * Note: ClientRequestToken can be used to make transactions idempotent,
2257
+ * ensuring the same transaction is not executed multiple times.
2258
+ *
2259
+ * @param options - Configuration options for the transaction
2260
+ * @returns The transaction builder for method chaining
2261
+ */
2262
+ withOptions(options) {
2263
+ this.options = { ...this.options, ...options };
2264
+ return this;
2265
+ }
2266
+ /**
2267
+ * Gets a human-readable representation of the transaction items.
2268
+ *
2269
+ * The method resolves all expression placeholders with their actual values,
2270
+ * making it easier to understand the transaction's operations.
2271
+ *
2272
+ * @example
2273
+ * ```typescript
2274
+ * // Add multiple operations
2275
+ * transaction
2276
+ * .put('orders', { orderId: '123', status: 'PENDING' })
2277
+ * .update('inventory',
2278
+ * { productId: 'ABC' },
2279
+ * 'SET quantity = quantity - :amount',
2280
+ * undefined,
2281
+ * { ':amount': 1 }
2282
+ * );
2283
+ *
2284
+ * // Debug the transaction
2285
+ * const debugInfo = transaction.debug();
2286
+ * console.log('Transaction operations:', debugInfo);
2287
+ * ```
2288
+ *
2289
+ * @returns An array of readable representations of the transaction items
2290
+ */
2291
+ debug() {
2292
+ return debugTransaction(this.items);
2293
+ }
2294
+ /**
2295
+ * Executes all operations in the transaction atomically.
2296
+ *
2297
+ * The transaction will only succeed if all operations succeed.
2298
+ * If any operation fails, the entire transaction is rolled back.
2299
+ *
2300
+ * @example
2301
+ * ```typescript
2302
+ * try {
2303
+ * // Build and execute transaction
2304
+ * await transaction
2305
+ * .put('orders', newOrder)
2306
+ * .update('inventory',
2307
+ * { productId: 'ABC' },
2308
+ * 'SET quantity = quantity - :qty',
2309
+ * undefined,
2310
+ * { ':qty': 1 }
2311
+ * )
2312
+ * .conditionCheck('products',
2313
+ * { productId: 'ABC' },
2314
+ * op => op.eq('status', 'ACTIVE')
2315
+ * )
2316
+ * .execute();
2317
+ *
2318
+ * console.log('Transaction completed successfully');
2319
+ * } catch (error) {
2320
+ * // Handle transaction failure
2321
+ * console.error('Transaction failed:', error);
2322
+ * }
2323
+ * ```
2324
+ *
2325
+ * @throws {Error} If no transaction items are specified
2326
+ * @throws {Error} If any operation in the transaction fails
2327
+ * @returns A promise that resolves when the transaction completes
2328
+ */
2329
+ async execute() {
2330
+ if (this.items.length === 0) {
2331
+ throw new Error("No transaction items specified");
2332
+ }
2333
+ const transactItems = this.items.map((item) => {
2334
+ switch (item.type) {
2335
+ case "Put":
2336
+ return {
2337
+ Put: {
2338
+ TableName: item.params.tableName,
2339
+ Item: item.params.item,
2340
+ ConditionExpression: item.params.conditionExpression,
2341
+ ExpressionAttributeNames: item.params.expressionAttributeNames,
2342
+ ExpressionAttributeValues: item.params.expressionAttributeValues
2343
+ }
2344
+ };
2345
+ case "Delete":
2346
+ return {
2347
+ Delete: {
2348
+ TableName: item.params.tableName,
2349
+ Key: item.params.key,
2350
+ ConditionExpression: item.params.conditionExpression,
2351
+ ExpressionAttributeNames: item.params.expressionAttributeNames,
2352
+ ExpressionAttributeValues: item.params.expressionAttributeValues
2353
+ }
2354
+ };
2355
+ case "Update":
2356
+ return {
2357
+ Update: {
2358
+ TableName: item.params.tableName,
2359
+ Key: item.params.key,
2360
+ UpdateExpression: item.params.updateExpression,
2361
+ ConditionExpression: item.params.conditionExpression,
2362
+ ExpressionAttributeNames: item.params.expressionAttributeNames,
2363
+ ExpressionAttributeValues: item.params.expressionAttributeValues
2364
+ }
2365
+ };
2366
+ case "ConditionCheck":
2367
+ return {
2368
+ ConditionCheck: {
2369
+ TableName: item.params.tableName,
2370
+ Key: item.params.key,
2371
+ ConditionExpression: item.params.conditionExpression,
2372
+ ExpressionAttributeNames: item.params.expressionAttributeNames,
2373
+ ExpressionAttributeValues: item.params.expressionAttributeValues
2374
+ }
2375
+ };
2376
+ default: {
2377
+ const exhaustiveCheck = item;
2378
+ throw new Error(`Unsupported transaction item type: ${String(exhaustiveCheck)}`);
2379
+ }
2380
+ }
2381
+ });
2382
+ const params = {
2383
+ TransactItems: transactItems,
2384
+ ClientRequestToken: this.options.clientRequestToken,
2385
+ ReturnConsumedCapacity: this.options.returnConsumedCapacity,
2386
+ ReturnItemCollectionMetrics: this.options.returnItemCollectionMetrics
2387
+ };
2388
+ try {
2389
+ await this.executor(params);
2390
+ } catch (error) {
2391
+ console.log(this.debug());
2392
+ console.error("Error executing transaction:", error);
2393
+ throw error;
2394
+ }
2395
+ }
2396
+ };
2397
+
2398
+ // src/builders/update-builder.ts
2399
+ var UpdateBuilder = class {
2400
+ updates = [];
2401
+ options = {
2402
+ returnValues: "ALL_NEW"
2403
+ };
2404
+ executor;
2405
+ tableName;
2406
+ key;
2407
+ constructor(executor, tableName, key) {
2408
+ this.executor = executor;
2409
+ this.tableName = tableName;
2410
+ this.key = key;
2411
+ }
2412
+ set(valuesOrPath, value) {
2413
+ if (typeof valuesOrPath === "object") {
2414
+ for (const [key, value2] of Object.entries(valuesOrPath)) {
2415
+ this.updates.push({
2416
+ type: "SET",
2417
+ path: key,
2418
+ value: value2
2419
+ });
2420
+ }
2421
+ } else {
2422
+ this.updates.push({
2423
+ type: "SET",
2424
+ path: valuesOrPath,
2425
+ value
2426
+ });
2427
+ }
2428
+ return this;
2429
+ }
2430
+ /**
2431
+ * Removes an attribute from the item.
2432
+ *
2433
+ * @example
2434
+ * ```typescript
2435
+ * // Remove simple attributes
2436
+ * builder
2437
+ * .remove('temporaryTag')
2438
+ * .remove('previousLocation');
2439
+ *
2440
+ * // Remove nested attributes
2441
+ * builder
2442
+ * .remove('metadata.testData')
2443
+ * .remove('stats.experimentalMetrics');
2444
+ * ```
2445
+ *
2446
+ * @param path - The path to the attribute to remove
2447
+ * @returns The builder instance for method chaining
2448
+ */
2449
+ remove(path) {
2450
+ this.updates.push({
2451
+ type: "REMOVE",
2452
+ path
2453
+ });
2454
+ return this;
2455
+ }
2456
+ /**
2457
+ * Adds a value to a number attribute or adds elements to a set.
2458
+ *
2459
+ * @example
2460
+ * ```typescript
2461
+ * // Increment counters
2462
+ * builder
2463
+ * .add('escapeAttempts', 1)
2464
+ * .add('feedingCount', 1);
2465
+ *
2466
+ * // Add to sets
2467
+ * builder
2468
+ * .add('knownBehaviors', new Set(['PACK_HUNTING', 'AMBUSH_TACTICS']))
2469
+ * .add('visitedZones', new Set(['ZONE_A', 'ZONE_B']));
2470
+ * ```
2471
+ *
2472
+ * @param path - The path to the attribute to update
2473
+ * @param value - The value to add (number or set)
2474
+ * @returns The builder instance for method chaining
2475
+ */
2476
+ add(path, value) {
2477
+ this.updates.push({
2478
+ type: "ADD",
2479
+ path,
2480
+ value
2481
+ });
2482
+ return this;
2483
+ }
2484
+ /**
2485
+ * Removes elements from a set attribute.
2486
+ *
2487
+ * @example
2488
+ * ```typescript
2489
+ * // Remove from sets using arrays
2490
+ * builder.deleteElementsFromSet(
2491
+ * 'allowedHabitats',
2492
+ * ['JUNGLE', 'COASTAL']
2493
+ * );
2494
+ *
2495
+ * // Remove from sets using Set DynamoItems
2496
+ * builder.deleteElementsFromSet(
2497
+ * 'knownBehaviors',
2498
+ * new Set(['NOCTURNAL', 'TERRITORIAL'])
2499
+ * );
2500
+ *
2501
+ * // Remove from nested sets
2502
+ * builder.deleteElementsFromSet(
2503
+ * 'stats.compatibleSpecies',
2504
+ * ['VELOCIRAPTOR', 'DILOPHOSAURUS']
2505
+ * );
2506
+ * ```
2507
+ *
2508
+ * @param path - The path to the set attribute
2509
+ * @param value - Elements to remove (array or Set)
2510
+ * @returns The builder instance for method chaining
2511
+ */
2512
+ deleteElementsFromSet(path, value) {
2513
+ let valuesToDelete;
2514
+ if (Array.isArray(value)) {
2515
+ valuesToDelete = new Set(value);
2516
+ } else {
2517
+ valuesToDelete = value;
2518
+ }
2519
+ this.updates.push({
2520
+ type: "DELETE",
2521
+ path,
2522
+ value: valuesToDelete
2523
+ });
2524
+ return this;
2525
+ }
2526
+ /**
2527
+ * Adds a condition that must be satisfied for the update to succeed.
2528
+ *
2529
+ * @example
2530
+ * ```typescript
2531
+ * // Simple condition
2532
+ * builder.condition(op =>
2533
+ * op.eq('status', 'ACTIVE')
2534
+ * );
2535
+ *
2536
+ * // Health check condition
2537
+ * builder.condition(op =>
2538
+ * op.and([
2539
+ * op.gt('health', 50),
2540
+ * op.eq('status', 'HUNTING')
2541
+ * ])
2542
+ * );
2543
+ *
2544
+ * // Complex security condition
2545
+ * builder.condition(op =>
2546
+ * op.and([
2547
+ * op.attributeExists('securitySystem'),
2548
+ * op.eq('containmentStatus', 'SECURE'),
2549
+ * op.lt('aggressionLevel', 8)
2550
+ * ])
2551
+ * );
2552
+ *
2553
+ * // Version check (optimistic locking)
2554
+ * builder.condition(op =>
2555
+ * op.eq('version', currentVersion)
2556
+ * );
2557
+ * ```
2558
+ *
2559
+ * @param condition - Either a Condition DynamoItem or a callback function that builds the condition
2560
+ * @returns The builder instance for method chaining
2561
+ */
2562
+ condition(condition) {
2563
+ if (typeof condition === "function") {
2564
+ const conditionOperator = {
2565
+ eq: chunk7UJJ7JXM_cjs.eq,
2566
+ ne: chunk7UJJ7JXM_cjs.ne,
2567
+ lt: chunk7UJJ7JXM_cjs.lt,
2568
+ lte: chunk7UJJ7JXM_cjs.lte,
2569
+ gt: chunk7UJJ7JXM_cjs.gt,
2570
+ gte: chunk7UJJ7JXM_cjs.gte,
2571
+ between: chunk7UJJ7JXM_cjs.between,
2572
+ inArray: chunk7UJJ7JXM_cjs.inArray,
2573
+ beginsWith: chunk7UJJ7JXM_cjs.beginsWith,
2574
+ contains: chunk7UJJ7JXM_cjs.contains,
2575
+ attributeExists: chunk7UJJ7JXM_cjs.attributeExists,
2576
+ attributeNotExists: chunk7UJJ7JXM_cjs.attributeNotExists,
2577
+ and: chunk7UJJ7JXM_cjs.and,
2578
+ or: chunk7UJJ7JXM_cjs.or,
2579
+ not: chunk7UJJ7JXM_cjs.not
2580
+ };
2581
+ this.options.condition = condition(conditionOperator);
2582
+ } else {
2583
+ this.options.condition = condition;
2584
+ }
2585
+ return this;
2586
+ }
2587
+ /**
2588
+ * Sets which item attributes to include in the response.
2589
+ *
2590
+ * Available options:
2591
+ * - ALL_NEW: All attributes after the update (default)
2592
+ * - UPDATED_NEW: Only updated attributes, new values
2593
+ * - ALL_OLD: All attributes before the update
2594
+ * - UPDATED_OLD: Only updated attributes, old values
2595
+ * - NONE: No attributes returned
2596
+ *
2597
+ * @example
2598
+ * ```typescript
2599
+ * // Get complete updated dinosaur
2600
+ * const result = await builder
2601
+ * .set('status', 'SLEEPING')
2602
+ * .returnValues('ALL_NEW')
2603
+ * .execute();
2604
+ *
2605
+ * // Track specific attribute changes
2606
+ * const result = await builder
2607
+ * .set({
2608
+ * 'stats.health': 100,
2609
+ * 'stats.energy': 95
2610
+ * })
2611
+ * .returnValues('UPDATED_OLD')
2612
+ * .execute();
2613
+ *
2614
+ * if (result.item) {
2615
+ * console.log('Previous health:', result.item.stats?.health);
2616
+ * }
2617
+ * ```
2618
+ *
2619
+ * @param returnValues - Which attributes to return in the response
2620
+ * @returns The builder instance for method chaining
2621
+ */
2622
+ returnValues(returnValues) {
2623
+ this.options.returnValues = returnValues;
2624
+ return this;
2625
+ }
2626
+ /**
2627
+ * Generate the DynamoDB command parameters
2628
+ */
2629
+ toDynamoCommand() {
2630
+ if (this.updates.length === 0) {
2631
+ throw new Error("No update actions specified");
2632
+ }
2633
+ const expressionParams = {
2634
+ expressionAttributeNames: {},
2635
+ expressionAttributeValues: {},
2636
+ valueCounter: { count: 0 }
2637
+ };
2638
+ let updateExpression = "";
2639
+ const setUpdates = [];
2640
+ const removeUpdates = [];
2641
+ const addUpdates = [];
2642
+ const deleteUpdates = [];
2643
+ for (const update of this.updates) {
2644
+ switch (update.type) {
2645
+ case "SET":
2646
+ setUpdates.push(update);
2647
+ break;
2648
+ case "REMOVE":
2649
+ removeUpdates.push(update);
2650
+ break;
2651
+ case "ADD":
2652
+ addUpdates.push(update);
2653
+ break;
2654
+ case "DELETE":
2655
+ deleteUpdates.push(update);
2656
+ break;
2657
+ }
2658
+ }
2659
+ if (setUpdates.length > 0) {
2660
+ updateExpression += "SET ";
2661
+ updateExpression += setUpdates.map((update) => {
2662
+ const attrName = generateAttributeName(expressionParams, update.path);
2663
+ const valueName = generateValueName(expressionParams, update.value);
2664
+ expressionParams.expressionAttributeValues[valueName] = update.value;
2665
+ return `${attrName} = ${valueName}`;
2666
+ }).join(", ");
2667
+ }
2668
+ if (removeUpdates.length > 0) {
2669
+ if (updateExpression) {
2670
+ updateExpression += " ";
2671
+ }
2672
+ updateExpression += "REMOVE ";
2673
+ updateExpression += removeUpdates.map((update) => {
2674
+ return generateAttributeName(expressionParams, update.path);
2675
+ }).join(", ");
2676
+ }
2677
+ if (addUpdates.length > 0) {
2678
+ if (updateExpression) {
2679
+ updateExpression += " ";
2680
+ }
2681
+ updateExpression += "ADD ";
2682
+ updateExpression += addUpdates.map((update) => {
2683
+ const attrName = generateAttributeName(expressionParams, update.path);
2684
+ const valueName = generateValueName(expressionParams, update.value);
2685
+ return `${attrName} ${valueName}`;
2686
+ }).join(", ");
2687
+ }
2688
+ if (deleteUpdates.length > 0) {
2689
+ if (updateExpression) {
2690
+ updateExpression += " ";
2691
+ }
2692
+ updateExpression += "DELETE ";
2693
+ updateExpression += deleteUpdates.map((update) => {
2694
+ const attrName = generateAttributeName(expressionParams, update.path);
2695
+ const valueName = generateValueName(expressionParams, update.value);
2696
+ return `${attrName} ${valueName}`;
2697
+ }).join(", ");
2698
+ }
2699
+ let conditionExpression;
2700
+ if (this.options.condition) {
2701
+ conditionExpression = buildExpression(this.options.condition, expressionParams);
2702
+ }
2703
+ const { expressionAttributeNames, expressionAttributeValues } = expressionParams;
2704
+ return {
2705
+ tableName: this.tableName,
2706
+ key: this.key,
2707
+ updateExpression,
2708
+ conditionExpression,
2709
+ expressionAttributeNames: Object.keys(expressionAttributeNames).length > 0 ? expressionAttributeNames : void 0,
2710
+ expressionAttributeValues: Object.keys(expressionAttributeValues).length > 0 ? expressionAttributeValues : void 0,
2711
+ returnValues: this.options.returnValues
2712
+ };
2713
+ }
2714
+ /**
2715
+ * Adds this update operation to a transaction.
2716
+ *
2717
+ * @example
2718
+ * ```typescript
2719
+ * const transaction = new TransactionBuilder(executor);
2720
+ *
2721
+ * // Update dinosaur status and habitat occupancy atomically
2722
+ * new UpdateBuilder(executor, 'dinosaurs', { id: 'TREX-001' })
2723
+ * .set('location', 'PADDOCK_A')
2724
+ * .set('status', 'CONTAINED')
2725
+ * .withTransaction(transaction);
2726
+ *
2727
+ * new UpdateBuilder(executor, 'habitats', { id: 'PADDOCK-A' })
2728
+ * .add('occupants', 1)
2729
+ * .set('lastOccupied', new Date().toISOString())
2730
+ * .withTransaction(transaction);
2731
+ *
2732
+ * // Execute all operations atomically
2733
+ * await transaction.execute();
2734
+ * ```
2735
+ *
2736
+ * @param transaction - The transaction builder to add this operation to
2737
+ * @returns The builder instance for method chaining
2738
+ */
2739
+ withTransaction(transaction) {
2740
+ const command = this.toDynamoCommand();
2741
+ transaction.updateWithCommand(command);
2742
+ }
2743
+ /**
2744
+ * Gets a human-readable representation of the update command.
2745
+ *
2746
+ * @example
2747
+ * ```typescript
2748
+ * // Create complex update
2749
+ * const builder = new UpdateBuilder(executor, 'dinosaurs', { id: 'RAPTOR-001' })
2750
+ * .set({
2751
+ * status: 'HUNTING',
2752
+ * 'stats.health': 95,
2753
+ * 'behavior.lastObserved': new Date().toISOString()
2754
+ * })
2755
+ * .add('huntingSuccesses', 1)
2756
+ * .condition(op => op.gt('health', 50));
2757
+ *
2758
+ * // Debug the update
2759
+ * const debugInfo = builder.debug();
2760
+ * console.log('Update operation:', debugInfo);
2761
+ * ```
2762
+ *
2763
+ * @returns A readable representation of the update command with resolved expressions
2764
+ */
2765
+ debug() {
2766
+ const command = this.toDynamoCommand();
2767
+ return debugCommand(command);
2768
+ }
2769
+ /**
2770
+ * Executes the update operation against DynamoDB.
2771
+ *
2772
+ * @example
2773
+ * ```typescript
2774
+ * try {
2775
+ * // Update dinosaur status with conditions
2776
+ * const result = await new UpdateBuilder(executor, 'dinosaurs', { id: 'TREX-001' })
2777
+ * .set({
2778
+ * status: 'FEEDING',
2779
+ * lastMeal: new Date().toISOString(),
2780
+ * 'stats.hunger': 0
2781
+ * })
2782
+ * .add('feedingCount', 1)
2783
+ * .condition(op =>
2784
+ * op.and([
2785
+ * op.gt('stats.hunger', 80),
2786
+ * op.eq('status', 'HUNTING')
2787
+ * ])
2788
+ * )
2789
+ * .returnValues('ALL_NEW')
2790
+ * .execute();
2791
+ *
2792
+ * if (result.item) {
2793
+ * console.log('Updated dinosaur:', result.item);
2794
+ * }
2795
+ * } catch (error) {
2796
+ * // Handle condition check failure
2797
+ * console.error('Failed to update dinosaur:', error);
2798
+ * // Check if dinosaur wasn't hungry enough
2799
+ * if (error.name === 'ConditionalCheckFailedException') {
2800
+ * console.log('Dinosaur not ready for feeding');
2801
+ * }
2802
+ * }
2803
+ * ```
2804
+ *
2805
+ * @returns A promise that resolves to an DynamoItem containing the updated item (if returnValues is set)
2806
+ * @throws {ConditionalCheckFailedException} If the condition check fails
2807
+ * @throws {Error} If the update operation fails for other reasons
2808
+ */
2809
+ async execute() {
2810
+ const params = this.toDynamoCommand();
2811
+ return this.executor(params);
2812
+ }
2813
+ };
2814
+
2815
+ // src/builders/condition-check-builder.ts
2816
+ var ConditionCheckBuilder = class {
2817
+ key;
2818
+ tableName;
2819
+ conditionExpression;
2820
+ constructor(tableName, key) {
2821
+ this.tableName = tableName;
2822
+ this.key = key;
2823
+ }
2824
+ /**
2825
+ * Adds a condition that must be satisfied for the check to succeed.
2826
+ *
2827
+ * @example
2828
+ * ```typescript
2829
+ * // Check dinosaur health and behavior
2830
+ * builder.condition(op =>
2831
+ * op.and([
2832
+ * op.gt('stats.health', 50),
2833
+ * op.not(op.eq('status', 'SEDATED')),
2834
+ * op.lt('aggressionLevel', 8)
2835
+ * ])
2836
+ * );
2837
+ *
2838
+ * // Verify habitat conditions
2839
+ * builder.condition(op =>
2840
+ * op.and([
2841
+ * op.eq('powerStatus', 'ONLINE'),
2842
+ * op.between('temperature', 20, 30),
2843
+ * op.attributeExists('lastMaintenance')
2844
+ * ])
2845
+ * );
2846
+ *
2847
+ * // Check breeding conditions
2848
+ * builder.condition(op =>
2849
+ * op.and([
2850
+ * op.eq('species', 'VELOCIRAPTOR'),
2851
+ * op.gte('age', 3),
2852
+ * op.eq('geneticPurity', 100)
2853
+ * ])
2854
+ * );
2855
+ * ```
2856
+ *
2857
+ * @param condition - Either a Condition DynamoItem or a callback function that builds the condition
2858
+ * @returns The builder instance for method chaining
2859
+ */
2860
+ condition(condition) {
2861
+ if (typeof condition === "function") {
2862
+ const conditionOperator = {
2863
+ eq: chunk7UJJ7JXM_cjs.eq,
2864
+ ne: chunk7UJJ7JXM_cjs.ne,
2865
+ lt: chunk7UJJ7JXM_cjs.lt,
2866
+ lte: chunk7UJJ7JXM_cjs.lte,
2867
+ gt: chunk7UJJ7JXM_cjs.gt,
2868
+ gte: chunk7UJJ7JXM_cjs.gte,
2869
+ between: chunk7UJJ7JXM_cjs.between,
2870
+ inArray: chunk7UJJ7JXM_cjs.inArray,
2871
+ beginsWith: chunk7UJJ7JXM_cjs.beginsWith,
2872
+ contains: chunk7UJJ7JXM_cjs.contains,
2873
+ attributeExists: chunk7UJJ7JXM_cjs.attributeExists,
2874
+ attributeNotExists: chunk7UJJ7JXM_cjs.attributeNotExists,
2875
+ and: chunk7UJJ7JXM_cjs.and,
2876
+ or: chunk7UJJ7JXM_cjs.or,
2877
+ not: chunk7UJJ7JXM_cjs.not
2878
+ };
2879
+ this.conditionExpression = condition(conditionOperator);
2880
+ } else {
2881
+ this.conditionExpression = condition;
2882
+ }
2883
+ return this;
2884
+ }
2885
+ /**
2886
+ * Generates the DynamoDB command parameters for direct execution.
2887
+ * Use this method when you want to:
2888
+ * - Execute the condition check as a standalone operation
2889
+ * - Get the raw DynamoDB command for custom execution
2890
+ * - Inspect the generated command parameters
2891
+ *
2892
+ * @example
2893
+ * ```ts
2894
+ * const command = new ConditionCheckBuilder('myTable', { id: '123' })
2895
+ * .condition(op => op.attributeExists('status'))
2896
+ * .toDynamoCommand();
2897
+ * // Use command with DynamoDB client
2898
+ * ```
2899
+ *
2900
+ * @throws {Error} If no condition has been set
2901
+ * @returns The DynamoDB command parameters
2902
+ */
2903
+ toDynamoCommand() {
2904
+ if (!this.conditionExpression) {
2905
+ throw new Error("Condition is required for condition check operations");
2906
+ }
2907
+ const { expression, names, values } = prepareExpressionParams(this.conditionExpression);
2908
+ if (!expression) {
2909
+ throw new Error("Failed to generate condition expression");
2910
+ }
2911
+ return {
2912
+ tableName: this.tableName,
2913
+ key: this.key,
2914
+ conditionExpression: expression,
2915
+ expressionAttributeNames: names,
2916
+ expressionAttributeValues: values
2917
+ };
2918
+ }
2919
+ /**
2920
+ * Adds this condition check operation to a transaction.
2921
+ *
2922
+ * @example
2923
+ * ```ts
2924
+ * const transaction = new TransactionBuilder();
2925
+ * new ConditionCheckBuilder('habitats', { id: 'PADDOCK-B' })
2926
+ * .condition(op => op.and([
2927
+ * op.eq('securityStatus', 'ACTIVE'),
2928
+ * op.lt('currentOccupants', 3),
2929
+ * op.eq('habitatType', 'CARNIVORE')
2930
+ * ]))
2931
+ * .withTransaction(transaction);
2932
+ * // Add dinosaur transfer operations
2933
+ * ```
2934
+ *
2935
+ * @param transaction - The transaction builder to add this operation to
2936
+ * @throws {Error} If no condition has been set
2937
+ * @returns The builder instance for method chaining
2938
+ */
2939
+ withTransaction(transaction) {
2940
+ if (!this.conditionExpression) {
2941
+ throw new Error("Condition is required for condition check operations");
2942
+ }
2943
+ const command = this.toDynamoCommand();
2944
+ transaction.conditionCheckWithCommand(command);
2945
+ return this;
2946
+ }
2947
+ /**
2948
+ * Gets a human-readable representation of the condition check command
2949
+ * with all expression placeholders replaced by their actual values.
2950
+ *
2951
+ * @example
2952
+ * ```ts
2953
+ * const debugInfo = new ConditionCheckBuilder('dinosaurs', { id: 'TREX-001' })
2954
+ * .condition(op => op.and([
2955
+ * op.between('stats.health', 50, 100),
2956
+ * op.not(op.eq('status', 'SEDATED')),
2957
+ * op.attributeExists('lastFeedingTime')
2958
+ * op.eq('version', 1)
2959
+ * ]))
2960
+ * .debug();
2961
+ * console.log(debugInfo);
2962
+ * ```
2963
+ *
2964
+ * @returns A readable representation of the condition check command with resolved expressions
2965
+ */
2966
+ debug() {
2967
+ const command = this.toDynamoCommand();
2968
+ return debugCommand(command);
2969
+ }
2970
+ };
2971
+
2972
+ // src/builders/get-builder.ts
2973
+ var GetBuilder = class {
2974
+ /**
2975
+ * Creates a new GetBuilder instance.
2976
+ *
2977
+ * @param executor - Function that executes the get operation
2978
+ * @param key - Primary key of the item to retrieve
2979
+ * @param tableName - Name of the DynamoDB table
2980
+ */
2981
+ constructor(executor, key, tableName) {
2982
+ this.executor = executor;
2983
+ this.params = {
2984
+ tableName,
2985
+ key
2986
+ };
2987
+ }
2988
+ params;
2989
+ options = {};
2990
+ selectedFields = /* @__PURE__ */ new Set();
2991
+ /**
2992
+ * Specifies which attributes to return in the get results.
2993
+ *
2994
+ * @example
2995
+ * ```typescript
2996
+ * // Select single attribute
2997
+ * builder.select('species')
2998
+ *
2999
+ * // Select multiple attributes
3000
+ * builder.select(['id', 'species', 'diet'])
3001
+ *
3002
+ * // Chain multiple select calls
3003
+ * builder
3004
+ * .select('id')
3005
+ * .select(['species', 'diet'])
3006
+ * ```
3007
+ *
3008
+ * @param fields - A single field name or an array of field names to return
3009
+ * @returns The builder instance for method chaining
3010
+ */
3011
+ select(fields) {
3012
+ if (typeof fields === "string") {
3013
+ this.selectedFields.add(fields);
3014
+ } else if (Array.isArray(fields)) {
3015
+ for (const field of fields) {
3016
+ this.selectedFields.add(field);
3017
+ }
3018
+ }
3019
+ this.options.projection = Array.from(this.selectedFields);
3020
+ return this;
3021
+ }
3022
+ /**
3023
+ * Sets whether to use strongly consistent reads for the get operation.
3024
+ * Use this method when you need:
3025
+ * - The most up-to-date dinosaur data
3026
+ * - To ensure you're reading the latest dinosaur status
3027
+ * - Critical safety information about dangerous species
3028
+ *
3029
+ * Note: Consistent reads consume twice the throughput
3030
+ *
3031
+ * @example
3032
+ * ```typescript
3033
+ * // Get the latest T-Rex data
3034
+ * const result = await new GetBuilder(executor, { pk: 'dinosaur#123', sk: 'profile' })
3035
+ * .consistentRead()
3036
+ * .execute();
3037
+ * ```
3038
+ *
3039
+ * @param consistentRead - Whether to use consistent reads (defaults to true)
3040
+ * @returns The builder instance for method chaining
3041
+ */
3042
+ consistentRead(consistentRead = true) {
3043
+ this.params.consistentRead = consistentRead;
3044
+ return this;
3045
+ }
3046
+ /**
3047
+ * Adds this get operation to a batch with optional entity type information.
3048
+ *
3049
+ * @example Basic Usage
3050
+ * ```ts
3051
+ * const batch = table.batchBuilder();
3052
+ *
3053
+ * // Add multiple get operations to batch
3054
+ * dinosaurRepo.get({ id: 'dino-1' }).withBatch(batch);
3055
+ * dinosaurRepo.get({ id: 'dino-2' }).withBatch(batch);
3056
+ * dinosaurRepo.get({ id: 'dino-3' }).withBatch(batch);
3057
+ *
3058
+ * // Execute all gets efficiently
3059
+ * const results = await batch.execute();
3060
+ * ```
3061
+ *
3062
+ * @example Typed Usage
3063
+ * ```ts
3064
+ * const batch = table.batchBuilder<{
3065
+ * User: UserEntity;
3066
+ * Order: OrderEntity;
3067
+ * }>();
3068
+ *
3069
+ * // Add operations with type information
3070
+ * userRepo.get({ id: 'user-1' }).withBatch(batch, 'User');
3071
+ * orderRepo.get({ id: 'order-1' }).withBatch(batch, 'Order');
3072
+ *
3073
+ * // Execute and get typed results
3074
+ * const result = await batch.execute();
3075
+ * const users: UserEntity[] = result.reads.itemsByType.User;
3076
+ * const orders: OrderEntity[] = result.reads.itemsByType.Order;
3077
+ * ```
3078
+ *
3079
+ * @param batch - The batch builder to add this operation to
3080
+ * @param entityType - Optional entity type key for type tracking
3081
+ */
3082
+ withBatch(batch, entityType) {
3083
+ const command = this.toDynamoCommand();
3084
+ batch.getWithCommand(command, entityType);
3085
+ }
3086
+ /**
3087
+ * Converts the builder configuration to a DynamoDB command
3088
+ */
3089
+ toDynamoCommand() {
3090
+ const expressionParams = {
3091
+ expressionAttributeNames: {}};
3092
+ const projectionExpression = Array.from(this.selectedFields).map((p) => generateAttributeName(expressionParams, p)).join(", ");
3093
+ const { expressionAttributeNames } = expressionParams;
3094
+ return {
3095
+ ...this.params,
3096
+ projectionExpression: projectionExpression.length > 0 ? projectionExpression : void 0,
3097
+ expressionAttributeNames: Object.keys(expressionAttributeNames).length > 0 ? expressionAttributeNames : void 0
3098
+ };
3099
+ }
3100
+ /**
3101
+ * Executes the get operation against DynamoDB.
3102
+ *
3103
+ * @example
3104
+ * ```typescript
3105
+ * try {
3106
+ * const result = await new GetBuilder(executor, { pk: 'dinosaur#123', sk: 'profile' })
3107
+ * .select(['species', 'name', 'diet'])
3108
+ * .consistentRead()
3109
+ * .execute();
3110
+ *
3111
+ * if (result.item) {
3112
+ * console.log('Dinosaur found:', result.item);
3113
+ * } else {
3114
+ * console.log('Dinosaur not found');
3115
+ * }
3116
+ * } catch (error) {
3117
+ * console.error('Error getting dinosaur:', error);
3118
+ * }
3119
+ * ```
3120
+ *
3121
+ * @returns A promise that resolves to an object containing:
3122
+ * - item: The retrieved dinosaur or undefined if not found
3123
+ */
3124
+ async execute() {
3125
+ const command = this.toDynamoCommand();
3126
+ return this.executor(command);
3127
+ }
3128
+ };
3129
+
3130
+ // src/builders/scan-builder.ts
3131
+ var ScanBuilder = class _ScanBuilder extends FilterBuilder {
3132
+ executor;
3133
+ constructor(executor) {
3134
+ super();
3135
+ this.executor = executor;
3136
+ }
3137
+ /**
3138
+ * Creates a deep clone of this ScanBuilder instance.
3139
+ *
3140
+ * @returns A new ScanBuilder instance with the same configuration
3141
+ */
3142
+ clone() {
3143
+ const clone = new _ScanBuilder(this.executor);
3144
+ clone.options = {
3145
+ ...this.options,
3146
+ filter: this.deepCloneFilter(this.options.filter)
3147
+ };
3148
+ clone.selectedFields = new Set(this.selectedFields);
3149
+ return clone;
3150
+ }
3151
+ deepCloneFilter(filter) {
3152
+ if (!filter) return filter;
3153
+ if (filter.type === "and" || filter.type === "or") {
3154
+ return {
3155
+ ...filter,
3156
+ conditions: filter.conditions?.map((condition) => this.deepCloneFilter(condition)).filter((c) => c !== void 0)
3157
+ };
3158
+ }
3159
+ return { ...filter };
3160
+ }
3161
+ /**
3162
+ * Executes the scan against DynamoDB and returns a generator that behaves like an array.
3163
+ *
3164
+ * The generator automatically handles pagination and provides array-like methods
3165
+ * for processing results efficiently without loading everything into memory at once.
3166
+ *
3167
+ * @example
3168
+ * ```typescript
3169
+ * try {
3170
+ * // Find all dinosaurs with high aggression levels with automatic pagination
3171
+ * const results = await new ScanBuilder(executor)
3172
+ * .filter(op =>
3173
+ * op.and([
3174
+ * op.eq('status', 'ACTIVE'),
3175
+ * op.gt('aggressionLevel', 7)
3176
+ * ])
3177
+ * )
3178
+ * .execute();
3179
+ *
3180
+ * // Use like an array with automatic pagination
3181
+ * for await (const dinosaur of results) {
3182
+ * console.log(`Processing dangerous dinosaur: ${dinosaur.name}`);
3183
+ * }
3184
+ *
3185
+ * // Or convert to array and use array methods
3186
+ * const allItems = await results.toArray();
3187
+ * const criticalThreats = allItems.filter(dino => dino.aggressionLevel > 9);
3188
+ * const totalCount = allItems.length;
3189
+ * } catch (error) {
3190
+ * console.error('Security scan failed:', error);
3191
+ * }
3192
+ * ```
3193
+ *
3194
+ * @returns A promise that resolves to a ResultGenerator that behaves like an array
3195
+ */
3196
+ async execute() {
3197
+ const directExecutor = () => this.executor(this.options);
3198
+ return new ResultIterator(this, directExecutor);
3199
+ }
3200
+ };
3201
+
3202
+ exports.BatchBuilder = BatchBuilder;
3203
+ exports.BatchError = BatchError;
3204
+ exports.ConditionCheckBuilder = ConditionCheckBuilder;
3205
+ exports.DeleteBuilder = DeleteBuilder;
3206
+ exports.FilterBuilder = FilterBuilder;
3207
+ exports.GetBuilder = GetBuilder;
3208
+ exports.Paginator = Paginator;
3209
+ exports.PutBuilder = PutBuilder;
3210
+ exports.QueryBuilder = QueryBuilder;
3211
+ exports.ResultIterator = ResultIterator;
3212
+ exports.ScanBuilder = ScanBuilder;
3213
+ exports.TransactionBuilder = TransactionBuilder;
3214
+ exports.UpdateBuilder = UpdateBuilder;
3215
+ exports.buildExpression = buildExpression;
3216
+ exports.debugCommand = debugCommand;
3217
+ exports.generateAttributeName = generateAttributeName;