Skip to content

Commit ceec522

Browse files
committed
Added support for @DynamoDbAutoGeneratedTimestampAttribute and @DynamoDbUpdateBehavior on attributes within nested objects
1 parent 91644e1 commit ceec522

File tree

2 files changed

+114
-12
lines changed

2 files changed

+114
-12
lines changed

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,17 @@ private Map<String, AttributeValue> processNestedObject(Map<String, AttributeVal
206206

207207
nestedMap.forEach((nestedKey, nestedValue) -> {
208208
if (nestedValue.hasM()) {
209-
updatedNestedMap.put(nestedKey,
210-
AttributeValue.builder().m(processNestedObject(nestedValue.m(), nestedSchema,
211-
currentInstant)).build());
209+
// Resolve the child-attribute schema; default to the current (parent) schema if none is registered
210+
Optional<? extends TableSchema<?>> childSchemaOptional = getNestedSchema(nestedSchema, nestedKey);
211+
TableSchema<?> schemaToUse = childSchemaOptional.isPresent()
212+
? childSchemaOptional.get()
213+
: nestedSchema;
214+
215+
updatedNestedMap.put(nestedKey, AttributeValue.builder()
216+
.m(processNestedObject(
217+
nestedValue.m(), schemaToUse, currentInstant))
218+
.build());
219+
212220
} else if (nestedValue.hasL() && !nestedValue.l().isEmpty()
213221
&& nestedValue.l().get(0).hasM()) {
214222
try {

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

Lines changed: 103 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,19 @@ public class AutoGeneratedTimestampRecordTest extends LocalDynamoDbSyncTestBase
7272
.tags(autoGeneratedTimestampAttribute()))
7373
.build();
7474

75+
76+
private static final TableSchema<SubNestedRecord> SUB_NESTED_TABLE_SCHEMA =
77+
StaticTableSchema.builder(SubNestedRecord.class)
78+
.newItemSupplier(SubNestedRecord::new)
79+
.addAttribute(Instant.class, a -> a.name("subNestedTimeAttribute")
80+
.getter(SubNestedRecord::getSubNestedTimeAttribute)
81+
.setter(SubNestedRecord::setSubNestedTimeAttribute)
82+
.tags(autoGeneratedTimestampAttribute()))
83+
.addAttribute(String.class, a -> a.name("subNestedAttribute")
84+
.getter(SubNestedRecord::getSubNestedAttribute)
85+
.setter(SubNestedRecord::setSubNestedAttribute))
86+
.build();
87+
7588
private static final TableSchema<NestedRecord> NESTED_TABLE_SCHEMA =
7689
StaticTableSchema.builder(NestedRecord.class)
7790
.newItemSupplier(NestedRecord::new)
@@ -82,6 +95,11 @@ public class AutoGeneratedTimestampRecordTest extends LocalDynamoDbSyncTestBase
8295
.addAttribute(String.class, a -> a.name("nestedAttribute")
8396
.getter(NestedRecord::getNestedAttribute)
8497
.setter(NestedRecord::setNestedAttribute))
98+
.addAttribute(
99+
EnhancedType.documentOf(SubNestedRecord.class, SUB_NESTED_TABLE_SCHEMA),
100+
a -> a.name("subNestedRecord")
101+
.getter(NestedRecord::getSubNestedRecord)
102+
.setter(NestedRecord::setSubNestedRecord))
85103
.build();
86104

87105
private static final TableSchema<Record> TABLE_SCHEMA =
@@ -162,14 +180,28 @@ public void deleteTable() {
162180

163181
@Test
164182
public void putNewRecordSetsInitialAutoGeneratedTimestampIncludingNestedFields() {
165-
Record item = new Record().setId("id").setAttribute("one")
166-
.setNestedRecord(new NestedRecord().setNestedAttribute("attribute"));
183+
NestedRecord nestedRecord = new NestedRecord()
184+
.setNestedAttribute("nestedAttribute")
185+
.setSubNestedRecord(new SubNestedRecord().setSubNestedAttribute("subNestedAttribute"));
186+
187+
Record item = new Record()
188+
.setId("id")
189+
.setAttribute("one")
190+
.setNestedRecord(nestedRecord);
191+
167192
mappedTable.putItem(r -> r.item(item));
168193
Record result = mappedTable.getItem(r -> r.key(k -> k.partitionValue("id")));
169194
GetItemResponse itemAsStoredInDDB = getItemAsStoredFromDDB();
170195
FlattenedRecord flattenedRecord = new FlattenedRecord().setGenerated(MOCKED_INSTANT_NOW);
171-
NestedRecord expectedNestedRecord = new NestedRecord().setNestedTimeAttribute(MOCKED_INSTANT_NOW)
172-
.setNestedAttribute("attribute");
196+
197+
SubNestedRecord expectedSubNestedRecord = new SubNestedRecord()
198+
.setSubNestedTimeAttribute(MOCKED_INSTANT_NOW)
199+
.setSubNestedAttribute("subNestedAttribute");
200+
NestedRecord expectedNestedRecord = new NestedRecord()
201+
.setNestedTimeAttribute(MOCKED_INSTANT_NOW)
202+
.setNestedAttribute("nestedAttribute")
203+
.setSubNestedRecord(expectedSubNestedRecord);
204+
173205
Record expectedRecord = new Record().setId("id")
174206
.setAttribute("one")
175207
.setLastUpdatedDate(MOCKED_INSTANT_NOW)
@@ -181,7 +213,8 @@ public void putNewRecordSetsInitialAutoGeneratedTimestampIncludingNestedFields()
181213
assertThat(result, is(expectedRecord));
182214
// The data in DDB is stored in converted time format
183215
assertThat(itemAsStoredInDDB.item().get("convertedLastUpdatedDate").s(), is("13 01 2019 14:00:00"));
184-
assertThat(itemAsStoredInDDB.item().get("nestedRecord").m().get("nestedTimeAttribute").s(), is(MOCKED_INSTANT_NOW.toString()));
216+
assertThat(itemAsStoredInDDB.item().get("nestedRecord").m().get("nestedTimeAttribute").s(),
217+
is(MOCKED_INSTANT_NOW.toString()));
185218
}
186219

187220
@Test
@@ -666,6 +699,7 @@ public String toString() {
666699
private static class NestedRecord {
667700
private Instant nestedTimeAttribute;
668701
private String nestedAttribute;
702+
private SubNestedRecord subNestedRecord;
669703

670704
public Instant getNestedTimeAttribute() {
671705
return nestedTimeAttribute;
@@ -676,13 +710,24 @@ public NestedRecord setNestedTimeAttribute(Instant nestedTimeAttribute) {
676710
return this;
677711
}
678712

679-
public String getNestedAttribute() {return nestedAttribute;}
713+
public String getNestedAttribute() {
714+
return nestedAttribute;
715+
}
680716

681717
public NestedRecord setNestedAttribute(String nestedAttribute) {
682718
this.nestedAttribute = nestedAttribute;
683719
return this;
684720
}
685721

722+
public SubNestedRecord getSubNestedRecord() {
723+
return subNestedRecord;
724+
}
725+
726+
public NestedRecord setSubNestedRecord(SubNestedRecord subNestedRecord) {
727+
this.subNestedRecord = subNestedRecord;
728+
return this;
729+
}
730+
686731
@Override
687732
public boolean equals(Object o) {
688733
if (this == o) {
@@ -693,19 +738,21 @@ public boolean equals(Object o) {
693738
}
694739
NestedRecord that = (NestedRecord) o;
695740
return Objects.equals(nestedTimeAttribute, that.nestedTimeAttribute) &&
696-
Objects.equals(nestedAttribute, that.nestedAttribute);
741+
Objects.equals(nestedAttribute, that.nestedAttribute) &&
742+
Objects.equals(subNestedRecord, that.subNestedRecord);
697743
}
698744

699745
@Override
700746
public int hashCode() {
701-
return Objects.hash(nestedTimeAttribute, nestedAttribute);
747+
return Objects.hash(nestedTimeAttribute, nestedAttribute, subNestedRecord);
702748
}
703749

704750
@Override
705751
public String toString() {
706752
return "NestedRecord{" +
707753
"nestedTimeAttribute=" + nestedTimeAttribute +
708-
"nestedAttribute=" + nestedAttribute +
754+
", nestedAttribute='" + nestedAttribute + '\'' +
755+
", subNestedRecord=" + subNestedRecord +
709756
'}';
710757
}
711758
}
@@ -761,5 +808,52 @@ public String toString() {
761808
}
762809
}
763810

811+
private static class SubNestedRecord {
812+
private Instant subNestedTimeAttribute;
813+
private String subNestedAttribute;
814+
815+
public Instant getSubNestedTimeAttribute() {
816+
return subNestedTimeAttribute;
817+
}
818+
819+
public SubNestedRecord setSubNestedTimeAttribute(Instant subNestedTimeAttribute) {
820+
this.subNestedTimeAttribute = subNestedTimeAttribute;
821+
return this;
822+
}
823+
824+
public String getSubNestedAttribute() {
825+
return subNestedAttribute;
826+
}
827+
828+
public SubNestedRecord setSubNestedAttribute(String subNestedAttribute) {
829+
this.subNestedAttribute = subNestedAttribute;
830+
return this;
831+
}
764832

833+
@Override
834+
public boolean equals(Object o) {
835+
if (this == o) {
836+
return true;
837+
}
838+
if (o == null || getClass() != o.getClass()) {
839+
return false;
840+
}
841+
SubNestedRecord that = (SubNestedRecord) o;
842+
return Objects.equals(subNestedTimeAttribute, that.subNestedTimeAttribute) &&
843+
Objects.equals(subNestedAttribute, that.subNestedAttribute);
844+
}
845+
846+
@Override
847+
public int hashCode() {
848+
return Objects.hash(subNestedTimeAttribute, subNestedAttribute);
849+
}
850+
851+
@Override
852+
public String toString() {
853+
return "SubNestedRecord{" +
854+
"subNestedTimeAttribute=" + subNestedTimeAttribute +
855+
", subNestedAttribute='" + subNestedAttribute + '\'' +
856+
'}';
857+
}
858+
}
765859
}

0 commit comments

Comments
 (0)