From 0e14426bf5de5981ac13f7c9305a473bdc283c71 Mon Sep 17 00:00:00 2001 From: Dongie Agnir Date: Wed, 15 Sep 2021 11:18:02 -0700 Subject: [PATCH] Implement return values for enhanced DeleteItem This commit introduces DynamoDbTable#deleteItemWithResponse() that allows customers to specify additional parameters on the request such as ReturnConsumedCapacity to get additional information the service response. --- ...eature-DynamoDBEnhancedClient-9086c03.json | 6 + ...DeleteItemWithResponseIntegrationTest.java | 166 ++++++++++++++++++ ...DeleteItemWithResponseIntegrationTest.java | 165 +++++++++++++++++ .../enhanced/dynamodb/DynamoDbAsyncTable.java | 61 +++++++ .../enhanced/dynamodb/DynamoDbTable.java | 60 +++++++ .../client/DefaultDynamoDbAsyncTable.java | 20 ++- .../internal/client/DefaultDynamoDbTable.java | 18 +- .../operations/DeleteItemOperation.java | 29 ++- .../model/DeleteItemEnhancedRequest.java | 102 ++++++++++- .../model/DeleteItemEnhancedResponse.java | 121 +++++++++++++ .../AsyncDeleteItemWithResponseTest.java | 119 +++++++++++++ .../DeleteItemWithResponseTest.java | 119 +++++++++++++ .../operations/DeleteItemOperationTest.java | 132 +++++++++++++- .../operations/PutItemOperationTest.java | 118 +++++++++++++ .../model/DeleteItemEnhancedRequestTest.java | 89 +++++++++- .../model/DeleteItemEnhancedResponseTest.java | 137 +++++++++++++++ 16 files changed, 1440 insertions(+), 22 deletions(-) create mode 100644 .changes/next-release/feature-DynamoDBEnhancedClient-9086c03.json create mode 100644 services-custom/dynamodb-enhanced/src/it/java/software/amazon/awssdk/enhanced/dynamodb/AsyncDeleteItemWithResponseIntegrationTest.java create mode 100644 services-custom/dynamodb-enhanced/src/it/java/software/amazon/awssdk/enhanced/dynamodb/DeleteItemWithResponseIntegrationTest.java create mode 100644 services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedResponse.java create mode 100644 services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/AsyncDeleteItemWithResponseTest.java create mode 100644 services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/DeleteItemWithResponseTest.java create mode 100644 services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedResponseTest.java diff --git a/.changes/next-release/feature-DynamoDBEnhancedClient-9086c03.json b/.changes/next-release/feature-DynamoDBEnhancedClient-9086c03.json new file mode 100644 index 000000000000..5e7921e3702d --- /dev/null +++ b/.changes/next-release/feature-DynamoDBEnhancedClient-9086c03.json @@ -0,0 +1,6 @@ +{ + "category": "DynamoDB Enhanced Client", + "contributor": "", + "type": "feature", + "description": "This commit introduces DynamoDbTable#deleteItemWithResponse() that allows customers to specify additional parameters on the request such as ReturnConsumedCapacity to get additional information the service response." +} diff --git a/services-custom/dynamodb-enhanced/src/it/java/software/amazon/awssdk/enhanced/dynamodb/AsyncDeleteItemWithResponseIntegrationTest.java b/services-custom/dynamodb-enhanced/src/it/java/software/amazon/awssdk/enhanced/dynamodb/AsyncDeleteItemWithResponseIntegrationTest.java new file mode 100644 index 000000000000..88687e6ac725 --- /dev/null +++ b/services-custom/dynamodb-enhanced/src/it/java/software/amazon/awssdk/enhanced/dynamodb/AsyncDeleteItemWithResponseIntegrationTest.java @@ -0,0 +1,166 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.enhanced.dynamodb; + +import static org.assertj.core.api.Assertions.assertThat; +import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.primaryPartitionKey; +import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.primarySortKey; +import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.secondaryPartitionKey; +import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.secondarySortKey; + +import java.util.Objects; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import software.amazon.awssdk.enhanced.dynamodb.mapper.StaticTableSchema; +import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedResponse; +import software.amazon.awssdk.enhanced.dynamodb.model.EnhancedLocalSecondaryIndex; +import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; +import software.amazon.awssdk.services.dynamodb.model.Projection; +import software.amazon.awssdk.services.dynamodb.model.ProjectionType; +import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity; +import software.amazon.awssdk.services.dynamodb.model.ReturnItemCollectionMetrics; + +public class AsyncDeleteItemWithResponseIntegrationTest extends DynamoDbEnhancedIntegrationTestBase { + private static class Record { + private Integer id; + private Integer id2; + private String stringAttr1; + + private Integer getId() { + return id; + } + + private Record setId(Integer id) { + this.id = id; + return this; + } + + private Integer getId2() { + return id2; + } + + private Record setId2(Integer id2) { + this.id2 = id2; + return this; + } + + private String getStringAttr1() { + return stringAttr1; + } + + private Record setStringAttr1(String stringAttr1) { + this.stringAttr1 = stringAttr1; + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Record record = (Record) o; + return Objects.equals(id, record.id) + && Objects.equals(id2, record.id2) + && Objects.equals(stringAttr1, record.stringAttr1); + } + + @Override + public int hashCode() { + return Objects.hash(id, id2, stringAttr1); + } + } + + private static final String TABLE_NAME = createTestTableName(); + + private static final TableSchema TABLE_SCHEMA = + StaticTableSchema.builder(Record.class) + .newItemSupplier(Record::new) + .addAttribute(Integer.class, a -> a.name("id_1") + .getter(Record::getId) + .setter(Record::setId) + .tags(primaryPartitionKey(), secondaryPartitionKey("index1"))) + .addAttribute(Integer.class, a -> a.name("id_2") + .getter(Record::getId2) + .setter(Record::setId2) + .tags(primarySortKey(), secondarySortKey("index1"))) + .addAttribute(String.class, a -> a.name("stringAttr1") + .getter(Record::getStringAttr1) + .setter(Record::setStringAttr1)) + .build(); + + private static final EnhancedLocalSecondaryIndex LOCAL_SECONDARY_INDEX = EnhancedLocalSecondaryIndex.builder() + .indexName("index1") + .projection(Projection.builder() + .projectionType(ProjectionType.ALL) + .build()) + .build(); + + private static DynamoDbAsyncClient dynamoDbClient; + private static DynamoDbEnhancedAsyncClient enhancedClient; + private static DynamoDbAsyncTable mappedTable; + + @BeforeClass + public static void setup() { + dynamoDbClient = createAsyncDynamoDbClient(); + enhancedClient = DynamoDbEnhancedAsyncClient.builder().dynamoDbClient(dynamoDbClient).build(); + mappedTable = enhancedClient.table(TABLE_NAME, TABLE_SCHEMA); + mappedTable.createTable(r -> r.localSecondaryIndices(LOCAL_SECONDARY_INDEX)).join(); + dynamoDbClient.waiter().waitUntilTableExists(r -> r.tableName(TABLE_NAME)).join(); + } + + @AfterClass + public static void teardown() { + try { + dynamoDbClient.deleteTable(r -> r.tableName(TABLE_NAME)); + } finally { + dynamoDbClient.close(); + } + } + + @Test + public void deleteItem_returnConsumedCapacity_unset_consumedCapacityNull() { + Key key = Key.builder().partitionValue(1).sortValue(10).build(); + + DeleteItemEnhancedResponse response = mappedTable.deleteItemWithResponse(r -> r.key(key)).join(); + + assertThat(response.consumedCapacity()).isNull(); + } + + @Test + public void deleteItem_returnConsumedCapacity_set_consumedCapacityNotNull() { + Key key = Key.builder().partitionValue(1).sortValue(10).build(); + + DeleteItemEnhancedResponse response = + mappedTable.deleteItemWithResponse(r -> r.key(key).returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)).join(); + + assertThat(response.consumedCapacity()).isNotNull(); + } + + @Test + public void delete_returnItemCollectionMetrics_set_itemCollectionMetricsNotNull() { + Key key = Key.builder().partitionValue(1).sortValue(10).build(); + + DeleteItemEnhancedResponse response = + mappedTable.deleteItemWithResponse(r -> r.key(key).returnItemCollectionMetrics(ReturnItemCollectionMetrics.SIZE)) + .join(); + + assertThat(response.itemCollectionMetrics()).isNotNull(); + } +} diff --git a/services-custom/dynamodb-enhanced/src/it/java/software/amazon/awssdk/enhanced/dynamodb/DeleteItemWithResponseIntegrationTest.java b/services-custom/dynamodb-enhanced/src/it/java/software/amazon/awssdk/enhanced/dynamodb/DeleteItemWithResponseIntegrationTest.java new file mode 100644 index 000000000000..7c8c2612e477 --- /dev/null +++ b/services-custom/dynamodb-enhanced/src/it/java/software/amazon/awssdk/enhanced/dynamodb/DeleteItemWithResponseIntegrationTest.java @@ -0,0 +1,165 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.enhanced.dynamodb; + +import static org.assertj.core.api.Assertions.assertThat; +import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.primaryPartitionKey; +import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.primarySortKey; +import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.secondaryPartitionKey; +import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.secondarySortKey; + +import java.util.Objects; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import software.amazon.awssdk.enhanced.dynamodb.mapper.StaticTableSchema; +import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedResponse; +import software.amazon.awssdk.enhanced.dynamodb.model.EnhancedLocalSecondaryIndex; +import software.amazon.awssdk.services.dynamodb.DynamoDbClient; +import software.amazon.awssdk.services.dynamodb.model.Projection; +import software.amazon.awssdk.services.dynamodb.model.ProjectionType; +import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity; +import software.amazon.awssdk.services.dynamodb.model.ReturnItemCollectionMetrics; + +public class DeleteItemWithResponseIntegrationTest extends DynamoDbEnhancedIntegrationTestBase { + private static class Record { + private Integer id; + private Integer id2; + private String stringAttr1; + + private Integer getId() { + return id; + } + + private Record setId(Integer id) { + this.id = id; + return this; + } + + private Integer getId2() { + return id2; + } + + private Record setId2(Integer id2) { + this.id2 = id2; + return this; + } + + private String getStringAttr1() { + return stringAttr1; + } + + private Record setStringAttr1(String stringAttr1) { + this.stringAttr1 = stringAttr1; + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Record record = (Record) o; + return Objects.equals(id, record.id) + && Objects.equals(id2, record.id2) + && Objects.equals(stringAttr1, record.stringAttr1); + } + + @Override + public int hashCode() { + return Objects.hash(id, id2, stringAttr1); + } + } + + private static final String TABLE_NAME = createTestTableName(); + + private static final TableSchema TABLE_SCHEMA = + StaticTableSchema.builder(Record.class) + .newItemSupplier(Record::new) + .addAttribute(Integer.class, a -> a.name("id_1") + .getter(Record::getId) + .setter(Record::setId) + .tags(primaryPartitionKey(), secondaryPartitionKey("index1"))) + .addAttribute(Integer.class, a -> a.name("id_2") + .getter(Record::getId2) + .setter(Record::setId2) + .tags(primarySortKey(), secondarySortKey("index1"))) + .addAttribute(String.class, a -> a.name("stringAttr1") + .getter(Record::getStringAttr1) + .setter(Record::setStringAttr1)) + .build(); + + private static final EnhancedLocalSecondaryIndex LOCAL_SECONDARY_INDEX = EnhancedLocalSecondaryIndex.builder() + .indexName("index1") + .projection(Projection.builder() + .projectionType(ProjectionType.ALL) + .build()) + .build(); + + private static DynamoDbClient dynamoDbClient; + private static DynamoDbEnhancedClient enhancedClient; + private static DynamoDbTable mappedTable; + + @BeforeClass + public static void setup() { + dynamoDbClient = createDynamoDbClient(); + enhancedClient = DynamoDbEnhancedClient.builder().dynamoDbClient(dynamoDbClient).build(); + mappedTable = enhancedClient.table(TABLE_NAME, TABLE_SCHEMA); + mappedTable.createTable(r -> r.localSecondaryIndices(LOCAL_SECONDARY_INDEX)); + dynamoDbClient.waiter().waitUntilTableExists(r -> r.tableName(TABLE_NAME)); + } + + @AfterClass + public static void teardown() { + try { + dynamoDbClient.deleteTable(r -> r.tableName(TABLE_NAME)); + } finally { + dynamoDbClient.close(); + } + } + + @Test + public void deleteItem_returnConsumedCapacity_unset_consumedCapacityNull() { + Key key = Key.builder().partitionValue(1).sortValue(10).build(); + + DeleteItemEnhancedResponse response = mappedTable.deleteItemWithResponse(r -> r.key(key)); + + assertThat(response.consumedCapacity()).isNull(); + } + + @Test + public void deleteItem_returnConsumedCapacity_set_consumedCapacityNotNull() { + Key key = Key.builder().partitionValue(1).sortValue(10).build(); + + DeleteItemEnhancedResponse response = + mappedTable.deleteItemWithResponse(r -> r.key(key).returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)); + + assertThat(response.consumedCapacity()).isNotNull(); + } + + @Test + public void delete_returnItemCollectionMetrics_set_itemCollectionMetricsNotNull() { + Key key = Key.builder().partitionValue(1).sortValue(10).build(); + + DeleteItemEnhancedResponse response = + mappedTable.deleteItemWithResponse(r -> r.key(key).returnItemCollectionMetrics(ReturnItemCollectionMetrics.SIZE)); + + assertThat(response.itemCollectionMetrics()).isNotNull(); + } +} diff --git a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/DynamoDbAsyncTable.java b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/DynamoDbAsyncTable.java index 5bf1cb2be2f5..d0bf1f3b7b60 100644 --- a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/DynamoDbAsyncTable.java +++ b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/DynamoDbAsyncTable.java @@ -20,6 +20,7 @@ import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.enhanced.dynamodb.model.CreateTableEnhancedRequest; import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedRequest; +import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedResponse; import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedRequest; import software.amazon.awssdk.enhanced.dynamodb.model.Page; import software.amazon.awssdk.enhanced.dynamodb.model.PagePublisher; @@ -30,6 +31,7 @@ import software.amazon.awssdk.enhanced.dynamodb.model.ScanEnhancedRequest; import software.amazon.awssdk.enhanced.dynamodb.model.UpdateItemEnhancedRequest; import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; +import software.amazon.awssdk.services.dynamodb.model.ConsumedCapacity; /** * Asynchronous interface for running commands against an object that is linked to a specific DynamoDb table resource @@ -236,6 +238,65 @@ default CompletableFuture deleteItem(T keyItem) { throw new UnsupportedOperationException(); } + /** + * Deletes a single item from the mapped table using a supplied primary {@link Key}. + *

