dynamodb_expression/update/
add.rs

1use core::fmt::{self, Write};
2
3use crate::{
4    path::Path,
5    value::{BinarySet, Num, NumSet, Ref, Set, StringSet, Value, ValueOrRef},
6};
7
8use super::Update;
9
10/// Represents an [`ADD` statement][1] in a [DynamoDB update expression][2].
11///
12/// Prefer [`Path::add`] over this.
13///
14/// See also: [`Update`], [`Set`]
15///
16/// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.ADD
17/// [2]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html
18#[must_use = "Use in an update expression with `Update::from(add)`"]
19#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct Add {
21    pub(crate) actions: Vec<AddAction>,
22}
23
24impl Add {
25    /// Creates an [`Add`] for the specified [`Path`] and value.
26    ///
27    /// Prefer [`Path::add`] over this.
28    pub fn new<N, V>(path: N, value: V) -> Self
29    where
30        N: Into<Path>,
31        V: Into<AddValue>,
32    {
33        Self::from(AddAction::new(path, value))
34    }
35
36    /// Add an additional [`Update`] statement to this `ADD` statement.
37    ///
38    /// ```
39    /// # fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
40    /// use dynamodb_expression::{Num, Path};
41    /// # use pretty_assertions::assert_eq;
42    ///
43    /// let update = "foo"
44    ///     .parse::<Path>()?
45    ///     .add(Num::new(7))
46    ///     .and("bar".parse::<Path>()?.set("a value"))
47    ///     .and("baz".parse::<Path>()?.remove());
48    /// assert_eq!(r#"SET bar = "a value" REMOVE baz ADD foo 7"#, update.to_string());
49    /// #
50    /// # Ok(())
51    /// # }
52    /// ```
53    pub fn and<T>(self, other: T) -> Update
54    where
55        T: Into<Update>,
56    {
57        Update::from(self).and(other)
58    }
59}
60
61impl fmt::Display for Add {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        f.write_str("ADD ")?;
64
65        let mut first = true;
66        self.actions.iter().try_for_each(|action| {
67            if first {
68                first = false;
69            } else {
70                f.write_str(", ")?;
71            }
72
73            action.fmt(f)
74        })
75    }
76}
77
78impl From<AddAction> for Add {
79    fn from(action: AddAction) -> Self {
80        Self {
81            actions: vec![action],
82        }
83    }
84}
85
86/// Represents an [`ADD` statement][1] in a [DynamoDB update expression][2].
87///
88/// Prefer [`Path::add`] over this.
89///
90/// See also: [`Add`], [`Update`], [`Set`]
91///
92/// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.ADD
93/// [2]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html
94#[must_use = "Use in an update expression with `Update::from(add)`"]
95#[derive(Debug, Clone, PartialEq, Eq)]
96pub struct AddAction {
97    pub(crate) path: Path,
98    pub(crate) value: ValueOrRef,
99}
100
101impl AddAction {
102    /// Creates an [`AddAction`] for the specified [`Path`] and value.
103    ///
104    /// Prefer [`Path::add`] over this.
105    pub fn new<N, V>(path: N, value: V) -> Self
106    where
107        N: Into<Path>,
108        V: Into<AddValue>,
109    {
110        Self {
111            path: path.into(),
112            value: match value.into() {
113                AddValue::Num(num) => Value::Scalar(num.into()).into(),
114                AddValue::Set(set) => set.into(),
115                AddValue::Ref(value_ref) => value_ref.into(),
116            },
117        }
118    }
119
120    /// Add an additional [`Update`] statement to this `ADD` statement.
121    ///
122    /// ```
123    /// # fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
124    /// use dynamodb_expression::{update::AddAction, Num, Path};
125    /// # use pretty_assertions::assert_eq;
126    ///
127    /// let update = AddAction::new("foo".parse::<Path>()?, Num::new(7))
128    ///     .and("bar".parse::<Path>()?.set("a value"))
129    ///     .and("baz".parse::<Path>()?.remove());
130    /// assert_eq!(r#"SET bar = "a value" REMOVE baz ADD foo 7"#, update.to_string());
131    /// #
132    /// # Ok(())
133    /// # }
134    /// ```
135    pub fn and<T>(self, other: T) -> Update
136    where
137        T: Into<Update>,
138    {
139        Update::from(self).and(other)
140    }
141}
142
143impl fmt::Display for AddAction {
144    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        self.path.fmt(f)?;
146        f.write_char(' ')?;
147        self.value.fmt(f)
148    }
149}
150
151/// A value that can be used for the [`ADD` operation][1] in a DynamoDB update expression.
152///
153/// See also: [`Path::add`], [`Add`]
154///
155/// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.ADD
156#[derive(Debug, Clone, PartialEq, Eq)]
157pub enum AddValue {
158    Set(Set),
159    Num(Num),
160    Ref(Ref),
161}
162
163impl fmt::Display for AddValue {
164    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165        match self {
166            Self::Set(value) => value.fmt(f),
167            Self::Num(value) => value.fmt(f),
168            Self::Ref(value) => value.fmt(f),
169        }
170    }
171}
172
173impl From<Set> for AddValue {
174    fn from(value: Set) -> Self {
175        Self::Set(value)
176    }
177}
178
179impl From<StringSet> for AddValue {
180    fn from(value: StringSet) -> Self {
181        Self::Set(value.into())
182    }
183}
184
185impl From<NumSet> for AddValue {
186    fn from(value: NumSet) -> Self {
187        Self::Set(value.into())
188    }
189}
190
191impl From<BinarySet> for AddValue {
192    fn from(value: BinarySet) -> Self {
193        Self::Set(value.into())
194    }
195}
196
197impl From<Num> for AddValue {
198    fn from(value: Num) -> Self {
199        Self::Num(value)
200    }
201}
202
203impl From<Ref> for AddValue {
204    fn from(value: Ref) -> Self {
205        Self::Ref(value)
206    }
207}