From 089e830d2697440164086fef84440c6c79c9d22c Mon Sep 17 00:00:00 2001 From: Sunli Date: Sat, 26 Sep 2020 09:22:54 +0800 Subject: [PATCH] Add StringNumber type. --- Cargo.toml | 4 +- src/types/mod.rs | 4 ++ src/types/string_number.rs | 78 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/types/string_number.rs diff --git a/Cargo.toml b/Cargo.toml index 62246a81..085d7ae2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,10 +14,11 @@ categories = ["network-programming", "asynchronous"] readme = "README.md" [features] -default = ["apollo_tracing", "uuid", "bson", "chrono", "chrono-tz", "log", "multipart", "tracing", "url", "unblock"] +default = ["apollo_tracing", "uuid", "bson", "chrono", "chrono-tz", "log", "multipart", "tracing", "url", "unblock", "string_number"] apollo_tracing = ["chrono"] multipart = ["multer", "bytes", "tempfile"] unblock = ["blocking"] +string_number = ["num-traits"] # Used for doc(cfg()) nightly = [] @@ -47,6 +48,7 @@ chrono-tz = { version = "0.5.1", optional = true } log = { version = "0.4.11", optional = true } tracing = { version = "0.1.19", optional = true } url = { version = "2.1.1", optional = true } +num-traits = { version = "0.2.12", optional = true } bytes = { version = "0.5.4", optional = true } multer = { version = "1.2.2", optional = true } diff --git a/src/types/mod.rs b/src/types/mod.rs index 09c94fc2..755c33cb 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -10,6 +10,8 @@ mod json; mod maybe_undefined; mod merged_object; mod query_root; +#[cfg(feature = "string_number")] +mod string_number; mod upload; mod external; @@ -21,6 +23,8 @@ pub use id::ID; pub use json::{Json, OutputJson}; pub use maybe_undefined::MaybeUndefined; pub use merged_object::{MergedObject, MergedObjectSubscriptionTail, MergedObjectTail}; +#[cfg(feature = "string_number")] +pub use string_number::StringNumber; pub use upload::Upload; pub(crate) use query_root::QueryRoot; diff --git a/src/types/string_number.rs b/src/types/string_number.rs new file mode 100644 index 00000000..0cf81a31 --- /dev/null +++ b/src/types/string_number.rs @@ -0,0 +1,78 @@ +use crate::{InputValueError, InputValueResult, Scalar, ScalarType, Value}; +use num_traits::Num; +use serde::{Deserialize, Serialize}; +use std::fmt::Display; + +/// A numeric value represented by a string. +#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] +#[serde(transparent)] +#[cfg_attr(feature = "nightly", doc(cfg(feature = "string_number")))] +pub struct StringNumber(pub T); + +#[Scalar(internal)] +impl ScalarType for StringNumber +where + ::FromStrRadixErr: Display, +{ + fn parse(value: Value) -> InputValueResult { + match value { + Value::String(s) => { + let n = T::from_str_radix(&s, 10) + .map_err(|err| InputValueError::Custom(err.to_string()))?; + Ok(StringNumber(n)) + } + _ => Err(InputValueError::ExpectedType(value)), + } + } + + fn is_valid(value: &Value) -> bool { + match value { + Value::String(_) => true, + _ => false, + } + } + + fn to_value(&self) -> Value { + Value::String(self.0.to_string()) + } +} + +#[cfg(test)] +mod test { + use crate::*; + + #[async_std::test] + async fn test_string_number() { + struct Query; + + #[Object(internal)] + impl Query { + async fn value(&self, n: StringNumber) -> StringNumber { + n + } + } + + let schema = Schema::new(Query, EmptyMutation, EmptySubscription); + assert_eq!( + schema + .execute( + r#"{ + value1: value(n: "100") + value2: value(n: "-100") + value3: value(n: "0") + value4: value(n: "1") + }"# + ) + .await + .into_result() + .unwrap() + .data, + serde_json::json!({ + "value1": "100", + "value2": "-100", + "value3": "0", + "value4": "1", + }) + ); + } +}