+ * The additional configuration parameters that the enhanced client supports are defined + * in the {@link DeleteItemEnhancedRequest}. + *

+ * This operation calls the low-level DynamoDB API DeleteItem operation. Consult the DeleteItem documentation for + * further details and constraints. Unlike {@link #deleteItem(DeleteItemEnhancedRequest)}, this returns a response object, + * allowing the user to retrieve additional information from DynamoDB related to the API call, such as + * {@link ConsumedCapacity} if specified on the request. + *

+ * Example: + *

+     * {@code
+     *
+     * DeleteItemEnhancedRequest request = DeleteItemEnhancedRequest.builder().key(key).build();
+     * DeleteItemEnhancedResponse response = mappedTable.deleteItemWithResponse(request).join();
+     * }
+     * 
+ * + * @param request A {@link DeleteItemEnhancedRequest} with key and optional directives for deleting an item from the + * table. + * @return A {@code CompletableFuture} containing the response returned by DynamoDB. + */ + default CompletableFuture> deleteItemWithResponse(DeleteItemEnhancedRequest request) { + throw new UnsupportedOperationException(); + } + + /** + * Deletes a single item from the mapped table using a supplied primary {@link Key}. + *

+ * The additional configuration parameters that the enhanced client supports are defined + * in the {@link DeleteItemEnhancedRequest}. + *

+ * This operation calls the low-level DynamoDB API DeleteItem operation. Consult the DeleteItem documentation for + * further details and constraints. Unlike {@link #deleteItem(Consumer)}, this returns a response object, allowing the user to + * retrieve additional information from DynamoDB related to the API call, such as {@link ConsumedCapacity} if specified on + * the request. + *

+ * Note: This is a convenience method that creates an instance of the request builder avoiding the need to + * create one manually via {@link DeleteItemEnhancedRequest#builder()}. + *

+ * Example: + *

+     * {@code
+     *
+     * DeleteItemEnhancedResponse response = mappedTable.deleteWithResponse(r -> r.key(key)).join();
+     * }
+     * 
+ * + * @param requestConsumer A {@link Consumer} of {@link DeleteItemEnhancedRequest} with key and + * optional directives for deleting an item from the table. + * @return A {@code CompletableFuture} containing the response returned by DynamoDB. + */ + default CompletableFuture> deleteItemWithResponse( + Consumer requestConsumer) { + throw new UnsupportedOperationException(); + } + /** * Retrieves a single item from the mapped table using a supplied primary {@link Key}. *

diff --git a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.java b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.java index 09db35e7580e..56231fef5070 100644 --- a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.java +++ b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.java @@ -20,6 +20,7 @@ import software.amazon.awssdk.core.pagination.sync.SdkIterable; import software.amazon.awssdk.enhanced.dynamodb.model.CreateTableEnhancedRequest; import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedRequest; +import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedResponse; import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedRequest; import software.amazon.awssdk.enhanced.dynamodb.model.Page; import software.amazon.awssdk.enhanced.dynamodb.model.PageIterable; @@ -30,6 +31,7 @@ import software.amazon.awssdk.enhanced.dynamodb.model.ScanEnhancedRequest; import software.amazon.awssdk.enhanced.dynamodb.model.UpdateItemEnhancedRequest; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; +import software.amazon.awssdk.services.dynamodb.model.ConsumedCapacity; /** * Synchronous interface for running commands against an object that is linked to a specific DynamoDb table resource @@ -235,6 +237,64 @@ default T deleteItem(T keyItem) { throw new UnsupportedOperationException(); } + /** + * Deletes a single item from the mapped table using a supplied primary {@link Key}. + *

+ * The additional configuration parameters that the enhanced client supports are defined + * in the {@link DeleteItemEnhancedRequest}. + *

+ * This operation calls the low-level DynamoDB API DeleteItem operation. Consult the DeleteItem documentation for + * further details and constraints. Unlike {@link #deleteItem(DeleteItemEnhancedRequest)}, this returns a response object, + * allowing the user to retrieve additional information from DynamoDB related to the API call, such as + * {@link ConsumedCapacity} if specified on the request. + *

+ * Example: + *

+     * {@code
+     *
+     * DeleteItemEnhancedRequest request = DeleteItemEnhancedRequest.builder().key(key).build();
+     * DeleteItemEnhancedResponse response = mappedTable.deleteItemWithResponse(request);
+     * }
+     * 
+ * + * @param request A {@link DeleteItemEnhancedRequest} with key and optional directives for deleting an item from the + * table. + * @return The response returned by DynamoDB. + */ + default DeleteItemEnhancedResponse deleteItemWithResponse(DeleteItemEnhancedRequest request) { + throw new UnsupportedOperationException(); + } + + /** + * Deletes a single item from the mapped table using a supplied primary {@link Key}. + *

+ * The additional configuration parameters that the enhanced client supports are defined + * in the {@link DeleteItemEnhancedRequest}. + *

+ * This operation calls the low-level DynamoDB API DeleteItem operation. Consult the DeleteItem documentation for + * further details and constraints. Unlike {@link #deleteItem(Consumer)}, this returns a response object, allowing the user to + * retrieve additional information from DynamoDB related to the API call, such as {@link ConsumedCapacity} if specified on + * the request. + *

+ * Note: This is a convenience method that creates an instance of the request builder avoiding the need to + * create one manually via {@link DeleteItemEnhancedRequest#builder()}. + *

+ * Example: + *

+     * {@code
+     *
+     * DeleteItemEnhancedResponse response = mappedTable.deleteWithResponse(r -> r.key(key));
+     * }
+     * 
+ * + * @param requestConsumer A {@link Consumer} of {@link DeleteItemEnhancedRequest} with key and + * optional directives for deleting an item from the table. + * @return The response returned by DynamoDB. + */ + default DeleteItemEnhancedResponse deleteItemWithResponse(Consumer requestConsumer) { + throw new UnsupportedOperationException(); + } + /** * Retrieves a single item from the mapped table using a supplied primary {@link Key}. *

diff --git a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbAsyncTable.java b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbAsyncTable.java index fcd7b0152ffe..14c7ec901425 100644 --- a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbAsyncTable.java +++ b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbAsyncTable.java @@ -37,6 +37,7 @@ import software.amazon.awssdk.enhanced.dynamodb.internal.operations.UpdateItemOperation; import software.amazon.awssdk.enhanced.dynamodb.model.CreateTableEnhancedRequest; import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedRequest; +import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedResponse; import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedRequest; import software.amazon.awssdk.enhanced.dynamodb.model.PagePublisher; import software.amazon.awssdk.enhanced.dynamodb.model.PutItemEnhancedRequest; @@ -111,8 +112,9 @@ public CompletableFuture createTable() { @Override public CompletableFuture deleteItem(DeleteItemEnhancedRequest request) { - TableOperation operation = DeleteItemOperation.create(request); - return operation.executeOnPrimaryIndexAsync(tableSchema, tableName, extension, dynamoDbClient); + TableOperation> operation = DeleteItemOperation.create(request); + return operation.executeOnPrimaryIndexAsync(tableSchema, tableName, extension, dynamoDbClient) + .thenApply(DeleteItemEnhancedResponse::attributes); } @Override @@ -132,6 +134,20 @@ public CompletableFuture deleteItem(T keyItem) { return deleteItem(keyFrom(keyItem)); } + @Override + public CompletableFuture> deleteItemWithResponse(DeleteItemEnhancedRequest request) { + TableOperation> operation = DeleteItemOperation.create(request); + return operation.executeOnPrimaryIndexAsync(tableSchema, tableName, extension, dynamoDbClient); + } + + @Override + public CompletableFuture> deleteItemWithResponse( + Consumer requestConsumer) { + DeleteItemEnhancedRequest.Builder builder = DeleteItemEnhancedRequest.builder(); + requestConsumer.accept(builder); + return deleteItemWithResponse(builder.build()); + } + @Override public CompletableFuture getItem(GetItemEnhancedRequest request) { TableOperation operation = GetItemOperation.create(request); diff --git a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbTable.java b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbTable.java index 3ea184a9a994..6fd6322a8608 100644 --- a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbTable.java +++ b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbTable.java @@ -36,6 +36,7 @@ import software.amazon.awssdk.enhanced.dynamodb.internal.operations.UpdateItemOperation; import software.amazon.awssdk.enhanced.dynamodb.model.CreateTableEnhancedRequest; import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedRequest; +import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedResponse; import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedRequest; import software.amazon.awssdk.enhanced.dynamodb.model.PageIterable; import software.amazon.awssdk.enhanced.dynamodb.model.PutItemEnhancedRequest; @@ -113,8 +114,8 @@ public void createTable() { @Override public T deleteItem(DeleteItemEnhancedRequest request) { - TableOperation operation = DeleteItemOperation.create(request); - return operation.executeOnPrimaryIndex(tableSchema, tableName, extension, dynamoDbClient); + TableOperation> operation = DeleteItemOperation.create(request); + return operation.executeOnPrimaryIndex(tableSchema, tableName, extension, dynamoDbClient).attributes(); } @Override @@ -134,6 +135,19 @@ public T deleteItem(T keyItem) { return deleteItem(keyFrom(keyItem)); } + @Override + public DeleteItemEnhancedResponse deleteItemWithResponse(DeleteItemEnhancedRequest request) { + TableOperation> operation = DeleteItemOperation.create(request); + return operation.executeOnPrimaryIndex(tableSchema, tableName, extension, dynamoDbClient); + } + + @Override + public DeleteItemEnhancedResponse deleteItemWithResponse(Consumer requestConsumer) { + DeleteItemEnhancedRequest.Builder builder = DeleteItemEnhancedRequest.builder(); + requestConsumer.accept(builder); + return deleteItemWithResponse(builder.build()); + } + @Override public T getItem(GetItemEnhancedRequest request) { TableOperation operation = GetItemOperation.create(request); diff --git a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/DeleteItemOperation.java b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/DeleteItemOperation.java index 4fb45d46da44..57e48eda8266 100644 --- a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/DeleteItemOperation.java +++ b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/DeleteItemOperation.java @@ -28,6 +28,7 @@ import software.amazon.awssdk.enhanced.dynamodb.TableSchema; import software.amazon.awssdk.enhanced.dynamodb.internal.EnhancedClientUtils; import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedRequest; +import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedResponse; import software.amazon.awssdk.enhanced.dynamodb.model.TransactDeleteItemEnhancedRequest; import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; @@ -43,7 +44,7 @@ @SdkInternalApi public class DeleteItemOperation - implements TableOperation, + implements TableOperation>, TransactableWriteOperation, BatchableWriteOperation { @@ -82,17 +83,27 @@ public DeleteItemRequest generateRequest(TableSchema tableSchema, .key(key.keyMap(tableSchema, operationContext.indexName())) .returnValues(ReturnValue.ALL_OLD); + if (request.left().isPresent()) { + requestBuilder = addPlainDeleteItemParameters(requestBuilder, request.left().get()); + } + requestBuilder = addExpressionsIfExist(requestBuilder); return requestBuilder.build(); } @Override - public T transformResponse(DeleteItemResponse response, - TableSchema tableSchema, - OperationContext operationContext, - DynamoDbEnhancedClientExtension extension) { - return EnhancedClientUtils.readAndTransformSingleItem(response.attributes(), tableSchema, operationContext, extension); + public DeleteItemEnhancedResponse transformResponse(DeleteItemResponse response, + TableSchema tableSchema, + OperationContext operationContext, + DynamoDbEnhancedClientExtension extension) { + T attributes = EnhancedClientUtils.readAndTransformSingleItem(response.attributes(), tableSchema, operationContext, + extension); + return DeleteItemEnhancedResponse.builder(null) + .attributes(attributes) + .consumedCapacity(response.consumedCapacity()) + .itemCollectionMetrics(response.itemCollectionMetrics()) + .build(); } @Override @@ -162,4 +173,10 @@ private DeleteItemRequest.Builder addExpressionsIfExist(DeleteItemRequest.Builde return requestBuilder; } + private DeleteItemRequest.Builder addPlainDeleteItemParameters(DeleteItemRequest.Builder requestBuilder, + DeleteItemEnhancedRequest enhancedRequest) { + requestBuilder = requestBuilder.returnConsumedCapacity(enhancedRequest.returnConsumedCapacityAsString()); + requestBuilder = requestBuilder.returnItemCollectionMetrics(enhancedRequest.returnItemCollectionMetricsAsString()); + return requestBuilder; + } } diff --git a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedRequest.java b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedRequest.java index eba0b19997e1..34870460a854 100644 --- a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedRequest.java +++ b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedRequest.java @@ -22,6 +22,10 @@ import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; import software.amazon.awssdk.enhanced.dynamodb.Expression; import software.amazon.awssdk.enhanced.dynamodb.Key; +import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest; +import software.amazon.awssdk.services.dynamodb.model.PutItemRequest; +import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity; +import software.amazon.awssdk.services.dynamodb.model.ReturnItemCollectionMetrics; /** * Defines parameters used to remove an item from a DynamoDb table using the deleteItem() operation (such as @@ -35,10 +39,14 @@ public final class DeleteItemEnhancedRequest { private final Key key; private final Expression conditionExpression; + private final String returnConsumedCapacity; + private final String returnItemCollectionMetrics; private DeleteItemEnhancedRequest(Builder builder) { this.key = builder.key; this.conditionExpression = builder.conditionExpression; + this.returnConsumedCapacity = builder.returnConsumedCapacity; + this.returnItemCollectionMetrics = builder.returnItemCollectionMetrics; } /** @@ -52,7 +60,10 @@ public static Builder builder() { * Returns a builder initialized with all existing values on the request object. */ public Builder toBuilder() { - return builder().key(key).conditionExpression(conditionExpression); + return builder().key(key) + .conditionExpression(conditionExpression) + .returnConsumedCapacity(returnConsumedCapacity) + .returnItemCollectionMetrics(returnItemCollectionMetrics); } /** @@ -69,6 +80,45 @@ public Expression conditionExpression() { return conditionExpression; } + /** + * Whether to return the capacity consumed by this operation. + * + * @see PutItemRequest#returnConsumedCapacity() + */ + public ReturnConsumedCapacity returnConsumedCapacity() { + return ReturnConsumedCapacity.fromValue(returnConsumedCapacity); + } + + /** + * Whether to return the capacity consumed by this operation. + *

+ * Similar to {@link #returnConsumedCapacity()} but return the value as a string. This is useful in situations where the + * value is not defined in {@link ReturnConsumedCapacity}. + */ + public String returnConsumedCapacityAsString() { + return returnConsumedCapacity; + } + + /** + * Whether to return the item collection metrics. + * + * @see DeleteItemRequest#returnItemCollectionMetrics() + */ + public ReturnItemCollectionMetrics returnItemCollectionMetrics() { + return ReturnItemCollectionMetrics.fromValue(returnItemCollectionMetrics); + } + + /** + * Whether to return the item collection metrics. + *

+ * Similar to {@link #returnItemCollectionMetrics()} but return the value as a string. This is useful in situations + * where the + * value is not defined in {@link ReturnItemCollectionMetrics}. + */ + public String returnItemCollectionMetricsAsString() { + return returnItemCollectionMetrics; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -78,13 +128,18 @@ public boolean equals(Object o) { return false; } DeleteItemEnhancedRequest that = (DeleteItemEnhancedRequest) o; - return Objects.equals(key, that.key) && Objects.equals(conditionExpression, that.conditionExpression); + return Objects.equals(key, that.key) + && Objects.equals(conditionExpression, that.conditionExpression) + && Objects.equals(returnConsumedCapacity, that.returnConsumedCapacity) + && Objects.equals(returnItemCollectionMetrics, that.returnItemCollectionMetrics); } @Override public int hashCode() { int result = key != null ? key.hashCode() : 0; result = 31 * result + (conditionExpression != null ? conditionExpression.hashCode() : 0); + result = 31 * result + (returnConsumedCapacity != null ? returnConsumedCapacity.hashCode() : 0); + result = 31 * result + (returnItemCollectionMetrics != null ? returnItemCollectionMetrics.hashCode() : 0); return result; } @@ -96,6 +151,8 @@ public int hashCode() { public static final class Builder { private Key key; private Expression conditionExpression; + private String returnConsumedCapacity; + private String returnItemCollectionMetrics; private Builder() { } @@ -138,6 +195,47 @@ public Builder conditionExpression(Expression conditionExpression) { return this; } + /** + * Whether to return the capacity consumed by this operation. + * + * @see DeleteItemRequest.Builder#returnConsumedCapacity(ReturnConsumedCapacity) + */ + public Builder returnConsumedCapacity(ReturnConsumedCapacity returnConsumedCapacity) { + this.returnConsumedCapacity = returnConsumedCapacity == null ? null : returnConsumedCapacity.toString(); + return this; + } + + /** + * Whether to return the capacity consumed by this operation. + * + * @see DeleteItemRequest.Builder#returnConsumedCapacity(String) + */ + public Builder returnConsumedCapacity(String returnConsumedCapacity) { + this.returnConsumedCapacity = returnConsumedCapacity; + return this; + } + + /** + * Whether to return the item collection metrics. + * + * @see DeleteItemRequest.Builder#returnItemCollectionMetrics(ReturnItemCollectionMetrics) + */ + public Builder returnItemCollectionMetrics(ReturnItemCollectionMetrics returnItemCollectionMetrics) { + this.returnItemCollectionMetrics = returnItemCollectionMetrics == null ? null : + returnItemCollectionMetrics.toString(); + return this; + } + + /** + * Whether to return the item collection metrics. + * + * @see DeleteItemRequest.Builder#returnItemCollectionMetrics(String) + */ + public Builder returnItemCollectionMetrics(String returnItemCollectionMetrics) { + this.returnItemCollectionMetrics = returnItemCollectionMetrics; + return this; + } + public DeleteItemEnhancedRequest build() { return new DeleteItemEnhancedRequest(this); } diff --git a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedResponse.java b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedResponse.java new file mode 100644 index 000000000000..9738c714aba1 --- /dev/null +++ b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedResponse.java @@ -0,0 +1,121 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.enhanced.dynamodb.model; + +import java.util.Objects; +import software.amazon.awssdk.annotations.SdkPublicApi; +import software.amazon.awssdk.enhanced.dynamodb.DynamoDbAsyncTable; +import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; +import software.amazon.awssdk.services.dynamodb.model.ConsumedCapacity; +import software.amazon.awssdk.services.dynamodb.model.DeleteItemResponse; +import software.amazon.awssdk.services.dynamodb.model.ItemCollectionMetrics; + +/** + * Defines the elements returned by DynamoDB from a {@code DeleteItem} operation, such as + * {@link DynamoDbTable#deleteItemWithResponse(DeleteItemEnhancedRequest)} and + * {@link DynamoDbAsyncTable#deleteItemWithResponse(DeleteItemEnhancedRequest)}. + * + * @param The type of the item. + */ +@SdkPublicApi +public final class DeleteItemEnhancedResponse { + private final T attributes; + private final ConsumedCapacity consumedCapacity; + private final ItemCollectionMetrics itemCollectionMetrics; + + private DeleteItemEnhancedResponse(Builder builder) { + this.attributes = builder.attributes; + this.consumedCapacity = builder.consumedCapacity; + this.itemCollectionMetrics = builder.itemCollectionMetrics; + } + + /** + * The attribute values as they appeared before the {@code DeleteItem} operation. + */ + public T attributes() { + return attributes; + } + + /** + * The capacity units consumed by the {@code DeleteItem} operation. + * + * @see DeleteItemResponse#consumedCapacity() for more information. + */ + public ConsumedCapacity consumedCapacity() { + return consumedCapacity; + } + + /** + * Information about item collections, if any, that were affected by the {@code DeleteItem} operation. + * + * @see DeleteItemResponse#itemCollectionMetrics() for more information. + */ + public ItemCollectionMetrics itemCollectionMetrics() { + return itemCollectionMetrics; + } + + public static Builder builder(Class clzz) { + return new Builder<>(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + DeleteItemEnhancedResponse that = (DeleteItemEnhancedResponse) o; + return Objects.equals(attributes, that.attributes) + && Objects.equals(consumedCapacity, that.consumedCapacity) + && Objects.equals(itemCollectionMetrics, that.itemCollectionMetrics); + } + + @Override + public int hashCode() { + int result = Objects.hashCode(attributes); + result = 31 * result + Objects.hashCode(consumedCapacity); + result = 31 * result + Objects.hashCode(itemCollectionMetrics); + return result; + } + + public static final class Builder { + private T attributes; + private ConsumedCapacity consumedCapacity; + private ItemCollectionMetrics itemCollectionMetrics; + + public Builder attributes(T attributes) { + this.attributes = attributes; + return this; + } + + public Builder consumedCapacity(ConsumedCapacity consumedCapacity) { + this.consumedCapacity = consumedCapacity; + return this; + } + + public Builder itemCollectionMetrics(ItemCollectionMetrics itemCollectionMetrics) { + this.itemCollectionMetrics = itemCollectionMetrics; + return this; + } + + public DeleteItemEnhancedResponse build() { + return new DeleteItemEnhancedResponse<>(this); + } + } +} \ No newline at end of file diff --git a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/AsyncDeleteItemWithResponseTest.java b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/AsyncDeleteItemWithResponseTest.java new file mode 100644 index 000000000000..d4c9c2492800 --- /dev/null +++ b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/AsyncDeleteItemWithResponseTest.java @@ -0,0 +1,119 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.enhanced.dynamodb.functionaltests; + +import static org.assertj.core.api.Assertions.assertThat; +import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.primaryPartitionKey; + +import java.util.Objects; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import software.amazon.awssdk.enhanced.dynamodb.DynamoDbAsyncTable; +import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedAsyncClient; +import software.amazon.awssdk.enhanced.dynamodb.Key; +import software.amazon.awssdk.enhanced.dynamodb.TableSchema; +import software.amazon.awssdk.enhanced.dynamodb.mapper.StaticTableSchema; +import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedResponse; +import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest; +import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity; + +public class AsyncDeleteItemWithResponseTest extends LocalDynamoDbAsyncTestBase { + private static class Record { + private Integer id; + private String stringAttr1; + + private Integer getId() { + return id; + } + + private Record setId(Integer id) { + this.id = id; + return this; + } + + private String getStringAttr1() { + return stringAttr1; + } + + private Record setStringAttr1(String stringAttr1) { + this.stringAttr1 = stringAttr1; + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Record record = (Record) o; + return Objects.equals(id, record.id) && Objects.equals(stringAttr1, record.stringAttr1); + } + + @Override + public int hashCode() { + return Objects.hash(id, stringAttr1); + } + } + + private static final TableSchema TABLE_SCHEMA = + StaticTableSchema.builder(Record.class) + .newItemSupplier(Record::new) + .addAttribute(Integer.class, a -> a.name("id_1") + .getter(Record::getId) + .setter(Record::setId) + .tags(primaryPartitionKey())) + .addAttribute(String.class, a -> a.name("stringAttr1") + .getter(Record::getStringAttr1) + .setter(Record::setStringAttr1)) + .build(); + + private DynamoDbEnhancedAsyncClient enhancedClient; + + private DynamoDbAsyncTable mappedTable1; + + @Before + public void createTable() { + enhancedClient = DynamoDbEnhancedAsyncClient.builder() + .dynamoDbClient(getDynamoDbAsyncClient()) + .build(); + + mappedTable1 = enhancedClient.table(getConcreteTableName("table-name-1"), TABLE_SCHEMA); + + mappedTable1.createTable(r -> r.provisionedThroughput(getDefaultProvisionedThroughput())).join(); + } + + @After + public void deleteTable() { + getDynamoDbAsyncClient().deleteTable(DeleteTableRequest.builder() + .tableName(getConcreteTableName("table-name-1")) + .build()); + } + + // Note: DynamoDB local seems to always return the consumed capacity even if not specified on the request. See + // AsyncDeleteItemWithResponseIntegrationTest for additional testing of this field against the actual service. + @Test + public void returnConsumedCapacity_set_consumedCapacityNotNull() { + Key key = Key.builder().partitionValue(1).build(); + DeleteItemEnhancedResponse response = mappedTable1.deleteItemWithResponse(r -> r.key(key) + .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)).join(); + + assertThat(response.consumedCapacity()).isNotNull(); + } +} diff --git a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/DeleteItemWithResponseTest.java b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/DeleteItemWithResponseTest.java new file mode 100644 index 000000000000..532bf220a842 --- /dev/null +++ b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/DeleteItemWithResponseTest.java @@ -0,0 +1,119 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.enhanced.dynamodb.functionaltests; + +import static org.assertj.core.api.Assertions.assertThat; +import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.primaryPartitionKey; + +import java.util.Objects; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient; +import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; +import software.amazon.awssdk.enhanced.dynamodb.Key; +import software.amazon.awssdk.enhanced.dynamodb.TableSchema; +import software.amazon.awssdk.enhanced.dynamodb.mapper.StaticTableSchema; +import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedResponse; +import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest; +import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity; + +public class DeleteItemWithResponseTest extends LocalDynamoDbSyncTestBase { + private static class Record { + private Integer id; + private String stringAttr1; + + private Integer getId() { + return id; + } + + private Record setId(Integer id) { + this.id = id; + return this; + } + + private String getStringAttr1() { + return stringAttr1; + } + + private Record setStringAttr1(String stringAttr1) { + this.stringAttr1 = stringAttr1; + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Record record = (Record) o; + return Objects.equals(id, record.id) && Objects.equals(stringAttr1, record.stringAttr1); + } + + @Override + public int hashCode() { + return Objects.hash(id, stringAttr1); + } + } + + private static final TableSchema TABLE_SCHEMA = + StaticTableSchema.builder(Record.class) + .newItemSupplier(Record::new) + .addAttribute(Integer.class, a -> a.name("id_1") + .getter(Record::getId) + .setter(Record::setId) + .tags(primaryPartitionKey())) + .addAttribute(String.class, a -> a.name("stringAttr1") + .getter(Record::getStringAttr1) + .setter(Record::setStringAttr1)) + .build(); + + private DynamoDbEnhancedClient enhancedClient; + + private DynamoDbTable mappedTable1; + + @Before + public void createTable() { + enhancedClient = DynamoDbEnhancedClient.builder() + .dynamoDbClient(getDynamoDbClient()) + .build(); + + mappedTable1 = enhancedClient.table(getConcreteTableName("table-name-1"), TABLE_SCHEMA); + + mappedTable1.createTable(r -> r.provisionedThroughput(getDefaultProvisionedThroughput())); + } + + @After + public void deleteTable() { + getDynamoDbClient().deleteTable(DeleteTableRequest.builder() + .tableName(getConcreteTableName("table-name-1")) + .build()); + } + + // Note: DynamoDB local seems to always return the consumed capacity even if not specified on the request. See + // AsyncDeleteItemWithResponseIntegrationTest for additional testing of this field against the actual service. + @Test + public void returnConsumedCapacity_set_consumedCapacityNotNull() { + Key key = Key.builder().partitionValue(1).build(); + DeleteItemEnhancedResponse response = mappedTable1.deleteItemWithResponse(r -> r.key(key) + .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)); + + assertThat(response.consumedCapacity()).isNotNull(); + } +} diff --git a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/DeleteItemOperationTest.java b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/DeleteItemOperationTest.java index 3ef03f75cf68..ddad7d7828f4 100644 --- a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/DeleteItemOperationTest.java +++ b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/DeleteItemOperationTest.java @@ -35,6 +35,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.UUID; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -56,6 +57,8 @@ import software.amazon.awssdk.services.dynamodb.model.Delete; import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest; import software.amazon.awssdk.services.dynamodb.model.DeleteItemResponse; +import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity; +import software.amazon.awssdk.services.dynamodb.model.ReturnItemCollectionMetrics; import software.amazon.awssdk.services.dynamodb.model.ReturnValue; import software.amazon.awssdk.services.dynamodb.model.TransactWriteItem; @@ -105,10 +108,97 @@ public void getServiceCall_makesTheRightCallAndReturnsResponse() { } @Test - public void generateRequest_partitionKeyOnly() { + public void generateRequest_withReturnConsumedCapacity_unknownValue_generatesCorrectRequest() { FakeItem keyItem = createUniqueFakeItem(); + + String returnConsumedCapacity = UUID.randomUUID().toString(); + DeleteItemOperation deleteItemOperation = - DeleteItemOperation.create(DeleteItemEnhancedRequest.builder().key(k -> k.partitionValue(keyItem.getId())).build()); + DeleteItemOperation.create(DeleteItemEnhancedRequest.builder() + .key(k -> k.partitionValue(keyItem.getId())) + .returnConsumedCapacity(returnConsumedCapacity) + .build()); + + DeleteItemRequest request = deleteItemOperation.generateRequest(FakeItem.getTableSchema(), + PRIMARY_CONTEXT, + null); + + Map expectedKeyMap = new HashMap<>(); + expectedKeyMap.put("id", AttributeValue.builder().s(keyItem.getId()).build()); + DeleteItemRequest expectedRequest = DeleteItemRequest.builder() + .tableName(TABLE_NAME) + .key(expectedKeyMap) + .returnValues(ReturnValue.ALL_OLD) + .returnConsumedCapacity(returnConsumedCapacity) + .build(); + assertThat(request, is(expectedRequest)); + } + + @Test + public void generateRequest_withReturnConsumedCapacity_knownValue_generatesCorrectRequest() { + FakeItem keyItem = createUniqueFakeItem(); + + ReturnConsumedCapacity returnConsumedCapacity = ReturnConsumedCapacity.TOTAL; + + DeleteItemOperation deleteItemOperation = + DeleteItemOperation.create(DeleteItemEnhancedRequest.builder() + .key(k -> k.partitionValue(keyItem.getId())) + .returnConsumedCapacity(returnConsumedCapacity) + .build()); + + DeleteItemRequest request = deleteItemOperation.generateRequest(FakeItem.getTableSchema(), + PRIMARY_CONTEXT, + null); + + Map expectedKeyMap = new HashMap<>(); + expectedKeyMap.put("id", AttributeValue.builder().s(keyItem.getId()).build()); + DeleteItemRequest expectedRequest = DeleteItemRequest.builder() + .tableName(TABLE_NAME) + .key(expectedKeyMap) + .returnValues(ReturnValue.ALL_OLD) + .returnConsumedCapacity(returnConsumedCapacity) + .build(); + assertThat(request, is(expectedRequest)); + } + + @Test + public void generateRequest_withReturnItemCollectionMetrics_unknownValue_generatesCorrectRequest() { + FakeItem keyItem = createUniqueFakeItem(); + + String returnItemCollectionMetrics = UUID.randomUUID().toString(); + + DeleteItemOperation deleteItemOperation = + DeleteItemOperation.create(DeleteItemEnhancedRequest.builder() + .key(k -> k.partitionValue(keyItem.getId())) + .returnItemCollectionMetrics(returnItemCollectionMetrics) + .build()); + + DeleteItemRequest request = deleteItemOperation.generateRequest(FakeItem.getTableSchema(), + PRIMARY_CONTEXT, + null); + + Map expectedKeyMap = new HashMap<>(); + expectedKeyMap.put("id", AttributeValue.builder().s(keyItem.getId()).build()); + DeleteItemRequest expectedRequest = DeleteItemRequest.builder() + .tableName(TABLE_NAME) + .key(expectedKeyMap) + .returnValues(ReturnValue.ALL_OLD) + .returnItemCollectionMetrics(returnItemCollectionMetrics) + .build(); + assertThat(request, is(expectedRequest)); + } + + @Test + public void generateRequest_withReturnItemCollectionMetrics_knownValue_generatesCorrectRequest() { + FakeItem keyItem = createUniqueFakeItem(); + + ReturnItemCollectionMetrics returnItemCollectionMetrics = ReturnItemCollectionMetrics.SIZE; + + DeleteItemOperation deleteItemOperation = + DeleteItemOperation.create(DeleteItemEnhancedRequest.builder() + .key(k -> k.partitionValue(keyItem.getId())) + .returnItemCollectionMetrics(returnItemCollectionMetrics) + .build()); DeleteItemRequest request = deleteItemOperation.generateRequest(FakeItem.getTableSchema(), PRIMARY_CONTEXT, @@ -117,10 +207,11 @@ public void generateRequest_partitionKeyOnly() { Map expectedKeyMap = new HashMap<>(); expectedKeyMap.put("id", AttributeValue.builder().s(keyItem.getId()).build()); DeleteItemRequest expectedRequest = DeleteItemRequest.builder() - .tableName(TABLE_NAME) - .key(expectedKeyMap) - .returnValues(ReturnValue.ALL_OLD) - .build(); + .tableName(TABLE_NAME) + .key(expectedKeyMap) + .returnValues(ReturnValue.ALL_OLD) + .returnItemCollectionMetrics(returnItemCollectionMetrics) + .build(); assertThat(request, is(expectedRequest)); } @@ -199,6 +290,26 @@ public void generateRequest_withIndex_throwsIllegalArgumentException() { deleteItemOperation.generateRequest(FakeItem.getTableSchema(), GSI_1_CONTEXT, null); } + @Test + public void generateRequest_partitionKeyOnly() { + FakeItem keyItem = createUniqueFakeItem(); + DeleteItemOperation deleteItemOperation = + DeleteItemOperation.create(DeleteItemEnhancedRequest.builder().key(k -> k.partitionValue(keyItem.getId())).build()); + + DeleteItemRequest request = deleteItemOperation.generateRequest(FakeItem.getTableSchema(), + PRIMARY_CONTEXT, + null); + + Map expectedKeyMap = new HashMap<>(); + expectedKeyMap.put("id", AttributeValue.builder().s(keyItem.getId()).build()); + DeleteItemRequest expectedRequest = DeleteItemRequest.builder() + .tableName(TABLE_NAME) + .key(expectedKeyMap) + .returnValues(ReturnValue.ALL_OLD) + .build(); + assertThat(request, is(expectedRequest)); + } + @Test public void transformResponse_correctlyTransformsIntoAnItem() { FakeItem keyItem = createUniqueFakeItem(); @@ -214,7 +325,8 @@ public void transformResponse_correctlyTransformsIntoAnItem() { FakeItem result = deleteItemOperation.transformResponse(response, FakeItem.getTableSchema(), PRIMARY_CONTEXT, - null); + null) + .attributes(); assertThat(result.getId(), is(keyItem.getId())); assertThat(result.getSubclassAttribute(), is("test-value")); @@ -231,7 +343,8 @@ public void transformResponse_noResults_returnsNull() { FakeItem result = deleteItemOperation.transformResponse(response, FakeItem.getTableSchema(), PRIMARY_CONTEXT, - null); + null) + .attributes(); assertThat(result, is(nullValue())); } @@ -274,7 +387,8 @@ public void transformResponse_withExtension_appliesItemModification() { FakeItem resultItem = deleteItemOperation.transformResponse(response, FakeItem.getTableSchema(), PRIMARY_CONTEXT, - mockDynamoDbEnhancedClientExtension); + mockDynamoDbEnhancedClientExtension) + .attributes(); assertThat(resultItem, is(fakeItem)); verify(mockDynamoDbEnhancedClientExtension).afterRead(DefaultDynamoDbExtensionContext.builder() diff --git a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/PutItemOperationTest.java b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/PutItemOperationTest.java index cc0904b35982..a8550f594fcc 100644 --- a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/PutItemOperationTest.java +++ b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/PutItemOperationTest.java @@ -53,6 +53,8 @@ import software.amazon.awssdk.services.dynamodb.model.Put; import software.amazon.awssdk.services.dynamodb.model.PutItemRequest; import software.amazon.awssdk.services.dynamodb.model.PutItemResponse; +import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity; +import software.amazon.awssdk.services.dynamodb.model.ReturnItemCollectionMetrics; import software.amazon.awssdk.services.dynamodb.model.ReturnValue; import software.amazon.awssdk.services.dynamodb.model.TransactWriteItem; @@ -233,6 +235,122 @@ public void generateRequest_withReturnValues_knownValue_generatesCorrectRequest( assertThat(request, is(expectedRequest)); } + @Test + public void generateRequest_withReturnConsumedCapacity_unknownValue_generatesCorrectRequest() { + FakeItem fakeItem = createUniqueFakeItem(); + fakeItem.setSubclassAttribute("subclass-value"); + + String returnConsumedCapacity = UUID.randomUUID().toString(); + + PutItemOperation putItemOperation = + PutItemOperation.create(PutItemEnhancedRequest.builder(FakeItem.class) + .item(fakeItem) + .returnConsumedCapacity(returnConsumedCapacity) + .build()); + + PutItemRequest request = putItemOperation.generateRequest(FakeItem.getTableSchema(), + PRIMARY_CONTEXT, + null); + + Map expectedItemMap = new HashMap<>(); + expectedItemMap.put("id", AttributeValue.builder().s(fakeItem.getId()).build()); + expectedItemMap.put("subclass_attribute", AttributeValue.builder().s("subclass-value").build()); + PutItemRequest expectedRequest = PutItemRequest.builder() + .tableName(TABLE_NAME) + .item(expectedItemMap) + .returnConsumedCapacity(returnConsumedCapacity) + .build(); + + assertThat(request, is(expectedRequest)); + } + + @Test + public void generateRequest_withReturnConsumedCapacity_knownValue_generatesCorrectRequest() { + FakeItem fakeItem = createUniqueFakeItem(); + fakeItem.setSubclassAttribute("subclass-value"); + + ReturnConsumedCapacity returnConsumedCapacity = ReturnConsumedCapacity.TOTAL; + + PutItemOperation putItemOperation = + PutItemOperation.create(PutItemEnhancedRequest.builder(FakeItem.class) + .item(fakeItem) + .returnConsumedCapacity(returnConsumedCapacity) + .build()); + + PutItemRequest request = putItemOperation.generateRequest(FakeItem.getTableSchema(), + PRIMARY_CONTEXT, + null); + + Map expectedItemMap = new HashMap<>(); + expectedItemMap.put("id", AttributeValue.builder().s(fakeItem.getId()).build()); + expectedItemMap.put("subclass_attribute", AttributeValue.builder().s("subclass-value").build()); + PutItemRequest expectedRequest = PutItemRequest.builder() + .tableName(TABLE_NAME) + .item(expectedItemMap) + .returnConsumedCapacity(returnConsumedCapacity) + .build(); + + assertThat(request, is(expectedRequest)); + } + + @Test + public void generateRequest_withReturnItemCollectionMetrics_unknownValue_generatesCorrectRequest() { + FakeItem fakeItem = createUniqueFakeItem(); + fakeItem.setSubclassAttribute("subclass-value"); + + String returnItemCollectionMetrics = UUID.randomUUID().toString(); + + PutItemOperation putItemOperation = + PutItemOperation.create(PutItemEnhancedRequest.builder(FakeItem.class) + .item(fakeItem) + .returnItemCollectionMetrics(returnItemCollectionMetrics) + .build()); + + PutItemRequest request = putItemOperation.generateRequest(FakeItem.getTableSchema(), + PRIMARY_CONTEXT, + null); + + Map expectedItemMap = new HashMap<>(); + expectedItemMap.put("id", AttributeValue.builder().s(fakeItem.getId()).build()); + expectedItemMap.put("subclass_attribute", AttributeValue.builder().s("subclass-value").build()); + PutItemRequest expectedRequest = PutItemRequest.builder() + .tableName(TABLE_NAME) + .item(expectedItemMap) + .returnItemCollectionMetrics(returnItemCollectionMetrics) + .build(); + + assertThat(request, is(expectedRequest)); + } + + @Test + public void generateRequest_withReturnItemCollectionMetrics_knownValue_generatesCorrectRequest() { + FakeItem fakeItem = createUniqueFakeItem(); + fakeItem.setSubclassAttribute("subclass-value"); + + ReturnItemCollectionMetrics returnItemCollectionMetrics = ReturnItemCollectionMetrics.SIZE; + + PutItemOperation putItemOperation = + PutItemOperation.create(PutItemEnhancedRequest.builder(FakeItem.class) + .item(fakeItem) + .returnItemCollectionMetrics(returnItemCollectionMetrics) + .build()); + + PutItemRequest request = putItemOperation.generateRequest(FakeItem.getTableSchema(), + PRIMARY_CONTEXT, + null); + + Map expectedItemMap = new HashMap<>(); + expectedItemMap.put("id", AttributeValue.builder().s(fakeItem.getId()).build()); + expectedItemMap.put("subclass_attribute", AttributeValue.builder().s("subclass-value").build()); + PutItemRequest expectedRequest = PutItemRequest.builder() + .tableName(TABLE_NAME) + .item(expectedItemMap) + .returnItemCollectionMetrics(returnItemCollectionMetrics) + .build(); + + assertThat(request, is(expectedRequest)); + } + @Test public void generateRequest_withMinimalConditionExpression() { FakeItem fakeItem = createUniqueFakeItem(); diff --git a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedRequestTest.java b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedRequestTest.java index 159d792e90d4..0e0a5a2e215b 100644 --- a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedRequestTest.java +++ b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedRequestTest.java @@ -27,6 +27,8 @@ import org.mockito.junit.MockitoJUnitRunner; import software.amazon.awssdk.enhanced.dynamodb.Expression; import software.amazon.awssdk.enhanced.dynamodb.Key; +import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity; +import software.amazon.awssdk.services.dynamodb.model.ReturnItemCollectionMetrics; @RunWith(MockitoJUnitRunner.class) public class DeleteItemEnhancedRequestTest { @@ -37,6 +39,10 @@ public void builder_minimal() { assertThat(builtObject.key(), is(nullValue())); assertThat(builtObject.conditionExpression(), is(nullValue())); + assertThat(builtObject.returnConsumedCapacity(), is(nullValue())); + assertThat(builtObject.returnConsumedCapacityAsString(), is(nullValue())); + assertThat(builtObject.returnItemCollectionMetrics(), is(nullValue())); + assertThat(builtObject.returnItemCollectionMetricsAsString(), is(nullValue())); } @Test @@ -51,20 +57,45 @@ public void builder_maximal() { .putExpressionValue(":value1", stringValue("three")) .build(); + ReturnConsumedCapacity returnConsumedCapacity = ReturnConsumedCapacity.TOTAL; + ReturnItemCollectionMetrics returnItemCollectionMetrics = ReturnItemCollectionMetrics.SIZE; + DeleteItemEnhancedRequest builtObject = DeleteItemEnhancedRequest.builder() .key(key) .conditionExpression(conditionExpression) + .returnConsumedCapacity(returnConsumedCapacity) + .returnItemCollectionMetrics(returnItemCollectionMetrics) .build(); assertThat(builtObject.key(), is(key)); assertThat(builtObject.conditionExpression(), is(conditionExpression)); + assertThat(builtObject.returnConsumedCapacity(), is(returnConsumedCapacity)); + assertThat(builtObject.returnConsumedCapacityAsString(), is(returnConsumedCapacity.toString())); + assertThat(builtObject.returnItemCollectionMetrics(), is(returnItemCollectionMetrics)); + assertThat(builtObject.returnItemCollectionMetricsAsString(), is(returnItemCollectionMetrics.toString())); } @Test public void toBuilder() { Key key = Key.builder().partitionValue("key").build(); - DeleteItemEnhancedRequest builtObject = DeleteItemEnhancedRequest.builder().key(key).build(); + Expression conditionExpression = Expression.builder() + .expression("#key = :value OR #key1 = :value1") + .putExpressionName("#key", "attribute") + .putExpressionName("#key1", "attribute3") + .putExpressionValue(":value", stringValue("wrong")) + .putExpressionValue(":value1", stringValue("three")) + .build(); + + ReturnConsumedCapacity returnConsumedCapacity = ReturnConsumedCapacity.TOTAL; + ReturnItemCollectionMetrics returnItemCollectionMetrics = ReturnItemCollectionMetrics.SIZE; + + DeleteItemEnhancedRequest builtObject = DeleteItemEnhancedRequest.builder() + .key(key) + .conditionExpression(conditionExpression) + .returnConsumedCapacity(returnConsumedCapacity) + .returnItemCollectionMetrics(returnItemCollectionMetrics) + .build(); DeleteItemEnhancedRequest copiedObject = builtObject.toBuilder().build(); @@ -111,6 +142,36 @@ public void equals_conditionExpressionNotEqual() { assertThat(builtObject1, not(equalTo(builtObject2))); } + @Test + public void equals_returnConsumedCapacityNotEqual() { + ReturnConsumedCapacity returnConsumedCapacity1 = ReturnConsumedCapacity.TOTAL; + ReturnConsumedCapacity returnConsumedCapacity2 = ReturnConsumedCapacity.NONE; + + DeleteItemEnhancedRequest builtObject1 = DeleteItemEnhancedRequest.builder() + .returnConsumedCapacity(returnConsumedCapacity1) + .build(); + DeleteItemEnhancedRequest builtObject2 = DeleteItemEnhancedRequest.builder() + .returnConsumedCapacity(returnConsumedCapacity2) + .build(); + + assertThat(builtObject1, not(equalTo(builtObject2))); + } + + @Test + public void equals_returnItemCollectionMetricsNotEqual() { + ReturnItemCollectionMetrics returnItemCollectionMetrics1 = ReturnItemCollectionMetrics.SIZE; + ReturnItemCollectionMetrics returnItemCollectionMetrics2 = ReturnItemCollectionMetrics.NONE; + + DeleteItemEnhancedRequest builtObject1 = DeleteItemEnhancedRequest.builder() + .returnItemCollectionMetrics(returnItemCollectionMetrics1) + .build(); + DeleteItemEnhancedRequest builtObject2 = DeleteItemEnhancedRequest.builder() + .returnItemCollectionMetrics(returnItemCollectionMetrics2) + .build(); + + assertThat(builtObject1, not(equalTo(builtObject2))); + } + @Test public void hashCode_minimal() { DeleteItemEnhancedRequest emptyRequest = DeleteItemEnhancedRequest.builder().build(); @@ -147,4 +208,30 @@ public void hashCode_includesConditionExpression() { assertThat(containsKey.hashCode(), not(equalTo(emptyRequest.hashCode()))); } + + @Test + public void hashCode_includesReturnConsumedCapacity() { + DeleteItemEnhancedRequest emptyRequest = DeleteItemEnhancedRequest.builder().build(); + + ReturnConsumedCapacity returnConsumedCapacity = ReturnConsumedCapacity.TOTAL; + + DeleteItemEnhancedRequest containsKey = DeleteItemEnhancedRequest.builder() + .returnConsumedCapacity(returnConsumedCapacity) + .build(); + + assertThat(containsKey.hashCode(), not(equalTo(emptyRequest.hashCode()))); + } + + @Test + public void hashCode_includesReturnItemCollectionMetrics() { + DeleteItemEnhancedRequest emptyRequest = DeleteItemEnhancedRequest.builder().build(); + + ReturnItemCollectionMetrics returnItemCollectionMetrics = ReturnItemCollectionMetrics.SIZE; + + DeleteItemEnhancedRequest containsKey = DeleteItemEnhancedRequest.builder() + .returnItemCollectionMetrics(returnItemCollectionMetrics) + .build(); + + assertThat(containsKey.hashCode(), not(equalTo(emptyRequest.hashCode()))); + } } diff --git a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedResponseTest.java b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedResponseTest.java new file mode 100644 index 000000000000..7145c3a0a479 --- /dev/null +++ b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/model/DeleteItemEnhancedResponseTest.java @@ -0,0 +1,137 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.enhanced.dynamodb.model; + +import static org.assertj.core.api.Assertions.assertThat; +import static software.amazon.awssdk.enhanced.dynamodb.functionaltests.models.FakeItem.createUniqueFakeItem; + +import java.util.HashMap; +import java.util.Map; +import org.junit.Test; +import software.amazon.awssdk.enhanced.dynamodb.functionaltests.models.FakeItem; +import software.amazon.awssdk.services.dynamodb.model.AttributeValue; +import software.amazon.awssdk.services.dynamodb.model.ConsumedCapacity; +import software.amazon.awssdk.services.dynamodb.model.ItemCollectionMetrics; + +public class DeleteItemEnhancedResponseTest { + @Test + public void builder_minimal() { + DeleteItemEnhancedResponse builtObject = DeleteItemEnhancedResponse.builder(FakeItem.class).build(); + + assertThat(builtObject.attributes()).isNull(); + assertThat(builtObject.consumedCapacity()).isNull(); + assertThat(builtObject.itemCollectionMetrics()).isNull(); + } + + @Test + public void builder_maximal() { + FakeItem fakeItem = createUniqueFakeItem(); + ConsumedCapacity consumedCapacity = ConsumedCapacity.builder().tableName("MyTable").build(); + Map collectionKey = new HashMap<>(); + collectionKey.put("foo", AttributeValue.builder().s("bar").build()); + + ItemCollectionMetrics itemCollectionMetrics = ItemCollectionMetrics.builder().itemCollectionKey(collectionKey).build(); + + DeleteItemEnhancedResponse builtObject = DeleteItemEnhancedResponse.builder(FakeItem.class) + .attributes(fakeItem) + .consumedCapacity(consumedCapacity) + .itemCollectionMetrics(itemCollectionMetrics) + .build(); + + + assertThat(builtObject.attributes()).isEqualTo(fakeItem); + assertThat(builtObject.consumedCapacity()).isEqualTo(consumedCapacity); + assertThat(builtObject.itemCollectionMetrics()).isEqualTo(itemCollectionMetrics); + } + + @Test + public void equals_self() { + DeleteItemEnhancedResponse builtObject = DeleteItemEnhancedResponse.builder(FakeItem.class).build(); + + assertThat(builtObject).isEqualTo(builtObject); + } + + @Test + public void equals_differentType() { + DeleteItemEnhancedResponse builtObject = DeleteItemEnhancedResponse.builder(FakeItem.class).build(); + + assertThat(builtObject).isNotEqualTo(new Object()); + } + + @Test + public void equals_attributesNotEqual() { + FakeItem fakeItem1 = createUniqueFakeItem(); + FakeItem fakeItem2 = createUniqueFakeItem(); + + DeleteItemEnhancedResponse builtObject1 = DeleteItemEnhancedResponse.builder(FakeItem.class) + .attributes(fakeItem1) + .build(); + DeleteItemEnhancedResponse builtObject2 = DeleteItemEnhancedResponse.builder(FakeItem.class) + .attributes(fakeItem2) + .build(); + assertThat(builtObject1).isNotEqualTo(builtObject2); + } + + @Test + public void hashCode_minimal() { + DeleteItemEnhancedResponse emptyResponse = DeleteItemEnhancedResponse.builder(FakeItem.class).build(); + + assertThat(emptyResponse.hashCode()).isEqualTo(0); + } + + @Test + public void hashCode_includesAttributes() { + DeleteItemEnhancedResponse emptyResponse = DeleteItemEnhancedResponse.builder(FakeItem.class).build(); + + FakeItem fakeItem = createUniqueFakeItem(); + + DeleteItemEnhancedResponse containsAttributes = DeleteItemEnhancedResponse.builder(FakeItem.class) + .attributes(fakeItem) + .build(); + + assertThat(containsAttributes.hashCode()).isNotEqualTo(emptyResponse.hashCode()); + } + + @Test + public void hashCode_includesConsumedCapacity() { + DeleteItemEnhancedResponse emptyResponse = DeleteItemEnhancedResponse.builder(FakeItem.class).build(); + + ConsumedCapacity consumedCapacity = ConsumedCapacity.builder().tableName("MyTable").build(); + + + DeleteItemEnhancedResponse containsConsumedCapacity = DeleteItemEnhancedResponse.builder(FakeItem.class) + .consumedCapacity(consumedCapacity) + .build(); + + assertThat(containsConsumedCapacity.hashCode()).isNotEqualTo(emptyResponse.hashCode()); + } + + @Test + public void hashCode_includesItemCollectionMetrics() { + DeleteItemEnhancedResponse emptyResponse = DeleteItemEnhancedResponse.builder(FakeItem.class).build(); + + Map collectionKey = new HashMap<>(); + collectionKey.put("foo", AttributeValue.builder().s("bar").build()); + + ItemCollectionMetrics itemCollectionMetrics = ItemCollectionMetrics.builder().itemCollectionKey(collectionKey).build(); + + DeleteItemEnhancedResponse containsItemCollectionMetrics = DeleteItemEnhancedResponse.builder(FakeItem.class) + .itemCollectionMetrics(itemCollectionMetrics) + .build(); + + assertThat(containsItemCollectionMetrics.hashCode()).isNotEqualTo(emptyResponse.hashCode()); + } +}