1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use std::collections::HashMap;

/// The value for an attribute that comes from DynamoDb.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum AttributeValue {
    /// An attribute of type Number. For example:
    ///
    /// ```text
    /// "N": "123.45"
    /// ```
    ///
    /// Numbers are sent across the network to DynamoDB as strings, to maximize compatibility across
    /// languages and libraries. However, DynamoDB treats them as number type attributes for
    /// mathematical operations.
    N(String),
    /// An attribute of type String. For example:
    ///
    /// ```text
    /// "S": "Hello"
    /// ```
    S(String),
    /// An attribute of type Boolean. For example:
    ///
    /// ```text
    /// "BOOL": true
    /// ```
    Bool(bool),
    /// An attribute of type Binary. For example:
    ///
    /// ```text
    /// "B": "dGhpcyB0ZXh0IGlzIGJhc2U2NC1lbmNvZGVk"
    /// ```
    ///
    /// Type: Base64-encoded binary data object
    B(Vec<u8>),
    /// An attribute of type Null. For example:
    ///
    /// ```text
    /// "NULL": true
    /// ```
    Null(bool),
    /// An attribute of type Map. For example:
    ///
    /// ```text
    /// "M": {"Name": {"S": "Joe"}, "Age": {"N": "35"}}
    /// ```
    ///
    /// Key Length Constraints: Maximum length of 65535.
    M(HashMap<String, AttributeValue>),
    /// An attribute of type List. For example:
    ///
    /// ```text
    /// "L": [ {"S": "Cookies"} , {"S": "Coffee"}, {"N": "3.14159"}]
    /// ```
    L(Vec<AttributeValue>),
    /// An attribute of type String Set. For example:
    ///
    /// ```text
    /// "SS": ["Giraffe", "Hippo" ,"Zebra"]
    /// ```
    Ss(Vec<String>),
    /// An attribute of type Number Set. For example:
    ///
    /// ```text
    /// "NS": ["42.2", "-19", "7.5", "3.14"]
    /// ```
    ///
    /// Numbers are sent across the network to DynamoDB as strings, to maximize compatibility across
    /// languages and libraries. However, DynamoDB treats them as number type attributes for
    /// mathematical operations.
    Ns(Vec<String>),
    /// An attribute of type Binary Set. For example:
    ///
    /// ```text
    /// "BS": ["U3Vubnk=", "UmFpbnk=", "U25vd3k="]
    /// ```
    ///
    /// Type: Array of Base64-encoded binary data objects
    Bs(Vec<Vec<u8>>),
}

/// An item that comes from DynamoDb.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Item(HashMap<String, AttributeValue>);

impl<T> From<Item> for HashMap<String, T>
where
    T: From<AttributeValue>,
{
    fn from(Item(m): Item) -> Self {
        m.into_iter()
            .map(|(key, value)| (key, T::from(value)))
            .collect()
    }
}

impl<T> From<HashMap<String, T>> for Item
where
    AttributeValue: From<T>,
{
    fn from(m: HashMap<String, T>) -> Self {
        Item(
            m.into_iter()
                .map(|(key, value)| (key, AttributeValue::from(value)))
                .collect(),
        )
    }
}

/// Multiple items that come from DynamoDb.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Items(Vec<Item>);

impl<T> From<Items> for Vec<HashMap<String, T>>
where
    HashMap<String, T>: From<Item>,
{
    fn from(Items(items): Items) -> Self {
        items.into_iter().map(Into::into).collect()
    }
}

impl<T> From<Vec<HashMap<String, T>>> for Items
where
    Item: From<HashMap<String, T>>,
{
    fn from(items: Vec<HashMap<String, T>>) -> Self {
        Items(items.into_iter().map(Into::into).collect())
    }
}