@ftschopp/dynatable-core 1.0.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 (197) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +17 -0
  3. package/dist/builders/batch-get/create-batch-get-builder.d.ts +18 -0
  4. package/dist/builders/batch-get/create-batch-get-builder.d.ts.map +1 -0
  5. package/dist/builders/batch-get/create-batch-get-builder.js +71 -0
  6. package/dist/builders/batch-get/index.d.ts +3 -0
  7. package/dist/builders/batch-get/index.d.ts.map +1 -0
  8. package/dist/builders/batch-get/index.js +18 -0
  9. package/dist/builders/batch-get/types.d.ts +25 -0
  10. package/dist/builders/batch-get/types.d.ts.map +1 -0
  11. package/dist/builders/batch-get/types.js +2 -0
  12. package/dist/builders/batch-write/create-batch-write-builder.d.ts +12 -0
  13. package/dist/builders/batch-write/create-batch-write-builder.d.ts.map +1 -0
  14. package/dist/builders/batch-write/create-batch-write-builder.js +35 -0
  15. package/dist/builders/batch-write/index.d.ts +3 -0
  16. package/dist/builders/batch-write/index.d.ts.map +1 -0
  17. package/dist/builders/batch-write/index.js +18 -0
  18. package/dist/builders/batch-write/types.d.ts +30 -0
  19. package/dist/builders/batch-write/types.d.ts.map +1 -0
  20. package/dist/builders/batch-write/types.js +2 -0
  21. package/dist/builders/delete/create-delete-builder.d.ts +9 -0
  22. package/dist/builders/delete/create-delete-builder.d.ts.map +1 -0
  23. package/dist/builders/delete/create-delete-builder.js +72 -0
  24. package/dist/builders/delete/index.d.ts +3 -0
  25. package/dist/builders/delete/index.d.ts.map +1 -0
  26. package/dist/builders/delete/index.js +18 -0
  27. package/dist/builders/delete/types.d.ts +11 -0
  28. package/dist/builders/delete/types.d.ts.map +1 -0
  29. package/dist/builders/delete/types.js +2 -0
  30. package/dist/builders/get/create-get-builder.d.ts +12 -0
  31. package/dist/builders/get/create-get-builder.d.ts.map +1 -0
  32. package/dist/builders/get/create-get-builder.js +95 -0
  33. package/dist/builders/get/index.d.ts +3 -0
  34. package/dist/builders/get/index.d.ts.map +1 -0
  35. package/dist/builders/get/index.js +18 -0
  36. package/dist/builders/get/types.d.ts +28 -0
  37. package/dist/builders/get/types.d.ts.map +1 -0
  38. package/dist/builders/get/types.js +2 -0
  39. package/dist/builders/index.d.ts +12 -0
  40. package/dist/builders/index.d.ts.map +1 -0
  41. package/dist/builders/index.js +29 -0
  42. package/dist/builders/put/create-put-builder.d.ts +9 -0
  43. package/dist/builders/put/create-put-builder.d.ts.map +1 -0
  44. package/dist/builders/put/create-put-builder.js +104 -0
  45. package/dist/builders/put/index.d.ts +3 -0
  46. package/dist/builders/put/index.d.ts.map +1 -0
  47. package/dist/builders/put/index.js +18 -0
  48. package/dist/builders/put/types.d.ts +17 -0
  49. package/dist/builders/put/types.d.ts.map +1 -0
  50. package/dist/builders/put/types.js +2 -0
  51. package/dist/builders/query/create-query-builder.d.ts +9 -0
  52. package/dist/builders/query/create-query-builder.d.ts.map +1 -0
  53. package/dist/builders/query/create-query-builder.js +283 -0
  54. package/dist/builders/query/index.d.ts +3 -0
  55. package/dist/builders/query/index.d.ts.map +1 -0
  56. package/dist/builders/query/index.js +18 -0
  57. package/dist/builders/query/types.d.ts +79 -0
  58. package/dist/builders/query/types.d.ts.map +1 -0
  59. package/dist/builders/query/types.js +2 -0
  60. package/dist/builders/scan/create-scan-builder.d.ts +12 -0
  61. package/dist/builders/scan/create-scan-builder.d.ts.map +1 -0
  62. package/dist/builders/scan/create-scan-builder.js +103 -0
  63. package/dist/builders/scan/index.d.ts +3 -0
  64. package/dist/builders/scan/index.d.ts.map +1 -0
  65. package/dist/builders/scan/index.js +18 -0
  66. package/dist/builders/scan/types.d.ts +43 -0
  67. package/dist/builders/scan/types.d.ts.map +1 -0
  68. package/dist/builders/scan/types.js +2 -0
  69. package/dist/builders/shared/conditions.d.ts +18 -0
  70. package/dist/builders/shared/conditions.d.ts.map +1 -0
  71. package/dist/builders/shared/conditions.js +48 -0
  72. package/dist/builders/shared/index.d.ts +4 -0
  73. package/dist/builders/shared/index.d.ts.map +1 -0
  74. package/dist/builders/shared/index.js +19 -0
  75. package/dist/builders/shared/operators.d.ts +12 -0
  76. package/dist/builders/shared/operators.d.ts.map +1 -0
  77. package/dist/builders/shared/operators.js +197 -0
  78. package/dist/builders/shared/types.d.ts +77 -0
  79. package/dist/builders/shared/types.d.ts.map +1 -0
  80. package/dist/builders/shared/types.js +6 -0
  81. package/dist/builders/transact-get/create-transact-get-builder.d.ts +18 -0
  82. package/dist/builders/transact-get/create-transact-get-builder.d.ts.map +1 -0
  83. package/dist/builders/transact-get/create-transact-get-builder.js +60 -0
  84. package/dist/builders/transact-get/index.d.ts +3 -0
  85. package/dist/builders/transact-get/index.d.ts.map +1 -0
  86. package/dist/builders/transact-get/index.js +18 -0
  87. package/dist/builders/transact-get/types.d.ts +28 -0
  88. package/dist/builders/transact-get/types.d.ts.map +1 -0
  89. package/dist/builders/transact-get/types.js +2 -0
  90. package/dist/builders/transact-write/create-transact-write-builder.d.ts +18 -0
  91. package/dist/builders/transact-write/create-transact-write-builder.d.ts.map +1 -0
  92. package/dist/builders/transact-write/create-transact-write-builder.js +97 -0
  93. package/dist/builders/transact-write/index.d.ts +3 -0
  94. package/dist/builders/transact-write/index.d.ts.map +1 -0
  95. package/dist/builders/transact-write/index.js +18 -0
  96. package/dist/builders/transact-write/types.d.ts +34 -0
  97. package/dist/builders/transact-write/types.d.ts.map +1 -0
  98. package/dist/builders/transact-write/types.js +2 -0
  99. package/dist/builders/update/create-update-builder.d.ts +14 -0
  100. package/dist/builders/update/create-update-builder.d.ts.map +1 -0
  101. package/dist/builders/update/create-update-builder.js +180 -0
  102. package/dist/builders/update/index.d.ts +3 -0
  103. package/dist/builders/update/index.d.ts.map +1 -0
  104. package/dist/builders/update/index.js +18 -0
  105. package/dist/builders/update/types.d.ts +35 -0
  106. package/dist/builders/update/types.d.ts.map +1 -0
  107. package/dist/builders/update/types.js +2 -0
  108. package/dist/core/types.d.ts +224 -0
  109. package/dist/core/types.d.ts.map +1 -0
  110. package/dist/core/types.js +3 -0
  111. package/dist/entity.d.ts +73 -0
  112. package/dist/entity.d.ts.map +1 -0
  113. package/dist/entity.js +161 -0
  114. package/dist/index.d.ts +4 -0
  115. package/dist/index.d.ts.map +1 -0
  116. package/dist/index.js +20 -0
  117. package/dist/table.d.ts +70 -0
  118. package/dist/table.d.ts.map +1 -0
  119. package/dist/table.js +69 -0
  120. package/dist/utils/dynamodb-logger.d.ts +118 -0
  121. package/dist/utils/dynamodb-logger.d.ts.map +1 -0
  122. package/dist/utils/dynamodb-logger.js +125 -0
  123. package/dist/utils/model-utils.d.ts +24 -0
  124. package/dist/utils/model-utils.d.ts.map +1 -0
  125. package/dist/utils/model-utils.js +88 -0
  126. package/dist/utils/zod-utils.d.ts +13 -0
  127. package/dist/utils/zod-utils.d.ts.map +1 -0
  128. package/dist/utils/zod-utils.js +35 -0
  129. package/eslint.config.mjs +4 -0
  130. package/jest.config.js +11 -0
  131. package/package.json +36 -0
  132. package/src/builders/README.md +272 -0
  133. package/src/builders/batch-get/README.md +98 -0
  134. package/src/builders/batch-get/create-batch-get-builder.test.ts +165 -0
  135. package/src/builders/batch-get/create-batch-get-builder.ts +106 -0
  136. package/src/builders/batch-get/index.ts +2 -0
  137. package/src/builders/batch-get/types.ts +29 -0
  138. package/src/builders/batch-write/README.md +204 -0
  139. package/src/builders/batch-write/create-batch-write-builder.test.ts +173 -0
  140. package/src/builders/batch-write/create-batch-write-builder.ts +49 -0
  141. package/src/builders/batch-write/index.ts +2 -0
  142. package/src/builders/batch-write/types.ts +33 -0
  143. package/src/builders/delete/create-delete-builder.test.ts +294 -0
  144. package/src/builders/delete/create-delete-builder.ts +100 -0
  145. package/src/builders/delete/index.ts +2 -0
  146. package/src/builders/delete/types.ts +11 -0
  147. package/src/builders/get/create-get-builder.test.ts +272 -0
  148. package/src/builders/get/create-get-builder.ts +140 -0
  149. package/src/builders/get/index.ts +2 -0
  150. package/src/builders/get/types.ts +30 -0
  151. package/src/builders/index.ts +14 -0
  152. package/src/builders/put/create-put-builder.test.ts +213 -0
  153. package/src/builders/put/create-put-builder.ts +151 -0
  154. package/src/builders/put/index.ts +2 -0
  155. package/src/builders/put/types.ts +18 -0
  156. package/src/builders/query/create-query-builder.test.ts +230 -0
  157. package/src/builders/query/create-query-builder.ts +353 -0
  158. package/src/builders/query/index.ts +2 -0
  159. package/src/builders/query/types.ts +95 -0
  160. package/src/builders/scan/create-scan-builder.test.ts +260 -0
  161. package/src/builders/scan/create-scan-builder.ts +217 -0
  162. package/src/builders/scan/index.ts +2 -0
  163. package/src/builders/scan/types.ts +49 -0
  164. package/src/builders/shared/conditions.ts +58 -0
  165. package/src/builders/shared/index.ts +3 -0
  166. package/src/builders/shared/operators.test.ts +270 -0
  167. package/src/builders/shared/operators.ts +200 -0
  168. package/src/builders/shared/types.ts +100 -0
  169. package/src/builders/transact-get/README.md +167 -0
  170. package/src/builders/transact-get/create-transact-get-builder.test.ts +239 -0
  171. package/src/builders/transact-get/create-transact-get-builder.ts +67 -0
  172. package/src/builders/transact-get/index.ts +2 -0
  173. package/src/builders/transact-get/types.ts +31 -0
  174. package/src/builders/transact-write/README.md +166 -0
  175. package/src/builders/transact-write/create-transact-write-builder.test.ts +288 -0
  176. package/src/builders/transact-write/create-transact-write-builder.ts +118 -0
  177. package/src/builders/transact-write/index.ts +2 -0
  178. package/src/builders/transact-write/types.ts +33 -0
  179. package/src/builders/update/create-update-builder.test.ts +333 -0
  180. package/src/builders/update/create-update-builder.ts +284 -0
  181. package/src/builders/update/index.ts +2 -0
  182. package/src/builders/update/types.ts +42 -0
  183. package/src/core/types.test.ts +506 -0
  184. package/src/core/types.ts +290 -0
  185. package/src/entity.ts +337 -0
  186. package/src/index.ts +22 -0
  187. package/src/table.ts +109 -0
  188. package/src/utils/dynamodb-logger.test.ts +246 -0
  189. package/src/utils/dynamodb-logger.ts +175 -0
  190. package/src/utils/model-utils.test.ts +232 -0
  191. package/src/utils/model-utils.ts +101 -0
  192. package/src/utils/zod-utils.test.ts +272 -0
  193. package/src/utils/zod-utils.ts +36 -0
  194. package/tests/integration/instagram-clone.integration.test.ts +966 -0
  195. package/tests/integration/pagination-timestamps.integration.test.ts +375 -0
  196. package/tests/integration/transactions.integration.test.ts +529 -0
  197. package/tsconfig.json +12 -0
