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}