From 8370001272a180c8554f35c9a509e4baf5ead365 Mon Sep 17 00:00:00 2001 From: Sunli Date: Sun, 8 Nov 2020 09:22:50 +0800 Subject: [PATCH] Implements Cow for OutputValueType. #189 --- src/base.rs | 4 +- src/types/external/cow.rs | 101 +++++++++++++++++++++++++++++++++++ src/types/external/mod.rs | 1 + src/types/external/string.rs | 6 +-- 4 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 src/types/external/cow.rs diff --git a/src/base.rs b/src/base.rs index 88c4bdde..ab83ad62 100644 --- a/src/base.rs +++ b/src/base.rs @@ -55,7 +55,7 @@ pub trait OutputValueType: Type { ) -> ServerResult; } -impl Type for &T { +impl Type for &T { fn type_name() -> Cow<'static, str> { T::type_name() } @@ -66,7 +66,7 @@ impl Type for &T { } #[async_trait::async_trait] -impl OutputValueType for &T { +impl OutputValueType for &T { #[allow(clippy::trivially_copy_pass_by_ref)] async fn resolve( &self, diff --git a/src/types/external/cow.rs b/src/types/external/cow.rs new file mode 100644 index 00000000..71921e6a --- /dev/null +++ b/src/types/external/cow.rs @@ -0,0 +1,101 @@ +use std::borrow::Cow; + +use crate::{ + registry, ContextSelectionSet, OutputValueType, Positioned, ServerResult, Type, Value, +}; +use async_graphql_parser::types::Field; + +impl<'a, T> Type for Cow<'a, T> +where + T: Type + ToOwned + ?Sized + Send + Sync, +{ + fn type_name() -> Cow<'static, str> { + T::type_name() + } + + fn create_type_info(registry: &mut registry::Registry) -> String { + ::create_type_info(registry) + } +} + +#[async_trait::async_trait] +impl<'a, T> OutputValueType for Cow<'a, T> +where + T: OutputValueType + ToOwned + ?Sized + Send + Sync, + ::Owned: Send + Sync, +{ + async fn resolve( + &self, + ctx: &ContextSelectionSet<'_>, + field: &Positioned, + ) -> ServerResult { + self.as_ref().resolve(ctx, field).await + } +} + +#[cfg(test)] +mod test { + use crate::*; + use std::borrow::Cow; + + #[async_std::test] + async fn test_cow_type() { + struct Query11 { + obj: MyObj, + } + + #[derive(SimpleObject, Clone)] + #[graphql(internal)] + struct MyObj { + a: i32, + b: i32, + } + + #[Object(internal)] + impl Query11 { + async fn value1(&self) -> Cow<'_, str> { + Cow::Borrowed("abc") + } + + async fn value2(&self) -> Cow<'_, str> { + Cow::Owned("def".to_string()) + } + + async fn obj1(&self) -> Cow<'_, MyObj> { + Cow::Borrowed(&self.obj) + } + + async fn obj2(&self) -> Cow<'_, MyObj> { + Cow::Owned(MyObj { a: 300, b: 400 }) + } + } + + let query = r#"{ + value1 + value2 + obj1 { + a b + } + obj2 { + a b + } + }"#; + let schema = Schema::new( + Query11 { + obj: MyObj { a: 100, b: 200 }, + }, + EmptyMutation, + EmptySubscription, + ); + + assert_eq!( + schema.execute(query).await.into_result().unwrap().data, + value!({ + "value1": "abc", + "value2": "def", + "obj1": {"a": 100, "b": 200}, + "obj2": {"a": 300, "b": 400}, + }) + ); + } +} diff --git a/src/types/external/mod.rs b/src/types/external/mod.rs index 4962f44c..e1c5dac4 100644 --- a/src/types/external/mod.rs +++ b/src/types/external/mod.rs @@ -2,6 +2,7 @@ mod bool; mod char; +mod cow; mod floats; mod integers; mod json_object; diff --git a/src/types/external/string.rs b/src/types/external/string.rs index 98655aa5..cfd766f5 100644 --- a/src/types/external/string.rs +++ b/src/types/external/string.rs @@ -25,7 +25,7 @@ impl ScalarType for String { } } -impl<'a> Type for &'a str { +impl Type for str { fn type_name() -> Cow<'static, str> { Cow::Borrowed("String") } @@ -36,12 +36,12 @@ impl<'a> Type for &'a str { } #[async_trait::async_trait] -impl<'a> OutputValueType for &'a str { +impl OutputValueType for str { async fn resolve( &self, _: &ContextSelectionSet<'_>, _field: &Positioned, ) -> ServerResult { - Ok(Value::String((*self).to_string())) + Ok(Value::String(self.to_string())) } }