Skip to content

Commit b636dca

Browse files
committed
Fixed DefaultDynamoDbAsyncTable::createTable() to create secondary indices that are defined on annotations of the POJO class, similar to DefaultDynamoDbTable::createTable()
1 parent 752d8ad commit b636dca

File tree

6 files changed

+253
-53
lines changed

6 files changed

+253
-53
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "bugfix",
3+
"category": "Amazon DynamoDB Enhanced Client",
4+
"contributor": "",
5+
"description": "Fixed DynamoDbEnhancedClient DefaultDynamoDbAsyncTable::createTable() to create secondary indices that are defined on annotations of the POJO class, similar to DefaultDynamoDbTable::createTable()."
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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.internal;
17+
18+
import java.util.List;
19+
import java.util.stream.Collectors;
20+
import software.amazon.awssdk.annotations.SdkInternalApi;
21+
import software.amazon.awssdk.enhanced.dynamodb.IndexMetadata;
22+
import software.amazon.awssdk.enhanced.dynamodb.TableMetadata;
23+
import software.amazon.awssdk.enhanced.dynamodb.model.EnhancedGlobalSecondaryIndex;
24+
import software.amazon.awssdk.enhanced.dynamodb.model.EnhancedLocalSecondaryIndex;
25+
import software.amazon.awssdk.services.dynamodb.model.ProjectionType;
26+
27+
@SdkInternalApi
28+
public class TableIndices {
29+
private final List<IndexMetadata> indices;
30+
31+
public TableIndices(List<IndexMetadata> indices) {
32+
this.indices = indices;
33+
}
34+
35+
public List<EnhancedLocalSecondaryIndex> localSecondaryIndices() {
36+
return indices.stream()
37+
.filter(index -> !TableMetadata.primaryIndexName().equals(index.name()))
38+
.filter(index -> !index.partitionKey().isPresent())
39+
.map(TableIndices::mapIndexMetadataToEnhancedLocalSecondaryIndex)
40+
.collect(Collectors.toList());
41+
}
42+
43+
public List<EnhancedGlobalSecondaryIndex> globalSecondaryIndices() {
44+
return indices.stream()
45+
.filter(index -> !TableMetadata.primaryIndexName().equals(index.name()))
46+
.filter(index -> index.partitionKey().isPresent())
47+
.map(TableIndices::mapIndexMetadataToEnhancedGlobalSecondaryIndex)
48+
.collect(Collectors.toList());
49+
}
50+
51+
private static EnhancedLocalSecondaryIndex mapIndexMetadataToEnhancedLocalSecondaryIndex(IndexMetadata indexMetadata) {
52+
return EnhancedLocalSecondaryIndex.builder()
53+
.indexName(indexMetadata.name())
54+
.projection(pb -> pb.projectionType(ProjectionType.ALL))
55+
.build();
56+
}
57+
58+
private static EnhancedGlobalSecondaryIndex mapIndexMetadataToEnhancedGlobalSecondaryIndex(IndexMetadata indexMetadata) {
59+
return EnhancedGlobalSecondaryIndex.builder()
60+
.indexName(indexMetadata.name())
61+
.projection(pb -> pb.projectionType(ProjectionType.ALL))
62+
.build();
63+
}
64+
}

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbAsyncTable.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static software.amazon.awssdk.enhanced.dynamodb.internal.EnhancedClientUtils.createKeyFromItem;
1919

