Skip to content

Commit 81d67c0

Browse files
composite key support for GSIs (#6574)
* composite key support for GSIs * Add temporary japicmp excludes (remove after release) * fix architecture tests --------- Co-authored-by: Alex Woods <[email protected]>
1 parent c3ccdc0 commit 81d67c0

File tree

79 files changed

+13223
-539
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+13223
-539
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "feature",
3+
"category": "Amazon DynamoDB Enhanced Client",
4+
"contributor": "",
5+
"description": "Add support for GSI composite key to handle up to 4 partition and 4 sort keys"
6+
}

pom.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,9 @@
691691
<exclude>software.amazon.awssdk.annotations.ReviewBeforeRelease</exclude>
692692
<exclude>software.amazon.awssdk.thirdparty.*</exclude>
693693
<exclude>software.amazon.awssdk.regions.*</exclude>
694+
<exclude>software.amazon.awssdk.regions.*</exclude>
695+
<exclude>software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey</exclude>
696+
<exclude>software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey</exclude>
694697
</excludes>
695698

696699
<ignoreMissingOldVersion>true</ignoreMissingOldVersion>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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;
17+
18+
import org.junit.jupiter.api.BeforeAll;
19+
import software.amazon.awssdk.enhanced.dynamodb.model.CompositeKeyRecord;
20+
21+
public class QueryGSICompositeKeysBeanSchemaIntegrationTest extends QueryGSICompositeKeysIntegrationTestBase {
22+
23+
private static final String TABLE_NAME = createTestTableName();
24+
25+
@BeforeAll
26+
public static void setup() {
27+
dynamoDbClient = createDynamoDbClient();
28+
enhancedClient = DynamoDbEnhancedClient.builder().dynamoDbClient(dynamoDbClient).build();
29+
mappedTable = enhancedClient.table(TABLE_NAME, TableSchema.fromClass(CompositeKeyRecord.class));
30+
mappedTable.createTable();
31+
dynamoDbClient.waiter().waitUntilTableExists(r -> r.tableName(TABLE_NAME));
32+
insertRecords();
33+
waitForGsiConsistency();
34+
}
35+
}

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

Lines changed: 1484 additions & 0 deletions
Large diffs are not rendered by default.

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

