From 2cb96d0fc4386b1ec5de8912cb0df0f271fa7cf8 Mon Sep 17 00:00:00 2001 From: Caio <c410.f3r@gmail.com> Date: Thu, 21 May 2020 05:13:31 -0300 Subject: [PATCH] impl GraphQLScalar for NaiveTime (#657) * impl GraphQLScalar for NaiveTime * Add feature --- juniper/Cargo.toml | 1 + juniper/src/integrations/chrono.rs | 75 ++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml index 202b03c0..69e970a6 100644 --- a/juniper/Cargo.toml +++ b/juniper/Cargo.toml @@ -31,6 +31,7 @@ default = [ "url", "uuid", ] +scalar-naivetime = [] [dependencies] juniper_codegen = { version = "0.14.2", path = "../juniper_codegen" } diff --git a/juniper/src/integrations/chrono.rs b/juniper/src/integrations/chrono.rs index 58696754..0d5a1696 100644 --- a/juniper/src/integrations/chrono.rs +++ b/juniper/src/integrations/chrono.rs @@ -11,6 +11,8 @@ | | | precise enough for nanoseconds. | | | | Values will be truncated to microsecond | | | | resolution. | +| `NaiveTime` | H:M:S | Optional. Use the `scalar-naivetime` | +| | | feature. | */ #![allow(clippy::needless_lifetimes)] @@ -99,6 +101,30 @@ where } } +#[cfg(feature = "scalar-naivetime")] +#[crate::graphql_scalar_internal(description = "NaiveTime")] +impl<S> GraphQLScalar for NaiveTime +where + S: ScalarValue, +{ + fn resolve(&self) -> Value { + Value::scalar(self.format("%H:%M:%S").to_string()) + } + + fn from_input_value(v: &InputValue) -> Option<NaiveTime> { + v.as_string_value() + .and_then(|s| NaiveTime::parse_from_str(s, "%H:%M:%S").ok()) + } + + fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, S> { + if let ScalarToken::String(value) = value { + Ok(S::from(value.to_owned())) + } else { + Err(ParseError::UnexpectedToken(Token::Scalar(value))) + } + } +} + // JSON numbers (i.e. IEEE doubles) are not precise enough for nanosecond // datetimes. Values will be truncated to microsecond resolution. #[crate::graphql_scalar_internal(description = "NaiveDateTime")] @@ -194,6 +220,20 @@ mod test { assert_eq!(parsed.day(), d); } + #[test] + #[cfg(feature = "scalar-naivetime")] + fn naivetime_from_input_value() { + let input: crate::InputValue<DefaultScalarValue>; + input = InputValue::scalar("21:12:19".to_string()); + let [h, m, s] = [21, 12, 19]; + let parsed: NaiveTime = crate::FromInputValue::from_input_value(&input).unwrap(); + let expected = NaiveTime::from_hms(h, m, s); + assert_eq!(parsed, expected); + assert_eq!(parsed.hour(), h); + assert_eq!(parsed.minute(), m); + assert_eq!(parsed.second(), s); + } + #[test] fn naivedatetime_from_input_value() { let raw = 1_000_000_000_f64; @@ -223,6 +263,27 @@ mod integration_test { struct Root; #[crate::graphql_object_internal] + #[cfg(feature = "scalar-naivetime")] + impl Root { + fn exampleNaiveDate() -> NaiveDate { + NaiveDate::from_ymd(2015, 3, 14) + } + fn exampleNaiveDateTime() -> NaiveDateTime { + NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11) + } + fn exampleNaiveTime() -> NaiveTime { + NaiveTime::from_hms(16, 7, 8) + } + fn exampleDateTimeFixedOffset() -> DateTime<FixedOffset> { + DateTime::parse_from_rfc3339("1996-12-19T16:39:57-08:00").unwrap() + } + fn exampleDateTimeUtc() -> DateTime<Utc> { + Utc.timestamp(61, 0) + } + } + + #[crate::graphql_object_internal] + #[cfg(not(feature = "scalar-naivetime"))] impl Root { fn exampleNaiveDate() -> NaiveDate { NaiveDate::from_ymd(2015, 3, 14) @@ -238,6 +299,18 @@ mod integration_test { } } + #[cfg(feature = "scalar-naivetime")] + let doc = r#" + { + exampleNaiveDate, + exampleNaiveDateTime, + exampleNaiveTime, + exampleDateTimeFixedOffset, + exampleDateTimeUtc, + } + "#; + + #[cfg(not(feature = "scalar-naivetime"))] let doc = r#" { exampleNaiveDate, @@ -265,6 +338,8 @@ mod integration_test { vec![ ("exampleNaiveDate", Value::scalar("2015-03-14")), ("exampleNaiveDateTime", Value::scalar(1_467_969_011.0)), + #[cfg(feature = "scalar-naivetime")] + ("exampleNaiveTime", Value::scalar("16:07:08")), ( "exampleDateTimeFixedOffset", Value::scalar("1996-12-19T16:39:57-08:00"),