use aws_sdk_dynamodb::operation::create_table::CreateTableOutput;
use aws_sdk_dynamodb::types::{
AttributeDefinition, GlobalSecondaryIndex, KeySchemaElement, KeyType, Projection,
ProjectionType, ProvisionedThroughput, ScalarAttributeType,
};
use std::fmt;
use crate::assert_not_reserved_key;
use crate::dynamodb_client;
use crate::error::Error;
use crate::table::{DynamoTable, GSITable};
pub async fn table<T>() -> Result<CreateTableOutput, Error>
where
T: DynamoTable,
T::PK: fmt::Display + Clone + Send + Sync + fmt::Debug,
T::SK: fmt::Display + Clone + Send + Sync + fmt::Debug,
{
let client = dynamodb_client().await;
assert_not_reserved_key(T::PARTITION_KEY);
let mut builder = client
.create_table()
.table_name(T::TABLE)
.key_schema(
KeySchemaElement::builder()
.attribute_name(T::PARTITION_KEY)
.key_type(KeyType::Hash)
.build()?,
)
.attribute_definitions(
AttributeDefinition::builder()
.attribute_name(T::PARTITION_KEY)
.attribute_type(ScalarAttributeType::S)
.build()?,
)
.provisioned_throughput(
ProvisionedThroughput::builder()
.read_capacity_units(10)
.write_capacity_units(10)
.build()?,
);
if let Some(sort_key) = T::SORT_KEY {
assert_not_reserved_key(sort_key);
builder = builder
.key_schema(
KeySchemaElement::builder()
.attribute_name(sort_key)
.key_type(KeyType::Range)
.build()?,
)
.attribute_definitions(
AttributeDefinition::builder()
.attribute_name(sort_key)
.attribute_type(ScalarAttributeType::S)
.build()?,
);
}
match builder.send().await {
Ok(output) => Ok(output),
Err(e) => {
if let Some(service_error) = e.as_service_error() {
if matches!(service_error, aws_sdk_dynamodb::operation::create_table::CreateTableError::ResourceInUseException(_)) {
return Ok(CreateTableOutput::builder().build());
}
}
Err(e.into())
}
}
}
pub async fn table_with_gsi<T>() -> Result<CreateTableOutput, Error>
where
T: DynamoTable + GSITable,
T::PK: fmt::Display + Clone + Send + Sync + fmt::Debug,
T::SK: fmt::Display + Clone + Send + Sync + fmt::Debug,
{
let client = dynamodb_client().await;
assert_not_reserved_key(T::PARTITION_KEY);
assert_not_reserved_key(T::GSI_PARTITION_KEY);
let mut builder = client
.create_table()
.table_name(T::TABLE)
.key_schema(
KeySchemaElement::builder()
.attribute_name(T::PARTITION_KEY)
.key_type(KeyType::Hash)
.build()?,
)
.attribute_definitions(
AttributeDefinition::builder()
.attribute_name(T::PARTITION_KEY)
.attribute_type(ScalarAttributeType::S)
.build()?,
)
.provisioned_throughput(
ProvisionedThroughput::builder()
.read_capacity_units(10)
.write_capacity_units(10)
.build()?,
);
if let Some(sort_key) = T::SORT_KEY {
assert_not_reserved_key(sort_key);
builder = builder
.key_schema(
KeySchemaElement::builder()
.attribute_name(sort_key)
.key_type(KeyType::Range)
.build()?,
)
.attribute_definitions(
AttributeDefinition::builder()
.attribute_name(sort_key)
.attribute_type(ScalarAttributeType::S)
.build()?,
);
}
builder = builder.attribute_definitions(
AttributeDefinition::builder()
.attribute_name(T::GSI_PARTITION_KEY)
.attribute_type(ScalarAttributeType::S)
.build()?,
);
let mut global_secondary_index = GlobalSecondaryIndex::builder()
.index_name(T::global_index_name())
.key_schema(
KeySchemaElement::builder()
.attribute_name(T::GSI_PARTITION_KEY)
.key_type(KeyType::Hash)
.build()?,
)
.projection(
Projection::builder()
.projection_type(ProjectionType::All)
.build(),
)
.provisioned_throughput(
ProvisionedThroughput::builder()
.read_capacity_units(10)
.write_capacity_units(10)
.build()?,
);
if let Some(gsi_sort_key) = T::GSI_SORT_KEY {
assert_not_reserved_key(gsi_sort_key);
if T::SORT_KEY != Some(gsi_sort_key) {
builder = builder.attribute_definitions(
AttributeDefinition::builder()
.attribute_name(gsi_sort_key)
.attribute_type(ScalarAttributeType::S)
.build()?,
);
}
global_secondary_index = global_secondary_index.key_schema(
KeySchemaElement::builder()
.attribute_name(gsi_sort_key)
.key_type(KeyType::Range)
.build()?,
);
}
builder = builder.global_secondary_indexes(global_secondary_index.build()?);
match builder.send().await {
Ok(output) => Ok(output),
Err(e) => {
if let Some(service_error) = e.as_service_error() {
if matches!(service_error, aws_sdk_dynamodb::operation::create_table::CreateTableError::ResourceInUseException(_)) {
return Ok(CreateTableOutput::builder().build());
}
}
Err(e.into())
}
}
}