diff --git a/dynomite-derive/src/lib.rs b/dynomite-derive/src/lib.rs index e401add..e85bb17 100644 --- a/dynomite-derive/src/lib.rs +++ b/dynomite-derive/src/lib.rs @@ -704,6 +704,12 @@ fn get_item_trait( let partition_key_insert = partition_key_field.map(get_key_inserter).transpose()?; let sort_key_insert = sort_key_field.map(get_key_inserter).transpose()?; + let partition_key_tuple = partition_key_field.map(get_key_tuple); + let sort_key_tuple = sort_key_field + .map(get_key_tuple) + .map(|tuple| quote! { Some(#tuple) }) + .unwrap_or_else(|| quote! { None }); + Ok(partition_key_field .map(|_| { quote! { @@ -714,6 +720,14 @@ fn get_item_trait( #sort_key_insert keys } + + fn partition_key(&self) -> (String, ::dynomite::dynamodb::AttributeValue) { + #partition_key_tuple + } + + fn sort_key(&self) -> Option<(String, ::dynomite::dynamodb::AttributeValue)> { + #sort_key_tuple + } } } }) @@ -738,6 +752,19 @@ fn get_key_inserter(field: &ItemField) -> syn::Result { }) } +/// ```rust,ignore +/// ("field_deser_name", to_attribute_value(field)) +/// ``` +fn get_key_tuple(field: &ItemField) -> impl ToTokens { + let to_attribute_value = quote!(::dynomite::Attribute::into_attr); + + let field_deser_name = field.deser_name(); + let field_ident = &field.field.ident; + quote! { + (#field_deser_name.to_string(), #to_attribute_value(self.#field_ident.clone())) + } +} + /// ```rust,ignore /// #[derive(Item, Debug, Clone, PartialEq)] /// pub struct NameKey { diff --git a/dynomite/src/lib.rs b/dynomite/src/lib.rs index 2ee2387..693e02f 100644 --- a/dynomite/src/lib.rs +++ b/dynomite/src/lib.rs @@ -398,9 +398,17 @@ pub type Attributes = HashMap; /// impl Item for Person { /// fn key(&self) -> Attributes { /// let mut attrs = HashMap::new(); -/// attrs.insert("id".into(), "123".to_string().into_attr()); +/// attrs.insert("id".into(), self.id.clone().into_attr()); /// attrs /// } +/// +/// fn partition_key(&self) -> (String, AttributeValue) { +/// ("id".into(), self.id.clone().into_attr()) +/// } +/// +/// fn sort_key(&self) -> Option<(String, AttributeValue)> { +/// None +/// } /// } /// /// impl FromAttributes for Person { @@ -518,6 +526,12 @@ pub trait Item: IntoAttributes + FromAttributes { /// /// This is often used in item look ups fn key(&self) -> Attributes; + + /// Returns a tuple containing the name and value of the partition key + fn partition_key(&self) -> (String, AttributeValue); + + /// Returns a tuple containing the name and value of the sort key, if this item has one + fn sort_key(&self) -> Option<(String, AttributeValue)>; } /// A type capable of being converted into an or from and AWS `AttributeValue` diff --git a/dynomite/tests/derived.rs b/dynomite/tests/derived.rs index b1a1300..09d720d 100644 --- a/dynomite/tests/derived.rs +++ b/dynomite/tests/derived.rs @@ -25,6 +25,7 @@ impl Default for Category { pub struct Book { #[dynomite(partition_key)] title: String, + #[dynomite(sort_key)] category: Category, authors: Option>, } @@ -130,6 +131,32 @@ mod tests { servings: 1, }; assert_eq!(value.key(), RecipeKey { id: "test".into() }.into()); + assert_eq!( + value.partition_key(), + ("RecipeId".to_string(), "test".to_string().into_attr()) + ); + assert!(value.sort_key().is_none()); + + let value = Book { + title: "rust".into(), + ..Default::default() + }; + assert_eq!( + value.key(), + BookKey { + title: "rust".into(), + category: Category::Foo, + } + .into() + ); + assert_eq!( + value.partition_key(), + ("title".to_string(), "rust".to_string().into_attr()) + ); + assert_eq!( + value.sort_key(), + Some(("category".to_string(), "Foo".to_string().into_attr())) + ) } #[test]