use crate::{HasAttribute, IntoAttributeValue};
use super::*;
pub struct Key<TD: TableDefinition>(HashMap<String, AttributeValue>, PhantomData<TD>);
impl<TD: TableDefinition> fmt::Debug for Key<TD> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl<TD: TableDefinition> Key<TD> {
pub fn into_inner(self) -> HashMap<String, AttributeValue> {
self.0
}
}
pub trait KeyBuilder<TD: TableDefinition> {
type KeyId<'id>;
fn get_key_from_id(key_id: Self::KeyId<'_>) -> Key<TD>;
fn get_key_id(&self) -> Self::KeyId<'_>;
fn get_key(&self) -> Key<TD> {
Self::get_key_from_id(self.get_key_id())
}
}
mod key_builder_helper {
use super::*;
impl<TD: TableDefinition, T> KeyBuilder<TD> for T
where
T: KeyBuilderHelper<TD, <TD::KeySchema as KeySchema>::Kind>,
{
type KeyId<'id> = KeyId<
<Self as KeyBuilderHelper<TD, <TD::KeySchema as KeySchema>::Kind>>::PkId<'id>,
<Self as KeyBuilderHelper<TD, <TD::KeySchema as KeySchema>::Kind>>::SkId<'id>,
>;
fn get_key_from_id(key_id: Self::KeyId<'_>) -> Key<TD> {
Self::get_key_from_id_helper(key_id)
}
fn get_key_id(&self) -> Self::KeyId<'_> {
self.get_key_id_helper()
}
}
pub trait KeyBuilderHelper<TD: TableDefinition, KSK: KeySchemaKind> {
type PkId<'pk>;
type SkId<'sk>;
fn get_key_from_id_helper(key_id: KeyId<Self::PkId<'_>, Self::SkId<'_>>) -> Key<TD>;
fn get_key_id_helper(&self) -> KeyId<Self::PkId<'_>, Self::SkId<'_>>;
}
impl<TD: TableDefinition, T: DynamoDBItem<TD>> KeyBuilderHelper<TD, SimpleKey> for T
where
TD::KeySchema: SimpleKeySchema,
T: HasTableKeyAttributes<TD>,
T: HasAttribute<PartitionKeyDefinition<TD>>,
{
type PkId<'pk> = <Self as HasAttribute<PartitionKeyDefinition<TD>>>::Id<'pk>;
type SkId<'sk> = NoId;
fn get_key_from_id_helper(key_id: KeyId<Self::PkId<'_>, Self::SkId<'_>>) -> Key<TD> {
let pk_value =
<Self as HasAttribute<PartitionKeyDefinition<TD>>>::attribute_value(key_id.pk);
Key(
HashMap::from([(
PartitionKeyDefinition::<TD>::NAME.to_owned(),
pk_value.into_attribute_value(),
)]),
PhantomData,
)
}
fn get_key_id_helper(&self) -> KeyId<Self::PkId<'_>, Self::SkId<'_>> {
let pk_id = T::attribute_id(self);
KeyId::pk(pk_id)
}
}
impl<TD: TableDefinition, T: DynamoDBItem<TD>> KeyBuilderHelper<TD, CompositeKey> for T
where
TD::KeySchema: CompositeKeySchema,
T: HasTableKeyAttributes<TD>,
T: HasAttribute<PartitionKeyDefinition<TD>>,
T: HasAttribute<SortKeyDefinition<TD>>,
{
type PkId<'pk> = <Self as HasAttribute<PartitionKeyDefinition<TD>>>::Id<'pk>;
type SkId<'sk> = <Self as HasAttribute<SortKeyDefinition<TD>>>::Id<'sk>;
fn get_key_from_id_helper(key_id: KeyId<Self::PkId<'_>, Self::SkId<'_>>) -> Key<TD> {
let pk_value =
<Self as HasAttribute<PartitionKeyDefinition<TD>>>::attribute_value(key_id.pk);
let sk_value =
<Self as HasAttribute<SortKeyDefinition<TD>>>::attribute_value(key_id.sk);
Key(
HashMap::from([
(
PartitionKeyDefinition::<TD>::NAME.to_owned(),
pk_value.into_attribute_value(),
),
(
SortKeyDefinition::<TD>::NAME.to_owned(),
sk_value.into_attribute_value(),
),
]),
PhantomData,
)
}
fn get_key_id_helper(&self) -> KeyId<Self::PkId<'_>, Self::SkId<'_>> {
let pk_id = <Self as HasAttribute<PartitionKeyDefinition<TD>>>::attribute_id(self);
let sk_id = <Self as HasAttribute<SortKeyDefinition<TD>>>::attribute_id(self);
KeyId::pk(pk_id).sk(sk_id)
}
}
}
impl<TD: TableDefinition> From<Key<TD>> for Item<TD> {
fn from(value: Key<TD>) -> Self {
Item(value.0, PhantomData)
}
}
impl<TD: TableDefinition> Item<TD>
where
Self: KeyItemExtractor<TD, <TD::KeySchema as KeySchema>::Kind>,
{
pub fn extract_key(self) -> (Key<TD>, HashMap<String, AttributeValue>) {
KeyItemExtractor::extract_key(self)
}
pub fn into_key_only(self) -> Key<TD> {
self.extract_key().0
}
}
pub trait KeyItemExtractor<TD: TableDefinition, KSK: KeySchemaKind> {
fn extract_key(self) -> (Key<TD>, HashMap<String, AttributeValue>);
}
fn transfer_keyschema_helper<TD: TableDefinition>(
from_item: &mut Item<TD>,
to_key: &mut Key<TD>,
k: &str,
) {
let v = from_item
.0
.remove(k)
.expect("Item is guaranteed to contain the KeySchema");
to_key.0.insert(k.to_owned(), v);
}
impl<TD: TableDefinition> KeyItemExtractor<TD, SimpleKey> for Item<TD>
where
TD::KeySchema: SimpleKeySchema,
{
fn extract_key(mut self) -> (Key<TD>, HashMap<String, AttributeValue>) {
let mut key = Key(HashMap::with_capacity(1), PhantomData);
transfer_keyschema_helper(
&mut self,
&mut key,
<TD::KeySchema as KeySchema>::PartitionKey::NAME,
);
(key, self.0)
}
}
impl<TD: TableDefinition> KeyItemExtractor<TD, CompositeKey> for Item<TD>
where
TD::KeySchema: CompositeKeySchema,
{
fn extract_key(mut self) -> (Key<TD>, HashMap<String, AttributeValue>) {
let mut key = Key(HashMap::with_capacity(2), PhantomData);
transfer_keyschema_helper(
&mut self,
&mut key,
<TD::KeySchema as KeySchema>::PartitionKey::NAME,
);
transfer_keyschema_helper(
&mut self,
&mut key,
<TD::KeySchema as CompositeKeySchema>::SortKey::NAME,
);
(key, self.0)
}
}