3030import software .amazon .awssdk .enhanced .dynamodb .model .PutItemEnhancedRequest ;
3131import software .amazon .awssdk .enhanced .dynamodb .model .PutItemEnhancedResponse ;
3232import software .amazon .awssdk .enhanced .dynamodb .model .Record ;
33+ import software .amazon .awssdk .enhanced .dynamodb .model .RecordWithVersion ;
34+ import software .amazon .awssdk .enhanced .dynamodb .model .TransactWriteItemsEnhancedRequest ;
3335import software .amazon .awssdk .enhanced .dynamodb .model .UpdateItemEnhancedRequest ;
3436import software .amazon .awssdk .enhanced .dynamodb .model .UpdateItemEnhancedResponse ;
3537import software .amazon .awssdk .services .dynamodb .DynamoDbAsyncClient ;
4042import software .amazon .awssdk .services .dynamodb .model .ReturnItemCollectionMetrics ;
4143import software .amazon .awssdk .services .dynamodb .model .ReturnValue ;
4244import software .amazon .awssdk .services .dynamodb .model .ReturnValuesOnConditionCheckFailure ;
45+ import software .amazon .awssdk .services .dynamodb .model .TransactionCanceledException ;
4346
4447public class AsyncCrudWithResponseIntegrationTest extends DynamoDbEnhancedIntegrationTestBase {
4548
@@ -55,13 +58,15 @@ public class AsyncCrudWithResponseIntegrationTest extends DynamoDbEnhancedIntegr
5558 private static DynamoDbAsyncClient dynamoDbClient ;
5659 private static DynamoDbEnhancedAsyncClient enhancedClient ;
5760 private static DynamoDbAsyncTable <Record > mappedTable ;
61+ private static DynamoDbAsyncTable <RecordWithVersion > recordWithVersionMappedTable ;
5862
5963 @ BeforeClass
6064 public static void beforeClass () {
6165 dynamoDbClient = createAsyncDynamoDbClient ();
6266 enhancedClient = DynamoDbEnhancedAsyncClient .builder ().dynamoDbClient (dynamoDbClient ).build ();
6367 mappedTable = enhancedClient .table (TABLE_NAME , TABLE_SCHEMA );
6468 mappedTable .createTable (r -> r .localSecondaryIndices (LOCAL_SECONDARY_INDEX )).join ();
69+ recordWithVersionMappedTable = enhancedClient .table (TABLE_NAME , RECORD_WITH_VERSION_TABLE_SCHEMA );
6570 dynamoDbClient .waiter ().waitUntilTableExists (r -> r .tableName (TABLE_NAME )).join ();
6671 }
6772
@@ -191,7 +196,7 @@ public void updateItem_returnValues_all_old() {
191196 Record record = new Record ().setId ("1" ).setSort (10 );
192197 mappedTable .putItem (record ).join ();
193198
194- Record updatedRecord = new Record ().setId ("1" ).setSort (10 ).setValue (11 ). setVersion ( 1 ) ;
199+ Record updatedRecord = new Record ().setId ("1" ).setSort (10 ).setValue (11 );
195200
196201
197202 UpdateItemEnhancedResponse <Record > response = mappedTable .updateItemWithResponse (r -> r .item (updatedRecord )
@@ -201,15 +206,14 @@ public void updateItem_returnValues_all_old() {
201206 assertThat (response .attributes ().getId ()).isEqualTo (record .getId ());
202207 assertThat (response .attributes ().getSort ()).isEqualTo (record .getSort ());
203208 assertThat (response .attributes ().getValue ()).isEqualTo (null );
204- assertThat (response .attributes ().getVersion ()).isEqualTo (1 );
205209 }
206210
207211 @ Test
208212 public void updateItem_returnValues_all_new () {
209213 Record record = new Record ().setId ("1" ).setSort (10 );
210214 mappedTable .putItem (record ).join ();
211215
212- Record updatedRecord = new Record ().setId ("1" ).setSort (10 ).setValue (11 ). setVersion ( 1 ) ;
216+ Record updatedRecord = new Record ().setId ("1" ).setSort (10 ).setValue (11 );
213217
214218
215219 UpdateItemEnhancedResponse <Record > response = mappedTable .updateItemWithResponse (r -> r .item (updatedRecord )
@@ -219,15 +223,14 @@ public void updateItem_returnValues_all_new() {
219223 assertThat (response .attributes ().getId ()).isEqualTo (updatedRecord .getId ());
220224 assertThat (response .attributes ().getSort ()).isEqualTo (updatedRecord .getSort ());
221225 assertThat (response .attributes ().getValue ()).isEqualTo (updatedRecord .getValue ());
222- assertThat (response .attributes ().getVersion ()).isEqualTo (updatedRecord .getVersion () + 1 );
223226 }
224227
225228 @ Test
226229 public void updateItem_returnValues_not_set () {
227230 Record record = new Record ().setId ("1" ).setSort (10 );
228231 mappedTable .putItem (record ).join ();
229232
230- Record updatedRecord = new Record ().setId ("1" ).setSort (10 ).setValue (11 ). setVersion ( 1 ) ;
233+ Record updatedRecord = new Record ().setId ("1" ).setSort (10 ).setValue (11 );
231234
232235
233236 UpdateItemEnhancedResponse <Record > response = mappedTable .updateItemWithResponse (r -> r .item (updatedRecord ))
@@ -236,7 +239,6 @@ public void updateItem_returnValues_not_set() {
236239 assertThat (response .attributes ().getId ()).isEqualTo (updatedRecord .getId ());
237240 assertThat (response .attributes ().getSort ()).isEqualTo (updatedRecord .getSort ());
238241 assertThat (response .attributes ().getValue ()).isEqualTo (updatedRecord .getValue ());
239- assertThat (response .attributes ().getVersion ()).isEqualTo (updatedRecord .getVersion () + 1 );
240242 }
241243
242244 @ Test
@@ -343,4 +345,61 @@ public void getItem_withoutReturnConsumedCapacity() {
343345 GetItemEnhancedResponse <Record > response = mappedTable .getItemWithResponse (req -> req .key (key )).join ();
344346 assertThat (response .consumedCapacity ()).isNull ();
345347 }
348+
349+ @ Test
350+ public void deleteItemWithOptimisticLockingEnabled_shouldSucceedIfVersionMatch () {
351+ RecordWithVersion originalItem = new RecordWithVersion ().setId ("123" ).setSort (10 ).setStringAttribute ("Original Item" );
352+ Key recordKey = Key .builder ()
353+ .partitionValue (originalItem .getId ())
354+ .sortValue (originalItem .getSort ())
355+ .build ();
356+ recordWithVersionMappedTable .putItem (originalItem ).join ();
357+
358+ // Retrieve the item
359+ RecordWithVersion retrievedItem = recordWithVersionMappedTable .getItem (r -> r .key (recordKey )).join ();
360+
361+ // Delete the item using a transaction
362+ TransactWriteItemsEnhancedRequest request = TransactWriteItemsEnhancedRequest .builder ()
363+ .addDeleteItem (recordWithVersionMappedTable , retrievedItem )
364+ .build ();
365+
366+ enhancedClient .transactWriteItems (request ).join ();
367+
368+ RecordWithVersion deletedItem = recordWithVersionMappedTable .getItem (r -> r .key (recordKey )).join ();
369+ assertThat (deletedItem ).isNull ();
370+ }
371+
372+ @ Test
373+ public void deleteItemWithOptimisticLockingEnabled_shouldFailIfVersionMismatch () {
374+ RecordWithVersion originalItem = new RecordWithVersion ().setId ("123" ).setSort (10 ).setStringAttribute ("Original Item" );
375+ Key recordKey = Key .builder ()
376+ .partitionValue (originalItem .getId ())
377+ .sortValue (originalItem .getSort ())
378+ .build ();
379+
380+ recordWithVersionMappedTable .putItem (originalItem ).join ();
381+
382+ // Retrieve the item and modify it separately
383+ RecordWithVersion modifiedItem = recordWithVersionMappedTable .getItem (r -> r .key (recordKey )).join ();
384+ modifiedItem .setStringAttribute ("Updated Item" );
385+
386+ // Update the item, which will increment the version
387+ recordWithVersionMappedTable .updateItem (modifiedItem ).join ();
388+
389+ // Now attempt to delete the original item using a transaction
390+ TransactWriteItemsEnhancedRequest request = TransactWriteItemsEnhancedRequest .builder ()
391+ .addDeleteItem (recordWithVersionMappedTable , modifiedItem )
392+ .build ();
393+
394+ assertThatThrownBy (() -> enhancedClient .transactWriteItems (request ).join ())
395+ .isInstanceOf (CompletionException .class )
396+ .satisfies (e ->
397+ assertThat (((TransactionCanceledException ) e .getCause ())
398+ .cancellationReasons ()
399+ .stream ()
400+ .anyMatch (reason ->
401+ "ConditionalCheckFailed" .equals (reason .code ())
402+ && "The conditional request failed" .equals (reason .message ())))
403+ .isTrue ());
404+ }
346405}
0 commit comments