dyno-table 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/README.md +200 -1860
  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-CC3NDfUU.d.cts → conditions-CcZL0sR2.d.cts} +1 -1
  17. package/dist/{conditions-DD0bvyHm.d.ts → conditions-D_w7vVYG.d.ts} +1 -1
  18. package/dist/conditions.cjs +67 -62
  19. package/dist/conditions.d.cts +1 -1
  20. package/dist/conditions.d.ts +1 -1
  21. package/dist/conditions.js +1 -48
  22. package/dist/entity.cjs +14 -625
  23. package/dist/entity.d.cts +5 -13
  24. package/dist/entity.d.ts +5 -13
  25. package/dist/entity.js +2 -626
  26. package/dist/index-2cbm07Bi.d.ts +2797 -0
  27. package/dist/index-DlN8G9hd.d.cts +2797 -0
  28. package/dist/index.cjs +111 -4446
  29. package/dist/index.d.cts +3 -11
  30. package/dist/index.d.ts +3 -11
  31. package/dist/index.js +5 -4428
  32. package/dist/standard-schema.cjs +0 -2
  33. package/dist/standard-schema.js +0 -2
  34. package/dist/table.cjs +7 -3782
  35. package/dist/table.d.cts +163 -12
  36. package/dist/table.d.ts +163 -12
  37. package/dist/table.js +3 -3785
  38. package/dist/types.cjs +0 -2
  39. package/dist/types.js +0 -2
  40. package/dist/utils.cjs +10 -30
  41. package/dist/utils.js +1 -31
  42. package/package.json +12 -67
  43. package/dist/batch-builder-BPoHyN_Q.d.cts +0 -398
  44. package/dist/batch-builder-Cdo49C2r.d.ts +0 -398
  45. package/dist/builder-types-BTVhQSHI.d.cts +0 -169
  46. package/dist/builder-types-CzuLR4Th.d.ts +0 -169
  47. package/dist/builders/condition-check-builder.cjs +0 -422
  48. package/dist/builders/condition-check-builder.cjs.map +0 -1
  49. package/dist/builders/condition-check-builder.d.cts +0 -153
  50. package/dist/builders/condition-check-builder.d.ts +0 -153
  51. package/dist/builders/condition-check-builder.js +0 -420
  52. package/dist/builders/condition-check-builder.js.map +0 -1
  53. package/dist/builders/delete-builder.cjs +0 -484
  54. package/dist/builders/delete-builder.cjs.map +0 -1
  55. package/dist/builders/delete-builder.d.cts +0 -211
  56. package/dist/builders/delete-builder.d.ts +0 -211
  57. package/dist/builders/delete-builder.js +0 -482
  58. package/dist/builders/delete-builder.js.map +0 -1
  59. package/dist/builders/paginator.cjs +0 -193
  60. package/dist/builders/paginator.cjs.map +0 -1
  61. package/dist/builders/paginator.d.cts +0 -155
  62. package/dist/builders/paginator.d.ts +0 -155
  63. package/dist/builders/paginator.js +0 -191
  64. package/dist/builders/paginator.js.map +0 -1
  65. package/dist/builders/put-builder.cjs +0 -554
  66. package/dist/builders/put-builder.cjs.map +0 -1
  67. package/dist/builders/put-builder.d.cts +0 -319
  68. package/dist/builders/put-builder.d.ts +0 -319
  69. package/dist/builders/put-builder.js +0 -552
  70. package/dist/builders/put-builder.js.map +0 -1
  71. package/dist/builders/query-builder.cjs +0 -743
  72. package/dist/builders/query-builder.cjs.map +0 -1
  73. package/dist/builders/query-builder.d.cts +0 -6
  74. package/dist/builders/query-builder.d.ts +0 -6
  75. package/dist/builders/query-builder.js +0 -741
  76. package/dist/builders/query-builder.js.map +0 -1
  77. package/dist/builders/transaction-builder.cjs +0 -906
  78. package/dist/builders/transaction-builder.cjs.map +0 -1
  79. package/dist/builders/transaction-builder.d.cts +0 -464
  80. package/dist/builders/transaction-builder.d.ts +0 -464
  81. package/dist/builders/transaction-builder.js +0 -904
  82. package/dist/builders/transaction-builder.js.map +0 -1
  83. package/dist/builders/update-builder.cjs +0 -668
  84. package/dist/builders/update-builder.cjs.map +0 -1
  85. package/dist/builders/update-builder.d.cts +0 -374
  86. package/dist/builders/update-builder.d.ts +0 -374
  87. package/dist/builders/update-builder.js +0 -666
  88. package/dist/builders/update-builder.js.map +0 -1
  89. package/dist/conditions.cjs.map +0 -1
  90. package/dist/conditions.js.map +0 -1
  91. package/dist/entity.cjs.map +0 -1
  92. package/dist/entity.js.map +0 -1
  93. package/dist/index.cjs.map +0 -1
  94. package/dist/index.js.map +0 -1
  95. package/dist/query-builder-CUWdavZw.d.ts +0 -477
  96. package/dist/query-builder-DoZzZz_c.d.cts +0 -477
  97. package/dist/standard-schema.cjs.map +0 -1
  98. package/dist/standard-schema.js.map +0 -1
  99. package/dist/table-CZBMkW2Z.d.ts +0 -276
  100. package/dist/table-f-3wsT7K.d.cts +0 -276
  101. package/dist/table.cjs.map +0 -1
  102. package/dist/table.js.map +0 -1
  103. package/dist/types.cjs.map +0 -1
  104. package/dist/types.js.map +0 -1
  105. package/dist/utils.cjs.map +0 -1
  106. package/dist/utils.js.map +0 -1
