dynamodb_expression/value/
mod.rs1mod list;
7mod map;
8mod num;
9mod scalar;
10mod set;
11mod value_or_ref;
12
13pub use list::List;
14pub use map::Map;
15pub use num::Num;
16pub use scalar::Scalar;
17pub use set::{BinarySet, NumSet, Set, StringSet};
18pub use value_or_ref::{Ref, StringOrRef};
19
20pub(crate) use value_or_ref::ValueOrRef;
21
22use core::fmt::{self, LowerExp, UpperExp};
23use std::error::Error;
24
25use aws_sdk_dynamodb::{primitives::Blob, types::AttributeValue};
26use base64::{engine::general_purpose, Engine as _};
27use itertools::Itertools;
28
29#[derive(Debug, Clone, PartialEq, Eq, Hash)]
31pub enum Value {
32 Scalar(Scalar),
33 Set(Set),
34 Map(Map),
35 List(List),
36}
37
38impl Value {
39 pub fn new_string<T>(value: T) -> Self
45 where
46 T: Into<String>,
47 {
48 value.into().into()
49 }
50
51 pub fn new_num<N>(value: N) -> Self
71 where
72 N: ToString + ::num::Num,
73 {
74 Num::new(value).into()
75 }
76
77 pub fn new_num_lower_exp<N>(value: N) -> Self
98 where
99 N: LowerExp + ::num::Num,
100 {
101 Num::new_lower_exp(value).into()
102 }
103
104 pub fn new_num_upper_exp<N>(value: N) -> Self
125 where
126 N: UpperExp + ::num::Num,
127 {
128 Num::new_upper_exp(value).into()
129 }
130
131 pub fn new_bool(b: bool) -> Self {
137 b.into()
138 }
139
140 pub fn new_binary<B>(binary: B) -> Self
146 where
147 B: Into<Vec<u8>>,
148 {
149 binary.into().into()
150 }
151
152 pub fn new_null() -> Self {
158 Self::Scalar(Scalar::Null)
159 }
160
161 pub fn new_string_set<T>(string_set: T) -> Self
164 where
165 T: Into<StringSet>,
166 {
167 string_set.into().into()
168 }
169
170 pub fn new_num_set<T>(num_set: T) -> Self
173 where
174 T: Into<NumSet>,
175 {
176 num_set.into().into()
177 }
178
179 pub fn new_binary_set<T>(binary_set: T) -> Self
182 where
183 T: Into<BinarySet>,
184 {
185 binary_set.into().into()
186 }
187
188 pub fn new_map<T>(map: T) -> Self
191 where
192 T: Into<Map>,
193 {
194 map.into().into()
195 }
196
197 pub fn new_list<T>(list: T) -> Self
200 where
201 T: Into<List>,
202 {
203 list.into().into()
204 }
205
206 pub(crate) fn into_attribute_value(self) -> AttributeValue {
211 match self {
212 Self::Scalar(value) => value.into_attribute_value(),
213 Self::Set(value) => value.into_attribute_value(),
214 Self::Map(value) => value.into_attribute_value(),
215 Self::List(value) => value.into_attribute_value(),
216 }
217 }
218}
219
220impl From<Scalar> for Value {
221 fn from(value: Scalar) -> Self {
222 Self::Scalar(value)
223 }
224}
225
226impl From<String> for Value {
227 fn from(value: String) -> Self {
228 Scalar::from(value).into()
229 }
230}
231
232impl From<&String> for Value {
233 fn from(value: &String) -> Self {
234 Scalar::from(value).into()
235 }
236}
237
238impl From<&str> for Value {
239 fn from(value: &str) -> Self {
240 Scalar::from(value).into()
241 }
242}
243
244impl From<&&str> for Value {
245 fn from(value: &&str) -> Self {
246 Scalar::from(value).into()
247 }
248}
249
250impl From<Num> for Value {
251 fn from(value: Num) -> Self {
252 Scalar::from(value).into()
253 }
254}
255
256impl From<bool> for Value {
257 fn from(value: bool) -> Self {
258 Scalar::from(value).into()
259 }
260}
261
262impl From<Vec<u8>> for Value {
263 fn from(value: Vec<u8>) -> Self {
264 Scalar::from(value).into()
265 }
266}
267
268impl<const N: usize> From<[u8; N]> for Value {
269 fn from(value: [u8; N]) -> Self {
270 Scalar::from(value).into()
271 }
272}
273
274impl From<()> for Value {
275 fn from(value: ()) -> Self {
276 Scalar::from(value).into()
277 }
278}
279
280impl FromIterator<u8> for Value {
281 fn from_iter<T>(iter: T) -> Self
282 where
283 T: IntoIterator<Item = u8>,
284 {
285 Scalar::from_iter(iter).into()
286 }
287}
288
289impl From<Set> for Value {
290 fn from(set: Set) -> Self {
291 Self::Set(set)
292 }
293}
294
295impl From<StringSet> for Value {
296 fn from(string_set: StringSet) -> Self {
297 Self::Set(string_set.into())
298 }
299}
300
301impl From<NumSet> for Value {
302 fn from(num_set: NumSet) -> Self {
303 Self::Set(num_set.into())
304 }
305}
306
307impl From<BinarySet> for Value {
308 fn from(string_set: BinarySet) -> Self {
309 Self::Set(string_set.into())
310 }
311}
312
313impl From<Map> for Value {
314 fn from(map: Map) -> Self {
315 Self::Map(map)
316 }
317}
318
319impl From<List> for Value {
320 fn from(list: List) -> Self {
321 Self::List(list)
322 }
323}
324
325impl TryFrom<AttributeValue> for Value {
326 type Error = UnknownAttributeValueError;
327
328 fn try_from(value: AttributeValue) -> Result<Self, Self::Error> {
333 Ok(match value {
334 AttributeValue::B(value) => Scalar::Binary(value.into_inner()).into(),
335 AttributeValue::Bool(value) => Scalar::Bool(value).into(),
336 AttributeValue::Bs(value) => {
337 BinarySet::from_iter(value.into_iter().map(Blob::into_inner)).into()
338 }
339 AttributeValue::L(value) => List::from(
340 value
341 .into_iter()
342 .map(Self::try_from)
343 .try_collect::<_, Vec<_>, _>()?,
344 )
345 .into(),
346 AttributeValue::M(value) => Map::from(
347 value
348 .into_iter()
349 .map(|(k, v)| Self::try_from(v).map(|v| (k, v)))
350 .try_collect::<_, Vec<_>, _>()?,
351 )
352 .into(),
353 AttributeValue::N(n) => Num { n }.into(),
354 AttributeValue::Ns(value) => {
355 NumSet::from_iter(value.into_iter().map(|n| Num { n })).into()
356 }
357 AttributeValue::Null(_value) => Scalar::Null.into(),
358 AttributeValue::S(value) => Scalar::String(value).into(),
359 AttributeValue::Ss(value) => StringSet::from(value).into(),
360 _ => return Err(UnknownAttributeValueError(value)),
361 })
362 }
363}
364
365#[derive(Debug)]
374pub struct UnknownAttributeValueError(pub AttributeValue);
375
376impl fmt::Display for UnknownAttributeValueError {
377 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378 write!(f, "unknown AttributeValue variant: {:?}", self.0)
379 }
380}
381
382impl Error for UnknownAttributeValueError {}
383
384impl fmt::Display for Value {
385 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
386 match self {
387 Self::Scalar(value) => value.fmt(f),
388 Self::Set(value) => value.fmt(f),
389 Self::Map(value) => value.fmt(f),
390 Self::List(value) => value.fmt(f),
391 }
392 }
393}
394
395pub(crate) fn base64<T>(b: T) -> String
397where
398 T: AsRef<[u8]>,
399{
400 general_purpose::STANDARD.encode(b)
401}
402
403#[cfg(test)]
404mod test {
405 use aws_sdk_dynamodb::types::AttributeValue;
406 use pretty_assertions::assert_eq;
407
408 use crate::value::{List, Map, Num};
409
410 use super::Value;
411
412 #[test]
413 fn display() {
414 assert_eq!(r#""a""#, Value::new_string("a").to_string());
415 assert_eq!(r#"1000"#, Value::new_num(1000).to_string());
416 assert_eq!(r#"1e3"#, Value::new_num_lower_exp(1000).to_string());
417 assert_eq!(r#"1E3"#, Value::new_num_upper_exp(1000).to_string());
418 assert_eq!(r#""YQ==""#, Value::new_binary("a").to_string());
419 assert_eq!("true", Value::new_bool(true).to_string());
420 assert_eq!("NULL", Value::new_null().to_string());
421
422 assert_eq!(
424 r#"["a", "b", "c"]"#,
425 Value::new_string_set(["a", "c", "b"]).to_string()
426 );
427 assert_eq!(
428 r#"[-7, 1e3, 42]"#,
429 Value::new_num_set([Num::new_lower_exp(1000), Num::new(42), Num::new(-7)]).to_string()
430 );
431 assert_eq!(
432 r#"["YQ==", "Yg==", "Yw=="]"#,
433 Value::new_binary_set([b"a", b"b", b"c"]).to_string()
434 );
435
436 assert_eq!(
437 r#"[NULL, 8, "a string"]"#,
438 Value::new_list([
439 Value::new_null(),
440 Value::new_num(8),
441 Value::new_string("a string")
442 ])
443 .to_string()
444 );
445
446 assert_eq!(
447 r#"{n: 8, null: NULL, s: "a string"}"#,
448 Value::new_map([
449 (String::from("s"), Value::new_string("a string")),
450 (String::from("n"), Value::new_num(8)),
451 (String::from("null"), Value::new_null()),
452 ])
453 .to_string()
454 );
455 }
456
457 #[test]
458 fn from_attribute_value() {
459 assert_eq!(
466 Value::from(Map::from([
467 ("s", Value::from("a string")),
468 ("int", Value::from(Num::from(8))),
469 ("null", Value::from(())),
470 ("yes", Value::from(true)),
471 ("no", Value::from(false)),
472 (
473 "list",
474 List::from([
475 Value::from("foo"),
476 Value::from(Num::from(42)),
477 Value::from(()),
478 ])
479 .into(),
480 ),
481 ])),
482 Value::try_from(AttributeValue::M(
483 [
484 ("s".to_string(), AttributeValue::S("a string".to_string())),
485 ("int".to_string(), AttributeValue::N("8".to_string())),
486 ("null".to_string(), AttributeValue::Null(true)),
487 ("yes".to_string(), AttributeValue::Bool(true)),
488 ("no".to_string(), AttributeValue::Bool(false)),
489 (
490 "list".to_string(),
491 AttributeValue::L(vec![
492 AttributeValue::S("foo".to_string()),
493 AttributeValue::N("42".to_string()),
494 AttributeValue::Null(true),
495 ]),
496 ),
497 ]
498 .into_iter()
499 .collect(),
500 ))
501 .expect("Could not convert AttributeValue to Value"),
502 );
503 }
504}