Skip to content

Commit dbd65a7

Browse files
committed
Fix changelog and add coverage
1 parent 351fbd3 commit dbd65a7

File tree

3 files changed

+83
-25
lines changed

3 files changed

+83
-25
lines changed

.changes/next-release/bugfix-DynamoDBEnhancedClient-191a1f8.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"type": "bugfix",
33
"category": "DynamoDB Enhanced Client",
44
"contributor": "",
5-
"description": "Allow versioning to start from 0"
5+
"description": "Allow new records to start at version=0 by supporting startAt=-1 in VersionedRecordExtension"
66
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "feature",
3+
"category": "DynamoDB Enhanced Client",
4+
"contributor": "",
5+
"description": "modify VersionedRecordExtension to support updating existing records with version=0 using OR condition"
6+
}

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

Lines changed: 76 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ public static class AnnotatedRecordStartAtNegativeOne {
161161
public void setAttribute(String attribute) { this.attribute = attribute; }
162162
}
163163

164+
165+
private static final int CUSTOM_START_AT = 10;
166+
private static final int CUSTOM_INCREMENT_BY = 2;
167+
private static final long ANNOTATED_START_AT = 5L;
168+
private static final long ANNOTATED_INCREMENT_BY = 3L;
169+
164170
private DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
165171
.dynamoDbClient(getDynamoDbClient())
166172
.extensions(VersionedRecordExtension.builder().build())
@@ -186,6 +192,16 @@ public static class AnnotatedRecordStartAtNegativeOne {
186192
)
187193
.build();
188194

195+
private DynamoDbEnhancedClient startAtNegativeOneIncrementByTwoClient = DynamoDbEnhancedClient.builder()
196+
.dynamoDbClient(getDynamoDbClient())
197+
.extensions(VersionedRecordExtension
198+
.builder()
199+
.startAt(-1L)
200+
.incrementBy(2L)
201+
.build()
202+
)
203+
.build();
204+
189205
private DynamoDbTable<Record> mappedTable = enhancedClient.table(getConcreteTableName("table-name"), TABLE_SCHEMA);
190206

191207
private DynamoDbTable<Record> mappedCustomVersionedTable = customVersionedEnhancedClient
@@ -194,6 +210,9 @@ public static class AnnotatedRecordStartAtNegativeOne {
194210
private DynamoDbTable<Record> startAtNegativeOneTable = startAtNegativeOneClient
195211
.table(getConcreteTableName("startAt-neg-one-table"), TABLE_SCHEMA);
196212

213+
private DynamoDbTable<Record> startAtNegativeOneIncrementByTwoTable = startAtNegativeOneIncrementByTwoClient
214+
.table(getConcreteTableName("startAt-neg-one-inc-two-table"), TABLE_SCHEMA);
215+
197216

198217
private static final TableSchema<AnnotatedRecord> ANNOTATED_TABLE_SCHEMA =
199218
TableSchema.fromBean(AnnotatedRecord.class);
@@ -219,6 +238,7 @@ public void createTable() {
219238
mappedCustomVersionedTable.createTable(r -> r.provisionedThroughput(getDefaultProvisionedThroughput()));
220239
annotatedTable.createTable(r -> r.provisionedThroughput(getDefaultProvisionedThroughput()));
221240
startAtNegativeOneTable.createTable(r -> r.provisionedThroughput(getDefaultProvisionedThroughput()));
241+
startAtNegativeOneIncrementByTwoTable.createTable(r -> r.provisionedThroughput(getDefaultProvisionedThroughput()));
222242
annotatedStartAtNegativeOneTable.createTable(r -> r.provisionedThroughput(getDefaultProvisionedThroughput()));
223243
}
224244

@@ -240,6 +260,10 @@ public void deleteTable() {
240260
.tableName(getConcreteTableName("startAt-neg-one-table"))
241261
.build());
242262

263+
getDynamoDbClient().deleteTable(DeleteTableRequest.builder()
264+
.tableName(getConcreteTableName("startAt-neg-one-inc-two-table"))
265+
.build());
266+
243267
getDynamoDbClient().deleteTable(DeleteTableRequest.builder()
244268
.tableName(getConcreteTableName("annotated-startAt-neg-one-table"))
245269
.build());
@@ -434,12 +458,12 @@ public void customStartAtValueIsUsedForFirstRecord() {
434458
mappedCustomVersionedTable.putItem(r -> r.item(new Record().setId("custom-start").setAttribute("test")));
435459

436460
Record record = mappedCustomVersionedTable.getItem(r -> r.key(k -> k.partitionValue("custom-start")));
437-
assertThat(record.getVersion(), is(12));
461+
assertThat(record.getVersion(), is(CUSTOM_START_AT + CUSTOM_INCREMENT_BY));
438462
}
439463

440464
@Test(expected = ConditionalCheckFailedException.class)
441465
public void recordWithVersionBetweenStartAtAndFirstVersionFails() {
442-
Record invalidRecord = new Record().setId("invalid-version").setAttribute("test").setVersion(11);
466+
Record invalidRecord = new Record().setId("invalid-version").setAttribute("test").setVersion(CUSTOM_START_AT + 1);
443467
mappedCustomVersionedTable.putItem(r -> r.item(invalidRecord));
444468
}
445469

@@ -449,14 +473,14 @@ public void annotationBasedCustomVersioningWorks() {
449473

450474
AnnotatedRecord result = annotatedTable.getItem(r -> r.key(k -> k.partitionValue("annotated")));
451475

452-
assertThat(result.getVersion(), is(8L));
476+
assertThat(result.getVersion(), is(ANNOTATED_START_AT + ANNOTATED_INCREMENT_BY));
453477

454478
AnnotatedRecord updated = annotatedTable.updateItem(r -> r.item(new AnnotatedRecord()
455479
.setId("annotated")
456480
.setAttribute("updated")
457-
.setVersion(8L)));
481+
.setVersion(ANNOTATED_START_AT + ANNOTATED_INCREMENT_BY)));
458482

