Skip to content

Commit 309c299

Browse files
Implement return values for enhanced UpdateItem (#5311)
* Implement return values for enhanced UpdateItem * Implement return values for enhanced UpdateItem * Implement return values for enhanced UpdateItem * Implement return values for enhanced UpdateItem --------- Co-authored-by: David Ho <[email protected]>
1 parent 7fd8ea1 commit 309c299

File tree

6 files changed

+226
-2
lines changed

6 files changed

+226
-2
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"category": "DynamoDB Enhanced Client",
3+
"contributor": "shetsa-amzn",
4+
"type": "feature",
5+
"description": "Adds support for specifying ReturnValue in UpdateItemEnhancedRequest"
6+
}

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

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
package software.amazon.awssdk.enhanced.dynamodb;
1717

18+
import static org.assertj.core.api.Assertions.as;
1819
import static org.assertj.core.api.Assertions.assertThat;
1920
import static org.assertj.core.api.Assertions.assertThatThrownBy;
2021

@@ -38,6 +39,7 @@
3839
import software.amazon.awssdk.services.dynamodb.model.ProjectionType;
3940
import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity;
4041
import software.amazon.awssdk.services.dynamodb.model.ReturnItemCollectionMetrics;
42+
import software.amazon.awssdk.services.dynamodb.model.ReturnValue;
4143
import software.amazon.awssdk.services.dynamodb.model.ReturnValuesOnConditionCheckFailure;
4244

4345
public class AsyncCrudWithResponseIntegrationTest extends DynamoDbEnhancedIntegrationTestBase {
@@ -185,6 +187,56 @@ public void putItem_returnValuesOnConditionCheckFailure_set_returnValuesOnCondit
185187
.satisfies(e -> assertThat(((ConditionalCheckFailedException) e.getCause()).hasItem()).isTrue());
186188
}
187189

