diff --git a/README.md b/README.md index 6bed49b7..b3d428a7 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ your Schemas automatically. - [uuid][uuid] - [url][url] - [chrono][chrono] +- [chrono-tz][chrono-tz] - [bson][bson] ### Web Frameworks @@ -112,5 +113,6 @@ Juniper has not reached 1.0 yet, thus some API instability should be expected. [uuid]: https://crates.io/crates/uuid [url]: https://crates.io/crates/url [chrono]: https://crates.io/crates/chrono +[chrono-tz]: https://crates.io/crates/chrono-tz [bson]: https://crates.io/crates/bson [juniper-from-schema]: https://github.com/davidpdrsn/juniper-from-schema diff --git a/juniper/CHANGELOG.md b/juniper/CHANGELOG.md index bfe229c3..762dbb21 100644 --- a/juniper/CHANGELOG.md +++ b/juniper/CHANGELOG.md @@ -33,6 +33,8 @@ - `ParseError` - `RuleError` +- Support `chrono-tz::Tz` scalar behind a `chrono-tz` feature flag. ([#519](https://github.com/graphql-rust/juniper/pull/519)) + ## Fixes - Massively improved the `#[graphql_union]` proc macro. ([#666](https://github.com/graphql-rust/juniper/pull/666)): diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml index 332454a6..37bc3347 100644 --- a/juniper/Cargo.toml +++ b/juniper/Cargo.toml @@ -38,6 +38,7 @@ anyhow = { default-features = false, version = "1.0.32", optional = true } async-trait = "0.1.39" bson = { version = "1.0", optional = true } chrono = { default-features = false, version = "0.4", optional = true } +chrono-tz = { version = "0.5", default-features = false, optional = true } fnv = "1.0.3" futures = { default-features = false, features = ["alloc"], version = "0.3.1" } futures-enum = "0.1.12" diff --git a/juniper/src/integrations/chrono_tz.rs b/juniper/src/integrations/chrono_tz.rs new file mode 100644 index 00000000..8f5becda --- /dev/null +++ b/juniper/src/integrations/chrono_tz.rs @@ -0,0 +1,80 @@ +//! [`Tz`] (timezone) scalar implementation, represented by its [IANA database][1] name. +//! +//! [`Tz`]: chrono_tz::Tz +//! [1]: http://www.iana.org/time-zones + +use chrono_tz::Tz; + +use crate::{ + graphql_scalar, + parser::{ParseError, ScalarToken, Token}, + value::ParseScalarResult, + Value, +}; + +#[graphql_scalar(name = "Tz", description = "Timezone")] +impl GraphQLScalar for Tz +where + S: ScalarValue, +{ + fn resolve(&self) -> Value { + Value::scalar(self.name().to_owned()) + } + + fn from_input_value(v: &InputValue) -> Option { + v.as_string_value().and_then(|s| s.parse::().ok()) + } + + fn from_str<'a>(val: ScalarToken<'a>) -> ParseScalarResult<'a, S> { + if let ScalarToken::String(s) = val { + Ok(S::from(s.to_owned())) + } else { + Err(ParseError::UnexpectedToken(Token::Scalar(val))) + } + } +} + +#[cfg(test)] +mod test { + mod from_input_value { + use chrono_tz::Tz; + + use crate::{DefaultScalarValue, FromInputValue, InputValue}; + + fn tz_input_test(raw: &'static str, expected: Option) { + let input = >::scalar(raw.to_string()); + let parsed: Option = FromInputValue::from_input_value(&input); + + assert_eq!(parsed, expected); + } + + #[test] + fn europe_zone() { + tz_input_test("Europe/London", Some(chrono_tz::Europe::London)); + } + + #[test] + fn etc_minus() { + tz_input_test("Etc/GMT-3", Some(chrono_tz::Etc::GMTMinus3)); + } + + mod invalid { + use super::tz_input_test; + + #[test] + fn forward_slash() { + tz_input_test("Abc/Xyz", None); + } + + #[test] + fn number() { + tz_input_test("8086", None); + } + + #[test] + fn no_forward_slash() { + tz_input_test("AbcXyz", None); + } + } + } +} diff --git a/juniper/src/integrations/mod.rs b/juniper/src/integrations/mod.rs index b1017ccf..ad4e29e3 100644 --- a/juniper/src/integrations/mod.rs +++ b/juniper/src/integrations/mod.rs @@ -7,6 +7,10 @@ pub mod serde; /// GraphQL support for [chrono](https://github.com/chronotope/chrono) types. pub mod chrono; +#[cfg(feature = "chrono-tz")] +/// GraphQL support for [chrono-tz](https://github.com/chronotope/chrono-tz) types. +pub mod chrono_tz; + #[cfg(feature = "url")] /// GraphQL support for [url](https://github.com/servo/rust-url) types. pub mod url; diff --git a/juniper_codegen/src/util/mod.rs b/juniper_codegen/src/util/mod.rs index 854e067f..bd82ed44 100644 --- a/juniper_codegen/src/util/mod.rs +++ b/juniper_codegen/src/util/mod.rs @@ -4,8 +4,7 @@ pub mod duplicate; pub mod parse_impl; pub mod span_container; -use std::collections::HashMap; -use std::str::FromStr; +use std::{collections::HashMap, str::FromStr}; use proc_macro2::{Span, TokenStream}; use proc_macro_error::abort;