@@ -1,906 +0,0 @@
1
- 'use strict';
2
-
3
- // src/expression.ts
4
- var generateAttributeName = (params, attr) => {
5
- if (attr.includes(".")) {
6
- const pathSegments = attr.split(".");
7
- const segmentNames = [];
8
- for (const segment of pathSegments) {
9
- let segmentName;
10
- for (const [existingName, existingAttr] of Object.entries(params.expressionAttributeNames)) {
11
- if (existingAttr === segment) {
12
- segmentName = existingName;
13
- break;
14
- }
15
- }
16
- if (!segmentName) {
17
- segmentName = `#${Object.keys(params.expressionAttributeNames).length}`;
18
- params.expressionAttributeNames[segmentName] = segment;
19
- }
20
- segmentNames.push(segmentName);
21
- }
22
- return segmentNames.join(".");
23
- }
24
- for (const [existingName, existingAttr] of Object.entries(params.expressionAttributeNames)) {
25
- if (existingAttr === attr) {
26
- return existingName;
27
- }
28
- }
29
- const attrName = `#${Object.keys(params.expressionAttributeNames).length}`;
30
- params.expressionAttributeNames[attrName] = attr;
31
- return attrName;
32
- };
33
- var generateValueName = (params, value) => {
34
- const valueName = `:${params.valueCounter.count++}`;
35
- params.expressionAttributeValues[valueName] = value;
36
- return valueName;
37
- };
38
- var validateCondition = (condition, requiresAttr = true, requiresValue = true) => {
39
- if (requiresAttr && !condition.attr) {
40
- throw new Error(`Attribute is required for ${condition.type} condition`);
41
- }
42
- if (requiresValue && condition.value === void 0) {
43
- throw new Error(`Value is required for ${condition.type} condition`);
44
- }
45
- };
46
- var buildComparisonExpression = (condition, operator, params) => {
47
- validateCondition(condition);
48
- if (!condition.attr) {
49
- throw new Error(`Attribute is required for ${condition.type} condition`);
50
- }
51
- const attrName = generateAttributeName(params, condition.attr);
52
- const valueName = generateValueName(params, condition.value);
53
- return `${attrName} ${operator} ${valueName}`;
54
- };
55
- var buildBetweenExpression = (condition, params) => {
56
- validateCondition(condition);
57
- if (!condition.attr) {
58
- throw new Error(`Attribute is required for ${condition.type} condition`);
59
- }
60
- if (!Array.isArray(condition.value) || condition.value.length !== 2) {
61
- throw new Error("Between condition requires an array of two values");
62
- }
63
- const attrName = generateAttributeName(params, condition.attr);
64
- const lowerName = generateValueName(params, condition.value[0]);
65
- const upperName = generateValueName(params, condition.value[1]);
66
- return `${attrName} BETWEEN ${lowerName} AND ${upperName}`;
67
- };
68
- var buildInExpression = (condition, params) => {
69
- validateCondition(condition);
70
- if (!condition.attr) {
71
- throw new Error(`Attribute is required for ${condition.type} condition`);
72
- }
73
- if (!Array.isArray(condition.value) || condition.value.length === 0) {
74
- throw new Error("In condition requires a non-empty array of values");
75
- }
76
- if (condition.value.length > 100) {
77
- throw new Error("In condition supports a maximum of 100 values");
78
- }
79
- const attrName = generateAttributeName(params, condition.attr);
80
- const valueNames = condition.value.map((value) => generateValueName(params, value));
81
- return `${attrName} IN (${valueNames.join(", ")})`;
82
- };
83
- var buildFunctionExpression = (functionName, condition, params) => {
84
- validateCondition(condition);
85
- if (!condition.attr) {
86
- throw new Error(`Attribute is required for ${condition.type} condition`);
87
- }
88
- const attrName = generateAttributeName(params, condition.attr);
89
- const valueName = generateValueName(params, condition.value);
90
- return `${functionName}(${attrName}, ${valueName})`;
91
- };
92
- var buildAttributeFunction = (functionName, condition, params) => {
93
- validateCondition(condition, true, false);
94
- if (!condition.attr) {
95
- throw new Error(`Attribute is required for ${condition.type} condition`);
96
- }
97
- const attrName = generateAttributeName(params, condition.attr);
98
- return `${functionName}(${attrName})`;
99
- };
100
- var buildLogicalExpression = (operator, conditions, params) => {
101
- if (!conditions || conditions.length === 0) {
102
- throw new Error(`At least one condition is required for ${operator} expression`);
103
- }
104
- const expressions = conditions.map((c) => buildExpression(c, params));
105
- return `(${expressions.join(` ${operator} `)})`;
106
- };
107
- var buildExpression = (condition, params) => {
108
- if (!condition) return "";
109
- try {
110
- const expressionBuilders = {
111
- eq: () => buildComparisonExpression(condition, "=", params),
112
- ne: () => buildComparisonExpression(condition, "<>", params),
113
- lt: () => buildComparisonExpression(condition, "<", params),
114
- lte: () => buildComparisonExpression(condition, "<=", params),
115
- gt: () => buildComparisonExpression(condition, ">", params),
116
- gte: () => buildComparisonExpression(condition, ">=", params),
117
- between: () => buildBetweenExpression(condition, params),
118
- in: () => buildInExpression(condition, params),
119
- beginsWith: () => buildFunctionExpression("begins_with", condition, params),
120
- contains: () => buildFunctionExpression("contains", condition, params),
121
- attributeExists: () => buildAttributeFunction("attribute_exists", condition, params),
122
- attributeNotExists: () => buildAttributeFunction("attribute_not_exists", condition, params),
123
- and: () => {
124
- if (!condition.conditions) {
125
- throw new Error("Conditions array is required for AND operator");
126
- }
127
- return buildLogicalExpression("AND", condition.conditions, params);
128
- },
129
- or: () => {
130
- if (!condition.conditions) {
131
- throw new Error("Conditions array is required for OR operator");
132
- }
133
- return buildLogicalExpression("OR", condition.conditions, params);
134
- },
135
- not: () => {
136
- if (!condition.condition) {
137
- throw new Error("Condition is required for NOT operator");
138
- }
139
- return `NOT (${buildExpression(condition.condition, params)})`;
140
- }
141
- };
142
- const builder = expressionBuilders[condition.type];
143
- if (!builder) {
144
- throw new Error(`Unknown condition type: ${condition.type}`);
145
- }
146
- return builder();
147
- } catch (error) {
148
- if (error instanceof Error) {
149
- console.error(`Error building expression for condition type ${condition.type}:`, error.message);
150
- } else {
151
- console.error(`Error building expression for condition type ${condition.type}:`, error);
152
- }
153
- throw error;
154
- }
155
- };
156
- var prepareExpressionParams = (condition) => {
157
- if (!condition) return {};
158
- const params = {
159
- expressionAttributeNames: {},
160
- expressionAttributeValues: {},
161
- valueCounter: { count: 0 }
162
- };
163
- const expression = buildExpression(condition, params);
164
- return {
165
- expression,
166
- names: Object.keys(params.expressionAttributeNames).length > 0 ? params.expressionAttributeNames : void 0,
167
- values: Object.keys(params.expressionAttributeValues).length > 0 ? params.expressionAttributeValues : void 0
168
- };
169
- };
170
-
171
- // src/utils/debug-expression.ts
172
- function debugCommand(command) {
173
- const result = {};
174
- function replaceAliases(expressionString) {
175
- if (!expressionString) {
176
- return expressionString;
177
- }
178
- let replacedString = expressionString;
179
- for (const alias in command.expressionAttributeNames) {
180
- const attributeName = command.expressionAttributeNames[alias];
181
- const regex = new RegExp(alias, "g");
182
- replacedString = replacedString.replace(regex, attributeName);
183
- }
184
- for (const alias in command.expressionAttributeValues) {
185
- let attributeValue = command.expressionAttributeValues[alias];
186
- if (attributeValue instanceof Set) {
187
- const array = Array.from(attributeValue);
188
- attributeValue = `Set(${array.length}){${array.map((v) => JSON.stringify(v)).join(", ")}}`;
189
- } else {
190
- attributeValue = JSON.stringify(attributeValue);
191
- }
192
- const regex = new RegExp(alias, "g");
193
- replacedString = replacedString.replace(regex, attributeValue);
194
- }
195
- return replacedString;
196
- }
197
- if (command.updateExpression) {
198
- result.updateExpression = replaceAliases(command.updateExpression);
199
- }
200
- if (command.conditionExpression) {
201
- result.conditionExpression = replaceAliases(command.conditionExpression);
202
- }
203
- if (command.filterExpression) {
204
- result.filterExpression = replaceAliases(command.filterExpression);
205
- }
206
- if (command.keyConditionExpression) {
207
- result.keyConditionExpression = replaceAliases(command.keyConditionExpression);
208
- }
209
- if (command.projectionExpression) {
210
- result.projectionExpression = replaceAliases(command.projectionExpression);
211
- }
212
- return {
213
- raw: command,
214
- readable: result
215
- };
216
- }
217
-
218
- // src/utils/debug-transaction.ts
219
- function debugTransactionItem(item) {
220
- const result = {
221
- type: item.type,
222
- tableName: item.params.tableName
223
- };
224
- if ("key" in item.params) {
225
- result.key = item.params.key;
226
- }
227
- if (item.type === "Put") {
228
- result.item = item.params.item;
229
- }
230
- switch (item.type) {
231
- case "Put":
232
- case "Delete":
233
- case "ConditionCheck":
234
- result.readable = debugCommand(item.params).readable;
235
- break;
236
- case "Update":
237
- result.readable = debugCommand(item.params).readable;
238
- break;
239
- }
240
- return result;
241
- }
242
- function debugTransaction(items) {
243
- return items.map((item) => debugTransactionItem(item));
244
- }
245
-
246
- // src/builders/transaction-builder.ts
247
- var TransactionBuilder = class {
248
- items = [];
249
- options = {};
250
- indexConfig;
251
- executor;
252
- constructor(executor, indexConfig) {
253
- this.executor = executor;
254
- this.indexConfig = indexConfig;
255
- }
256
- /**
257
- * Checks if an item with the same primary key already exists in the transaction
258
- * @private
259
- */
260
- checkForDuplicateItem(tableName, newItem) {
261
- const pkName = this.indexConfig.partitionKey;
262
- const skName = this.indexConfig.sortKey ?? "";
263
- const pkValue = newItem[pkName];
264
- const skValue = skName ? newItem[skName] : void 0;
265
- if (!pkValue) {
266
- throw new Error(`Primary key value for '${pkName}' is missing`);
267
- }
268
- const duplicateItem = this.items.find((item) => {
269
- let itemKey;
270
- let itemTableName;
271
- switch (item.type) {
272
- case "Put":
273
- itemTableName = item.params.tableName;
274
- itemKey = item.params.item;
275
- break;
276
- case "Update":
277
- case "Delete":
278
- case "ConditionCheck":
279
- itemTableName = item.params.tableName;
280
- itemKey = item.params.key;
281
- break;
282
- }
283
- if (itemTableName === tableName && itemKey) {
284
- const itemPkValue = itemKey[pkName];
285
- const itemSkValue = skName ? itemKey[skName] : void 0;
286
- if (itemPkValue === pkValue) {
287
- if (skValue === void 0 && itemSkValue === void 0) {
288
- return true;
289
- }
290
- if (skValue !== void 0 && itemSkValue !== void 0 && skValue === itemSkValue) {
291
- return true;
292
- }
293
- }
294
- }
295
- return false;
296
- });
297
- if (duplicateItem) {
298
- throw new Error(
299
- `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.`
300
- );
301
- }
302
- }
303
- createKeyForPrimaryIndex(key) {
304
- const keyCondition = {
305
- [this.indexConfig.partitionKey]: key.pk
306
- };
307
- if (this.indexConfig.sortKey) {
308
- if (key.sk === void 0) {
309
- throw new Error("Sort key is required for delete operation");
310
- }
311
- keyCondition[this.indexConfig.sortKey] = key.sk;
312
- }
313
- return keyCondition;
314
- }
315
- /**
316
- * Adds a put operation to the transaction.
317
- *
318
- * The method automatically checks for duplicate items within the transaction
319
- * to prevent multiple operations on the same item.
320
- *
321
- * @example
322
- * ```typescript
323
- * // Simple put operation
324
- * transaction.put('orders', {
325
- * orderId: '123',
326
- * status: 'PENDING',
327
- * amount: 100
328
- * });
329
- *
330
- * // Conditional put operation
331
- * transaction.put(
332
- * 'inventory',
333
- * { productId: 'ABC', quantity: 50 },
334
- * op => op.attributeNotExists('productId')
335
- * );
336
- *
337
- * // Put with complex condition
338
- * transaction.put(
339
- * 'users',
340
- * { userId: '123', status: 'ACTIVE' },
341
- * op => op.and([
342
- * op.attributeNotExists('userId'),
343
- * op.beginsWith('status', 'ACTIVE')
344
- * ])
345
- * );
346
- * ```
347
- *
348
- * @param tableName - The name of the DynamoDB table
349
- * @param item - The item to put into the table
350
- * @param condition - Optional condition that must be satisfied
351
- * @returns The transaction builder for method chaining
352
- * @throws {Error} If a duplicate item is detected in the transaction
353
- */
354
- put(tableName, item, condition) {
355
- this.checkForDuplicateItem(tableName, item);
356
- const transactionItem = {
357
- type: "Put",
358
- params: {
359
- tableName,
360
- item
361
- }
362
- };
363
- if (condition) {
364
- const { expression, names, values } = prepareExpressionParams(condition);
365
- transactionItem.params.conditionExpression = expression;
366
- transactionItem.params.expressionAttributeNames = names;
367
- transactionItem.params.expressionAttributeValues = values;
368
- }
369
- this.items.push(transactionItem);
370
- return this;
371
- }
372
- /**
373
- * Adds a pre-configured put operation to the transaction.
374
- *
375
- * This method is particularly useful when working with PutBuilder
376
- * to maintain consistency in put operations across your application.
377
- *
378
- * @example
379
- * ```typescript
380
- * // Create a put command with PutBuilder
381
- * const putCommand = new PutBuilder(executor, newItem, 'users')
382
- * .condition(op => op.attributeNotExists('userId'))
383
- * .toDynamoCommand();
384
- *
385
- * // Add the command to the transaction
386
- * transaction.putWithCommand(putCommand);
387
- * ```
388
- *
389
- * @param command - The complete put command configuration
390
- * @returns The transaction builder for method chaining
391
- * @throws {Error} If a duplicate item is detected in the transaction
392
- * @see PutBuilder for creating put commands
393
- */
394
- putWithCommand(command) {
395
- this.checkForDuplicateItem(command.tableName, command.item);
396
- const transactionItem = {
397
- type: "Put",
398
- params: command
399
- };
400
- this.items.push(transactionItem);
401
- return this;
402
- }
403
- /**
404
- * Adds a delete operation to the transaction.
405
- *
406
- * The method automatically checks for duplicate items within the transaction
407
- * to prevent multiple operations on the same item.
408
- *
409
- * @example
410
- * ```typescript
411
- * // Simple delete operation
412
- * transaction.delete('orders', {
413
- * pk: 'ORDER#123',
414
- * sk: 'METADATA'
415
- * });
416
- *
417
- * // Conditional delete operation
418
- * transaction.delete(
419
- * 'users',
420
- * { pk: 'USER#123' },
421
- * op => op.eq('status', 'INACTIVE')
422
- * );
423
- *
424
- * // Delete with complex condition
425
- * transaction.delete(
426
- * 'products',
427
- * { pk: 'PROD#ABC' },
428
- * op => op.and([
429
- * op.eq('status', 'DRAFT'),
430
- * op.lt('version', 5)
431
- * ])
432
- * );
433
- * ```
434
- *
435
- * @param tableName - The name of the DynamoDB table
436
- * @param key - The primary key of the item to delete
437
- * @param condition - Optional condition that must be satisfied
438
- * @returns The transaction builder for method chaining
439
- * @throws {Error} If a duplicate item is detected in the transaction
440
- */
441
- delete(tableName, key, condition) {
442
- const keyCondition = this.createKeyForPrimaryIndex(key);
443
- this.checkForDuplicateItem(tableName, keyCondition);
444
- const transactionItem = {
445
- type: "Delete",
446
- params: {
447
- tableName,
448
- key: keyCondition
449
- }
450
- };
451
- if (condition) {
452
- const { expression, names, values } = prepareExpressionParams(condition);
453
- transactionItem.params.conditionExpression = expression;
454
- transactionItem.params.expressionAttributeNames = names;
455
- transactionItem.params.expressionAttributeValues = values;
456
- }
457
- this.items.push(transactionItem);
458
- return this;
459
- }
460
- /**
461
- * Adds a pre-configured delete operation to the transaction.
462
- *
463
- * This method is particularly useful when working with DeleteBuilder
464
- * to maintain consistency in delete operations across your application.
465
- *
466
- * @example
467
- * ```typescript
468
- * // Create a delete command with DeleteBuilder
469
- * const deleteCommand = new DeleteBuilder(executor, 'users', { pk: 'USER#123' })
470
- * .condition(op => op.and([
471
- * op.attributeExists('pk'),
472
- * op.eq('status', 'INACTIVE')
473
- * ]))
474
- * .toDynamoCommand();
475
- *
476
- * // Add the command to the transaction
477
- * transaction.deleteWithCommand(deleteCommand);
478
- * ```
479
- *
480
- * @param command - The complete delete command configuration
481
- * @returns The transaction builder for method chaining
482
- * @throws {Error} If a duplicate item is detected in the transaction
483
- * @see DeleteBuilder for creating delete commands
484
- */
485
- deleteWithCommand(command) {
486
- let keyForDuplicateCheck;
487
- let keyForTransaction;
488
- if (typeof command.key === "object" && command.key !== null && "pk" in command.key) {
489
- keyForTransaction = this.createKeyForPrimaryIndex(command.key);
490
- keyForDuplicateCheck = keyForTransaction;
491
- } else {
492
- keyForTransaction = command.key;
493
- keyForDuplicateCheck = command.key;
494
- }
495
- this.checkForDuplicateItem(command.tableName, keyForDuplicateCheck);
496
- const transactionItem = {
497
- type: "Delete",
498
- params: {
499
- ...command,
500
- key: keyForTransaction
501
- }
502
- };
503
- this.items.push(transactionItem);
504
- return this;
505
- }
506
- /**
507
- * Adds an update operation to the transaction.
508
- *
509
- * The method supports all DynamoDB update expressions:
510
- * - SET: Modify or add attributes
511
- * - REMOVE: Delete attributes
512
- * - ADD: Update numbers and sets
513
- * - DELETE: Remove elements from a set
514
- *
515
- * @example
516
- * ```typescript
517
- * // Simple update
518
- * transaction.update(
519
- * 'orders',
520
- * { pk: 'ORDER#123' },
521
- * 'SET #status = :status',
522
- * { '#status': 'status' },
523
- * { ':status': 'PROCESSING' }
524
- * );
525
- *
526
- * // Complex update with multiple operations
527
- * transaction.update(
528
- * 'products',
529
- * { pk: 'PROD#ABC' },
530
- * 'SET #qty = #qty - :amount, #status = :status REMOVE #oldAttr',
531
- * { '#qty': 'quantity', '#status': 'status', '#oldAttr': 'deprecated_field' },
532
- * { ':amount': 1, ':status': 'LOW_STOCK' }
533
- * );
534
- *
535
- * // Conditional update
536
- * transaction.update(
537
- * 'users',
538
- * { pk: 'USER#123' },
539
- * 'SET #lastLogin = :now',
540
- * { '#lastLogin': 'lastLoginDate' },
541
- * { ':now': new Date().toISOString() },
542
- * op => op.attributeExists('pk')
543
- * );
544
- * ```
545
- *
546
- * @param tableName - The name of the DynamoDB table
547
- * @param key - The primary key of the item to update
548
- * @param updateExpression - The update expression (SET, REMOVE, ADD, DELETE)
549
- * @param expressionAttributeNames - Map of attribute name placeholders to actual names
550
- * @param expressionAttributeValues - Map of value placeholders to actual values
551
- * @param condition - Optional condition that must be satisfied
552
- * @returns The transaction builder for method chaining
553
- * @throws {Error} If a duplicate item is detected in the transaction
554
- */
555
- update(tableName, key, updateExpression, expressionAttributeNames, expressionAttributeValues, condition) {
556
- const keyCondition = this.createKeyForPrimaryIndex(key);
557
- this.checkForDuplicateItem(tableName, keyCondition);
558
- const transactionItem = {
559
- type: "Update",
560
- params: {
561
- tableName,
562
- key: keyCondition,
563
- updateExpression,
564
- expressionAttributeNames,
565
- expressionAttributeValues
566
- }
567
- };
568
- if (condition) {
569
- const { expression, names, values } = prepareExpressionParams(condition);
570
- transactionItem.params.conditionExpression = expression;
571
- transactionItem.params.expressionAttributeNames = {
572
- ...transactionItem.params.expressionAttributeNames,
573
- ...names
574
- };
575
- transactionItem.params.expressionAttributeValues = {
576
- ...transactionItem.params.expressionAttributeValues,
577
- ...values
578
- };
579
- }
580
- this.items.push(transactionItem);
581
- return this;
582
- }
583
- /**
584
- * Adds a pre-configured update operation to the transaction.
585
- *
586
- * This method is particularly useful when working with UpdateBuilder
587
- * to maintain consistency in update operations across your application.
588
- *
589
- * @example
590
- * ```typescript
591
- * // Create an update command with UpdateBuilder
592
- * const updateCommand = new UpdateBuilder(executor, 'inventory', { pk: 'PROD#ABC' })
593
- * .set('quantity', ':qty')
594
- * .set('lastUpdated', ':now')
595
- * .values({
596
- * ':qty': 100,
597
- * ':now': new Date().toISOString()
598
- * })
599
- * .condition(op => op.gt('quantity', 0))
600
- * .toDynamoCommand();
601
- *
602
- * // Add the command to the transaction
603
- * transaction.updateWithCommand(updateCommand);
604
- * ```
605
- *
606
- * @param command - The complete update command configuration
607
- * @returns The transaction builder for method chaining
608
- * @throws {Error} If a duplicate item is detected in the transaction
609
- * @see UpdateBuilder for creating update commands
610
- */
611
- updateWithCommand(command) {
612
- let keyForDuplicateCheck;
613
- let keyForTransaction;
614
- if (typeof command.key === "object" && command.key !== null && "pk" in command.key) {
615
- keyForTransaction = this.createKeyForPrimaryIndex(command.key);
616
- keyForDuplicateCheck = keyForTransaction;
617
- } else {
618
- keyForTransaction = command.key;
619
- keyForDuplicateCheck = command.key;
620
- }
621
- this.checkForDuplicateItem(command.tableName, keyForDuplicateCheck);
622
- const transactionItem = {
623
- type: "Update",
624
- params: {
625
- ...command,
626
- key: keyForTransaction
627
- }
628
- };
629
- this.items.push(transactionItem);
630
- return this;
631
- }
632
- /**
633
- * Adds a condition check operation to the transaction.
634
- *
635
- * Condition checks are particularly useful for:
636
- * - Implementing optimistic locking
637
- * - Ensuring referential integrity
638
- * - Validating business rules atomically
639
- *
640
- * @example
641
- * ```typescript
642
- * // Check if order is in correct state
643
- * transaction.conditionCheck(
644
- * 'orders',
645
- * { pk: 'ORDER#123' },
646
- * op => op.eq('status', 'PENDING')
647
- * );
648
- *
649
- * // Complex condition check
650
- * transaction.conditionCheck(
651
- * 'inventory',
652
- * { pk: 'PROD#ABC' },
653
- * op => op.and([
654
- * op.gt('quantity', 0),
655
- * op.eq('status', 'ACTIVE'),
656
- * op.attributeExists('lastRestockDate')
657
- * ])
658
- * );
659
- *
660
- * // Check with multiple attributes
661
- * transaction.conditionCheck(
662
- * 'users',
663
- * { pk: 'USER#123' },
664
- * op => op.or([
665
- * op.eq('status', 'PREMIUM'),
666
- * op.gte('credits', 100)
667
- * ])
668
- * );
669
- * ```
670
- *
671
- * @param tableName - The name of the DynamoDB table
672
- * @param key - The primary key of the item to check
673
- * @param condition - The condition that must be satisfied
674
- * @returns The transaction builder for method chaining
675
- * @throws {Error} If a duplicate item is detected in the transaction
676
- * @throws {Error} If condition expression generation fails
677
- */
678
- conditionCheck(tableName, key, condition) {
679
- const keyCondition = this.createKeyForPrimaryIndex(key);
680
- this.checkForDuplicateItem(tableName, keyCondition);
681
- const { expression, names, values } = prepareExpressionParams(condition);
682
- if (!expression) {
683
- throw new Error("Failed to generate condition expression");
684
- }
685
- const transactionItem = {
686
- type: "ConditionCheck",
687
- params: {
688
- tableName,
689
- key: keyCondition,
690
- conditionExpression: expression,
691
- expressionAttributeNames: names,
692
- expressionAttributeValues: values
693
- }
694
- };
695
- this.items.push(transactionItem);
696
- return this;
697
- }
698
- /**
699
- * Adds a pre-configured condition check operation to the transaction.
700
- *
701
- * This method is particularly useful when working with ConditionCheckBuilder
702
- * to maintain consistency in condition checks across your application.
703
- *
704
- * @example
705
- * ```typescript
706
- * // Create a condition check with ConditionCheckBuilder
707
- * const checkCommand = new ConditionCheckBuilder('inventory', { pk: 'PROD#ABC' })
708
- * .condition(op => op.and([
709
- * op.between('quantity', 10, 100),
710
- * op.beginsWith('category', 'ELECTRONICS'),
711
- * op.attributeExists('lastAuditDate')
712
- * ]))
713
- * .toDynamoCommand();
714
- *
715
- * // Add the command to the transaction
716
- * transaction.conditionCheckWithCommand(checkCommand);
717
- * ```
718
- *
719
- * @param command - The complete condition check command configuration
720
- * @returns The transaction builder for method chaining
721
- * @throws {Error} If a duplicate item is detected in the transaction
722
- * @see ConditionCheckBuilder for creating condition check commands
723
- */
724
- conditionCheckWithCommand(command) {
725
- let keyForDuplicateCheck;
726
- let keyForTransaction;
727
- if (typeof command.key === "object" && command.key !== null && "pk" in command.key) {
728
- keyForTransaction = this.createKeyForPrimaryIndex(command.key);
729
- keyForDuplicateCheck = keyForTransaction;
730
- } else {
731
- keyForTransaction = command.key;
732
- keyForDuplicateCheck = command.key;
733
- }
734
- this.checkForDuplicateItem(command.tableName, keyForDuplicateCheck);
735
- const transactionItem = {
736
- type: "ConditionCheck",
737
- params: {
738
- ...command,
739
- key: keyForTransaction
740
- }
741
- };
742
- this.items.push(transactionItem);
743
- return this;
744
- }
745
- /**
746
- * Sets options for the transaction execution.
747
- *
748
- * @example
749
- * ```typescript
750
- * // Enable idempotency and capacity tracking
751
- * transaction.withOptions({
752
- * clientRequestToken: 'unique-request-id-123',
753
- * returnConsumedCapacity: 'TOTAL'
754
- * });
755
- *
756
- * // Track item collection metrics
757
- * transaction.withOptions({
758
- * returnItemCollectionMetrics: 'SIZE'
759
- * });
760
- * ```
761
- *
762
- * Note: ClientRequestToken can be used to make transactions idempotent,
763
- * ensuring the same transaction is not executed multiple times.
764
- *
765
- * @param options - Configuration options for the transaction
766
- * @returns The transaction builder for method chaining
767
- */
768
- withOptions(options) {
769
- this.options = { ...this.options, ...options };
770
- return this;
771
- }
772
- /**
773
- * Gets a human-readable representation of the transaction items.
774
- *
775
- * The method resolves all expression placeholders with their actual values,
776
- * making it easier to understand the transaction's operations.
777
- *
778
- * @example
779
- * ```typescript
780
- * // Add multiple operations
781
- * transaction
782
- * .put('orders', { orderId: '123', status: 'PENDING' })
783
- * .update('inventory',
784
- * { productId: 'ABC' },
785
- * 'SET quantity = quantity - :amount',
786
- * undefined,
787
- * { ':amount': 1 }
788
- * );
789
- *
790
- * // Debug the transaction
791
- * const debugInfo = transaction.debug();
792
- * console.log('Transaction operations:', debugInfo);
793
- * ```
794
- *
795
- * @returns An array of readable representations of the transaction items
796
- */
797
- debug() {
798
- return debugTransaction(this.items);
799
- }
800
- /**
801
- * Executes all operations in the transaction atomically.
802
- *
803
- * The transaction will only succeed if all operations succeed.
804
- * If any operation fails, the entire transaction is rolled back.
805
- *
806
- * @example
807
- * ```typescript
808
- * try {
809
- * // Build and execute transaction
810
- * await transaction
811
- * .put('orders', newOrder)
812
- * .update('inventory',
813
- * { productId: 'ABC' },
814
- * 'SET quantity = quantity - :qty',
815
- * undefined,
816
- * { ':qty': 1 }
817
- * )
818
- * .conditionCheck('products',
819
- * { productId: 'ABC' },
820
- * op => op.eq('status', 'ACTIVE')
821
- * )
822
- * .execute();
823
- *
824
- * console.log('Transaction completed successfully');
825
- * } catch (error) {
826
- * // Handle transaction failure
827
- * console.error('Transaction failed:', error);
828
- * }
829
- * ```
830
- *
831
- * @throws {Error} If no transaction items are specified
832
- * @throws {Error} If any operation in the transaction fails
833
- * @returns A promise that resolves when the transaction completes
834
- */
835
- async execute() {
836
- if (this.items.length === 0) {
837
- throw new Error("No transaction items specified");
838
- }
839
- const transactItems = this.items.map((item) => {
840
- switch (item.type) {
841
- case "Put":
842
- return {
843
- Put: {
844
- TableName: item.params.tableName,
845
- Item: item.params.item,
846
- ConditionExpression: item.params.conditionExpression,
847
- ExpressionAttributeNames: item.params.expressionAttributeNames,
848
- ExpressionAttributeValues: item.params.expressionAttributeValues
849
- }
850
- };
851
- case "Delete":
852
- return {
853
- Delete: {
854
- TableName: item.params.tableName,
855
- Key: item.params.key,
856
- ConditionExpression: item.params.conditionExpression,
857
- ExpressionAttributeNames: item.params.expressionAttributeNames,
858
- ExpressionAttributeValues: item.params.expressionAttributeValues
859
- }
860
- };
861
- case "Update":
862
- return {
863
- Update: {
864
- TableName: item.params.tableName,
865
- Key: item.params.key,
866
- UpdateExpression: item.params.updateExpression,
867
- ConditionExpression: item.params.conditionExpression,
868
- ExpressionAttributeNames: item.params.expressionAttributeNames,
869
- ExpressionAttributeValues: item.params.expressionAttributeValues
870
- }
871
- };
872
- case "ConditionCheck":
873
- return {
874
- ConditionCheck: {
875
- TableName: item.params.tableName,
876
- Key: item.params.key,
877
- ConditionExpression: item.params.conditionExpression,
878
- ExpressionAttributeNames: item.params.expressionAttributeNames,
879
- ExpressionAttributeValues: item.params.expressionAttributeValues
880
- }
881
- };
882
- default: {
883
- const exhaustiveCheck = item;
884
- throw new Error(`Unsupported transaction item type: ${String(exhaustiveCheck)}`);
885
- }
886
- }
887
- });
888
- const params = {
889
- TransactItems: transactItems,
890
- ClientRequestToken: this.options.clientRequestToken,
891
- ReturnConsumedCapacity: this.options.returnConsumedCapacity,
892
- ReturnItemCollectionMetrics: this.options.returnItemCollectionMetrics
893
- };
894
- try {
895
- await this.executor(params);
896
- } catch (error) {
897
- console.log(this.debug());
898
- console.error("Error executing transaction:", error);
899
- throw error;
900
- }
901
- }
902
- };
903
-
904
- exports.TransactionBuilder = TransactionBuilder;
905
- //# sourceMappingURL=transaction-builder.cjs.map
906
- //# sourceMappingURL=transaction-builder.cjs.map