diff --git a/services/blob/src/database/client.rs b/services/blob/src/database/client.rs --- a/services/blob/src/database/client.rs +++ b/services/blob/src/database/client.rs @@ -4,7 +4,7 @@ Error as DynamoDBError, }; use chrono::Utc; -use comm_services_lib::database::parse_string_attribute; +use comm_services_lib::database::TryFromAttribute; use std::{collections::HashMap, sync::Arc}; use tracing::{debug, error, trace}; @@ -205,7 +205,7 @@ // filter out rows that are blob items // we cannot do it in key condition expression - it doesn't support the <> operator // filter expression doesn't work either - it doesn't support filtering by sort key - match parse_string_attribute(ATTR_HOLDER, row.remove(ATTR_HOLDER)) { + match String::try_from_attr(ATTR_HOLDER, row.remove(ATTR_HOLDER)) { Ok(value) if value.as_str() == BLOB_ITEM_ROW_HOLDER_VALUE => None, holder => Some(holder), } diff --git a/services/blob/src/database/old.rs b/services/blob/src/database/old.rs --- a/services/blob/src/database/old.rs +++ b/services/blob/src/database/old.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] + use aws_sdk_dynamodb::{ operation::get_item::GetItemOutput, types::AttributeValue, }; diff --git a/services/blob/src/database/types.rs b/services/blob/src/database/types.rs --- a/services/blob/src/database/types.rs +++ b/services/blob/src/database/types.rs @@ -1,7 +1,7 @@ use aws_sdk_dynamodb::types::AttributeValue; use chrono::{DateTime, Utc}; use comm_services_lib::database::{ - parse_string_attribute, parse_timestamp_attribute, DBItemError, Value, + parse_timestamp_attribute, AttributeTryInto, DBItemError, Value, }; use derive_more::Constructor; use std::collections::HashMap; @@ -29,10 +29,10 @@ type Error = DBError; fn try_from(attributes: RawAttributes) -> Result { - let holder = parse_string_attribute( - ATTR_HOLDER, - attributes.get(ATTR_HOLDER).cloned(), - )?; + let holder: String = attributes + .get(ATTR_HOLDER) + .cloned() + .attr_try_into(ATTR_HOLDER)?; let row = match holder.as_str() { BLOB_ITEM_ROW_HOLDER_VALUE => DBRow::BlobItem(attributes.try_into()?), _ => DBRow::HolderAssignment(attributes.try_into()?), @@ -79,12 +79,12 @@ type Error = DBError; fn try_from(mut attributes: RawAttributes) -> Result { - let blob_hash = parse_string_attribute( - ATTR_BLOB_HASH, - attributes.remove(ATTR_BLOB_HASH), - )?; - let s3_path = - parse_string_attribute(ATTR_S3_PATH, attributes.remove(ATTR_S3_PATH))?; + let blob_hash = attributes + .remove(ATTR_BLOB_HASH) + .attr_try_into(ATTR_BLOB_HASH)?; + let s3_path: String = attributes + .remove(ATTR_S3_PATH) + .attr_try_into(ATTR_S3_PATH)?; let created_at = parse_timestamp_attribute( ATTR_CREATED_AT, attributes.remove(ATTR_CREATED_AT), @@ -123,12 +123,10 @@ type Error = DBError; fn try_from(mut attributes: RawAttributes) -> Result { - let holder = - parse_string_attribute(ATTR_HOLDER, attributes.remove(ATTR_HOLDER))?; - let blob_hash = parse_string_attribute( - ATTR_BLOB_HASH, - attributes.remove(ATTR_BLOB_HASH), - )?; + let holder = attributes.remove(ATTR_HOLDER).attr_try_into(ATTR_HOLDER)?; + let blob_hash = attributes + .remove(ATTR_BLOB_HASH) + .attr_try_into(ATTR_BLOB_HASH)?; let created_at = parse_timestamp_attribute( ATTR_CREATED_AT, attributes.remove(ATTR_CREATED_AT), @@ -174,12 +172,10 @@ type Error = DBError; fn try_from(mut attributes: RawAttributes) -> Result { - let blob_hash = parse_string_attribute( - ATTR_BLOB_HASH, - attributes.remove(ATTR_BLOB_HASH), - )?; - let holder = - parse_string_attribute(ATTR_HOLDER, attributes.remove(ATTR_HOLDER))?; + let blob_hash = attributes + .remove(ATTR_BLOB_HASH) + .attr_try_into(ATTR_BLOB_HASH)?; + let holder = attributes.remove(ATTR_HOLDER).attr_try_into(ATTR_HOLDER)?; Ok(PrimaryKey { blob_hash, holder }) } } diff --git a/services/blob/src/service.rs b/services/blob/src/service.rs --- a/services/blob/src/service.rs +++ b/services/blob/src/service.rs @@ -211,7 +211,7 @@ trace!("Getting blob item"); let Some(blob_item) = self.db.get_blob_item(&blob_hash).await? else { trace!("Blob item not found, nothing to do"); - return Ok(()) + return Ok(()); }; trace!("Deleting S3 object"); 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 @@ -1,11 +1,27 @@ use aws_sdk_dynamodb::types::AttributeValue; use aws_sdk_dynamodb::Error as DynamoDBError; use chrono::{DateTime, Utc}; -use std::collections::HashMap; use std::fmt::{Display, Formatter}; use std::num::ParseIntError; use std::str::FromStr; +// # Useful type aliases + +// Rust exports `pub type` only into the so-called "type namespace", but in +// order to use them e.g. with the `TryFromAttribute` trait, they also need +// to be exported into the "value namespace" which is what `pub use` does. +// +// To overcome that, a dummy module is created and aliases are re-exported +// with `pub use` construct +mod aliases { + use aws_sdk_dynamodb::types::AttributeValue; + use std::collections::HashMap; + pub type AttributeMap = HashMap; +} +pub use self::aliases::AttributeMap; + +// # Error handling + #[derive( Debug, derive_more::Display, derive_more::From, derive_more::Error, )] @@ -167,7 +183,7 @@ } } -impl TryFromAttribute for HashMap { +impl TryFromAttribute for AttributeMap { fn try_from_attr( attribute_name: impl Into, attribute_value: Option, @@ -233,11 +249,11 @@ DateTime::::try_from_attr(attribute_name, attribute_value) } -#[deprecated = "Use `HashMap::::try_from_attr()` instead"] +#[deprecated = "Use `AttributeMap::try_from_attr()` instead"] pub fn parse_map_attribute( attribute_name: impl Into, attribute_value: Option, -) -> Result, DBItemError> { +) -> Result { attribute_value.attr_try_into(attribute_name) } diff --git a/services/feature-flags/src/database.rs b/services/feature-flags/src/database.rs --- a/services/feature-flags/src/database.rs +++ b/services/feature-flags/src/database.rs @@ -5,7 +5,9 @@ PLATFORM_IOS, }; use aws_sdk_dynamodb::types::{AttributeValue, Select}; -use comm_services_lib::database::{self, DBItemError, Error}; +use comm_services_lib::database::{ + self, AttributeMap, DBItemError, Error, TryFromAttribute, +}; use std::collections::HashMap; use std::sync::Arc; use tracing::error; @@ -20,12 +22,12 @@ value: Option, ) -> Result { let mut code_version_config_map = - database::parse_map_attribute(FEATURE_FLAGS_CONFIG_FIELD, value)?; - let staff = database::parse_bool_attribute( + AttributeMap::try_from_attr(FEATURE_FLAGS_CONFIG_FIELD, value)?; + let staff = bool::try_from_attr( FEATURE_FLAGS_STAFF_FIELD, code_version_config_map.remove(FEATURE_FLAGS_STAFF_FIELD), )?; - let non_staff = database::parse_bool_attribute( + let non_staff = bool::try_from_attr( FEATURE_FLAGS_NON_STAFF_FIELD, code_version_config_map.remove(FEATURE_FLAGS_NON_STAFF_FIELD), )?; @@ -39,13 +41,13 @@ } fn parse_feature_config( - mut attribute_value: HashMap, + mut attribute_value: AttributeMap, ) -> Result { - let feature_name = database::parse_string_attribute( + let feature_name = String::try_from_attr( FEATURE_FLAGS_FEATURE_FIELD, attribute_value.remove(FEATURE_FLAGS_FEATURE_FIELD), )?; - let config_map = database::parse_map_attribute( + let config_map = AttributeMap::try_from_attr( FEATURE_FLAGS_CONFIG_FIELD, attribute_value.remove(FEATURE_FLAGS_CONFIG_FIELD), )?;