20+
import java.util.ArrayList;
2021
import java.util.concurrent.CompletableFuture;
2122
import java.util.function.Consumer;
2223
import software.amazon.awssdk.annotations.SdkInternalApi;
@@ -25,6 +26,7 @@
2526
import software.amazon.awssdk.enhanced.dynamodb.Key;
2627
import software.amazon.awssdk.enhanced.dynamodb.TableMetadata;
2728
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
29+
import software.amazon.awssdk.enhanced.dynamodb.internal.TableIndices;
2830
import software.amazon.awssdk.enhanced.dynamodb.internal.operations.CreateTableOperation;
2931
import software.amazon.awssdk.enhanced.dynamodb.internal.operations.DeleteItemOperation;
3032
import software.amazon.awssdk.enhanced.dynamodb.internal.operations.DeleteTableOperation;
@@ -114,7 +116,12 @@ public CompletableFuture<Void> createTable(Consumer<CreateTableEnhancedRequest.B
114116

115117
@Override
116118
public CompletableFuture<Void> createTable() {
117-
return createTable(CreateTableEnhancedRequest.builder().build());
119+
TableIndices indices = new TableIndices(new ArrayList<>(tableSchema.tableMetadata().indices()));
120+
121+
return createTable(CreateTableEnhancedRequest.builder()
122+
.localSecondaryIndices(indices.localSecondaryIndices())
123+
.globalSecondaryIndices(indices.globalSecondaryIndices())
124+
.build());
118125
}
119126

120127
@Override

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbTable.java

Lines changed: 6 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,17 @@
1515

1616
package software.amazon.awssdk.enhanced.dynamodb.internal.client;
1717

18-
import static java.util.Collections.emptyList;
1918
import static software.amazon.awssdk.enhanced.dynamodb.internal.EnhancedClientUtils.createKeyFromItem;
2019

21-
import java.util.Collection;
22-
import java.util.List;
23-
import java.util.Map;
20+
import java.util.ArrayList;
2421
import java.util.function.Consumer;
25-
import java.util.stream.Collectors;
2622
import software.amazon.awssdk.annotations.SdkInternalApi;
2723
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClientExtension;
2824
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
29-
import software.amazon.awssdk.enhanced.dynamodb.IndexMetadata;
3025
import software.amazon.awssdk.enhanced.dynamodb.Key;
31-
import software.amazon.awssdk.enhanced.dynamodb.KeyAttributeMetadata;
3226
import software.amazon.awssdk.enhanced.dynamodb.TableMetadata;
3327
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
28+
import software.amazon.awssdk.enhanced.dynamodb.internal.TableIndices;
3429
import software.amazon.awssdk.enhanced.dynamodb.internal.operations.CreateTableOperation;
3530
import software.amazon.awssdk.enhanced.dynamodb.internal.operations.DeleteItemOperation;
3631
import software.amazon.awssdk.enhanced.dynamodb.internal.operations.DeleteTableOperation;
@@ -46,8 +41,6 @@
4641
import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedRequest;
4742
import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedResponse;
4843
import software.amazon.awssdk.enhanced.dynamodb.model.DescribeTableEnhancedResponse;
49-
import software.amazon.awssdk.enhanced.dynamodb.model.EnhancedGlobalSecondaryIndex;
50-
import software.amazon.awssdk.enhanced.dynamodb.model.EnhancedLocalSecondaryIndex;
5144
import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedRequest;
5245
import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedResponse;
5346
import software.amazon.awssdk.enhanced.dynamodb.model.PageIterable;
@@ -61,7 +54,6 @@
6154
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
6255
import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest;
6356
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
64-
import software.amazon.awssdk.services.dynamodb.model.ProjectionType;
6557

6658
@SdkInternalApi
6759
public class DefaultDynamoDbTable<T> implements DynamoDbTable<T> {
@@ -126,52 +118,14 @@ public void createTable(Consumer<CreateTableEnhancedRequest.Builder> requestCons
126118

127119
@Override
128120
public void createTable() {
129-
Map<IndexType, List<IndexMetadata>> indexGroups = splitSecondaryIndicesToLocalAndGlobalOnes();
121+
TableIndices indices = new TableIndices(new ArrayList<>(tableSchema.tableMetadata().indices()));
122+
130123
createTable(CreateTableEnhancedRequest.builder()
131-
.localSecondaryIndices(extractLocalSecondaryIndices(indexGroups))
132-
.globalSecondaryIndices(extractGlobalSecondaryIndices(indexGroups))
124+
.localSecondaryIndices(indices.localSecondaryIndices())
125+
.globalSecondaryIndices(indices.globalSecondaryIndices())
133126
.build());
134127
}
135128

136-
private Map<IndexType, List<IndexMetadata>> splitSecondaryIndicesToLocalAndGlobalOnes() {
137-
Collection<IndexMetadata> indices = tableSchema.tableMetadata().indices();
138-
return indices.stream()
139-
.filter(index -> !TableMetadata.primaryIndexName().equals(index.name()))
140-
.collect(Collectors.groupingBy(metadata -> {
141-
String partitionKeyName = metadata.partitionKey().map(KeyAttributeMetadata::name).orElse(null);
142-
if (partitionKeyName == null) {
143-
return IndexType.LSI;
144-
}
145-
return IndexType.GSI;
146-
}));
147-
}
148-
149-
private List<EnhancedLocalSecondaryIndex> extractLocalSecondaryIndices(Map<IndexType, List<IndexMetadata>> indicesGroups) {
150-
return indicesGroups.getOrDefault(IndexType.LSI, emptyList()).stream()
151-
.map(this::mapIndexMetadataToEnhancedLocalSecondaryIndex)
152-
.collect(Collectors.toList());
153-
}
154-
155-
private EnhancedLocalSecondaryIndex mapIndexMetadataToEnhancedLocalSecondaryIndex(IndexMetadata indexMetadata) {
156-
return EnhancedLocalSecondaryIndex.builder()
157-
.indexName(indexMetadata.name())
158-
.projection(pb -> pb.projectionType(ProjectionType.ALL))
159-
.build();
160-
}
161-
162-
private List<EnhancedGlobalSecondaryIndex> extractGlobalSecondaryIndices(Map<IndexType, List<IndexMetadata>> indicesGroups) {
163-
return indicesGroups.getOrDefault(IndexType.GSI, emptyList()).stream()
164-
.map(this::mapIndexMetadataToEnhancedGlobalSecondaryIndex)
165-
.collect(Collectors.toList());
166-
}
167-
168-
private EnhancedGlobalSecondaryIndex mapIndexMetadataToEnhancedGlobalSecondaryIndex(IndexMetadata indexMetadata) {
169-
return EnhancedGlobalSecondaryIndex.builder()
170-
.indexName(indexMetadata.name())
171-
.projection(pb -> pb.projectionType(ProjectionType.ALL))
172-
.build();
173-
}
174-
175129
@Override
176130
public T deleteItem(DeleteItemEnhancedRequest request) {
177131
TableOperation<T, ?, ?, DeleteItemEnhancedResponse<T>> operation = DeleteItemOperation.create(request);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package software.amazon.awssdk.enhanced.dynamodb;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertTrue;
5+
6+
import java.util.Arrays;
7+
import java.util.Collections;
8+
import java.util.List;
9+
import org.junit.jupiter.api.Test;
10+
import software.amazon.awssdk.enhanced.dynamodb.internal.TableIndices;
11+
import software.amazon.awssdk.enhanced.dynamodb.internal.mapper.StaticIndexMetadata;
12+
import software.amazon.awssdk.enhanced.dynamodb.internal.mapper.StaticKeyAttributeMetadata;
13+
import software.amazon.awssdk.enhanced.dynamodb.model.EnhancedGlobalSecondaryIndex;
14+
import software.amazon.awssdk.enhanced.dynamodb.model.EnhancedLocalSecondaryIndex;
15+
16+
public class TableIndicesTest {
17+
18+
@Test
19+
public void testLocalSecondaryIndices_onlyIncludesLSIs() {
20+
List<IndexMetadata> indices = Arrays.asList(StaticIndexMetadata.builder()
21+
.name("lsi-1")
22+
.build(),
23+
StaticIndexMetadata.builder()
24+
.name("lsi-2")
25+
.build(),
26+
StaticIndexMetadata.builder()
27+
.name("gsi-1")
28+
.partitionKey(StaticKeyAttributeMetadata.create(
29+
"GlobalIndexPartitionKey",
30+
AttributeValueType.N))
31+
.build());
32+
33+
TableIndices tableIndices = new TableIndices(indices);
34+
35+
List<EnhancedLocalSecondaryIndex> lsiList = tableIndices.localSecondaryIndices();
36+
37+
assertEquals(2, lsiList.size());
38+
assertTrue(lsiList.stream().anyMatch(i -> "lsi-1".equals(i.indexName())));
39+
assertTrue(lsiList.stream().anyMatch(i -> "lsi-2".equals(i.indexName())));
40+
}
41+
42+
@Test
43+
public void testGlobalSecondaryIndices_onlyIncludesGSIs() {
44+
List<IndexMetadata> indices = Arrays.asList(StaticIndexMetadata.builder()
45+
.name("lsi-1")
46+
.build(),
47+
StaticIndexMetadata.builder()
48+
.name("gsi-1")
49+
.partitionKey(StaticKeyAttributeMetadata.create(
50+
"GlobalIndexPartitionKey1",
51+
AttributeValueType.N))
52+
.build(),
53+
StaticIndexMetadata.builder()
54+
.name("gsi-2")
55+
.partitionKey(StaticKeyAttributeMetadata.create(
56+
"GlobalIndexPartitionKey2",
57+
AttributeValueType.N))
58+
.build());
59+
60+
TableIndices tableIndices = new TableIndices(indices);
61+
62+
List<EnhancedGlobalSecondaryIndex> gsiList = tableIndices.globalSecondaryIndices();
63+
64+
assertEquals(2, gsiList.size());
65+
assertTrue(gsiList.stream().anyMatch(i -> "gsi-1".equals(i.indexName())));
66+
assertTrue(gsiList.stream().anyMatch(i -> "gsi-2".equals(i.indexName())));
67+
}
68+
69+
@Test
70+
public void testPrimaryIndexIsExcluded() {
71+
List<IndexMetadata> indices = Arrays.asList(StaticIndexMetadata.builder()
72+
.name(TableMetadata.primaryIndexName())
73+
.partitionKey(StaticKeyAttributeMetadata.create("pk",
74+
AttributeValueType.S))
75+
.build(),
76+
StaticIndexMetadata.builder()
77+
.name("lsi-1")
78+
.build(),
79+
StaticIndexMetadata.builder()
80+
.name("gsi-1")
81+
.partitionKey(StaticKeyAttributeMetadata.create(
82+
"GlobalIndexPartitionKey",
83+
AttributeValueType.N))
84+
.build());
85+
86+
TableIndices tableIndices = new TableIndices(indices);
87+
88+
List<EnhancedGlobalSecondaryIndex> gsiList = tableIndices.globalSecondaryIndices();
89+
List<EnhancedLocalSecondaryIndex> lsiList = tableIndices.localSecondaryIndices();
90+
91+
assertEquals(1, gsiList.size());
92+
assertEquals("gsi-1", gsiList.get(0).indexName());
93+
94+
assertEquals(1, lsiList.size());
95+
assertEquals("lsi-1", lsiList.get(0).indexName());
96+
}
97+
98+
@Test
99+
public void testEmptyIndexList() {
100+
TableIndices tableIndices = new TableIndices(Collections.emptyList());
101+
102+
assertTrue(tableIndices.globalSecondaryIndices().isEmpty());
103+
assertTrue(tableIndices.localSecondaryIndices().isEmpty());
104+
}
105+
}

0 commit comments

Comments
 (0)