459-
assertThat(updated.getVersion(), is(11L));
483+
assertThat(updated.getVersion(), is(ANNOTATED_START_AT + ANNOTATED_INCREMENT_BY + ANNOTATED_INCREMENT_BY));
460484
}
461485

462486
@Test
@@ -478,45 +502,45 @@ public void updateItem_existingRecordWithVersionZero_defaultStartAt_shouldSuccee
478502
public void updateItem_existingRecordWithVersionEqualToBuilderStartAt_shouldSucceed() {
479503
Map<String, AttributeValue> item = new HashMap<>();
480504
item.put("id", stringValue("version-ten"));
481-
item.put("version", AttributeValue.builder().n("10").build());
505+
item.put("version", AttributeValue.builder().n(String.valueOf(CUSTOM_START_AT)).build());
482506

483507
getDynamoDbClient().putItem(r -> r.tableName(getConcreteTableName("table-name2")).item(item));
484508

485509
Record retrieved = mappedCustomVersionedTable.getItem(r -> r.key(k -> k.partitionValue("version-ten")));
486-
assertThat(retrieved.getVersion(), is(10));
510+
assertThat(retrieved.getVersion(), is(CUSTOM_START_AT));
487511

488512
Record updated = mappedCustomVersionedTable.updateItem(retrieved);
489-
assertThat(updated.getVersion(), is(12));
513+
assertThat(updated.getVersion(), is(CUSTOM_START_AT + CUSTOM_INCREMENT_BY));
490514
}
491515

492516
@Test
493517
public void updateItem_existingRecordWithVersionEqualToAnnotationStartAt_shouldSucceed() {
494518
Map<String, AttributeValue> item = new HashMap<>();
495519
item.put("id", stringValue("version-five"));
496-
item.put("version", AttributeValue.builder().n("5").build());
520+
item.put("version", AttributeValue.builder().n(String.valueOf(ANNOTATED_START_AT)).build());
497521

498522
getDynamoDbClient().putItem(r -> r.tableName(getConcreteTableName("annotated-table")).item(item));
499523

500524
AnnotatedRecord retrieved = annotatedTable.getItem(r -> r.key(k -> k.partitionValue("version-five")));
501-
assertThat(retrieved.getVersion(), is(5L));
525+
assertThat(retrieved.getVersion(), is(ANNOTATED_START_AT));
502526

503527
AnnotatedRecord updated = annotatedTable.updateItem(retrieved);
504-
assertThat(updated.getVersion(), is(8L));
528+
assertThat(updated.getVersion(), is(ANNOTATED_START_AT + ANNOTATED_INCREMENT_BY));
505529
}
506530

