Implement OutputType for FieldResult

This commit is contained in:
sunli 2020-05-03 22:32:37 +08:00
parent 4aaba01a88
commit f3697e6a1a
3 changed files with 144 additions and 1 deletions

View File

@ -1,5 +1,5 @@
use crate::registry::Registry;
use crate::{registry, Context, ContextSelectionSet, QueryError, Result, ID};
use crate::{registry, Context, ContextSelectionSet, FieldResult, QueryError, Result, ID};
use graphql_parser::query::Value;
use graphql_parser::Pos;
use std::borrow::Cow;
@ -238,3 +238,38 @@ impl<T: OutputValueType + Send + Sync> OutputValueType for Arc<T> {
T::resolve(&*value, ctx, pos).await
}
}
impl<T: Type> Type for FieldResult<T> {
fn type_name() -> Cow<'static, str> {
T::type_name()
}
fn qualified_type_name() -> String {
T::qualified_type_name()
}
fn create_type_info(registry: &mut registry::Registry) -> String {
T::create_type_info(registry);
T::type_name().to_string()
}
}
#[async_trait::async_trait]
impl<T: OutputValueType + Sync> OutputValueType for FieldResult<T> {
async fn resolve(
value: &Self,
ctx: &ContextSelectionSet<'_>,
pos: Pos,
) -> crate::Result<serde_json::Value> where {
match value.as_ref() {
Ok(value) => Ok(OutputValueType::resolve(value, ctx, pos).await?),
Err(err) => Err(err.clone().into_error_with_path(
pos,
match &ctx.path_node {
Some(path) => path.to_json(),
None => serde_json::Value::Null,
},
)),
}
}
}

59
tests/fieldresult.rs Normal file
View File

@ -0,0 +1,59 @@
use async_graphql::*;
#[async_std::test]
pub async fn test_fieldresult() {
struct Query;
#[Object]
impl Query {
async fn error(&self) -> FieldResult<i32> {
Err("TestError".into())
}
async fn opt_error(&self) -> Option<FieldResult<i32>> {
Some(Err("TestError".into()))
}
async fn vec_error(&self) -> Vec<FieldResult<i32>> {
vec![Ok(1), Err("TestError".into())]
}
}
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
assert_eq!(
schema.execute("{ error }").await.unwrap_err(),
Error::Query {
pos: Pos { line: 1, column: 3 },
path: Some(serde_json::json!(["error"])),
err: QueryError::FieldError {
err: "TestError".to_string(),
extended_error: None,
},
}
);
assert_eq!(
schema.execute("{ optError }").await.unwrap_err(),
Error::Query {
pos: Pos { line: 1, column: 3 },
path: Some(serde_json::json!(["optError"])),
err: QueryError::FieldError {
err: "TestError".to_string(),
extended_error: None,
},
}
);
assert_eq!(
schema.execute("{ vecError }").await.unwrap_err(),
Error::Query {
pos: Pos { line: 1, column: 3 },
path: Some(serde_json::json!(["vecError", 1])),
err: QueryError::FieldError {
err: "TestError".to_string(),
extended_error: None,
},
}
);
}

View File

@ -489,3 +489,52 @@ pub async fn test_subscription_error() {
assert!(stream.next().await.is_none());
}
#[async_std::test]
pub async fn test_subscription_fieldresult() {
struct QueryRoot;
#[Object]
impl QueryRoot {}
struct SubscriptionRoot;
#[Subscription]
impl SubscriptionRoot {
async fn values(&self) -> impl Stream<Item = FieldResult<i32>> {
futures::stream::iter(0..5)
.map(FieldResult::Ok)
.chain(futures::stream::once(
async move { Err("StreamErr".into()) },
))
}
}
let schema = Schema::new(QueryRoot, EmptyMutation, SubscriptionRoot);
let mut stream = schema
.create_subscription_stream("subscription { values }", None, Default::default(), None)
.await
.unwrap();
for i in 0i32..5 {
assert_eq!(
Some(Ok(serde_json::json!({ "values": i }))),
stream.next().await
);
}
assert_eq!(
stream.next().await,
Some(Err(Error::Query {
pos: Pos {
line: 1,
column: 16
},
path: Some(serde_json::json!(["values"])),
err: QueryError::FieldError {
err: "StreamErr".to_string(),
extended_error: None,
},
}))
);
assert!(stream.next().await.is_none());
}