190+
@Test
191+
public void updateItem_returnValues_all_old() {
192+
Record record = new Record().setId("1").setSort(10);
193+
mappedTable.putItem(record).join();
194+
195+
Record updatedRecord = new Record().setId("1").setSort(10).setValue(11);
196+
197+
198+
UpdateItemEnhancedResponse<Record> response = mappedTable.updateItemWithResponse(r -> r.item(updatedRecord)
199+
.returnValues(ReturnValue.ALL_OLD))
200+
.join();
201+
202+
assertThat(response.attributes().getId()).isEqualTo(record.getId());
203+
assertThat(response.attributes().getSort()).isEqualTo(record.getSort());
204+
assertThat(response.attributes().getValue()).isEqualTo(null);
205+
}
206+
207+
@Test
208+
public void updateItem_returnValues_all_new() {
209+
Record record = new Record().setId("1").setSort(10);
210+
mappedTable.putItem(record).join();
211+
212+
Record updatedRecord = new Record().setId("1").setSort(10).setValue(11);
213+
214+
215+
UpdateItemEnhancedResponse<Record> response = mappedTable.updateItemWithResponse(r -> r.item(updatedRecord)
216+
.returnValues(ReturnValue.ALL_NEW))
217+
.join();
218+
219+
assertThat(response.attributes().getId()).isEqualTo(updatedRecord.getId());
220+
assertThat(response.attributes().getSort()).isEqualTo(updatedRecord.getSort());
221+
assertThat(response.attributes().getValue()).isEqualTo(updatedRecord.getValue());
222+
}
223+
224+
@Test
225+
public void updateItem_returnValues_not_set() {
226+
Record record = new Record().setId("1").setSort(10);
227+
mappedTable.putItem(record).join();
228+
229+
Record updatedRecord = new Record().setId("1").setSort(10).setValue(11);
230+
231+
232+
UpdateItemEnhancedResponse<Record> response = mappedTable.updateItemWithResponse(r -> r.item(updatedRecord))
233+
.join();
234+
235+
assertThat(response.attributes().getId()).isEqualTo(updatedRecord.getId());
236+
assertThat(response.attributes().getSort()).isEqualTo(updatedRecord.getSort());
237+
assertThat(response.attributes().getValue()).isEqualTo(updatedRecord.getValue());
238+
}
239+
188240
@Test
189241
public void updateItem_returnValuesOnConditionCheckFailure_set_returnValuesOnConditionCheckFailureNull() {
190242
Record record = new Record().setId("1").setSort(10);

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/UpdateItemOperation.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,7 @@ public UpdateItemRequest generateRequest(TableSchema<T> tableSchema,
121121

122122
UpdateItemRequest.Builder requestBuilder = UpdateItemRequest.builder()
123123
.tableName(operationContext.tableName())
124-
.key(keyAttributes)
125-
.returnValues(ReturnValue.ALL_NEW);
124+
.key(keyAttributes);
126125

127126
if (request.left().isPresent()) {
128127
addPlainUpdateItemParameters(requestBuilder, request.left().get());
@@ -253,6 +252,14 @@ private UpdateItemRequest.Builder addPlainUpdateItemParameters(UpdateItemRequest
253252
requestBuilder = requestBuilder.returnItemCollectionMetrics(enhancedRequest.returnItemCollectionMetricsAsString());
254253
requestBuilder =
255254
requestBuilder.returnValuesOnConditionCheckFailure(enhancedRequest.returnValuesOnConditionCheckFailureAsString());
255+
256+
// Set the default returnValue to ReturnValue.ALL_NEW if not specified
257+
ReturnValue returnValue = enhancedRequest.returnValuesAsString() == null
258+
? ReturnValue.ALL_NEW
259+
: ReturnValue.fromValue(enhancedRequest.returnValuesAsString());
260+
261+
requestBuilder.returnValues(returnValue.toString());
262+
256263
return requestBuilder;
257264
}
258265

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/model/UpdateItemEnhancedRequest.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
package software.amazon.awssdk.enhanced.dynamodb.model;
1717

18+
import static software.amazon.awssdk.services.dynamodb.model.ReturnValue.ALL_NEW;
19+
1820
import java.util.Objects;
1921
import software.amazon.awssdk.annotations.NotThreadSafe;
2022
import software.amazon.awssdk.annotations.SdkPublicApi;
@@ -26,6 +28,7 @@
2628
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
2729
import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity;
2830
import software.amazon.awssdk.services.dynamodb.model.ReturnItemCollectionMetrics;
31+
import software.amazon.awssdk.services.dynamodb.model.ReturnValue;
2932
import software.amazon.awssdk.services.dynamodb.model.ReturnValuesOnConditionCheckFailure;
3033
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
3134

@@ -45,6 +48,7 @@ public final class UpdateItemEnhancedRequest<T> {
4548
private final T item;
4649
private final Boolean ignoreNulls;
4750
private final Expression conditionExpression;
51+
private final String returnValues;
4852
private final String returnConsumedCapacity;
4953
private final String returnItemCollectionMetrics;
5054
private final String returnValuesOnConditionCheckFailure;
@@ -54,6 +58,7 @@ private UpdateItemEnhancedRequest(Builder<T> builder) {
5458
this.item = builder.item;
5559
this.ignoreNulls = builder.ignoreNulls;
5660
this.conditionExpression = builder.conditionExpression;
61+
this.returnValues = builder.returnValues;
5762
this.returnConsumedCapacity = builder.returnConsumedCapacity;
5863
this.returnItemCollectionMetrics = builder.returnItemCollectionMetrics;
5964
this.returnValuesOnConditionCheckFailure = builder.returnValuesOnConditionCheckFailure;
@@ -77,6 +82,7 @@ public Builder<T> toBuilder() {
7782
return new Builder<T>().item(item)
7883
.ignoreNulls(ignoreNulls)
7984
.conditionExpression(conditionExpression)
85+
.returnValues(returnValues)
8086
.returnConsumedCapacity(returnConsumedCapacity)
8187
.returnItemCollectionMetrics(returnItemCollectionMetrics)
8288
.returnValuesOnConditionCheckFailure(returnValuesOnConditionCheckFailure);
@@ -103,6 +109,25 @@ public Expression conditionExpression() {
103109
return conditionExpression;
104110
}
105111

112+
/**
113+
* Whether to return the values of the item before this request.
114+
*
115+
* @see UpdateItemRequest#returnValues()
116+
*/
117+
public ReturnValue returnValues() {
118+
return ReturnValue.fromValue(returnValues);
119+
}
120+
121+
/**
122+
* Whether to return the values of the item before this request.
123+
* <p>
124+
* Similar to {@link #returnValues()} but returns the value as a string. This is useful in situations where the value is
125+
* not defined in {@link ReturnValue}.
126+
*/
127+
public String returnValuesAsString() {
128+
return returnValues;
129+
}
130+
106131
/**
107132
* Whether to return the capacity consumed by this operation.
108133
*
@@ -173,6 +198,7 @@ public boolean equals(Object o) {
173198
return Objects.equals(item, that.item)
174199
&& Objects.equals(ignoreNulls, that.ignoreNulls)
175200
&& Objects.equals(conditionExpression, that.conditionExpression)
201+
&& Objects.equals(returnValues, that.returnValues)
176202
&& Objects.equals(returnConsumedCapacity, that.returnConsumedCapacity)
177203
&& Objects.equals(returnItemCollectionMetrics, that.returnItemCollectionMetrics)
178204
&& Objects.equals(returnValuesOnConditionCheckFailure, that.returnValuesOnConditionCheckFailure);
@@ -183,6 +209,7 @@ public int hashCode() {
183209
int result = item != null ? item.hashCode() : 0;
184210
result = 31 * result + (ignoreNulls != null ? ignoreNulls.hashCode() : 0);
185211
result = 31 * result + (conditionExpression != null ? conditionExpression.hashCode() : 0);
212+
result = 31 * result + (returnValues != null ? returnValues.hashCode() : 0);
186213
result = 31 * result + (returnConsumedCapacity != null ? returnConsumedCapacity.hashCode() : 0);
187214
result = 31 * result + (returnItemCollectionMetrics != null ? returnItemCollectionMetrics.hashCode() : 0);
188215
result = 31 * result + (returnValuesOnConditionCheckFailure != null ? returnValuesOnConditionCheckFailure.hashCode() : 0);
@@ -199,6 +226,7 @@ public static final class Builder<T> {
199226
private T item;
200227
private Boolean ignoreNulls;
201228
private Expression conditionExpression;
229+
private String returnValues;
202230
private String returnConsumedCapacity;
203231
private String returnItemCollectionMetrics;
204232
private String returnValuesOnConditionCheckFailure;
@@ -235,6 +263,26 @@ public Builder<T> conditionExpression(Expression conditionExpression) {
235263
return this;
236264
}
237265

266+
/**
267+
* Whether to return the values of the item before this request.
268+
*
269+
* @see UpdateItemRequest.Builder#returnValues(ReturnValue)
270+
*/
271+
public UpdateItemEnhancedRequest.Builder<T> returnValues(ReturnValue returnValues) {
272+
this.returnValues = returnValues == null ? ALL_NEW.toString() : returnValues.toString();
273+
return this;
274+
}
275+
276+
/**
277+
* Whether to return the values of the item before this request.
278+
*
279+
* @see UpdateItemRequest.Builder#returnValues(String)
280+
*/
281+
public UpdateItemEnhancedRequest.Builder<T> returnValues(String returnValues) {
282+
this.returnValues = returnValues;
283+
return this;
284+
}
285+
238286
/**
239287
* Sets the item to write to DynamoDb. Required.
240288
*

services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/AsyncUpdateItemWithResponseTest.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package software.amazon.awssdk.enhanced.dynamodb.functionaltests;
1717

1818
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.junit.Assert.assertNull;
1920
import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.primaryPartitionKey;
2021

2122
import java.util.Objects;
@@ -29,6 +30,7 @@
2930
import software.amazon.awssdk.enhanced.dynamodb.model.UpdateItemEnhancedResponse;
3031
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
3132
import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity;
33+
import software.amazon.awssdk.services.dynamodb.model.ReturnValue;
3234

3335
public class AsyncUpdateItemWithResponseTest extends LocalDynamoDbAsyncTestBase {
3436
private static class Record {
@@ -155,4 +157,98 @@ public void returnItemCollectionMetrics_unset_itemCollectionMetricsNull() {
155157

156158
assertThat(response.itemCollectionMetrics()).isNull();
157159
}
160+
161+
@Test
162+
public void returnValues_Null_attributesMapped() {
163+
Record original = new Record().setId(1).setStringAttr1("attr");
164+
mappedTable1.putItem(original).join();
165+
166+
Record updated = new Record().setId(1).setStringAttr1("attr2");
167+
168+
UpdateItemEnhancedResponse<Record> response = mappedTable1.updateItemWithResponse(r -> r.item(updated)
169+
.returnConsumedCapacity(ReturnConsumedCapacity.TOTAL))
170+
.join();
171+
AsyncUpdateItemWithResponseTest.Record returned = response.attributes();
172+
173+
assertThat(returned).isEqualTo(updated);
174+
}
175+
176+
@Test
177+
public void returnValues_allOld_attributesMapped() {
178+
Record original = new Record().setId(1).setStringAttr1("attr");
179+
mappedTable1.putItem(original).join();
180+
181+
Record updated = new Record().setId(1).setStringAttr1("attr2");
182+
183+
UpdateItemEnhancedResponse<Record> response = mappedTable1.updateItemWithResponse(r -> r.item(updated)
184+
.returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
185+
.returnValues(ReturnValue.ALL_OLD))
186+
.join();
187+
188+
AsyncUpdateItemWithResponseTest.Record returned = response.attributes();
189+
190+
assertThat(returned).isEqualTo(original);
191+
}
192+
193+
@Test
194+
public void returnValues_allNew_attributesMapped() {
195+
Record original = new Record().setId(1).setStringAttr1("attr");
196+
mappedTable1.putItem(original).join();
197+
198+
Record updated = new Record().setId(1).setStringAttr1("attr2");
199+
200+
UpdateItemEnhancedResponse<Record> response = mappedTable1.updateItemWithResponse(r -> r.item(updated)
201+
.returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
202+
.returnValues(ReturnValue.ALL_NEW))
203+
.join();
204+
AsyncUpdateItemWithResponseTest.Record returned = response.attributes();
205+
206+
assertThat(returned).isEqualTo(updated);
207+
}
208+
209+
@Test
210+
public void returnValues_None_attributesMapped() {
211+
Record original = new Record().setId(1).setStringAttr1("attr");
212+
mappedTable1.putItem(original).join();
213+
214+
Record updated = new Record().setId(1).setStringAttr1("attr2");
215+
216+
UpdateItemEnhancedResponse<Record> response = mappedTable1.updateItemWithResponse(r -> r.item(updated)
217+
.returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
218+
.returnValues(ReturnValue.NONE))
219+
.join();
220+
AsyncUpdateItemWithResponseTest.Record returned = response.attributes();
221+
222+
assertNull(returned);
223+
}
224+
225+
@Test
226+
public void returnValues_Updated_Old_attributesMapped() {
227+
Record original = new Record().setId(1).setStringAttr1("attr");
228+
mappedTable1.putItem(original).join();
229+
230+
Record updated = new Record().setId(1).setStringAttr1("attr2");
231+
232+
UpdateItemEnhancedResponse<Record> response = mappedTable1.updateItemWithResponse(r -> r.item(updated)
233+
.returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
234+
.returnValues(ReturnValue.UPDATED_OLD))
235+
.join();
236+
AsyncUpdateItemWithResponseTest.Record returned = response.attributes();
237+
assertThat(returned.getStringAttr1()).isEqualTo(original.stringAttr1);
238+
}
239+
240+
@Test
241+
public void returnValues_Updated_New_attributesMapped() {
242+
Record original = new Record().setId(1).setStringAttr1("attr");
243+
mappedTable1.putItem(original).join();
244+
245+
Record updated = new Record().setId(1).setStringAttr1("attr2");
246+
247+
UpdateItemEnhancedResponse<Record> response = mappedTable1.updateItemWithResponse(r -> r.item(updated)
248+
.returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
249+
.returnValues(ReturnValue.UPDATED_NEW))
250+
.join();
251+
AsyncUpdateItemWithResponseTest.Record returned = response.attributes();
252+
assertThat(returned.getStringAttr1()).isEqualTo(updated.getStringAttr1());
253+
}
158254
}

services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/UpdateItemOperationTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,21 @@ public void generateRequest_withReturnValuesOnConditionCheckFailure_knownValue_g
618618
assertThat(request, is(expectedRequest));
619619
}
620620

621+
@Test
622+
public void generateRequest_withReturnValues_knownValue_generatesCorrectRequest() {
623+
FakeItem item = createUniqueFakeItem();
624+
ReturnValue returnValue = ReturnValue.ALL_OLD;
625+
626+
UpdateItemOperation<FakeItem> updateItemOperation =
627+
UpdateItemOperation.create(requestFakeItem(item, b -> b.ignoreNulls(true).returnValues(returnValue)));
628+
629+
UpdateItemRequest request = updateItemOperation.generateRequest(FakeItem.getTableSchema(), PRIMARY_CONTEXT, null);
630+
UpdateItemRequest expectedRequest = ddbRequest(ddbKey(item.getId()), b -> b.returnValues(returnValue));
631+
632+
assertThat(request, is(expectedRequest));
633+
}
634+
635+
621636
@Test
622637
public void transformResponse_withExtension_returnsCorrectTransformedItem() {
623638
FakeItem baseFakeItem = createUniqueFakeItem();

0 commit comments

Comments
 (0)