diff --git a/.changes/next-release/bugfix-AmazonDynamoDBEnhancedClient-bd68809.json b/.changes/next-release/bugfix-AmazonDynamoDBEnhancedClient-bd68809.json new file mode 100644 index 000000000000..aa88bc16aab9 --- /dev/null +++ b/.changes/next-release/bugfix-AmazonDynamoDBEnhancedClient-bd68809.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "Amazon DynamoDB Enhanced Client", + "contributor": "", + "description": "Fixed DynamoDbEnhancedClient DefaultDynamoDbAsyncTable::createTable() to create secondary indices that are defined on annotations of the POJO class, similar to DefaultDynamoDbTable::createTable()." +} diff --git a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/IndexUtils.java b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/IndexUtils.java new file mode 100644 index 000000000000..ac3dabed6ad4 --- /dev/null +++ b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/IndexUtils.java @@ -0,0 +1,76 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.enhanced.dynamodb.internal; + +import static java.util.Collections.emptyList; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.enhanced.dynamodb.IndexMetadata; +import software.amazon.awssdk.enhanced.dynamodb.KeyAttributeMetadata; +import software.amazon.awssdk.enhanced.dynamodb.TableMetadata; +import software.amazon.awssdk.enhanced.dynamodb.internal.client.IndexType; +import software.amazon.awssdk.enhanced.dynamodb.model.EnhancedGlobalSecondaryIndex; +import software.amazon.awssdk.enhanced.dynamodb.model.EnhancedLocalSecondaryIndex; +import software.amazon.awssdk.services.dynamodb.model.ProjectionType; + +@SdkInternalApi +public final class IndexUtils { + + private IndexUtils() { + } + + public static Map> splitSecondaryIndicesToLocalAndGlobalOnes(Collection indices) { + return indices.stream() + .filter(index -> !TableMetadata.primaryIndexName().equals(index.name())) + .collect(Collectors.groupingBy(metadata -> { + String partitionKeyName = metadata.partitionKey().map(KeyAttributeMetadata::name).orElse(null); + if (partitionKeyName == null) { + return IndexType.LSI; + } + return IndexType.GSI; + })); + } + + public static List extractLocalSecondaryIndices(Map> indicesGroups) { + return indicesGroups.getOrDefault(IndexType.LSI, emptyList()).stream() + .map(IndexUtils::mapIndexMetadataToEnhancedLocalSecondaryIndex) + .collect(Collectors.toList()); + } + + private static EnhancedLocalSecondaryIndex mapIndexMetadataToEnhancedLocalSecondaryIndex(IndexMetadata indexMetadata) { + return EnhancedLocalSecondaryIndex.builder() + .indexName(indexMetadata.name()) + .projection(pb -> pb.projectionType(ProjectionType.ALL)) + .build(); + } + + public static List extractGlobalSecondaryIndices(Map> indicesGroups) { + return indicesGroups.getOrDefault(IndexType.GSI, emptyList()).stream() + .map(IndexUtils::mapIndexMetadataToEnhancedGlobalSecondaryIndex) + .collect(Collectors.toList()); + } + + private static EnhancedGlobalSecondaryIndex mapIndexMetadataToEnhancedGlobalSecondaryIndex(IndexMetadata indexMetadata) { + return EnhancedGlobalSecondaryIndex.builder() + .indexName(indexMetadata.name()) + .projection(pb -> pb.projectionType(ProjectionType.ALL)) + .build(); + } +} diff --git a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbAsyncTable.java b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbAsyncTable.java index 1538e977b4c3..4a0a71c5ca80 100644 --- a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbAsyncTable.java +++ b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbAsyncTable.java @@ -16,12 +16,19 @@ package software.amazon.awssdk.enhanced.dynamodb.internal.client; import static software.amazon.awssdk.enhanced.dynamodb.internal.EnhancedClientUtils.createKeyFromItem; +import static software.amazon.awssdk.enhanced.dynamodb.internal.IndexUtils.extractGlobalSecondaryIndices; +import static software.amazon.awssdk.enhanced.dynamodb.internal.IndexUtils.extractLocalSecondaryIndices; +import static software.amazon.awssdk.enhanced.dynamodb.internal.IndexUtils.splitSecondaryIndicesToLocalAndGlobalOnes; +import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.enhanced.dynamodb.DynamoDbAsyncTable; import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClientExtension; +import software.amazon.awssdk.enhanced.dynamodb.IndexMetadata; import software.amazon.awssdk.enhanced.dynamodb.Key; import software.amazon.awssdk.enhanced.dynamodb.TableMetadata; import software.amazon.awssdk.enhanced.dynamodb.TableSchema; @@ -114,7 +121,12 @@ public CompletableFuture createTable(Consumer createTable() { - return createTable(CreateTableEnhancedRequest.builder().build()); + Collection indices = tableSchema.tableMetadata().indices(); + Map> indexGroups = splitSecondaryIndicesToLocalAndGlobalOnes(indices); + return createTable(CreateTableEnhancedRequest.builder() + .localSecondaryIndices(extractLocalSecondaryIndices(indexGroups)) + .globalSecondaryIndices(extractGlobalSecondaryIndices(indexGroups)) + .build()); } @Override diff --git a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbTable.java b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbTable.java index 1bd2638892bd..11cc9d1e41b9 100644 --- a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbTable.java +++ b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/client/DefaultDynamoDbTable.java @@ -15,20 +15,20 @@ package software.amazon.awssdk.enhanced.dynamodb.internal.client; -import static java.util.Collections.emptyList; import static software.amazon.awssdk.enhanced.dynamodb.internal.EnhancedClientUtils.createKeyFromItem; +import static software.amazon.awssdk.enhanced.dynamodb.internal.IndexUtils.extractGlobalSecondaryIndices; +import static software.amazon.awssdk.enhanced.dynamodb.internal.IndexUtils.extractLocalSecondaryIndices; +import static software.amazon.awssdk.enhanced.dynamodb.internal.IndexUtils.splitSecondaryIndicesToLocalAndGlobalOnes; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.function.Consumer; -import java.util.stream.Collectors; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClientExtension; import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; import software.amazon.awssdk.enhanced.dynamodb.IndexMetadata; import software.amazon.awssdk.enhanced.dynamodb.Key; -import software.amazon.awssdk.enhanced.dynamodb.KeyAttributeMetadata; import software.amazon.awssdk.enhanced.dynamodb.TableMetadata; import software.amazon.awssdk.enhanced.dynamodb.TableSchema; import software.amazon.awssdk.enhanced.dynamodb.internal.operations.CreateTableOperation; @@ -46,8 +46,6 @@ import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedRequest; import software.amazon.awssdk.enhanced.dynamodb.model.DeleteItemEnhancedResponse; import software.amazon.awssdk.enhanced.dynamodb.model.DescribeTableEnhancedResponse; -import software.amazon.awssdk.enhanced.dynamodb.model.EnhancedGlobalSecondaryIndex; -import software.amazon.awssdk.enhanced.dynamodb.model.EnhancedLocalSecondaryIndex; import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedRequest; import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedResponse; import software.amazon.awssdk.enhanced.dynamodb.model.PageIterable; @@ -61,7 +59,6 @@ import software.amazon.awssdk.services.dynamodb.DynamoDbClient; import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest; import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse; -import software.amazon.awssdk.services.dynamodb.model.ProjectionType; @SdkInternalApi public class DefaultDynamoDbTable implements DynamoDbTable { @@ -126,52 +123,14 @@ public void createTable(Consumer requestCons @Override public void createTable() { - Map> indexGroups = splitSecondaryIndicesToLocalAndGlobalOnes(); + Collection indices = tableSchema.tableMetadata().indices(); + Map> indexGroups = splitSecondaryIndicesToLocalAndGlobalOnes(indices); createTable(CreateTableEnhancedRequest.builder() .localSecondaryIndices(extractLocalSecondaryIndices(indexGroups)) .globalSecondaryIndices(extractGlobalSecondaryIndices(indexGroups)) .build()); } - private Map> splitSecondaryIndicesToLocalAndGlobalOnes() { - Collection indices = tableSchema.tableMetadata().indices(); - return indices.stream() - .filter(index -> !TableMetadata.primaryIndexName().equals(index.name())) - .collect(Collectors.groupingBy(metadata -> { - String partitionKeyName = metadata.partitionKey().map(KeyAttributeMetadata::name).orElse(null); - if (partitionKeyName == null) { - return IndexType.LSI; - } - return IndexType.GSI; - })); - } - - private List extractLocalSecondaryIndices(Map> indicesGroups) { - return indicesGroups.getOrDefault(IndexType.LSI, emptyList()).stream() - .map(this::mapIndexMetadataToEnhancedLocalSecondaryIndex) - .collect(Collectors.toList()); - } - - private EnhancedLocalSecondaryIndex mapIndexMetadataToEnhancedLocalSecondaryIndex(IndexMetadata indexMetadata) { - return EnhancedLocalSecondaryIndex.builder() - .indexName(indexMetadata.name()) - .projection(pb -> pb.projectionType(ProjectionType.ALL)) - .build(); - } - - private List extractGlobalSecondaryIndices(Map> indicesGroups) { - return indicesGroups.getOrDefault(IndexType.GSI, emptyList()).stream() - .map(this::mapIndexMetadataToEnhancedGlobalSecondaryIndex) - .collect(Collectors.toList()); - } - - private EnhancedGlobalSecondaryIndex mapIndexMetadataToEnhancedGlobalSecondaryIndex(IndexMetadata indexMetadata) { - return EnhancedGlobalSecondaryIndex.builder() - .indexName(indexMetadata.name()) - .projection(pb -> pb.projectionType(ProjectionType.ALL)) - .build(); - } - @Override public T deleteItem(DeleteItemEnhancedRequest request) { TableOperation> operation = DeleteItemOperation.create(request); diff --git a/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/IndexUtilsTest.java b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/IndexUtilsTest.java new file mode 100644 index 000000000000..798e2b115808 --- /dev/null +++ b/services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/IndexUtilsTest.java @@ -0,0 +1,51 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.enhanced.dynamodb; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.enhanced.dynamodb.internal.IndexUtils; +import software.amazon.awssdk.enhanced.dynamodb.internal.client.IndexType; +import software.amazon.awssdk.enhanced.dynamodb.internal.mapper.StaticIndexMetadata; +import software.amazon.awssdk.enhanced.dynamodb.internal.mapper.StaticKeyAttributeMetadata; + +public class IndexUtilsTest { + + @Test + public void splitSecondaryIndicesToLocalAndGlobalOnes_separateIndices() { + Collection indices = Arrays.asList(StaticIndexMetadata.builder() + .name("LocalIndex1") + .build(), + StaticIndexMetadata.builder() + .name("GlobalIndex1") + .partitionKey(StaticKeyAttributeMetadata.create( + "GlobalIndexPartitionKey", + AttributeValueType.N)) + .build()); + + Map> indexGroups = IndexUtils.splitSecondaryIndicesToLocalAndGlobalOnes(indices); + + assertThat(indexGroups.get(IndexType.LSI)).hasSize(1); + assertThat(indexGroups.get(IndexType.LSI).get(0).name()).isEqualTo("LocalIndex1"); + assertThat(indexGroups.get(IndexType.GSI)).hasSize(1); + assertThat(indexGroups.get(IndexType.GSI).get(0).name()).isEqualTo("GlobalIndex1"); + } +} \ No newline at end of file