Now when the resolver returns the Result type, E can be all types that implement Into<async_graphql::Error>.

This commit is contained in:
Sunli 2021-04-09 15:04:01 +08:00
parent 8835f03c92
commit 572f907df7
6 changed files with 67 additions and 11 deletions

View File

@ -309,7 +309,7 @@ pub fn generate(
let resolve_obj = quote! { let resolve_obj = quote! {
{ {
let res = self.#field_ident(ctx, #(#use_params),*).await; let res = self.#field_ident(ctx, #(#use_params),*).await;
res.map_err(|err| err.into_server_error().at(ctx.item.pos))? res.map_err(|err| ::std::convert::Into::<#crate_name::Error>::into(err).into_server_error().at(ctx.item.pos))?
} }
}; };

View File

@ -237,7 +237,9 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
for enum_name in &enum_names { for enum_name in &enum_names {
calls.push(quote! { calls.push(quote! {
#ident::#enum_name(obj) => obj.#method_name(#(#use_params),*).await.map(::std::convert::Into::into) #ident::#enum_name(obj) => obj.#method_name(#(#use_params),*)
.await.map_err(|err| ::std::convert::Into::<#crate_name::Error>::into(err))
.map(::std::convert::Into::into)
}); });
} }
@ -287,7 +289,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
let resolve_obj = quote! { let resolve_obj = quote! {
self.#method_name(#(#use_params),*) self.#method_name(#(#use_params),*)
.await .await
.map_err(|err| err.into_server_error().at(ctx.item.pos))? .map_err(|err| ::std::convert::Into::<#crate_name::Error>::into(err).into_server_error().at(ctx.item.pos))?
}; };
resolvers.push(quote! { resolvers.push(quote! {

View File

@ -209,7 +209,7 @@ pub fn generate(
syn::parse2::<ReturnType>(quote! { -> #crate_name::Result<#inner_ty> }) syn::parse2::<ReturnType>(quote! { -> #crate_name::Result<#inner_ty> })
.expect("invalid result type"); .expect("invalid result type");
} }
let do_find = quote! { self.#field_ident(ctx, #(#use_keys),*).await.map_err(|err| err.into_server_error().at(ctx.item.pos))? }; let do_find = quote! { self.#field_ident(ctx, #(#use_keys),*).await.map_err(|err| ::std::convert::Into::<#crate_name::Error>::into(err).into_server_error().at(ctx.item.pos))? };
find_entities.push(( find_entities.push((
args.len(), args.len(),
@ -513,7 +513,7 @@ pub fn generate(
let resolve_obj = quote! { let resolve_obj = quote! {
{ {
let res = self.#field_ident(ctx, #(#use_params),*).await; let res = self.#field_ident(ctx, #(#use_params),*).await;
res.map_err(|err| err.into_server_error().at(ctx.item.pos))? res.map_err(|err| ::std::convert::Into::<#crate_name::Error>::into(err).into_server_error().at(ctx.item.pos))?
} }
}; };

View File

@ -318,7 +318,7 @@ pub fn generate(
self.#ident(ctx, #(#use_params),*) self.#ident(ctx, #(#use_params),*)
.await .await
.map_err(|err| { .map_err(|err| {
err.into_server_error() ::std::convert::Into::<#crate_name::Error>::into(err).into_server_error()
.at(ctx.item.pos) .at(ctx.item.pos)
.path(#crate_name::PathSegment::Field(::std::borrow::ToOwned::to_owned(&*field_name))) .path(#crate_name::PathSegment::Field(::std::borrow::ToOwned::to_owned(&*field_name)))
})? })?

View File

@ -6,8 +6,8 @@ use async_graphql_value::ConstValue;
use crate::parser::types::Field; use crate::parser::types::Field;
use crate::registry::{self, Registry}; use crate::registry::{self, Registry};
use crate::{ use crate::{
ContainerType, Context, ContextSelectionSet, InputValueError, InputValueResult, Positioned, ContainerType, Context, ContextSelectionSet, Error, InputValueError, InputValueResult,
Result, ServerResult, Value, Positioned, Result, ServerResult, Value,
}; };
#[doc(hidden)] #[doc(hidden)]
@ -86,7 +86,7 @@ impl<T: OutputType + ?Sized> OutputType for &T {
} }
} }
impl<T: Type> Type for Result<T> { impl<T: Type, E: Into<Error> + Send + Sync + Clone> Type for Result<T, E> {
fn type_name() -> Cow<'static, str> { fn type_name() -> Cow<'static, str> {
T::type_name() T::type_name()
} }
@ -101,7 +101,7 @@ impl<T: Type> Type for Result<T> {
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl<T: OutputType + Sync> OutputType for Result<T> { impl<T: OutputType + Sync, E: Into<Error> + Send + Sync + Clone> OutputType for Result<T, E> {
async fn resolve( async fn resolve(
&self, &self,
ctx: &ContextSelectionSet<'_>, ctx: &ContextSelectionSet<'_>,
@ -109,7 +109,7 @@ impl<T: OutputType + Sync> OutputType for Result<T> {
) -> ServerResult<Value> { ) -> ServerResult<Value> {
match self { match self {
Ok(value) => Ok(value.resolve(ctx, field).await?), Ok(value) => Ok(value.resolve(ctx, field).await?),
Err(err) => Err(err.clone().into_server_error().at(field.pos)), Err(err) => Err(err.clone().into().into_server_error().at(field.pos)),
} }
} }
} }

View File

@ -1,4 +1,5 @@
use async_graphql::*; use async_graphql::*;
use futures_util::stream::Stream;
#[tokio::test] #[tokio::test]
pub async fn test_fieldresult() { pub async fn test_fieldresult() {
@ -62,3 +63,56 @@ pub async fn test_fieldresult() {
}] }]
); );
} }
#[tokio::test]
pub async fn test_custom_error() {
#[derive(Clone)]
struct MyError;
impl From<MyError> for Error {
fn from(_: MyError) -> Self {
Error::new("custom error")
}
}
#[derive(SimpleObject)]
#[graphql(complex)]
struct MyObj {
value1: i32,
}
#[ComplexObject]
impl MyObj {
async fn value2(&self) -> Result<i32, MyError> {
Err(MyError)
}
}
#[derive(Interface)]
#[graphql(field(name = "value2", type = "i32"))]
enum MyInterface {
MyObj(MyObj),
}
struct Query;
#[Object]
impl Query {
async fn value(&self) -> Result<i32, MyError> {
Err(MyError)
}
}
struct Subscription;
#[Subscription]
impl Subscription {
async fn value1(&self) -> Result<impl Stream<Item = i32>, MyError> {
Err::<futures_util::stream::Once<futures_util::future::Ready<i32>>, _>(MyError)
}
async fn value2(&self) -> impl Stream<Item = Result<i32, MyError>> {
futures_util::stream::once(async move { Err(MyError) })
}
}
}