507531
@Test
508532
public void putItem_existingRecordWithVersionEqualToStartAt_shouldSucceed() {
509533
Map<String, AttributeValue> item = new HashMap<>();
510534
item.put("id", stringValue("put-version-ten"));
511-
item.put("version", AttributeValue.builder().n("10").build());
535+
item.put("version", AttributeValue.builder().n(String.valueOf(CUSTOM_START_AT)).build());
512536

513537
getDynamoDbClient().putItem(r -> r.tableName(getConcreteTableName("table-name2")).item(item));
514538

515-
Record overwrite = new Record().setId("put-version-ten").setVersion(10);
539+
Record overwrite = new Record().setId("put-version-ten").setVersion(CUSTOM_START_AT);
516540
mappedCustomVersionedTable.putItem(overwrite);
517541

518542
Record retrieved = mappedCustomVersionedTable.getItem(r -> r.key(k -> k.partitionValue("put-version-ten")));
519-
assertThat(retrieved.getVersion(), is(12));
543+
assertThat(retrieved.getVersion(), is(CUSTOM_START_AT + CUSTOM_INCREMENT_BY));
520544
}
521545

522546
@Test
@@ -567,43 +591,43 @@ public void updateItem_bothBuilderAndAnnotationWithVersionEqualToStartAt_shouldS
567591
Map<String, AttributeValue> item = new HashMap<>();
568592
item.put("id", stringValue("both-config"));
569593
item.put("attribute", stringValue("initial"));
570-
item.put("version", AttributeValue.builder().n("5").build());
594+
item.put("version", AttributeValue.builder().n(String.valueOf(ANNOTATED_START_AT)).build());
571595
getDynamoDbClient().putItem(r -> r.tableName(getConcreteTableName("annotated-table")).item(item));
572596

573597
AnnotatedRecord retrieved = annotatedTable.getItem(r -> r.key(k -> k.partitionValue("both-config")));
574-
assertThat(retrieved.getVersion(), is(5L));
598+
assertThat(retrieved.getVersion(), is(ANNOTATED_START_AT));
575599

576600
retrieved.setAttribute("updated");
577601
AnnotatedRecord updated = annotatedTable.updateItem(retrieved);
578-
assertThat(updated.getVersion(), is(8L));
602+
assertThat(updated.getVersion(), is(ANNOTATED_START_AT + ANNOTATED_INCREMENT_BY));
579603
}
580604

581605
@Test
582606
public void putItem_annotationConfigWithVersionEqualToStartAt_shouldSucceed() {
583607
Map<String, AttributeValue> item = new HashMap<>();
584608
item.put("id", stringValue("annotation-put"));
585609
item.put("attribute", stringValue("initial"));
586-
item.put("version", AttributeValue.builder().n("5").build());
610+
item.put("version", AttributeValue.builder().n(String.valueOf(ANNOTATED_START_AT)).build());
587611
getDynamoDbClient().putItem(r -> r.tableName(getConcreteTableName("annotated-table")).item(item));
588612

589-
AnnotatedRecord overwrite = new AnnotatedRecord().setId("annotation-put").setAttribute("overwritten").setVersion(5L);
613+
AnnotatedRecord overwrite = new AnnotatedRecord().setId("annotation-put").setAttribute("overwritten").setVersion(ANNOTATED_START_AT);
590614
annotatedTable.putItem(overwrite);
591615

592616
AnnotatedRecord retrieved = annotatedTable.getItem(r -> r.key(k -> k.partitionValue("annotation-put")));
593617
assertThat(retrieved.getAttribute(), is("overwritten"));
594-
assertThat(retrieved.getVersion(), is(8L));
618+
assertThat(retrieved.getVersion(), is(ANNOTATED_START_AT + ANNOTATED_INCREMENT_BY));
595619
}
596620

