Skip to content

Commit b7b79c2

Browse files
committed
refactoring and adding test coverage
1 parent b787406 commit b7b79c2

File tree

6 files changed

+197
-16
lines changed

6 files changed

+197
-16
lines changed

.changes/next-release/feature-DynamoDBEnhancedClient-2a501d8.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"type": "feature",
33
"category": "DynamoDB Enhanced Client",
44
"contributor": "akiesler",
5-
"description": "DynamoDB Enhanced Client: Support for Version Starting at 0 with Configurable Increment"
5+
"description": "Support for Version Starting at 0 with Configurable Increment"
66
}

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@
680680
<includeModule>polly</includeModule>
681681
</includeModules>
682682
<excludes>
683+
<!-- TODO remove after release -->
683684
<exclude>software.amazon.awssdk.enhanced.dynamodb.extensions.annotations.DynamoDbVersionAttribute#incrementBy()</exclude>
684685
<exclude>software.amazon.awssdk.enhanced.dynamodb.extensions.annotations.DynamoDbVersionAttribute#startAt()</exclude>
685686
<exclude>*.internal.*</exclude>

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import software.amazon.awssdk.annotations.SdkPublicApi;
2727
import software.amazon.awssdk.annotations.ThreadSafe;
2828
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
29+
import software.amazon.awssdk.utils.ToString;
2930

