Skip to content

Commit ac15f07

Browse files
Introduce the possibility to specify returnValuesOnConditionCheckFailure in DynamoDB Enhanced operations (#4708)
* Add returnValuesOnConditionCheckFailure param to UpdateItemEnhancedRequest (#4442) * Add returnValuesOnConditionCheckFailure param to DeleteItemEnhancedRequest (#4442) * Add returnValuesOnConditionCheckFailure param to PutItemEnhancedRequest (#4442) * Cover returnValuesOnConditionCheckFailure changes with integration tests (#4442) * Document new returnValuesOnConditionCheckFailure related API (#4442) * Extend changelog by description of returnValuesOnConditionCheckFailure related changes (#4442) * Fix minor codestyle issues (#4442) --------- Co-authored-by: anirudh9391 <[email protected]>
1 parent 5bd66ce commit ac15f07

File tree

15 files changed

+693
-25
lines changed

15 files changed

+693
-25
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"category": "Amazon DynamoDB Enhanced",
3+
"contributor": "breader124",
4+
"type": "feature",
5+
"description": "Introduce the possibility to specify returnValuesOnConditionCheckFailure in DynamoDB Enhanced operations"
6+
}

services-custom/dynamodb-enhanced/src/it/java/software/amazon/awssdk/enhanced/dynamodb/AsyncCrudWithResponseIntegrationTest.java

Lines changed: 141 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616
package software.amazon.awssdk.enhanced.dynamodb;
1717

1818
import static org.assertj.core.api.Assertions.assertThat;
19-
import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.secondaryPartitionKey;
20-
import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.secondarySortKey;
19+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
2120

22-
import org.assertj.core.data.Offset;
21+
import java.util.concurrent.CompletionException;
22+
import org.junit.After;
2323
import org.junit.AfterClass;
2424
import org.junit.BeforeClass;
2525
import org.junit.Test;
26+
import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedRequest;
2627
import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedResponse;
2728
import software.amazon.awssdk.enhanced.dynamodb.model.EnhancedLocalSecondaryIndex;
2829
import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedResponse;
@@ -32,18 +33,17 @@
3233
import software.amazon.awssdk.enhanced.dynamodb.model.UpdateItemEnhancedRequest;
3334
import software.amazon.awssdk.enhanced.dynamodb.model.UpdateItemEnhancedResponse;
3435
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
35-
import software.amazon.awssdk.services.dynamodb.model.ConsumedCapacity;
36+
import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException;
3637
import software.amazon.awssdk.services.dynamodb.model.Projection;
3738
import software.amazon.awssdk.services.dynamodb.model.ProjectionType;
3839
import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity;
3940
import software.amazon.awssdk.services.dynamodb.model.ReturnItemCollectionMetrics;
41+
import software.amazon.awssdk.services.dynamodb.model.ReturnValuesOnConditionCheckFailure;
4042

4143
public class AsyncCrudWithResponseIntegrationTest extends DynamoDbEnhancedIntegrationTestBase {
4244

4345

4446
private static final String TABLE_NAME = createTestTableName();
45-
46-
4747
private static final EnhancedLocalSecondaryIndex LOCAL_SECONDARY_INDEX = EnhancedLocalSecondaryIndex.builder()
4848
.indexName("index1")
4949
.projection(Projection.builder()
@@ -56,16 +56,24 @@ public class AsyncCrudWithResponseIntegrationTest extends DynamoDbEnhancedIntegr
5656
private static DynamoDbAsyncTable<Record> mappedTable;
5757

5858
@BeforeClass
59-
public static void setup() {
59+
public static void beforeClass() {
6060
dynamoDbClient = createAsyncDynamoDbClient();
6161
enhancedClient = DynamoDbEnhancedAsyncClient.builder().dynamoDbClient(dynamoDbClient).build();
6262
mappedTable = enhancedClient.table(TABLE_NAME, TABLE_SCHEMA);
6363
mappedTable.createTable(r -> r.localSecondaryIndices(LOCAL_SECONDARY_INDEX)).join();
6464
dynamoDbClient.waiter().waitUntilTableExists(r -> r.tableName(TABLE_NAME)).join();
6565
}
6666

67+
@After
68+
public void tearDown() {
69+
mappedTable.scan()
70+
.items()
71+
.subscribe(record -> mappedTable.deleteItem(record).join())
72+
.join();
73+
}
74+
6775
@AfterClass
68-
public static void teardown() {
76+
public static void afterClass() {
6977
try {
7078
dynamoDbClient.deleteTable(r -> r.tableName(TABLE_NAME)).join();
7179
} finally {
@@ -125,33 +133,149 @@ public void updateItem_returnItemCollectionMetrics_set_itemCollectionMetricsNotN
125133
}
126134

127135
@Test
128-
public void deleteItem_returnConsumedCapacity_unset_consumedCapacityNull() {
136+
public void deleteItem_returnItemCollectionMetrics_set_itemCollectionMetricsNull() {
129137
Key key = Key.builder().partitionValue("1").sortValue(10).build();
130138

131139
DeleteItemEnhancedResponse<Record> response = mappedTable.deleteItemWithResponse(r -> r.key(key)).join();
132140

133-
assertThat(response.consumedCapacity()).isNull();
141+
assertThat(response.itemCollectionMetrics()).isNull();
134142
}
135143

136144
@Test
137-
public void deleteItem_returnConsumedCapacity_set_consumedCapacityNotNull() {
145+
public void deleteItem_returnItemCollectionMetrics_set_itemCollectionMetricsNotNull() {
138146
Key key = Key.builder().partitionValue("1").sortValue(10).build();
139147

140148
DeleteItemEnhancedResponse<Record> response =
141-
mappedTable.deleteItemWithResponse(r -> r.key(key).returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)).join();
149+
mappedTable.deleteItemWithResponse(r -> r.key(key).returnItemCollectionMetrics(ReturnItemCollectionMetrics.SIZE))
150+
.join();
142151

143-
assertThat(response.consumedCapacity()).isNotNull();
152+
assertThat(response.itemCollectionMetrics()).isNotNull();
153+
}
154+
155+
@Test
156+
public void putItem_returnValuesOnConditionCheckFailure_set_returnValuesOnConditionCheckFailureNull() {
157+
Record record = new Record().setId("1").setSort(10);
158+
mappedTable.putItem(record).join();
159+
160+
Expression itemDoesNotExist = Expression.builder().expression("attribute_not_exists(id)").build();
161+
PutItemEnhancedRequest<Record> request = PutItemEnhancedRequest.builder(Record.class)
162+
.item(record)
163+
.conditionExpression(itemDoesNotExist)
164+
.build();
165+
166+
assertThatThrownBy(() -> mappedTable.putItem(request).join())
167+
.isInstanceOf(CompletionException.class)
168+
.satisfies(e -> assertThat(((ConditionalCheckFailedException) e.getCause()).hasItem()).isFalse());
169+
}
170+
171+
@Test
172+
public void putItem_returnValuesOnConditionCheckFailure_set_returnValuesOnConditionCheckFailureNotNull() {
173+
Record record = new Record().setId("1").setSort(10);
174+
mappedTable.putItem(record).join();
175+
176+
Expression itemDoesNotExist = Expression.builder().expression("attribute_not_exists(id)").build();
177+
PutItemEnhancedRequest<Record> request = PutItemEnhancedRequest.builder(Record.class)
178+
.item(record)
179+
.conditionExpression(itemDoesNotExist)
180+
.returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD)
181+
.build();
182+
183+
assertThatThrownBy(() -> mappedTable.putItem(request).join())
184+
.isInstanceOf(CompletionException.class)
185+
.satisfies(e -> assertThat(((ConditionalCheckFailedException) e.getCause()).hasItem()).isTrue());
186+
}
187+
188+
@Test
189+
public void updateItem_returnValuesOnConditionCheckFailure_set_returnValuesOnConditionCheckFailureNull() {
190+
Record record = new Record().setId("1").setSort(10);
191+
mappedTable.putItem(record).join();
192+
193+
Expression itemDoesNotExist = Expression.builder().expression("attribute_not_exists(id)").build();
194+
UpdateItemEnhancedRequest<Record> request = UpdateItemEnhancedRequest.builder(Record.class)
195+
.item(record)
196+
.conditionExpression(itemDoesNotExist)
197+
.build();
198+
199+
assertThatThrownBy(() -> mappedTable.updateItem(request).join())
200+
.isInstanceOf(CompletionException.class)
201+
.satisfies(e -> assertThat(((ConditionalCheckFailedException) e.getCause()).hasItem()).isFalse());
202+
}
203+
204+
@Test
205+
public void updateItem_returnValuesOnConditionCheckFailure_set_returnValuesOnConditionCheckFailureNotNull() {
206+
Record record = new Record().setId("1").setSort(10);
207+
mappedTable.putItem(record).join();
208+
209+
Expression itemDoesNotExist = Expression.builder().expression("attribute_not_exists(id)").build();
210+
UpdateItemEnhancedRequest<Record> request = UpdateItemEnhancedRequest.builder(Record.class)
211+
.item(record)
212+
.conditionExpression(itemDoesNotExist)
213+
.returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD)
214+
.build();
215+
216+
assertThatThrownBy(() -> mappedTable.updateItem(request).join())
217+
.isInstanceOf(CompletionException.class)
218+
.satisfies(e -> assertThat(((ConditionalCheckFailedException) e.getCause()).hasItem()).isTrue());
219+
}
220+
221+
@Test
222+
public void deleteItem_returnValuesOnConditionCheckFailure_set_returnValuesOnConditionCheckFailureNull() {
223+
Record record = new Record().setId("1").setSort(10);
224+
Key recordKey = Key.builder()
225+
.partitionValue(record.getId())
226+
.sortValue(record.getSort())
227+
.build();
228+
mappedTable.putItem(record).join();
229+
230+
Expression itemDoesNotExist = Expression.builder().expression("attribute_not_exists(id)").build();
231+
DeleteItemEnhancedRequest request = DeleteItemEnhancedRequest.builder()
232+
.key(recordKey)
233+
.conditionExpression(itemDoesNotExist)
234+
.build();
235+
236+
assertThatThrownBy(() -> mappedTable.deleteItem(request).join())
237+
.isInstanceOf(CompletionException.class)
238+
.satisfies(e -> assertThat(((ConditionalCheckFailedException) e.getCause()).hasItem()).isFalse());
239+
}
240+
241+
@Test
242+
public void deleteItem_returnValuesOnConditionCheckFailure_set_returnValuesOnConditionCheckFailureNotNull() {
243+
Record record = new Record().setId("1").setSort(10);
244+
Key recordKey = Key.builder()
245+
.partitionValue(record.getId())
246+
.sortValue(record.getSort())
247+
.build();
248+
mappedTable.putItem(record).join();
249+
250+
Expression itemDoesNotExist = Expression.builder().expression("attribute_not_exists(id)").build();
251+
DeleteItemEnhancedRequest request = DeleteItemEnhancedRequest.builder()
252+
.key(recordKey)
253+
.conditionExpression(itemDoesNotExist)
254+
.returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD)
255+
.build();
256+
257+
assertThatThrownBy(() -> mappedTable.deleteItem(request).join())
258+
.isInstanceOf(CompletionException.class)
259+
.satisfies(e -> assertThat(((ConditionalCheckFailedException) e.getCause()).hasItem()).isTrue());
260+
}
261+
262+
@Test
263+
public void deleteItem_returnConsumedCapacity_unset_consumedCapacityNull() {
264+
Key key = Key.builder().partitionValue("1").sortValue(10).build();
265+
266+
DeleteItemEnhancedResponse<Record> response = mappedTable.deleteItemWithResponse(r -> r.key(key)).join();
267+
268+
assertThat(response.consumedCapacity()).isNull();
144269
}
145270

146271
@Test
147-
public void delete_returnItemCollectionMetrics_set_itemCollectionMetricsNotNull() {
272+
public void deleteItem_returnConsumedCapacity_set_consumedCapacityNotNull() {
148273
Key key = Key.builder().partitionValue("1").sortValue(10).build();
149274

150275
DeleteItemEnhancedResponse<Record> response =
151-
mappedTable.deleteItemWithResponse(r -> r.key(key).returnItemCollectionMetrics(ReturnItemCollectionMetrics.SIZE))
152-
.join();
276+
mappedTable.deleteItemWithResponse(r -> r.key(key).returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)).join();
153277

154-
assertThat(response.itemCollectionMetrics()).isNotNull();
278+
assertThat(response.consumedCapacity()).isNotNull();
155279
}
156280

157281
@Test

0 commit comments

Comments
 (0)