597621
@Test
598622
public void deleteItem_builderConfigWithVersionEqualToStartAt_shouldSucceed() {
599623
Map<String, AttributeValue> item = new HashMap<>();
600624
item.put("id", stringValue("delete-builder"));
601625
item.put("attribute", stringValue("test"));
602-
item.put("version", AttributeValue.builder().n("10").build());
626+
item.put("version", AttributeValue.builder().n(String.valueOf(CUSTOM_START_AT)).build());
603627
getDynamoDbClient().putItem(r -> r.tableName(getConcreteTableName("table-name2")).item(item));
604628

605629
Record toDelete = mappedCustomVersionedTable.getItem(r -> r.key(k -> k.partitionValue("delete-builder")));
606-
assertThat(toDelete.getVersion(), is(10));
630+
assertThat(toDelete.getVersion(), is(CUSTOM_START_AT));
607631

608632
mappedCustomVersionedTable.deleteItem(toDelete);
609633

@@ -616,11 +640,11 @@ public void deleteItem_annotationConfigWithVersionEqualToStartAt_shouldSucceed()
616640
Map<String, AttributeValue> item = new HashMap<>();
617641
item.put("id", stringValue("delete-annotation"));
618642
item.put("attribute", stringValue("test"));
619-
item.put("version", AttributeValue.builder().n("5").build());
643+
item.put("version", AttributeValue.builder().n(String.valueOf(ANNOTATED_START_AT)).build());
620644
getDynamoDbClient().putItem(r -> r.tableName(getConcreteTableName("annotated-table")).item(item));
621645

622646
AnnotatedRecord toDelete = annotatedTable.getItem(r -> r.key(k -> k.partitionValue("delete-annotation")));
623-
assertThat(toDelete.getVersion(), is(5L));
647+
assertThat(toDelete.getVersion(), is(ANNOTATED_START_AT));
624648

625649
annotatedTable.deleteItem(toDelete);
626650

@@ -648,6 +672,26 @@ public void updateItem_startAtNegativeOne_incrementsFromZero() {
648672
assertThat(result.getVersion(), is(1));
649673
}
650674

675+
@Test
676+
public void putItem_startAtNegativeOne_incrementByTwo_firstVersionIsOne() {
677+
startAtNegativeOneIncrementByTwoTable.putItem(r -> r.item(new Record().setId("test-id").setAttribute("value")));
678+
679+
Record result = startAtNegativeOneIncrementByTwoTable.getItem(r -> r.key(k -> k.partitionValue("test-id")));
680+
assertThat(result.getVersion(), is(1));
681+
}
682+
683+
@Test
684+
public void updateItem_startAtNegativeOne_incrementByTwo_incrementsByTwo() {
685+
startAtNegativeOneIncrementByTwoTable.putItem(r -> r.item(new Record().setId("test-id-2").setAttribute("value")));
686+
687+
Record recordToUpdate = startAtNegativeOneIncrementByTwoTable.getItem(r -> r.key(k -> k.partitionValue("test-id-2")));
688+
recordToUpdate.setAttribute("updated");
689+
startAtNegativeOneIncrementByTwoTable.updateItem(r -> r.item(recordToUpdate));
690+
691+
Record result = startAtNegativeOneIncrementByTwoTable.getItem(r -> r.key(k -> k.partitionValue("test-id-2")));
692+
assertThat(result.getVersion(), is(3));
693+
}
694+
651695
@Test
652696
public void updateItem_startAtNegativeOne_versionMatchesStartAt_shouldSucceed() {
653697
Map<String, AttributeValue> item = new HashMap<>();
@@ -662,6 +706,14 @@ public void updateItem_startAtNegativeOne_versionMatchesStartAt_shouldSucceed()
662706
assertThat(result.getVersion(), is(0));
663707
}
664708

709+
@Test(expected = IllegalArgumentException.class)
710+
public void builder_startAtNegativeTwo_throwsException() {
711+
VersionedRecordExtension.builder()
712+
.startAt(-2L)
713+
.incrementBy(1L)
714+
.build();
715+
}
716+
665717
@Test
666718
public void annotatedRecord_startAtNegativeOne_firstVersionIsZero() {
667719
AnnotatedRecordStartAtNegativeOne record = new AnnotatedRecordStartAtNegativeOne();

0 commit comments

Comments
 (0)