Skip to content

Commit ba4cae8

Browse files
feat(1447): Implementing DynamoDb update partial using UpdateItemEnhancedRequest
1 parent 64393f7 commit ba4cae8

File tree

3 files changed

+68
-15
lines changed

3 files changed

+68
-15
lines changed

spring-cloud-aws-dynamodb/src/main/java/io/awspring/cloud/dynamodb/DynamoDbOperations.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@
1616
package io.awspring.cloud.dynamodb;
1717

1818
import org.springframework.lang.Nullable;
19+
1920
import software.amazon.awssdk.enhanced.dynamodb.Key;
2021
import software.amazon.awssdk.enhanced.dynamodb.model.PageIterable;
2122
import software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest;
2223
import software.amazon.awssdk.enhanced.dynamodb.model.ScanEnhancedRequest;
24+
import software.amazon.awssdk.enhanced.dynamodb.model.UpdateItemEnhancedRequest;
2325

2426
/**
2527
* Interface for simple DynamoDB template operations.
2628
*
2729
* @author Matej Nedic
30+
* @author Marcus Voltolim
2831
* @since 3.0.0
2932
*/
3033
public interface DynamoDbOperations {
@@ -45,6 +48,14 @@ public interface DynamoDbOperations {
4548
*/
4649
<T> T update(T entity);
4750

51+
/**
52+
* Updates Entity with configurations like ignore null to DynamoDB table.
53+
*
54+
* @param request - UpdateItemEnhancedRequest with entity and configurations to be saved.
55+
* @param <T> Type of Entity object.
56+
*/
57+
<T> T update(UpdateItemEnhancedRequest<T> request);
58+
4859
/**
4960
* Deletes a record for a given Key.
5061
*

spring-cloud-aws-dynamodb/src/main/java/io/awspring/cloud/dynamodb/DynamoDbTemplate.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,29 @@
1616
package io.awspring.cloud.dynamodb;
1717

1818
import java.util.Collections;
19+
1920
import org.springframework.lang.Nullable;
2021
import org.springframework.util.Assert;
22+
2123
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
2224
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
2325
import software.amazon.awssdk.enhanced.dynamodb.Key;
2426
import software.amazon.awssdk.enhanced.dynamodb.model.PageIterable;
2527
import software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest;
2628
import software.amazon.awssdk.enhanced.dynamodb.model.ScanEnhancedRequest;
29+
import software.amazon.awssdk.enhanced.dynamodb.model.UpdateItemEnhancedRequest;
2730

2831
/**
2932
* Default implementation of {@link DynamoDbOperations}.
3033
*
3134
* @author Matej Nedic
3235
* @author Arun Patra
3336
* @author Maciej Walkowiak
37+
* @author Marcus Voltolim
3438
* @since 3.0
3539
*/
3640
public class DynamoDbTemplate implements DynamoDbOperations {
41+
3742
private final DynamoDbEnhancedClient dynamoDbEnhancedClient;
3843
private final DynamoDbTableSchemaResolver dynamoDbTableSchemaResolver;
3944
private final DynamoDbTableNameResolver tableNameResolver;
@@ -49,7 +54,7 @@ public DynamoDbTemplate(DynamoDbEnhancedClient dynamoDbEnhancedClient) {
4954
}
5055

5156
public DynamoDbTemplate(DynamoDbEnhancedClient dynamoDbEnhancedClient,
52-
DynamoDbTableSchemaResolver dynamoDbTableSchemaResolver, DynamoDbTableNameResolver tableNameResolver) {
57+
DynamoDbTableSchemaResolver dynamoDbTableSchemaResolver, DynamoDbTableNameResolver tableNameResolver) {
5358
this.dynamoDbEnhancedClient = dynamoDbEnhancedClient;
5459
this.dynamoDbTableSchemaResolver = dynamoDbTableSchemaResolver;
5560
this.tableNameResolver = tableNameResolver;
@@ -66,6 +71,12 @@ public <T> T update(T entity) {
6671
return prepareTable(entity).updateItem(entity);
6772
}
6873

74+
@Override
75+
public <T> T update(UpdateItemEnhancedRequest<T> request) {
76+
Assert.notNull(request, "updateItemEnhancedRequest is required");
77+
return prepareTable(request.item()).updateItem(request);
78+
}
79+
6980
public <T> T delete(Key key, Class<T> clazz) {
7081
Assert.notNull(key, "key is required");
7182
Assert.notNull(clazz, "clazz is required");

spring-cloud-aws-dynamodb/src/test/java/io/awspring/cloud/dynamodb/DynamoDbTemplateIntegrationTest.java

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.ArrayList;
2121
import java.util.List;
2222
import java.util.UUID;
23+
import java.util.stream.Stream;
2324
import org.junit.jupiter.api.BeforeAll;
2425
import org.junit.jupiter.params.ParameterizedTest;
2526
import org.junit.jupiter.params.provider.Arguments;
@@ -33,10 +34,7 @@
3334
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
3435
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
3536
import software.amazon.awssdk.enhanced.dynamodb.*;
36-
import software.amazon.awssdk.enhanced.dynamodb.model.PageIterable;
37-
import software.amazon.awssdk.enhanced.dynamodb.model.QueryConditional;
38-
import software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest;
39-
import software.amazon.awssdk.enhanced.dynamodb.model.ScanEnhancedRequest;
37+
import software.amazon.awssdk.enhanced.dynamodb.model.*;
4038
import software.amazon.awssdk.regions.Region;
4139
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
4240
import software.amazon.awssdk.services.dynamodb.model.*;
@@ -46,6 +44,7 @@
4644
*
4745
* @author Matej Nedic
4846
* @author Arun Patra
47+
* @author Marcus Voltolim
4948
*/
5049
@Testcontainers
5150
public class DynamoDbTemplateIntegrationTest {
@@ -62,7 +61,7 @@ public class DynamoDbTemplateIntegrationTest {
6261
DockerImageName.parse("localstack/localstack:4.4.0"));
6362

6463
@BeforeAll
65-
public static void createTable() {
64+
static void createTable() {
6665
DynamoDbClient dynamoDbClient = DynamoDbClient.builder().endpointOverride(localstack.getEndpoint())
6766
.region(Region.of(localstack.getRegion()))
6867
.credentialsProvider(StaticCredentialsProvider
@@ -107,16 +106,45 @@ void dynamoDbTemplate_read_entitySuccessful_returnsNull(DynamoDbTable<PersonEnti
107106
@ParameterizedTest
108107
@MethodSource("argumentSource")
109108
void dynamoDbTemplate_saveUpdateAndRead_entitySuccessful(DynamoDbTable<PersonEntity> dynamoDbTable,
110-
DynamoDbTemplate dynamoDbTemplate) {
109+
DynamoDbTemplate dynamoDbTemplate) {
111110
PersonEntity personEntity = new PersonEntity(UUID.randomUUID(), "foo", "bar");
112111
dynamoDbTemplate.save(personEntity);
113112

113+
personEntity.setName(null);
114114
personEntity.setLastName("xxx");
115115
dynamoDbTemplate.update(personEntity);
116116

117-
PersonEntity personEntity1 = dynamoDbTemplate
118-
.load(Key.builder().partitionValue(personEntity.getUuid().toString()).build(), PersonEntity.class);
119-
assertThat(personEntity1).isEqualTo(personEntity);
117+
118+
Key key = Key.builder().partitionValue(personEntity.getUuid().toString()).build();
119+
120+
assertThat(dynamoDbTemplate.load(key, PersonEntity.class))
121+
.extracting(PersonEntity::getName, PersonEntity::getLastName)
122+
.containsExactly(null, "xxx");
123+
124+
// clean up
125+
cleanUp(dynamoDbTable, personEntity.getUuid());
126+
}
127+
128+
@ParameterizedTest
129+
@MethodSource("argumentSource")
130+
void dynamoDbTemplate_saveUpdateIgnoreNullAndRead_entitySuccessful(DynamoDbTable<PersonEntity> dynamoDbTable,
131+
DynamoDbTemplate dynamoDbTemplate) {
132+
PersonEntity personEntity = new PersonEntity(UUID.randomUUID(), "foo", "bar");
133+
dynamoDbTemplate.save(personEntity);
134+
135+
personEntity.setName(null);
136+
personEntity.setLastName("xxx");
137+
UpdateItemEnhancedRequest<PersonEntity> request = UpdateItemEnhancedRequest.builder(PersonEntity.class)
138+
.item(personEntity)
139+
.ignoreNullsMode(IgnoreNullsMode.SCALAR_ONLY)
140+
.build();
141+
dynamoDbTemplate.update(request);
142+
143+
Key key = Key.builder().partitionValue(personEntity.getUuid().toString()).build();
144+
145+
assertThat(dynamoDbTemplate.load(key, PersonEntity.class))
146+
.extracting(PersonEntity::getName, PersonEntity::getLastName)
147+
.containsExactly("foo", "xxx");
120148

121149
// clean up
122150
cleanUp(dynamoDbTable, personEntity.getUuid());
@@ -314,16 +342,18 @@ public static void cleanUp(DynamoDbTable<PersonEntity> dynamoDbTable, UUID uuid)
314342
dynamoDbTable.deleteItem(Key.builder().partitionValue(uuid.toString()).build());
315343
}
316344

317-
private static java.util.stream.Stream<Arguments> argumentSource() {
318-
return java.util.stream.Stream.of(Arguments.of(dynamoDbTable, dynamoDbTemplate),
319-
Arguments.of(prefixedDynamoDbTable, prefixedDynamoDbTemplate));
345+
private static Stream<Arguments> argumentSource() {
346+
return Stream.of(
347+
Arguments.of(dynamoDbTable, dynamoDbTemplate),
348+
Arguments.of(prefixedDynamoDbTable, prefixedDynamoDbTemplate)
349+
);
320350
}
321351

322352
private static void describeAndCreateTable(DynamoDbClient dynamoDbClient, @Nullable String tablePrefix) {
323-
ArrayList<AttributeDefinition> attributeDefinitions = new ArrayList<AttributeDefinition>();
353+
ArrayList<AttributeDefinition> attributeDefinitions = new ArrayList<>();
324354
attributeDefinitions.add(AttributeDefinition.builder().attributeName("uuid").attributeType("S").build());
325355
attributeDefinitions.add(AttributeDefinition.builder().attributeName(nameOfGSPK).attributeType("S").build());
326-
ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>();
356+
ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<>();
327357
tableKeySchema.add(KeySchemaElement.builder().attributeName("uuid").keyType(KeyType.HASH).build());
328358
List<KeySchemaElement> indexKeySchema = new ArrayList<>();
329359
indexKeySchema.add(KeySchemaElement.builder().attributeName(nameOfGSPK).keyType(KeyType.HASH).build());
@@ -347,4 +377,5 @@ private static void describeAndCreateTable(DynamoDbClient dynamoDbClient, @Nulla
347377
// table already exists, do nothing
348378
}
349379
}
380+
350381
}

0 commit comments

Comments
 (0)