Page MenuHomePhabricator

D8438.id28472.diff
No OneTemporary

D8438.id28472.diff

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
@@ -4,6 +4,7 @@
use std::collections::HashMap;
use std::fmt::{Display, Formatter};
use std::num::ParseIntError;
+use std::str::FromStr;
#[derive(
Debug, derive_more::Display, derive_more::From, derive_more::Error,
@@ -55,6 +56,8 @@
#[display(...)]
IncorrectType,
#[display(...)]
+ TimestampOutOfRange,
+ #[display(...)]
InvalidTimestamp(chrono::ParseError),
#[display(...)]
InvalidNumberFormat(ParseIntError),
@@ -98,6 +101,30 @@
}
}
+pub fn parse_int_attribute<T>(
+ attribute_name: &'static str,
+ attribute_value: Option<AttributeValue>,
+) -> Result<T, DBItemError>
+where
+ T: FromStr<Err = ParseIntError>,
+{
+ match &attribute_value {
+ Some(AttributeValue::N(numeric_str)) => {
+ parse_integer(attribute_name, &numeric_str)
+ }
+ Some(_) => Err(DBItemError::new(
+ attribute_name,
+ Value::AttributeValue(attribute_value),
+ DBItemAttributeError::IncorrectType,
+ )),
+ None => Err(DBItemError::new(
+ attribute_name,
+ Value::AttributeValue(attribute_value),
+ DBItemAttributeError::Missing,
+ )),
+ }
+}
+
pub fn parse_datetime_attribute(
attribute_name: &'static str,
attribute_value: Option<AttributeValue>,
@@ -120,6 +147,24 @@
}
}
+/// Parses the UTC timestamp in milliseconds from a DynamoDB numeric attribute
+pub fn parse_timestamp_attribute(
+ attribute_name: &'static str,
+ attribute_value: Option<AttributeValue>,
+) -> Result<DateTime<Utc>, DBItemError> {
+ let timestamp =
+ parse_int_attribute::<i64>(attribute_name, attribute_value.clone())?;
+ let naive_datetime = chrono::NaiveDateTime::from_timestamp_millis(timestamp)
+ .ok_or_else(|| {
+ DBItemError::new(
+ attribute_name,
+ Value::AttributeValue(attribute_value),
+ DBItemAttributeError::TimestampOutOfRange,
+ )
+ })?;
+ Ok(DateTime::from_utc(naive_datetime, Utc))
+}
+
pub fn parse_map_attribute(
attribute_name: &'static str,
attribute_value: Option<AttributeValue>,
@@ -139,11 +184,14 @@
}
}
-pub fn parse_number(
+pub fn parse_integer<T>(
attribute_name: &'static str,
attribute_value: &str,
-) -> Result<i32, DBItemError> {
- attribute_value.parse::<i32>().map_err(|e| {
+) -> Result<T, DBItemError>
+where
+ T: FromStr<Err = ParseIntError>,
+{
+ attribute_value.parse::<T>().map_err(|e| {
DBItemError::new(
attribute_name,
Value::String(attribute_value.to_string()),
@@ -151,3 +199,50 @@
)
})
}
+
+#[cfg(test)]
+
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_parse_integer() {
+ assert!(parse_integer::<i32>("some_attr", "123").is_ok());
+ assert!(parse_integer::<i32>("negative", "-123").is_ok());
+
+ assert!(parse_integer::<i32>("float", "3.14").is_err());
+ assert!(parse_integer::<i32>("NaN", "foo").is_err());
+
+ assert!(parse_integer::<u32>("negative_uint", "-123").is_err());
+ assert!(parse_integer::<u8>("too_large", "65536").is_err());
+ }
+
+ #[test]
+ fn test_parse_timestamp() {
+ let timestamp = Utc::now().timestamp_millis();
+ let attr = AttributeValue::N(timestamp.to_string());
+
+ let parsed_timestamp = parse_timestamp_attribute("some_attr", Some(attr));
+
+ assert!(parsed_timestamp.is_ok());
+ assert_eq!(parsed_timestamp.unwrap().timestamp_millis(), timestamp);
+ }
+
+ #[test]
+ fn test_parse_invalid_timestamp() {
+ let attr = AttributeValue::N("foo".to_string());
+ let parsed_timestamp = parse_timestamp_attribute("some_attr", Some(attr));
+ assert!(parsed_timestamp.is_err());
+ }
+
+ #[test]
+ fn test_parse_timestamp_out_of_range() {
+ let attr = AttributeValue::N(i64::MAX.to_string());
+ let parsed_timestamp = parse_timestamp_attribute("some_attr", Some(attr));
+ assert!(parsed_timestamp.is_err());
+ assert!(matches!(
+ parsed_timestamp.unwrap_err().attribute_error,
+ DBItemAttributeError::TimestampOutOfRange
+ ));
+ }
+}
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
@@ -52,7 +52,7 @@
let mut config = HashMap::new();
for (code_version_string, code_version_config) in config_map {
let code_version: i32 =
- database::parse_number("code_version", code_version_string.as_str())?;
+ database::parse_integer("code_version", code_version_string.as_str())?;
let version_config =
parse_code_version_specific_feature_config(Some(code_version_config))?;
config.insert(code_version, version_config);

File Metadata

Mime Type
text/plain
Expires
Sun, Sep 29, 8:39 PM (20 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2198447
Default Alt Text
D8438.id28472.diff (4 KB)

Event Timeline