/*
* 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 software.amazon.awssdk.enhanced.dynamodb.internal.AttributeValues.nullAttributeValue;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import software.amazon.awssdk.annotations.NotThreadSafe;
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.annotations.ThreadSafe;
import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.enhanced.dynamodb.internal.AttributeValues;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.utils.Validate;
/**
* An object that represents a key that can be used to either identify a specific record or form part of a query
* conditional. Keys are literal and hence not typed, and can be re-used in commands for different modelled types if
* the literal values are to be the same.
*
* A key will always have a single partition key value associated with it, and optionally will have a sort key value.
* The names of the keys themselves are not part of this object.
*/
@SdkPublicApi
@ThreadSafe
public final class Key {
private final AttributeValue partitionValue;
private final AttributeValue sortValue;
private Key(Builder builder) {
Validate.isTrue(builder.partitionValue != null && !builder.partitionValue.equals(nullAttributeValue()),
"partitionValue should not be null");
this.partitionValue = builder.partitionValue;
this.sortValue = builder.sortValue;
}
/**
* Returns a new builder that can be used to construct an instance of this class.
* @return A newly initialized {@link Builder} object.
*/
public static Builder builder() {
return new Builder();
}
/**
* Return a map of the key elements that can be passed directly to DynamoDb.
* @param tableSchema A tableschema to determine the key attribute names from.
* @param index The name of the index to use when determining the key attribute names.
* @return A map of attribute names to {@link AttributeValue}.
*/
public Map keyMap(TableSchema> tableSchema, String index) {
Map keyMap = new HashMap<>();
keyMap.put(tableSchema.tableMetadata().indexPartitionKey(index), partitionValue);
if (sortValue != null) {
keyMap.put(tableSchema.tableMetadata().indexSortKey(index).orElseThrow(
() -> new IllegalArgumentException("A sort key value was supplied for an index that does not support "
+ "one. Index: " + index)), sortValue);
}
return Collections.unmodifiableMap(keyMap);
}
/**
* Get the literal value of the partition key stored in this object.
* @return An {@link AttributeValue} representing the literal value of the partition key.
*/
public AttributeValue partitionKeyValue() {
return partitionValue;
}
/**
* Get the literal value of the sort key stored in this object if available.
* @return An optional {@link AttributeValue} representing the literal value of the sort key, or empty if there
* is no sort key value in this Key.
*/
public Optional sortKeyValue() {
return Optional.ofNullable(sortValue);
}
/**
* Return a map of the key elements that form the primary key of a table that can be passed directly to DynamoDb.
* @param tableSchema A tableschema to determine the key attribute names from.
* @return A map of attribute names to {@link AttributeValue}.
*/
public Map primaryKeyMap(TableSchema> tableSchema) {
return keyMap(tableSchema, TableMetadata.primaryIndexName());
}
/**
* Converts an existing key into a builder object that can be used to modify its values and then create a new key.
* @return A {@link Builder} initialized with the values of this key.
*/
public Builder toBuilder() {
return new Builder().partitionValue(this.partitionValue).sortValue(this.sortValue);
}
/**
* Builder for {@link Key}
*/
@NotThreadSafe
public static final class Builder {
private AttributeValue partitionValue;
private AttributeValue sortValue;
private Builder() {
}
/**
* Value to be used for the partition key
* @param partitionValue partition key value
*/
public Builder partitionValue(AttributeValue partitionValue) {
this.partitionValue = partitionValue;
return this;
}
/**
* String value to be used for the partition key. The string will be converted into an AttributeValue of type S.
* @param partitionValue partition key value
*/
public Builder partitionValue(String partitionValue) {
this.partitionValue = AttributeValues.stringValue(partitionValue);
return this;
}
/**
* Numeric value to be used for the partition key. The number will be converted into an AttributeValue of type N.
* @param partitionValue partition key value
*/
public Builder partitionValue(Number partitionValue) {
this.partitionValue = AttributeValues.numberValue(partitionValue);
return this;
}
/**
* Binary value to be used for the partition key. The input will be converted into an AttributeValue of type B.
* @param partitionValue the bytes to be used for the binary key value.
*/
public Builder partitionValue(SdkBytes partitionValue) {
this.partitionValue = AttributeValues.binaryValue(partitionValue);
return this;
}
/**
* Value to be used for the sort key
* @param sortValue sort key value
*/
public Builder sortValue(AttributeValue sortValue) {
this.sortValue = sortValue;
return this;
}
/**
* String value to be used for the sort key. The string will be converted into an AttributeValue of type S.
* @param sortValue sort key value
*/
public Builder sortValue(String sortValue) {
this.sortValue = AttributeValues.stringValue(sortValue);
return this;
}
/**
* Numeric value to be used for the sort key. The number will be converted into an AttributeValue of type N.
* @param sortValue sort key value
*/
public Builder sortValue(Number sortValue) {
this.sortValue = AttributeValues.numberValue(sortValue);
return this;
}
/**
* Binary value to be used for the sort key. The input will be converted into an AttributeValue of type B.
* @param sortValue the bytes to be used for the binary key value.
*/
public Builder sortValue(SdkBytes sortValue) {
this.sortValue = AttributeValues.binaryValue(sortValue);
return this;
}
/**
* Construct a {@link Key} from this builder.
*/
public Key build() {
return new Key(this);
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Key key = (Key) o;
if (partitionValue != null ? ! partitionValue.equals(key.partitionValue) :
key.partitionValue != null) {
return false;
}
return sortValue != null ? sortValue.equals(key.sortValue) : key.sortValue == null;
}
@Override
public int hashCode() {
int result = partitionValue != null ? partitionValue.hashCode() : 0;
result = 31 * result + (sortValue != null ? sortValue.hashCode() : 0);
return result;
}
}