Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3521439
D8438.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
4 KB
Referenced Files
None
Subscribers
None
D8438.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Tue, Dec 24, 3:31 AM (19 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2698156
Default Alt Text
D8438.diff (4 KB)
Attached To
Mode
D8438: [services-lib] Add integer and timestamp parsing helpers
Attached
Detach File
Event Timeline
Log In to Comment