Lines changed: 2300 additions & 0 deletions
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
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;
17+
18+
import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.primaryPartitionKey;
19+
import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.primarySortKey;
20+
import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.secondaryPartitionKey;
21+
import static software.amazon.awssdk.enhanced.dynamodb.mapper.StaticAttributeTags.secondarySortKey;
22+
23+
import org.junit.jupiter.api.BeforeAll;
24+
import software.amazon.awssdk.enhanced.dynamodb.mapper.Order;
25+
import software.amazon.awssdk.enhanced.dynamodb.mapper.StaticTableSchema;
26+
import software.amazon.awssdk.enhanced.dynamodb.model.CompositeKeyRecord;
27+
import software.amazon.awssdk.enhanced.dynamodb.model.FlattenedRecord;
28+
29+
public class QueryGSICompositeKeysStaticSchemaIntegrationTest extends QueryGSICompositeKeysIntegrationTestBase {
30+
31+
private static final String TABLE_NAME = createTestTableName();
32+
33+
private static final StaticTableSchema<FlattenedRecord> FLATTENED_RECORD_SCHEMA =
34+
StaticTableSchema.builder(FlattenedRecord.class)
35+
.newItemSupplier(FlattenedRecord::new)
36+
.addAttribute(Double.class, a -> a.name("flpk2")
37+
.getter(FlattenedRecord::getFlpk2)
38+
.setter(FlattenedRecord::setFlpk2)
39+
.tags(secondaryPartitionKey("gsi5", Order.SECOND)))
40+
.addAttribute(String.class, a -> a.name("flpk3")
41+
.getter(FlattenedRecord::getFlpk3)
42+
.setter(FlattenedRecord::setFlpk3)
43+
.tags(secondaryPartitionKey("gsi5", Order.THIRD)))
44+
.addAttribute(String.class, a -> a.name("flsk2")
45+
.getter(FlattenedRecord::getFlsk2)
46+
.setter(FlattenedRecord::setFlsk2)
47+
.tags(secondarySortKey("gsi5", Order.SECOND),
48+
secondarySortKey("gsi6", Order.FIRST)))
49+
.addAttribute(java.time.Instant.class, a -> a.name("flsk3")
50+
.getter(FlattenedRecord::getFlsk3)
51+
.setter(FlattenedRecord::setFlsk3)
52+
.tags(secondarySortKey("gsi5", Order.THIRD)))
53+
.addAttribute(String.class, a -> a.name("fldata")
54+
.getter(FlattenedRecord::getFldata)
55+
.setter(FlattenedRecord::setFldata))
56+
.build(ExecutionContext.FLATTENED);
57+
58+
private static final TableSchema<CompositeKeyRecord> COMPOSITE_KEY_SCHEMA =
59+
StaticTableSchema.builder(CompositeKeyRecord.class)
60+
.newItemSupplier(CompositeKeyRecord::new)
61+
.addAttribute(String.class, a -> a.name("id")
62+
.getter(CompositeKeyRecord::getId)
63+
.setter(CompositeKeyRecord::setId)
64+
.tags(primaryPartitionKey()))
65+
.addAttribute(String.class, a -> a.name("sort")
66+
.getter(CompositeKeyRecord::getSort)
67+
.setter(CompositeKeyRecord::setSort)
68+
.tags(primarySortKey()))
69+
.addAttribute(String.class, a -> a.name("pk1")
70+
.getter(CompositeKeyRecord::getPk1)
71+
.setter(CompositeKeyRecord::setPk1)
72+
.tags(secondaryPartitionKey("gsi1", Order.FIRST),
73+
secondaryPartitionKey("gsi2", Order.FIRST),
74+
secondaryPartitionKey("gsi3", Order.FIRST),
75+
secondaryPartitionKey("gsi4", Order.FIRST),
76+
secondaryPartitionKey("gsi5", Order.FIRST)))
77+
.addAttribute(Integer.class, a -> a.name("pk2")
78+
.getter(CompositeKeyRecord::getPk2)
79+
.setter(CompositeKeyRecord::setPk2)
80+
.tags(secondaryPartitionKey("gsi2", Order.SECOND),
81+
secondaryPartitionKey("gsi3", Order.SECOND),
82+
secondaryPartitionKey("gsi4", Order.SECOND),
83+
secondaryPartitionKey("gsi6", Order.FIRST)))
84+
.addAttribute(String.class, a -> a.name("pk3")
85+
.getter(CompositeKeyRecord::getPk3)
86+
.setter(CompositeKeyRecord::setPk3)
87+
.tags(secondaryPartitionKey("gsi3", Order.THIRD),
88+
secondaryPartitionKey("gsi4", Order.THIRD),
89+
secondaryPartitionKey("gsi6", Order.SECOND)))
90+
.addAttribute(java.time.Instant.class, a -> a.name("pk4")
91+
.getter(CompositeKeyRecord::getPk4)
92+
.setter(CompositeKeyRecord::setPk4)
93+
.tags(secondaryPartitionKey("gsi4", Order.FOURTH)))
94+
.addAttribute(String.class, a -> a.name("sk1")
95+
.getter(CompositeKeyRecord::getSk1)
96+
.setter(CompositeKeyRecord::setSk1)
97+
.tags(secondarySortKey("gsi1", Order.FIRST),
98+
secondarySortKey("gsi2", Order.FIRST),
99+
secondarySortKey("gsi3", Order.FIRST),
100+
secondarySortKey("gsi4", Order.FIRST),
101+
secondarySortKey("gsi5", Order.FIRST)))
102+
.addAttribute(String.class, a -> a.name("sk2")
103+
.getter(CompositeKeyRecord::getSk2)
104+
.setter(CompositeKeyRecord::setSk2)
105+
.tags(secondarySortKey("gsi2", Order.SECOND),
106+
secondarySortKey("gsi3", Order.SECOND),
107+
secondarySortKey("gsi4", Order.SECOND)))
108+
.addAttribute(java.time.Instant.class, a -> a.name("sk3")
109+
.getter(CompositeKeyRecord::getSk3)
110+
.setter(CompositeKeyRecord::setSk3)
111+
.tags(secondarySortKey("gsi3", Order.THIRD),
112+
secondarySortKey("gsi4", Order.THIRD),
113+
secondarySortKey("gsi6", Order.SECOND)))
114+
.addAttribute(Integer.class, a -> a.name("sk4")
115+
.getter(CompositeKeyRecord::getSk4)
116+
.setter(CompositeKeyRecord::setSk4)
117+
.tags(secondarySortKey("gsi4", Order.FOURTH)))
118+
.addAttribute(String.class, a -> a.name("data")
119+
.getter(CompositeKeyRecord::getData)
120+
.setter(CompositeKeyRecord::setData))
121+
.flatten(FLATTENED_RECORD_SCHEMA, CompositeKeyRecord::getFlattenedRecord,
122+
CompositeKeyRecord::setFlattenedRecord)
123+
.build();
124+
125+
@BeforeAll
126+
public static void setup() {
127+
dynamoDbClient = createDynamoDbClient();
128+
enhancedClient = DynamoDbEnhancedClient.builder().dynamoDbClient(dynamoDbClient).build();
129+
mappedTable = enhancedClient.table(TABLE_NAME, COMPOSITE_KEY_SCHEMA);
130+
mappedTable.createTable();
131+
dynamoDbClient.waiter().waitUntilTableExists(r -> r.tableName(TABLE_NAME));
132+
insertRecords();
133+
waitForGsiConsistency();
134+
}
135+
136+
}
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
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.model;
17+
18+
import java.time.Instant;
19+
import java.util.Objects;
20+
import software.amazon.awssdk.enhanced.dynamodb.mapper.Order;
21+
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
22+
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbFlatten;
23+
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
24+
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
25+
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey;
26+
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;
27+
28+
@DynamoDbBean
29+
public class CompositeKeyRecord {
30+
private String id;
31+
private String sort;
32+
private String pk1;
33+
private Integer pk2;
34+
private String pk3;
35+
private Instant pk4;
36+
private String sk1;
37+
private String sk2;
38+
private Instant sk3;
39+
private Integer sk4;
40+
private String data;
41+
private FlattenedRecord flattenedRecord;
42+
43+
@DynamoDbPartitionKey
44+
public String getId() {
45+
return id;
46+
}
47+
48+
public void setId(String id) {
49+
this.id = id;
50+
}
51+
52+
@DynamoDbSortKey
53+
public String getSort() {
54+
return sort;
55+
}
56+
57+
public void setSort(String sort) {
58+
this.sort = sort;
59+
}
60+
61+
@DynamoDbSecondaryPartitionKey(indexNames = {"gsi1", "gsi2", "gsi3", "gsi4", "gsi5"}, order = Order.FIRST)
62+
public String getPk1() {
63+
return pk1;
64+
}
65+
66+
public void setPk1(String pk1) {
67+
this.pk1 = pk1;
68+
}
69+
70+
@DynamoDbSecondaryPartitionKey(indexNames = {"gsi2", "gsi3", "gsi4"}, order = Order.SECOND)
71+
@DynamoDbSecondaryPartitionKey(indexNames = "gsi6", order = Order.FIRST)
72+
public Integer getPk2() {
73+
return pk2;
74+
}
75+
76+
public void setPk2(Integer pk2) {
77+
this.pk2 = pk2;
78+
}
79+
80+
@DynamoDbSecondaryPartitionKey(indexNames = {"gsi3", "gsi4"}, order = Order.THIRD)
81+
@DynamoDbSecondaryPartitionKey(indexNames = "gsi6", order = Order.SECOND)
82+
public String getPk3() {
83+
return pk3;
84+
}
85+
86+
public void setPk3(String pk3) {
87+
this.pk3 = pk3;
88+
}
89+
90+
@DynamoDbSecondaryPartitionKey(indexNames = "gsi4", order = Order.FOURTH)
91+
public Instant getPk4() {
92+
return pk4;
93+
}
94+
95+
public void setPk4(Instant pk4) {
96+
this.pk4 = pk4;
97+
}
98+
99+
@DynamoDbSecondarySortKey(indexNames = {"gsi1", "gsi2", "gsi3", "gsi4", "gsi5"}, order = Order.FIRST)
100+
public String getSk1() {
101+
return sk1;
102+
}
103+
104+
public void setSk1(String sk1) {
105+
this.sk1 = sk1;
106+
}
107+
108+
@DynamoDbSecondarySortKey(indexNames = {"gsi2", "gsi3", "gsi4"}, order = Order.SECOND)
109+
public String getSk2() {
110+
return sk2;
111+
}
112+
113+
public void setSk2(String sk2) {
114+
this.sk2 = sk2;
115+
}
116+
117+
@DynamoDbSecondarySortKey(indexNames = {"gsi3", "gsi4"}, order = Order.THIRD)
118+
@DynamoDbSecondarySortKey(indexNames = "gsi6", order = Order.SECOND)
119+
public Instant getSk3() {
120+
return sk3;
121+
}
122+
123+
public void setSk3(Instant sk3) {
124+
this.sk3 = sk3;
125+
}
126+
127+
@DynamoDbSecondarySortKey(indexNames = "gsi4", order = Order.FOURTH)
128+
public Integer getSk4() {
129+
return sk4;
130+
}
131+
132+
public void setSk4(Integer sk4) {
133+
this.sk4 = sk4;
134+
}
135+
136+
public String getData() {
137+
return data;
138+
}
139+
140+
public void setData(String data) {
141+
this.data = data;
142+
}
143+
144+
@DynamoDbFlatten
145+
public FlattenedRecord getFlattenedRecord() {
146+
return flattenedRecord;
147+
}
148+
149+
public void setFlattenedRecord(FlattenedRecord flattenedRecord) {
150+
this.flattenedRecord = flattenedRecord;
151+
}
152+
153+
@Override
154+
public boolean equals(Object o) {
155+
if (this == o) {
156+
return true;
157+
}
158+
if (o == null || getClass() != o.getClass()) {
159+
return false;
160+
}
161+
CompositeKeyRecord that = (CompositeKeyRecord) o;
162+
return Objects.equals(id, that.id) &&
163+
Objects.equals(sort, that.sort) &&
164+
Objects.equals(pk1, that.pk1) &&
165+
Objects.equals(pk2, that.pk2) &&
166+
Objects.equals(pk3, that.pk3) &&
167+
Objects.equals(pk4, that.pk4) &&
168+
Objects.equals(sk1, that.sk1) &&
169+
Objects.equals(sk2, that.sk2) &&
170+
Objects.equals(sk3, that.sk3) &&
171+
Objects.equals(sk4, that.sk4) &&
172+
Objects.equals(data, that.data) &&
173+
Objects.equals(flattenedRecord, that.flattenedRecord);
174+
}
175+
176+
@Override
177+
public int hashCode() {
178+
return Objects.hash(id, sort, pk1, pk2, pk3, pk4, sk1, sk2, sk3, sk4, data, flattenedRecord);
179+
}
180+
}

0 commit comments

Comments
 (0)