Skip to main content

dynamodb_expression/value/
num.rs

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