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