
software.amazon.awssdk.enhanced.dynamodb.mapper.StaticTableMetadata Maven / Gradle / Ivy
/*
* 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.mapper;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import software.amazon.awssdk.annotations.NotThreadSafe;
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.annotations.ThreadSafe;
import software.amazon.awssdk.enhanced.dynamodb.AttributeValueType;
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.mapper.StaticIndexMetadata;
import software.amazon.awssdk.enhanced.dynamodb.internal.mapper.StaticKeyAttributeMetadata;
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
/**
* Implementation of {@link TableMetadata} that can be constructed directly using literal values for metadata objects.
* This implementation is used by {@link StaticTableSchema} and associated interfaces such as {@link StaticAttributeTag}
* and {@link StaticTableTag} which permit manipulation of the table metadata.
*/
@SdkPublicApi
@ThreadSafe
public final class StaticTableMetadata implements TableMetadata {
private final Map customMetadata;
private final Map indexByNameMap;
private final Map keyAttributes;
private StaticTableMetadata(Builder builder) {
this.customMetadata = Collections.unmodifiableMap(builder.customMetadata);
this.indexByNameMap = Collections.unmodifiableMap(builder.indexByNameMap);
this.keyAttributes = Collections.unmodifiableMap(builder.keyAttributes);
}
/**
* Create a new builder for this class
* @return A newly initialized {@link Builder} for building a {@link StaticTableMetadata} object.
*/
public static Builder builder() {
return new Builder();
}
@Override
public Optional customMetadataObject(String key, Class extends T> objectClass) {
Object genericObject = customMetadata.get(key);
if (genericObject == null) {
return Optional.empty();
}
if (!objectClass.isAssignableFrom(genericObject.getClass())) {
throw new IllegalArgumentException("Attempt to retrieve a custom metadata object as a type that is not "
+ "assignable for that object. Custom metadata key: " + key + "; "
+ "requested object class: " + objectClass.getCanonicalName() + "; "
+ "found object class: " + genericObject.getClass().getCanonicalName());
}
return Optional.of(objectClass.cast(genericObject));
}
@Override
public String indexPartitionKey(String indexName) {
IndexMetadata index = getIndex(indexName);
if (!index.partitionKey().isPresent()) {
if (!TableMetadata.primaryIndexName().equals(indexName) && index.sortKey().isPresent()) {
// Local secondary index, use primary partition key
return primaryPartitionKey();
}
throw new IllegalArgumentException("Attempt to execute an operation against an index that requires a "
+ "partition key without assigning a partition key to that index. "
+ "Index name: " + indexName);
}
return index.partitionKey().get().name();
}
@Override
public Optional indexSortKey(String indexName) {
IndexMetadata index = getIndex(indexName);
return index.sortKey().map(KeyAttributeMetadata::name);
}
@Override
public Collection indexKeys(String indexName) {
IndexMetadata index = getIndex(indexName);
if (index.sortKey().isPresent()) {
if (!TableMetadata.primaryIndexName().equals(indexName) && !index.partitionKey().isPresent()) {
// Local secondary index, use primary index for partition key
return Collections.unmodifiableList(Arrays.asList(primaryPartitionKey(), index.sortKey().get().name()));
}
return Collections.unmodifiableList(Arrays.asList(index.partitionKey().get().name(), index.sortKey().get().name()));
} else {
return Collections.singletonList(index.partitionKey().get().name());
}
}
@Override
public Collection allKeys() {
return this.keyAttributes.keySet();
}
@Override
public Collection indices() {
return indexByNameMap.values();
}
@Override
public Map customMetadata() {
return this.customMetadata;
}
@Override
public Collection keyAttributes() {
return this.keyAttributes.values();
}
private IndexMetadata getIndex(String indexName) {
IndexMetadata index = indexByNameMap.get(indexName);
if (index == null) {
if (TableMetadata.primaryIndexName().equals(indexName)) {
throw new IllegalArgumentException("Attempt to execute an operation that requires a primary index "
+ "without defining any primary key attributes in the table "
+ "metadata.");
} else {
throw new IllegalArgumentException("Attempt to execute an operation that requires a secondary index "
+ "without defining the index attributes in the table metadata. "
+ "Index name: " + indexName);
}
}
return index;
}
@Override
public Optional scalarAttributeType(String keyAttribute) {
KeyAttributeMetadata key = this.keyAttributes.get(keyAttribute);
if (key == null) {
throw new IllegalArgumentException("Key attribute '" + keyAttribute + "' not found in table metadata.");
}
return Optional.ofNullable(key.attributeValueType().scalarAttributeType());
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
StaticTableMetadata that = (StaticTableMetadata) o;
if (customMetadata != null ? ! customMetadata.equals(that.customMetadata) : that.customMetadata != null) {
return false;
}
if (indexByNameMap != null ? ! indexByNameMap.equals(that.indexByNameMap) : that.indexByNameMap != null) {
return false;
}
return keyAttributes != null ? keyAttributes.equals(that.keyAttributes) : that.keyAttributes == null;
}
@Override
public int hashCode() {
int result = customMetadata != null ? customMetadata.hashCode() : 0;
result = 31 * result + (indexByNameMap != null ? indexByNameMap.hashCode() : 0);
result = 31 * result + (keyAttributes != null ? keyAttributes.hashCode() : 0);
return result;
}
/**
* Builder for {@link StaticTableMetadata}
*/
@NotThreadSafe
public static class Builder {
private final Map customMetadata = new LinkedHashMap<>();
private final Map indexByNameMap = new LinkedHashMap<>();
private final Map keyAttributes = new LinkedHashMap<>();
private Builder() {
}
/**
* Builds an immutable instance of {@link StaticTableMetadata} from the values supplied to the builder.
*/
public StaticTableMetadata build() {
return new StaticTableMetadata(this);
}
/**
* Adds a single custom object to the metadata, keyed by a string. Attempting to add a metadata object with a
* key that matches one that has already been added will cause an exception to be thrown.
* @param key a string key that will be used to retrieve the custom metadata
* @param object an object that will be stored in the custom metadata map
* @throws IllegalArgumentException if the custom metadata map already contains an entry with the same key
*/
public Builder addCustomMetadataObject(String key, Object object) {
if (customMetadata.containsKey(key)) {
throw new IllegalArgumentException("Attempt to set a custom metadata object that has already been set. "
+ "Custom metadata object key: " + key);
}
customMetadata.put(key, object);
return this;
}
/**
* Adds collection of custom objects to the custom metadata, keyed by a string.
* If a collection is already present then it will append the newly added collection to the existing collection.
*
* @param key a string key that will be used to retrieve the custom metadata
* @param objects Collection of objects that will be stored in the custom metadata map
*/
public Builder addCustomMetadataObject(String key, Collection
© 2015 - 2025 Weber Informatics LLC | Privacy Policy