#dynamo-db #aws #macro-derive #struct #conversion #hash-map #dynamodel

macro dynamodel_derive

Macros 1.1 implementation of #[derive(Dynamodel)]

4 releases (2 breaking)

new 0.3.1 May 26, 2024
0.3.0 May 26, 2024
0.2.0 May 19, 2024
0.1.0 May 18, 2024

#49 in #dynamo-db

Download history 354/week @ 2024-05-18

354 downloads per month
Used in dynamodel

MIT license

36KB
869 lines

dynamodel

Version License Test

This library provides a derive macro to implement conversions between your object and HashMap<String, AttributeValue>.

Usage

use dynamodel::Dynamodel;
use std::collections::HashMap;
use aws_sdk_dynamodb::types::AttributeValue;

// Using `Dynamodel` macro, you can implement both
// `From<your struct> for HashMap<String, AttributeValue>` and
// `TryFrom<HashMap<String, AttributeValue>> for your struct` traits.
#[derive(Dynamodel, Debug, Clone, PartialEq)]
struct Person {
    first_name: String,
    last_name: String,
    age: u8,
}

let person = Person {
    first_name: "Kanji".into(),
    last_name: "Tanaka".into(),
    age: 23,
};

let item: HashMap<String, AttributeValue> = [
    ("first_name".to_string(), AttributeValue::S("Kanji".into())),
    ("last_name".to_string(), AttributeValue::S("Tanaka".into())),
    ("age".to_string(), AttributeValue::N("23".into()))
].into();

// Convert from Person into HashMap<String, AttributeValue>.
let converted: HashMap<String, AttributeValue> = person.clone().into();
assert_eq!(converted, item);

// Convert from HashMap<String, AttributeValue> into Person.
// This conversion uses std::convert::TryFrom trait, so this returns a Result.
let converted: Person = item.try_into().unwrap();
assert_eq!(converted, person);

Implicit conversion

This macro implicitly converts some types, so you don't have to add any code. The types are as follows.

Type AttributeValue variant Condition
String AttributeValue::S none
u8, u16, u32, u64, u128, usize
i8, i16, i32, i64, i128, isize
f32, f64
AttributeValue::N none
bool AttributeValue::Bool none
Any structs or enums AttributeValue::M must implement both
Into<HashMap<String, AttributeValue>>
and
TryFrom<HashMap<String, AttributeValue>, Error = ConvertError>
Vec<inner type> AttributeValue::L the inner type must be one of the implicit conversion types.
Option<inner type> Depends on the inner type tye inner type must be one of the implicit conversion types.

Explicit conversion

Using the field attribute, you can implement custom conversion methods for any type like this.

use dynamodel::{Dynamodel, ConvertError};
use std::collections::HashMap;
use aws_sdk_dynamodb::{types::AttributeValue, primitives::Blob};

// Vec<u8> is converted to AttributeValue::L by default,
// but this case, the `data` field is converted to AttributeValue::B.
#[derive(Dynamodel)]
struct BinaryData {
    #[dynamodel(into = "to_blob", try_from = "from_blob")]
    data: Vec<u8>
}

fn to_blob(value: Vec<u8>) -> AttributeValue {
    AttributeValue::B(Blob::new(value))
}

fn from_blob(value: &AttributeValue) -> Result<Vec<u8>, ConvertError> {
    value.as_b()
        .map(|b| b.clone().into_inner())
        .map_err(|err| ConvertError::AttributeValueUnmatched("B".to_string(), err.clone()))
}

The function definition must meet these conditions.

Field attribute Argument Return
#[dynamodel(into = "...")] field type AttributeValue
#[dynamodel(try_from = "...")] &AttributeValue Result<field type, ConvertError>

More features

For more features, refer to this wiki.

License

This software is released under the MIT License.

Dependencies

~0.7–1.2MB
~26K SLoC