Skip to main content

dynamodb_expression/value/set/
num_set.rs

1use core::fmt;
2use std::collections::BTreeSet;
3
4use aws_sdk_dynamodb::types::AttributeValue;
5
6use crate::Num;
7
8/// Represents a [DynamoDB number set][1].
9///
10/// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes.SetTypes
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub struct NumSet(BTreeSet<Num>);
13
14impl NumSet {
15    /// Creates a value to use as a [DynamoDB number set][1].
16    ///
17    /// See also: [`Set::new_num_set`], [`Value::new_num_set`], [`Num`]
18    ///
19    /// # Examples
20    ///
21    /// ```rust
22    /// # use pretty_assertions::assert_eq;
23    /// #
24    /// use dynamodb_expression::value::{Num, NumSet};
25    ///
26    /// assert_eq!(
27    ///     NumSet::new([Num::from(1), Num::from(2), Num::from(3)]),
28    ///     NumSet::new([1, 2, 2, 3]),
29    /// );
30    /// ```
31    ///
32    /// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes.SetTypes
33    /// [`Set::new_num_set`]: crate::Set::new_num_set
34    /// [`Value::new_num_set`]: crate::Value::new_num_set
35    pub fn new<T>(set: T) -> Self
36    where
37        T: Into<NumSet>,
38    {
39        set.into()
40    }
41
42    // Intentionally not using `impl From<NumSet> for AttributeValue` because
43    // I don't want to make this a public API people rely on. The purpose of this
44    // crate is not to make creating `AttributeValues` easier. They should try
45    // `serde_dynamo`.
46    pub(super) fn into_attribute_value(self) -> AttributeValue {
47        AttributeValue::Ns(self.0.into_iter().map(Into::into).collect())
48    }
49}
50
51impl<T> FromIterator<T> for NumSet
52where
53    T: Into<Num>,
54{
55    fn from_iter<I>(iter: I) -> Self
56    where
57        I: IntoIterator<Item = T>,
58    {
59        Self(iter.into_iter().map(Into::into).collect())
60    }
61}
62
63impl<I, T> From<I> for NumSet
64where
65    I: IntoIterator<Item = T>,
66    T: Into<Num>,
67{
68    fn from(values: I) -> Self {
69        Self::from_iter(values)
70    }
71}
72
73impl fmt::Display for NumSet {
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        f.debug_list().entries(self.0.iter().map(DebugNum)).finish()
76    }
77}
78
79struct DebugNum<'a>(&'a Num);
80
81impl<'a> fmt::Debug for DebugNum<'a> {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        f.write_str(&self.0.n)
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use pretty_assertions::assert_eq;
90
91    use super::{Num, NumSet};
92
93    #[test]
94    fn test_display() {
95        let set = NumSet::new([1, 2, 3]);
96        assert_eq!("[1, 2, 3]", set.to_string());
97    }
98
99    #[test]
100    fn test_mixed_num_types() {
101        let set = NumSet::new([
102            Num::new(1),
103            Num::new_lower_exp(41_000),
104            Num::new_upper_exp(2600),
105        ]);
106        assert_eq!("[1, 2.6E3, 4.1e4]", set.to_string());
107    }
108}