macro_rules! has_attributes {
{
$item:ty {
$(
$attr:path {$($blk:tt)+}
)+
}
} => { ... };
{
@inner $attr:path ; $item:ty {
fn attribute_value ($id:ident) -> $outty:ty $produce:block
fn attribute_id ($(&)?$self:ident) -> $idty:ty $extract:block
}
} => { ... };
{
@inner $attr:path ; $item:ty {
fn attribute_value ($id:ident) -> $outty:ty $produce:block
}
} => { ... };
{
@inner $attr:path ; $item:ty {
fn $id_fct:ident ($(&)?$self:ident) -> $idty:ty $extract:block
fn $value_fct:ident ($id:ident) -> $outty:ty $produce:block
}
} => { ... };
{
@inner $attr:path ; $item:ty {
const VALUE: $t:ty = $v:expr;
}
} => { ... };
($($tt:tt)*) => { ... };
}Expand description
Manually implements HasAttribute or
HasConstAttribute for a type.
Use this macro when you need to implement the attribute traits without going
through dynamodb_item! — for example, when writing a manual
DynamoDBItem implementation or when adding
attribute bindings to a type that is already wired to a table.
§Syntax
Each attribute block uses one of two forms:
Constant attribute — implements HasConstAttribute:
has_attributes! {
MyType {
MyAttr { const VALUE: AttrValueType = expr; }
}
}Dynamic attribute — implements HasAttribute:
has_attributes! {
MyType {
MyAttr {
fn attribute_id(&self) -> IdType { ... }
fn attribute_value(id) -> ValueType { ... }
}
}
}The attribute_id and attribute_value functions may appear in either
order. If attribute_id is omitted, it defaults to returning
NoId.
Multiple attribute blocks can appear in a single invocation.
§The attribute_id → attribute_value pipeline
For dynamic attributes, the return type of attribute_id(&self) is
always the input type of attribute_value(id). The two functions
form a pipeline: attribute_id extracts a lightweight identifier from
&self, and attribute_value transforms it into the final DynamoDB
value. This separation allows for independant usages of the methods,
in particular it powers the “_by_id” variants of the get/update/delete
operations.
§The 'id lifetime
When attribute_id returns a reference — typically &str — you must
annotate it with the 'id lifetime: &'id str. This lifetime
comes from the Id<'id> associated type on
HasAttribute and must be used exactly as-is.
The typical use-case is when the identifier is a String field on the
struct and the final attribute value is a formatted composition of that
field (e.g. format!("USER#{id}")). Returning &'id str lets
attribute_id borrow the field without cloning it, and
attribute_value can then use the reference to produce an owned
String.
If the attribute does not need data from &self (e.g. the value is
always a constant), you can omit attribute_id entirely — the macro
defaults it to returning NoId.
§Examples
use dynamodb_facade::has_attributes;
struct CourseStatus(String);
has_attributes! {
CourseStatus {
// Constant attribute: always the same value
ItemType { const VALUE: &'static str = "COURSE_STATUS"; }
// Dynamic attribute: attribute_id borrows &self.0 as &'id str,
// then attribute_value receives that same &str to format the
// DynamoDB value — no .clone() needed.
SK {
fn attribute_id(&self) -> &'id str { &self.0 }
fn attribute_value(id) -> String { format!("STATUS#{id}") }
}
}
}
use dynamodb_facade::HasConstAttribute;
assert_eq!(<CourseStatus as HasConstAttribute<ItemType>>::VALUE, "COURSE_STATUS");
use dynamodb_facade::HasAttribute;
let status = CourseStatus("draft".to_owned());
assert_eq!(
<CourseStatus as HasAttribute<SK>>::attribute(&status),
"STATUS#draft".to_owned()
);