dynamodb_expression/value/
num.rs

1use core::fmt::{self, LowerExp, UpperExp};
2
3use aws_sdk_dynamodb::types::AttributeValue;
4
5/// A DynamoDB [numeric][1] value.
6///
7/// See also: [`Scalar::new_num`], [`Value::new_num`],
8/// [`Scalar::new_num_lower_exp`], [`Value::new_num_lower_exp`],
9/// [`Scalar::new_num_upper_exp`], [`Value::new_num_upper_exp`]
10///
11/// # Examples
12///
13/// ```
14/// use dynamodb_expression::value::Num;
15/// # use pretty_assertions::assert_eq;
16///
17/// let value = Num::new(2600);
18/// assert_eq!("2600", value.to_string());
19///
20/// let value = Num::new_lower_exp(2600);
21/// assert_eq!("2.6e3", value.to_string());
22///
23/// let value = Num::new_upper_exp(2600);
24/// assert_eq!("2.6E3", value.to_string());
25///
26/// let value = Num::new(2600.0);
27/// assert_eq!("2600", value.to_string());
28///
29/// let value = Num::new_lower_exp(2600.0);
30/// assert_eq!("2.6e3", value.to_string());
31///
32/// let value = Num::new_upper_exp(2600.0);
33/// assert_eq!("2.6E3", value.to_string());
34/// ```
35///
36/// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes.Number
37/// [`Scalar::new_num`]: crate::value::Scalar::new_num
38/// [`Scalar::new_num_lower_exp`]: crate::value::Scalar::new_num_lower_exp
39/// [`Scalar::new_num_upper_exp`]: crate::value::Scalar::new_num_upper_exp
40/// [`Value::new_num`]: crate::value::Value::new_num
41/// [`Value::new_num_lower_exp`]: crate::value::Value::new_num_lower_exp
42/// [`Value::new_num_upper_exp`]: crate::value::Value::new_num_upper_exp
43#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
44pub struct Num {
45    pub(crate) n: String,
46}
47
48impl Num {
49    /// Creates a DynamoDB [numeric][1] value.
50    ///
51    /// See also: [`Num::new_lower_exp`], [`Num::new_upper_exp`], [`Scalar::new_num`],
52    /// [`Value::new_num`]
53    ///
54    /// # Examples
55    ///
56    /// ```
57    /// use dynamodb_expression::value::Num;
58    /// # use pretty_assertions::assert_eq;
59    ///
60    /// let value = Num::new(2600);
61    /// assert_eq!("2600", value.to_string());
62    ///
63    /// let value = Num::new(2600.0);
64    /// assert_eq!("2600", value.to_string());
65    /// ```
66    ///
67    /// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes.Number
68    /// [`Scalar::new_num`]: crate::value::Scalar::new_num
69    /// [`Value::new_num`]: crate::value::Value::new_num
70    pub fn new<T>(value: T) -> Self
71    where
72        T: ToString + num::Num,
73    {
74        Self {
75            n: value.to_string(),
76        }
77    }
78
79    /// Creates a DynamoDB [numeric][1] value.
80    ///
81    /// See also: [`Num::new`], [`Num::new_upper_exp`], [`Scalar::new_num_lower_exp`],
82    /// [`Value::new_num_lower_exp`]
83    ///
84    /// # Examples
85    ///
86    /// ```
87    /// use dynamodb_expression::value::Num;
88    /// # use pretty_assertions::assert_eq;
89    ///
90    /// let value = Num::new_lower_exp(2600);
91    /// assert_eq!("2.6e3", value.to_string());
92    ///
93    /// let value = Num::new_lower_exp(2600.0);
94    /// assert_eq!("2.6e3", value.to_string());
95    /// ```
96    ///
97    /// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes.Number
98    /// [`Scalar::new_num_lower_exp`]: crate::value::Scalar::new_num_lower_exp
99    /// [`Value::new_num_lower_exp`]: crate::value::Value::new_num_lower_exp
100    pub fn new_lower_exp<T>(value: T) -> Self
101    where
102        T: LowerExp + num::Num,
103    {
104        Self {
105            n: format!("{value:e}"),
106        }
107    }
108
109    /// Creates a DynamoDB [numeric][1] value.
110    ///
111    /// See also: [`Num::new`], [`Num::new_lower_exp`], [`Scalar::new_num_upper_exp`],
112    /// [`Value::new_num_upper_exp`]
113    ///
114    /// # Examples
115    ///
116    /// ```
117    /// use dynamodb_expression::value::Num;
118    /// # use pretty_assertions::assert_eq;
119    ///
120    /// let value = Num::new_upper_exp(2600);
121    /// assert_eq!("2.6E3", value.to_string());
122    ///
123    /// let value = Num::new_upper_exp(2600.0);
124    /// assert_eq!("2.6E3", value.to_string());
125    /// ```
126    ///
127    /// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes.Number
128    /// [`Scalar::new_num_upper_exp`]: crate::value::Scalar::new_num_upper_exp
129    /// [`Value::new_num_upper_exp`]: crate::value::Value::new_num_upper_exp
130    pub fn new_upper_exp<T>(value: T) -> Self
131    where
132        T: UpperExp + num::Num,
133    {
134        Self {
135            n: format!("{value:E}"),
136        }
137    }
138
139    // Intentionally not using `impl From<Num> for AttributeValue` because
140    // I don't want to make this a public API people rely on. The purpose of this
141    // crate is not to make creating `AttributeValues` easier. They should try
142    // `serde_dynamo`.
143    pub(super) fn into_attribute_value(self) -> AttributeValue {
144        AttributeValue::N(self.n)
145    }
146}
147
148impl fmt::Display for Num {
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        self.n.fmt(f)
151    }
152}
153
154impl<T> From<T> for Num
155where
156    T: ToString + num::Num,
157{
158    fn from(num: T) -> Self {
159        Num::new(num)
160    }
161}
162
163impl From<Num> for String {
164    fn from(num: Num) -> Self {
165        num.n
166    }
167}