3031
/**
3132
* High-level representation of a DynamoDB 'expression' that can be used in various situations where the API requires
@@ -313,11 +314,16 @@ public int hashCode() {
313314

314315
@Override
315316
public String toString() {
316-
return "Expression{" +
317-
"expression='" + expression + '\'' +
318-
", expressionValues=" + expressionValues +
319-
", expressionNames=" + expressionNames +
320-
'}';
317+
// return "Expression{" +
318+
// "expression='" + expression + '\'' +
319+
// ", expressionValues=" + expressionValues +
320+
// ", expressionNames=" + expressionNames +
321+
// '}';
322+
return ToString.builder("Expression")
323+
.add("expression", expression)
324+
.add("expressionValues", expressionValues)
325+
.add("expressionNames", expressionNames)
326+
.build();
321327
}
322328

323329
/**

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/extensions/VersionedRecordExtension.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ private VersionedRecordExtension(Long startAt, Long incrementBy) {
6969
Validate.isNotNegativeOrNull(startAt, "startAt");
7070

7171
if (incrementBy != null && incrementBy < 1) {
72-
throw new IllegalArgumentException("IncrementBy must be greater than 0.");
72+
throw new IllegalArgumentException("incrementBy must be greater than 0.");
7373
}
7474

7575
this.startAt = startAt != null ? startAt : 0L;
@@ -156,13 +156,7 @@ public WriteModification beforeWrite(DynamoDbExtensionContext.BeforeWrite contex
156156
Optional<Long> versionIncrementByFromAnnotation = context.tableMetadata()
157157
.customMetadataObject(VersionAttribute.INCREMENT_BY_METADATA_KEY,
158158
Long.class);
159-
160-
if (!existingVersionValue.isPresent() || isNullAttributeValue(existingVersionValue.get()) ||
161-
(existingVersionValue.get().n() != null &&
162-
((versionStartAtFromAnnotation.isPresent() &&
163-
Long.parseLong(existingVersionValue.get().n()) == versionStartAtFromAnnotation.get()) ||
164-
Long.parseLong(existingVersionValue.get().n()) == this.startAt))) {
165-
159+
if (isInitialVersion(existingVersionValue, versionStartAtFromAnnotation)) {
166160
long startValue = versionStartAtFromAnnotation.orElse(this.startAt);
167161
long increment = versionIncrementByFromAnnotation.orElse(this.incrementBy);
168162

@@ -200,10 +194,25 @@ public WriteModification beforeWrite(DynamoDbExtensionContext.BeforeWrite contex
200194
.build();
201195
}
202196

197+
private boolean isInitialVersion(Optional<AttributeValue> existingVersionValue, Optional<Long> versionStartAtFromAnnotation) {
198+
if (!existingVersionValue.isPresent() || isNullAttributeValue(existingVersionValue.get())) {
199+
return true;
200+
}
201+
202+
AttributeValue value = existingVersionValue.get();
203+
if (value.n() != null) {
204+
long currentVersion = Long.parseLong(value.n());
205+
return (versionStartAtFromAnnotation.isPresent() && currentVersion == versionStartAtFromAnnotation.get())
206+
|| currentVersion == this.startAt;
207+
}
208+
209+
return false;
210+
}
211+
203212
@NotThreadSafe
204213
public static final class Builder {
205-
private Long startAt = 0L;
206-
private Long incrementBy = 1L;
214+
private Long startAt;
215+
private Long incrementBy;
207216

208217
private Builder() {
209218
}

services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/extensions/VersionedRecordExtensionTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,18 @@
3030
import org.junit.jupiter.params.ParameterizedTest;
3131
import org.junit.jupiter.params.provider.Arguments;
3232
import org.junit.jupiter.params.provider.MethodSource;
33+
import software.amazon.awssdk.enhanced.dynamodb.AttributeConverterProvider;
34+
import software.amazon.awssdk.enhanced.dynamodb.AttributeValueType;
3335
import software.amazon.awssdk.enhanced.dynamodb.Expression;
3436
import software.amazon.awssdk.enhanced.dynamodb.OperationContext;
3537
import software.amazon.awssdk.enhanced.dynamodb.TableMetadata;
3638
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
39+
import software.amazon.awssdk.enhanced.dynamodb.document.DocumentTableSchema;
40+
import software.amazon.awssdk.enhanced.dynamodb.document.EnhancedDocument;
3741
import software.amazon.awssdk.enhanced.dynamodb.extensions.annotations.DynamoDbVersionAttribute;
3842
import software.amazon.awssdk.enhanced.dynamodb.functionaltests.models.FakeItem;
3943
import software.amazon.awssdk.enhanced.dynamodb.functionaltests.models.FakeItemWithSort;
44+
import software.amazon.awssdk.enhanced.dynamodb.functionaltests.models.ImmutableFakeVersionedItem;
4045
import software.amazon.awssdk.enhanced.dynamodb.internal.extensions.DefaultDynamoDbExtensionContext;
4146
import software.amazon.awssdk.enhanced.dynamodb.internal.operations.DefaultOperationContext;
4247
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
@@ -511,6 +516,44 @@ public void customIncrementForExistingVersion_worksAsExpected(Long startAt, Long
511516
is("#AMZN_MAPPED_version = :old_version_value"));
512517
}
513518

519+
@ParameterizedTest
520+
@MethodSource("customIncrementForExistingVersionValues")
521+
public void customIncrementForExistingVersion_withImmutableSchema_worksAsExpected(Long startAt, Long incrementBy,
522+
Long existingVersion, String expectedNextVersion) {
523+
VersionedRecordExtension.Builder recordExtensionBuilder = VersionedRecordExtension.builder();
524+
if (startAt != null) {
525+
recordExtensionBuilder.startAt(startAt);
526+
}
527+
if (incrementBy != null) {
528+
recordExtensionBuilder.incrementBy(incrementBy);
529+
}
530+
VersionedRecordExtension recordExtension = recordExtensionBuilder.build();
531+
532+
ImmutableFakeVersionedItem fakeItem = ImmutableFakeVersionedItem
533+
.builder()
534+
.id(UUID.randomUUID().toString())
535+
.version(existingVersion)
536+
.build();
537+
538+
Map<String, AttributeValue> inputMap =
539+
new HashMap<>(ImmutableFakeVersionedItem.getTableSchema().itemToMap(fakeItem, true));
540+
541+
Map<String, AttributeValue> expectedVersionedItem =
542+
new HashMap<>(ImmutableFakeVersionedItem.getTableSchema().itemToMap(fakeItem, true));
543+
expectedVersionedItem.put("version", AttributeValue.builder().n(expectedNextVersion).build());
544+
545+
WriteModification result =
546+
recordExtension.beforeWrite(DefaultDynamoDbExtensionContext
547+
.builder()
548+
.items(inputMap)
549+
.tableMetadata(ImmutableFakeVersionedItem.getTableMetadata())
550+
.operationContext(PRIMARY_CONTEXT).build());
551+
552+
assertThat(result.transformedItem(), is(expectedVersionedItem));
553+
assertThat(result.additionalConditionalExpression().expression(),
554+
is("#AMZN_MAPPED_version = :old_version_value"));
555+
}
556+
514557
public static Stream<Arguments> customIncrementForExistingVersionValues() {
515558
return Stream.of(
516559
Arguments.of(0L, 1L, 5L, "6"),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.enhanced.dynamodb.functionaltests.models;
17+
18+
import static software.amazon.awssdk.enhanced.dynamodb.extensions.VersionedRecordExtension.AttributeTags.versionAttribute;
19+
import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.primaryPartitionKey;
20+
21+
import java.util.Objects;
22+
import software.amazon.awssdk.enhanced.dynamodb.TableMetadata;
23+
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
24+
import software.amazon.awssdk.enhanced.dynamodb.mapper.StaticImmutableTableSchema;
25+
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbImmutable;
26+
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
27+
28+
@DynamoDbImmutable(builder = ImmutableFakeVersionedItem.Builder.class)
29+
public class ImmutableFakeVersionedItem {
30+
private final String id;
31+
private final String attribute;
32+
private final long version;
33+
34+
private ImmutableFakeVersionedItem(Builder b) {
35+
this.id = b.id;
36+
this.attribute = b.attribute;
37+
this.version = b.version;
38+
}
39+
40+
public static Builder builder() {
41+
return new Builder();
42+
}
43+
44+
public String attribute() {
45+
return attribute;
46+
}
47+
48+
@DynamoDbPartitionKey
49+
public String id() {
50+
return id;
51+
}
52+
53+
public long version() {
54+
return version;
55+
}
56+
57+
@Override
58+
public boolean equals(Object o) {
59+
if (this == o) {
60+
return true;
61+
}
62+
if (o == null || getClass() != o.getClass()) {
63+
return false;
64+
}
65+
ImmutableFakeVersionedItem that = (ImmutableFakeVersionedItem) o;
66+
return version == that.version && Objects.equals(id, that.id) && Objects.equals(attribute, that.attribute);
67+
}
68+
69+
@Override
70+
public int hashCode() {
71+
return Objects.hash(id, attribute, version);
72+
}
73+
74+
public static TableSchema<ImmutableFakeVersionedItem> getTableSchema() {
75+
return StaticImmutableTableSchema.builder(ImmutableFakeVersionedItem.class, ImmutableFakeVersionedItem.Builder.class)
76+
.newItemBuilder(ImmutableFakeVersionedItem::builder, ImmutableFakeVersionedItem.Builder::build)
77+
.addAttribute(String.class, a -> a.name("id")
78+
.getter(ImmutableFakeVersionedItem::id)
79+
.setter(ImmutableFakeVersionedItem.Builder::id)
80+
.tags(primaryPartitionKey()))
81+
.addAttribute(Long.class, a -> a.name("version")
82+
.getter(ImmutableFakeVersionedItem::version)
83+
.setter(ImmutableFakeVersionedItem.Builder::version)
84+
.tags(versionAttribute()))
85+
.addAttribute(String.class, a -> a.name("attribute")
86+
.getter(ImmutableFakeVersionedItem::attribute)
87+
.setter(ImmutableFakeVersionedItem.Builder::attribute))
88+
.build();
89+
}
90+
91+
92+
93+
94+
public static TableMetadata getTableMetadata() {
95+
return getTableSchema().tableMetadata();
96+
}
97+
98+
public static final class Builder {
99+
private String id;
100+
private String attribute;
101+
private long version;
102+
103+
public Builder id(String id) {
104+
this.id = id;
105+
return this;
106+
}
107+
108+
public Builder version(long version) {
109+
this.version = version;
110+
return this;
111+
}
112+
113+
public Builder attribute(String attribute) {
114+
this.attribute = attribute;
115+
return this;
116+
}
117+
118+
public ImmutableFakeVersionedItem build() {
119+
return new ImmutableFakeVersionedItem(this);
120+
}
121+
}
122+
}

0 commit comments

Comments
 (0)