@@ -0,0 +1,288 @@
1
+ import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
2
+ import { createTransactWriteBuilder } from './create-transact-write-builder';
3
+
4
+ const client = new DynamoDBClient({});
5
+
6
+ describe('TransactWrite Builder - Functional API', () => {
7
+ test('should create empty transaction', () => {
8
+ const params = createTransactWriteBuilder(client).dbParams();
9
+
10
+ expect(params).toEqual({
11
+ TransactItems: [],
12
+ });
13
+ });
14
+
15
+ test('should add single Put operation', () => {
16
+ const putParams = {
17
+ TableName: 'InstagramClone',
18
+ Item: {
19
+ pk: 'USER#alice',
20
+ sk: 'USER#alice',
21
+ username: 'alice',
22
+ name: 'Alice Smith',
23
+ followerCount: 0,
24
+ followingCount: 0,
25
+ },
26
+ };
27
+
28
+ const params = createTransactWriteBuilder(client).addPut(putParams).dbParams();
29
+
30
+ expect(params).toEqual({
31
+ TransactItems: [{ Put: putParams }],
32
+ });
33
+ });
34
+
35
+ test('should add single Update operation', () => {
36
+ const updateParams = {
37
+ TableName: 'InstagramClone',
38
+ Key: { pk: 'USER#alice', sk: 'USER#alice' },
39
+ UpdateExpression: 'ADD #followerCount :followerCount_0',
40
+ ExpressionAttributeNames: { '#followerCount': 'followerCount' },
41
+ ExpressionAttributeValues: { ':followerCount_0': 1 },
42
+ };
43
+
44
+ const params = createTransactWriteBuilder(client).addUpdate(updateParams).dbParams();
45
+
46
+ expect(params).toEqual({
47
+ TransactItems: [{ Update: updateParams }],
48
+ });
49
+ });
50
+
51
+ test('should add single Delete operation', () => {
52
+ const deleteParams = {
53
+ TableName: 'InstagramClone',
54
+ Key: { pk: 'USER#alice', sk: 'USER#alice' },
55
+ };
56
+
57
+ const params = createTransactWriteBuilder(client).addDelete(deleteParams).dbParams();
58
+
59
+ expect(params).toEqual({
60
+ TransactItems: [{ Delete: deleteParams }],
61
+ });
62
+ });
63
+
64
+ test('should add ConditionCheck operation', () => {
65
+ const conditionCheckParams = {
66
+ TableName: 'InstagramClone',
67
+ Key: { pk: 'USER#admin', sk: 'USER#admin' },
68
+ ConditionExpression: 'attribute_exists(#username)',
69
+ ExpressionAttributeNames: { '#username': 'username' },
70
+ };
71
+
72
+ const params = createTransactWriteBuilder(client)
73
+ .addConditionCheck(conditionCheckParams)
74
+ .dbParams();
75
+
76
+ expect(params).toEqual({
77
+ TransactItems: [{ ConditionCheck: conditionCheckParams }],
78
+ });
79
+ });
80
+
81
+ test('should chain multiple operations - Like a Photo', () => {
82
+ // Like a Photo: Create Like + Increment Photo.likesCount
83
+ const putLikeParams = {
84
+ TableName: 'InstagramClone',
85
+ Item: {
86
+ pk: 'PL#photo123',
87
+ sk: 'LIKE#juanca',
88
+ photoId: 'photo123',
89
+ likingUsername: 'juanca',
90
+ likeId: '01K16ZP43BRX67DG50SHGZ11DS',
91
+ },
92
+ ConditionExpression: '(attribute_not_exists(#PK)) AND (attribute_not_exists(#SK))',
93
+ ExpressionAttributeNames: { '#PK': 'pk', '#SK': 'sk' },
94
+ };
95
+
96
+ const updatePhotoParams = {
97
+ TableName: 'InstagramClone',
98
+ Key: { pk: 'UP#alice', sk: 'PHOTO#photo123' },
99
+ UpdateExpression: 'ADD #likesCount :likesCount_0',
100
+ ExpressionAttributeNames: { '#likesCount': 'likesCount' },
101
+ ExpressionAttributeValues: { ':likesCount_0': 1 },
102
+ };
103
+
104
+ const params = createTransactWriteBuilder(client)
105
+ .addPut(putLikeParams)
106
+ .addUpdate(updatePhotoParams)
107
+ .dbParams();
108
+
109
+ expect(params).toEqual({
110
+ TransactItems: [{ Put: putLikeParams }, { Update: updatePhotoParams }],
111
+ });
112
+ expect(params.TransactItems).toHaveLength(2);
113
+ });
114
+
115
+ test('should chain multiple operations - Follow a User', () => {
116
+ // Follow: Create Follow + Update both user counts
117
+ const putFollowParams = {
118
+ TableName: 'InstagramClone',
119
+ Item: {
120
+ pk: 'FOLLOW#alice',
121
+ sk: 'FOLLOW#bob',
122
+ followedUsername: 'alice',
123
+ followingUsername: 'bob',
124
+ },
125
+ ConditionExpression: '(attribute_not_exists(#PK)) AND (attribute_not_exists(#SK))',
126
+ ExpressionAttributeNames: { '#PK': 'pk', '#SK': 'sk' },
127
+ };
128
+
129
+ const updateFollowedParams = {
130
+ TableName: 'InstagramClone',
131
+ Key: { pk: 'USER#alice', sk: 'USER#alice' },
132
+ UpdateExpression: 'ADD #followerCount :followerCount_0',
133
+ ExpressionAttributeNames: { '#followerCount': 'followerCount' },
134
+ ExpressionAttributeValues: { ':followerCount_0': 1 },
135
+ };
136
+
137
+ const updateFollowingParams = {
138
+ TableName: 'InstagramClone',
139
+ Key: { pk: 'USER#bob', sk: 'USER#bob' },
140
+ UpdateExpression: 'ADD #followingCount :followingCount_0',
141
+ ExpressionAttributeNames: { '#followingCount': 'followingCount' },
142
+ ExpressionAttributeValues: { ':followingCount_0': 1 },
143
+ };
144
+
145
+ const params = createTransactWriteBuilder(client)
146
+ .addPut(putFollowParams)
147
+ .addUpdate(updateFollowedParams)
148
+ .addUpdate(updateFollowingParams)
149
+ .dbParams();
150
+
151
+ expect(params.TransactItems).toHaveLength(3);
152
+ expect(params.TransactItems[0]).toEqual({ Put: putFollowParams });
153
+ expect(params.TransactItems[1]).toEqual({ Update: updateFollowedParams });
154
+ expect(params.TransactItems[2]).toEqual({ Update: updateFollowingParams });
155
+ });
156
+
157
+ test('should chain multiple operations - Comment on Photo', () => {
158
+ const putCommentParams = {
159
+ TableName: 'InstagramClone',
160
+ Item: {
161
+ pk: 'PC#photo123',
162
+ sk: 'COMMENT#comment456',
163
+ photoId: 'photo123',
164
+ commentId: 'comment456',
165
+ commentingUsername: 'bob',
166
+ content: 'Great photo!',
167
+ },
168
+ };
169
+
170
+ const updatePhotoParams = {
171
+ TableName: 'InstagramClone',
172
+ Key: { pk: 'UP#alice', sk: 'PHOTO#photo123' },
173
+ UpdateExpression: 'ADD #commentCount :commentCount_0',
174
+ ExpressionAttributeNames: { '#commentCount': 'commentCount' },
175
+ ExpressionAttributeValues: { ':commentCount_0': 1 },
176
+ };
177
+
178
+ const params = createTransactWriteBuilder(client)
179
+ .addPut(putCommentParams)
180
+ .addUpdate(updatePhotoParams)
181
+ .dbParams();
182
+
183
+ expect(params.TransactItems).toHaveLength(2);
184
+ expect(params.TransactItems[0]).toEqual({ Put: putCommentParams });
185
+ expect(params.TransactItems[1]).toEqual({ Update: updatePhotoParams });
186
+ });
187
+
188
+ test('should support client request token for idempotency', () => {
189
+ const putParams = {
190
+ TableName: 'InstagramClone',
191
+ Item: { pk: 'USER#alice', sk: 'USER#alice', username: 'alice' },
192
+ };
193
+
194
+ const params = createTransactWriteBuilder(client)
195
+ .addPut(putParams)
196
+ .withClientRequestToken('my-unique-token-123')
197
+ .dbParams();
198
+
199
+ expect(params).toEqual({
200
+ TransactItems: [{ Put: putParams }],
201
+ ClientRequestToken: 'my-unique-token-123',
202
+ });
203
+ });
204
+
205
+ test('should preserve immutability - original builder unchanged', () => {
206
+ const builder1 = createTransactWriteBuilder(client);
207
+ const putParams = {
208
+ TableName: 'InstagramClone',
209
+ Item: { pk: 'USER#alice', sk: 'USER#alice' },
210
+ };
211
+
212
+ const builder2 = builder1.addPut(putParams);
213
+ const builder3 = builder2.withClientRequestToken('token');
214
+
215
+ // Each builder should be independent
216
+ expect(builder1.dbParams().TransactItems).toHaveLength(0);
217
+ expect(builder2.dbParams().TransactItems).toHaveLength(1);
218
+ expect(builder3.dbParams().ClientRequestToken).toBe('token');
219
+ expect(builder2.dbParams().ClientRequestToken).toBeUndefined();
220
+ });
221
+
222
+ test('should handle complex transaction - Delete Photo only if no engagement', () => {
223
+ const deletePhotoParams = {
224
+ TableName: 'InstagramClone',
225
+ Key: { pk: 'UP#alice', sk: 'PHOTO#photo123' },
226
+ ConditionExpression: '(#likesCount = :likesCount_0) AND (#commentCount = :commentCount_1)',
227
+ ExpressionAttributeNames: {
228
+ '#likesCount': 'likesCount',
229
+ '#commentCount': 'commentCount',
230
+ },
231
+ ExpressionAttributeValues: {
232
+ ':likesCount_0': 0,
233
+ ':commentCount_1': 0,
234
+ },
235
+ };
236
+
237
+ const params = createTransactWriteBuilder(client).addDelete(deletePhotoParams).dbParams();
238
+
239
+ expect(params.TransactItems).toHaveLength(1);
240
+ expect(params.TransactItems[0]).toEqual({ Delete: deletePhotoParams });
241
+ });
242
+
243
+ test('should handle max operations (100 items limit)', () => {
244
+ let builder = createTransactWriteBuilder(client);
245
+
246
+ // Add 100 Put operations (DynamoDB limit)
247
+ for (let i = 0; i < 100; i++) {
248
+ builder = builder.addPut({
249
+ TableName: 'InstagramClone',
250
+ Item: { pk: `USER#user${i}`, sk: `USER#user${i}` },
251
+ });
252
+ }
253
+
254
+ const params = builder.dbParams();
255
+ expect(params.TransactItems).toHaveLength(100);
256
+ });
257
+
258
+ test('should mix all operation types', () => {
259
+ const params = createTransactWriteBuilder(client)
260
+ .addPut({
261
+ TableName: 'InstagramClone',
262
+ Item: { pk: 'USER#alice', sk: 'USER#alice' },
263
+ })
264
+ .addUpdate({
265
+ TableName: 'InstagramClone',
266
+ Key: { pk: 'USER#bob', sk: 'USER#bob' },
267
+ UpdateExpression: 'ADD #count :val',
268
+ ExpressionAttributeNames: { '#count': 'followerCount' },
269
+ ExpressionAttributeValues: { ':val': 1 },
270
+ })
271
+ .addDelete({
272
+ TableName: 'InstagramClone',
273
+ Key: { pk: 'PHOTO#old', sk: 'PHOTO#old' },
274
+ })
275
+ .addConditionCheck({
276
+ TableName: 'InstagramClone',
277
+ Key: { pk: 'USER#admin', sk: 'USER#admin' },
278
+ ConditionExpression: 'attribute_exists(pk)',
279
+ })
280
+ .dbParams();
281
+
282
+ expect(params.TransactItems).toHaveLength(4);
283
+ expect(params.TransactItems[0]).toHaveProperty('Put');
284
+ expect(params.TransactItems[1]).toHaveProperty('Update');
285
+ expect(params.TransactItems[2]).toHaveProperty('Delete');
286
+ expect(params.TransactItems[3]).toHaveProperty('ConditionCheck');
287
+ });
288
+ });
@@ -0,0 +1,118 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
3
+ import { TransactWriteCommand } from '@aws-sdk/lib-dynamodb';
4
+ import { TransactWriteBuilder, TransactWriteState } from './types';
5
+
6
+ /**
7
+ * Creates the initial state for a TransactWrite builder
8
+ */
9
+ const createInitialState = (client: DynamoDBClient): TransactWriteState => ({
10
+ client,
11
+ items: [],
12
+ });
13
+
14
+ /**
15
+ * Adds a Put operation to the transaction
16
+ */
17
+ const addPutItem =
18
+ (state: TransactWriteState) =>
19
+ (params: any): TransactWriteState => ({
20
+ ...state,
21
+ items: [...state.items, { Put: params }],
22
+ });
23
+
24
+ /**
25
+ * Adds an Update operation to the transaction
26
+ */
27
+ const addUpdateItem =
28
+ (state: TransactWriteState) =>
29
+ (params: any): TransactWriteState => ({
30
+ ...state,
31
+ items: [...state.items, { Update: params }],
32
+ });
33
+
34
+ /**
35
+ * Adds a Delete operation to the transaction
36
+ */
37
+ const addDeleteItem =
38
+ (state: TransactWriteState) =>
39
+ (params: any): TransactWriteState => ({
40
+ ...state,
41
+ items: [...state.items, { Delete: params }],
42
+ });
43
+
44
+ /**
45
+ * Adds a ConditionCheck operation to the transaction
46
+ */
47
+ const addConditionCheckItem =
48
+ (state: TransactWriteState) =>
49
+ (params: any): TransactWriteState => ({
50
+ ...state,
51
+ items: [...state.items, { ConditionCheck: params }],
52
+ });
53
+
54
+ /**
55
+ * Sets the client request token for idempotency
56
+ */
57
+ const setClientRequestToken =
58
+ (state: TransactWriteState) =>
59
+ (token: string): TransactWriteState => ({
60
+ ...state,
61
+ clientRequestToken: token,
62
+ });
63
+
64
+ /**
65
+ * Converts the builder state to DynamoDB parameters
66
+ */
67
+ const toDbParams = (state: TransactWriteState) => {
68
+ const params: any = {
69
+ TransactItems: state.items,
70
+ };
71
+
72
+ if (state.clientRequestToken) {
73
+ params.ClientRequestToken = state.clientRequestToken;
74
+ }
75
+
76
+ return params;
77
+ };
78
+
79
+ /**
80
+ * Executes the transaction
81
+ */
82
+ const execute = async (state: TransactWriteState) => {
83
+ const params = toDbParams(state);
84
+ const command = new TransactWriteCommand(params);
85
+ return await state.client.send(command);
86
+ };
87
+
88
+ /**
89
+ * Creates a builder from the current state
90
+ */
91
+ const createBuilder = (state: TransactWriteState): TransactWriteBuilder => ({
92
+ addPut: (params: any) => createBuilder(addPutItem(state)(params)),
93
+ addUpdate: (params: any) => createBuilder(addUpdateItem(state)(params)),
94
+ addDelete: (params: any) => createBuilder(addDeleteItem(state)(params)),
95
+ addConditionCheck: (params: any) => createBuilder(addConditionCheckItem(state)(params)),
96
+ withClientRequestToken: (token: string) => createBuilder(setClientRequestToken(state)(token)),
97
+ dbParams: () => toDbParams(state),
98
+ execute: () => execute(state),
99
+ });
100
+
101
+ /**
102
+ * Creates a new TransactWrite builder
103
+ *
104
+ * @param client - DynamoDB client instance
105
+ * @returns A TransactWriteBuilder
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * const result = await createTransactWriteBuilder(client)
110
+ * .addPut(putParams)
111
+ * .addUpdate(updateParams)
112
+ * .execute();
113
+ * ```
114
+ */
115
+ export const createTransactWriteBuilder = (client: DynamoDBClient): TransactWriteBuilder => {
116
+ const initialState = createInitialState(client);
117
+ return createBuilder(initialState);
118
+ };
@@ -0,0 +1,2 @@
1
+ export * from './types';
2
+ export * from './create-transact-write-builder';
@@ -0,0 +1,33 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
3
+
4
+ /**
5
+ * Represents a single item in a TransactWrite operation
6
+ */
7
+ export type TransactWriteItem =
8
+ | { Put: any }
9
+ | { Update: any }
10
+ | { Delete: any }
11
+ | { ConditionCheck: any };
12
+
13
+ /**
14
+ * State for the TransactWrite builder
15
+ */
16
+ export type TransactWriteState = {
17
+ readonly client: DynamoDBClient;
18
+ readonly items: readonly TransactWriteItem[];
19
+ readonly clientRequestToken?: string;
20
+ };
21
+
22
+ /**
23
+ * TransactWrite builder interface
24
+ */
25
+ export type TransactWriteBuilder = {
26
+ readonly addPut: (params: any) => TransactWriteBuilder;
27
+ readonly addUpdate: (params: any) => TransactWriteBuilder;
28
+ readonly addDelete: (params: any) => TransactWriteBuilder;
29
+ readonly addConditionCheck: (params: any) => TransactWriteBuilder;
30
+ readonly withClientRequestToken: (token: string) => TransactWriteBuilder;
31
+ readonly dbParams: () => any;
32
+ readonly execute: () => Promise<any>;
33
+ };