From 2784e8d2ff19c0bb2291be1c683db43e5693a11f Mon Sep 17 00:00:00 2001 From: CodeSteak Date: Tue, 7 May 2019 18:44:59 +0200 Subject: [PATCH] implement date parsing as FromStr trait --- server/texture-sync-server/src/model/date.rs | 61 ++++++++++++++----- .../src/persistency/search/query_filter.rs | 4 +- 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/server/texture-sync-server/src/model/date.rs b/server/texture-sync-server/src/model/date.rs index 12e4b94..a4f969d 100644 --- a/server/texture-sync-server/src/model/date.rs +++ b/server/texture-sync-server/src/model/date.rs @@ -1,6 +1,7 @@ use serde::de::Error; use serde::Serialize; use serde::{Deserialize, Deserializer, Serializer}; +use std::str::FromStr; #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct Date { @@ -14,23 +15,49 @@ impl Date { pub fn new(year: u16, month: u8, day: u8) -> Self { Date { year, month, day } } +} - pub fn from_str(input: &str) -> Option { +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum DateParseError { + InvalidNumber, + MonthOutOfRange, + DayOutOfRange, + WrongFormat, +} + +impl FromStr for Date { + type Err = DateParseError; + + fn from_str(input: &str) -> Result { let mut parts = input.splitn(3, "-"); - let year = parts.next()?.parse::().ok()?; - let month = parts.next()?.parse::().ok()?; - let day = parts.next()?.parse::().ok()?; + let year = parts + .next() + .ok_or(DateParseError::WrongFormat)? + .parse::() + .map_err(|_| DateParseError::InvalidNumber)?; + + let month = parts + .next() + .ok_or(DateParseError::WrongFormat)? + .parse::() + .map_err(|_| DateParseError::InvalidNumber)?; + + let day = parts + .next() + .ok_or(DateParseError::WrongFormat)? + .parse::() + .map_err(|_| DateParseError::InvalidNumber)?; if month > 12 { - return None; + return Err(DateParseError::DayOutOfRange); } if day > 31 { - return None; + return Err(DateParseError::MonthOutOfRange); } - Some(Date { year, month, day }) + Ok(Date { year, month, day }) } } @@ -54,8 +81,8 @@ impl<'de> Deserialize<'de> for Date { let data = String::deserialize(deserializer)?; match Date::from_str(&data) { - Some(date) => Ok(date), - None => Err(D::Error::custom( + Ok(date) => Ok(date), + Err(_) => Err(D::Error::custom( "Expected a String in this format: YYYY-MM-DD.", )), } @@ -76,14 +103,20 @@ mod test { #[test] fn from_str() { - assert_eq!(Some(Date::new(2019, 10, 10)), Date::from_str("2019-10-10")); - assert_eq!(Some(Date::new(2019, 1, 1)), Date::from_str("2019-1-1")); - assert_eq!(None, Date::from_str("2019-1-1-444")); + assert_eq!(Ok(Date::new(2019, 10, 10)), Date::from_str("2019-10-10")); + + assert_eq!(Ok(Date::new(2019, 1, 1)), Date::from_str("2019-1-1")); + + assert!(Date::from_str("2019-1-1-444").is_err()); + assert_eq!( - Some(Date::new(2019, 1, 1)), + Ok(Date::new(2019, 1, 1)), Date::from_str("2019-0000000000001-00000001") ); - assert_eq!(None, Date::from_str("400-400-400")); + + assert!(Date::from_str("XXX-400-400").is_err()); + + assert!(Date::from_str("400-400-400").is_err()); } } diff --git a/server/texture-sync-server/src/persistency/search/query_filter.rs b/server/texture-sync-server/src/persistency/search/query_filter.rs index 0a43db6..fae15e4 100644 --- a/server/texture-sync-server/src/persistency/search/query_filter.rs +++ b/server/texture-sync-server/src/persistency/search/query_filter.rs @@ -114,13 +114,13 @@ impl FromStr for QueryFilter { } "a" | "after" => { let date = Date::from_str(filter_arg) - .ok_or(QueryFilterSyntaxError::DateArgumentInvalid)?; + .map_err(|_| QueryFilterSyntaxError::DateArgumentInvalid)?; Ok(QueryFilter::SpecialAfterDate(date)) } "b" | "bef" | "before" => { let date = Date::from_str(filter_arg) - .ok_or(QueryFilterSyntaxError::DateArgumentInvalid)?; + .map_err(|_| QueryFilterSyntaxError::DateArgumentInvalid)?; Ok(QueryFilter::SpecialBeforeDate(date)) }