diff --git a/services/comm-services-lib/src/database.rs b/services/comm-services-lib/src/database.rs --- a/services/comm-services-lib/src/database.rs +++ b/services/comm-services-lib/src/database.rs @@ -98,42 +98,147 @@ } } +impl TryFromAttribute for String { + fn try_from_attr( + attribute_name: impl Into, + attribute_value: Option, + ) -> Result { + match attribute_value { + Some(AttributeValue::S(value)) => Ok(value), + Some(_) => Err(DBItemError::new( + attribute_name.into(), + Value::AttributeValue(attribute_value), + DBItemAttributeError::IncorrectType, + )), + None => Err(DBItemError::new( + attribute_name.into(), + Value::AttributeValue(attribute_value), + DBItemAttributeError::Missing, + )), + } + } +} + +impl TryFromAttribute for bool { + fn try_from_attr( + attribute_name: impl Into, + attribute_value: Option, + ) -> Result { + match attribute_value { + Some(AttributeValue::Bool(value)) => Ok(value), + Some(_) => Err(DBItemError::new( + attribute_name.into(), + Value::AttributeValue(attribute_value), + DBItemAttributeError::IncorrectType, + )), + None => Err(DBItemError::new( + attribute_name.into(), + Value::AttributeValue(attribute_value), + DBItemAttributeError::Missing, + )), + } + } +} + +impl TryFromAttribute for DateTime { + fn try_from_attr( + attribute_name: impl Into, + attribute: Option, + ) -> Result { + match &attribute { + Some(AttributeValue::S(datetime)) => datetime.parse().map_err(|e| { + DBItemError::new( + attribute_name.into(), + Value::AttributeValue(attribute), + DBItemAttributeError::InvalidTimestamp(e), + ) + }), + Some(_) => Err(DBItemError::new( + attribute_name.into(), + Value::AttributeValue(attribute), + DBItemAttributeError::IncorrectType, + )), + None => Err(DBItemError::new( + attribute_name.into(), + Value::AttributeValue(attribute), + DBItemAttributeError::Missing, + )), + } + } +} + +impl TryFromAttribute for HashMap { + fn try_from_attr( + attribute_name: impl Into, + attribute_value: Option, + ) -> Result { + match attribute_value { + Some(AttributeValue::M(map)) => Ok(map), + Some(_) => Err(DBItemError::new( + attribute_name.into(), + Value::AttributeValue(attribute_value), + DBItemAttributeError::IncorrectType, + )), + None => Err(DBItemError::new( + attribute_name.into(), + Value::AttributeValue(attribute_value), + DBItemAttributeError::Missing, + )), + } + } +} + +impl TryFromAttribute for Vec { + fn try_from_attr( + attribute_name: impl Into, + attribute_value: Option, + ) -> Result { + match attribute_value { + Some(AttributeValue::B(data)) => Ok(data.into_inner()), + Some(_) => Err(DBItemError::new( + attribute_name.into(), + Value::AttributeValue(attribute_value), + DBItemAttributeError::IncorrectType, + )), + None => Err(DBItemError::new( + attribute_name.into(), + Value::AttributeValue(attribute_value), + DBItemAttributeError::Missing, + )), + } + } +} + +#[deprecated = "Use `String::try_from_attr()` instead"] pub fn parse_string_attribute( attribute_name: impl Into, attribute_value: Option, ) -> Result { - match attribute_value { - Some(AttributeValue::S(value)) => Ok(value), - Some(_) => Err(DBItemError::new( - attribute_name.into(), - Value::AttributeValue(attribute_value), - DBItemAttributeError::IncorrectType, - )), - None => Err(DBItemError::new( - attribute_name.into(), - Value::AttributeValue(attribute_value), - DBItemAttributeError::Missing, - )), - } + String::try_from_attr(attribute_name, attribute_value) } +#[deprecated = "Use `bool::try_from_attr()` instead"] pub fn parse_bool_attribute( attribute_name: impl Into, attribute_value: Option, ) -> Result { - match attribute_value { - Some(AttributeValue::Bool(value)) => Ok(value), - Some(_) => Err(DBItemError::new( - attribute_name.into(), - Value::AttributeValue(attribute_value), - DBItemAttributeError::IncorrectType, - )), - None => Err(DBItemError::new( - attribute_name.into(), - Value::AttributeValue(attribute_value), - DBItemAttributeError::Missing, - )), - } + bool::try_from_attr(attribute_name, attribute_value) +} + +#[deprecated = "Use `DateTime::::try_from_attr()` instead"] +pub fn parse_datetime_attribute( + attribute_name: impl Into, + attribute_value: Option, +) -> Result, DBItemError> { + DateTime::::try_from_attr(attribute_name, attribute_value) +} + +#[deprecated = "Use `HashMap::::try_from_attr()` instead"] +pub fn parse_map_attribute( + attribute_name: impl Into, + attribute_value: Option, +) -> Result, DBItemError> { + attribute_value.attr_try_into(attribute_name) } pub fn parse_int_attribute( @@ -160,28 +265,6 @@ } } -pub fn parse_datetime_attribute( - attribute_name: impl Into, - attribute_value: Option, -) -> Result, DBItemError> { - if let Some(AttributeValue::S(datetime)) = &attribute_value { - // parse() accepts a relaxed RFC3339 string - datetime.parse().map_err(|e| { - DBItemError::new( - attribute_name.into(), - Value::AttributeValue(attribute_value), - DBItemAttributeError::InvalidTimestamp(e), - ) - }) - } else { - Err(DBItemError::new( - attribute_name.into(), - Value::AttributeValue(attribute_value), - DBItemAttributeError::Missing, - )) - } -} - /// Parses the UTC timestamp in milliseconds from a DynamoDB numeric attribute pub fn parse_timestamp_attribute( attribute_name: impl Into, @@ -203,25 +286,6 @@ Ok(DateTime::from_utc(naive_datetime, Utc)) } -pub fn parse_map_attribute( - attribute_name: impl Into, - attribute_value: Option, -) -> Result, DBItemError> { - match attribute_value { - Some(AttributeValue::M(map)) => Ok(map), - Some(_) => Err(DBItemError::new( - attribute_name.into(), - Value::AttributeValue(attribute_value), - DBItemAttributeError::IncorrectType, - )), - None => Err(DBItemError::new( - attribute_name.into(), - Value::AttributeValue(attribute_value), - DBItemAttributeError::Missing, - )), - } -} - pub fn parse_integer( attribute_name: impl Into, attribute_value: &str,