#[Object] on impl dyn TraitObj. #381
This commit is contained in:
parent
1e449f9da6
commit
5a29f74062
|
@ -1,7 +1,8 @@
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
use proc_macro2::Span;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::ext::IdentExt;
|
use syn::ext::IdentExt;
|
||||||
use syn::{Block, Error, FnArg, ImplItem, ItemImpl, Pat, ReturnType, Type, TypeReference};
|
use syn::{Block, Error, FnArg, Ident, ImplItem, ItemImpl, Pat, ReturnType, Type, TypeReference};
|
||||||
|
|
||||||
use crate::args::{self, ComplexityType, RenameRuleExt, RenameTarget};
|
use crate::args::{self, ComplexityType, RenameRuleExt, RenameTarget};
|
||||||
use crate::output_type::OutputType;
|
use crate::output_type::OutputType;
|
||||||
|
@ -18,12 +19,14 @@ pub fn generate(
|
||||||
let crate_name = get_crate_name(object_args.internal);
|
let crate_name = get_crate_name(object_args.internal);
|
||||||
let (self_ty, self_name) = get_type_path_and_name(item_impl.self_ty.as_ref())?;
|
let (self_ty, self_name) = get_type_path_and_name(item_impl.self_ty.as_ref())?;
|
||||||
let generics = &item_impl.generics;
|
let generics = &item_impl.generics;
|
||||||
|
let generics_params = &generics.params;
|
||||||
let where_clause = &item_impl.generics.where_clause;
|
let where_clause = &item_impl.generics.where_clause;
|
||||||
let extends = object_args.extends;
|
let extends = object_args.extends;
|
||||||
let gql_typename = object_args
|
let gql_typename = object_args
|
||||||
.name
|
.name
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| RenameTarget::Type.rename(self_name.clone()));
|
.unwrap_or_else(|| RenameTarget::Type.rename(self_name.clone()));
|
||||||
|
let shadow_type = Ident::new(&format!("__Shadow{}", gql_typename), Span::call_site());
|
||||||
|
|
||||||
let desc = if object_args.use_type_description {
|
let desc = if object_args.use_type_description {
|
||||||
quote! { ::std::option::Option::Some(<Self as #crate_name::Description>::description()) }
|
quote! { ::std::option::Option::Some(<Self as #crate_name::Description>::description()) }
|
||||||
|
@ -466,8 +469,10 @@ pub fn generate(
|
||||||
let block = &method.block;
|
let block = &method.block;
|
||||||
let new_block = quote!({
|
let new_block = quote!({
|
||||||
{
|
{
|
||||||
let value:#inner_ty = async move #block.await;
|
::std::result::Result::Ok(async move {
|
||||||
::std::result::Result::Ok(value)
|
let value:#inner_ty = #block;
|
||||||
|
value
|
||||||
|
}.await)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
method.block = syn::parse2::<Block>(new_block).expect("invalid block");
|
method.block = syn::parse2::<Block>(new_block).expect("invalid block");
|
||||||
|
@ -534,11 +539,15 @@ pub fn generate(
|
||||||
}
|
}
|
||||||
|
|
||||||
let visible = visible_fn(&object_args.visible);
|
let visible = visible_fn(&object_args.visible);
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
#item_impl
|
#item_impl
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
type #shadow_type<#generics_params> = #self_ty;
|
||||||
|
|
||||||
#[allow(clippy::all, clippy::pedantic)]
|
#[allow(clippy::all, clippy::pedantic)]
|
||||||
impl #generics #crate_name::Type for #self_ty #where_clause {
|
impl #generics #crate_name::Type for #shadow_type<#generics_params> #where_clause {
|
||||||
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
|
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
|
||||||
::std::borrow::Cow::Borrowed(#gql_typename)
|
::std::borrow::Cow::Borrowed(#gql_typename)
|
||||||
}
|
}
|
||||||
|
@ -566,7 +575,7 @@ pub fn generate(
|
||||||
#[allow(clippy::all, clippy::pedantic, clippy::suspicious_else_formatting)]
|
#[allow(clippy::all, clippy::pedantic, clippy::suspicious_else_formatting)]
|
||||||
#[allow(unused_braces, unused_variables, unused_parens, unused_mut)]
|
#[allow(unused_braces, unused_variables, unused_parens, unused_mut)]
|
||||||
#[#crate_name::async_trait::async_trait]
|
#[#crate_name::async_trait::async_trait]
|
||||||
impl#generics #crate_name::resolver_utils::ContainerType for #self_ty #where_clause {
|
impl#generics #crate_name::resolver_utils::ContainerType for #shadow_type<#generics_params> #where_clause {
|
||||||
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> {
|
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> {
|
||||||
#(#resolvers)*
|
#(#resolvers)*
|
||||||
::std::result::Result::Ok(::std::option::Option::None)
|
::std::result::Result::Ok(::std::option::Option::None)
|
||||||
|
@ -592,13 +601,16 @@ pub fn generate(
|
||||||
|
|
||||||
#[allow(clippy::all, clippy::pedantic)]
|
#[allow(clippy::all, clippy::pedantic)]
|
||||||
#[#crate_name::async_trait::async_trait]
|
#[#crate_name::async_trait::async_trait]
|
||||||
impl #generics #crate_name::OutputType for #self_ty #where_clause {
|
impl #generics #crate_name::OutputType for #shadow_type<#generics_params> #where_clause {
|
||||||
async fn resolve(&self, ctx: &#crate_name::ContextSelectionSet<'_>, _field: &#crate_name::Positioned<#crate_name::parser::types::Field>) -> #crate_name::ServerResult<#crate_name::Value> {
|
async fn resolve(&self, ctx: &#crate_name::ContextSelectionSet<'_>, _field: &#crate_name::Positioned<#crate_name::parser::types::Field>) -> #crate_name::ServerResult<#crate_name::Value> {
|
||||||
#crate_name::resolver_utils::resolve_container(ctx, self).await
|
#crate_name::resolver_utils::resolve_container(ctx, self).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl #generics #crate_name::ObjectType for #self_ty #where_clause {}
|
impl #generics #crate_name::ObjectType for #shadow_type<#generics_params> #where_clause {}
|
||||||
};
|
};
|
||||||
|
if gql_typename == "QueryRoot11" {
|
||||||
|
println!("{}", expanded);
|
||||||
|
}
|
||||||
Ok(expanded.into())
|
Ok(expanded.into())
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use quote::quote;
|
||||||
use syn::visit::Visit;
|
use syn::visit::Visit;
|
||||||
use syn::{
|
use syn::{
|
||||||
Attribute, Error, Expr, ExprPath, Ident, Lit, LitStr, Meta, NestedMeta, Type, TypeGroup,
|
Attribute, Error, Expr, ExprPath, Ident, Lit, LitStr, Meta, NestedMeta, Type, TypeGroup,
|
||||||
TypePath,
|
TypeParamBound,
|
||||||
};
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -380,10 +380,10 @@ pub fn remove_graphql_attrs(attrs: &mut Vec<Attribute>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_type_path_and_name(ty: &Type) -> GeneratorResult<(&TypePath, String)> {
|
pub fn get_type_path_and_name(ty: &Type) -> GeneratorResult<(&Type, String)> {
|
||||||
match ty {
|
match ty {
|
||||||
Type::Path(path) => Ok((
|
Type::Path(path) => Ok((
|
||||||
path,
|
ty,
|
||||||
path.path
|
path.path
|
||||||
.segments
|
.segments
|
||||||
.last()
|
.last()
|
||||||
|
@ -391,6 +391,19 @@ pub fn get_type_path_and_name(ty: &Type) -> GeneratorResult<(&TypePath, String)>
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)),
|
)),
|
||||||
Type::Group(TypeGroup { elem, .. }) => get_type_path_and_name(&elem),
|
Type::Group(TypeGroup { elem, .. }) => get_type_path_and_name(&elem),
|
||||||
|
Type::TraitObject(trait_object) => Ok((
|
||||||
|
ty,
|
||||||
|
trait_object
|
||||||
|
.bounds
|
||||||
|
.iter()
|
||||||
|
.find_map(|bound| match bound {
|
||||||
|
TypeParamBound::Trait(t) => {
|
||||||
|
Some(t.path.segments.last().map(|s| s.ident.to_string()).unwrap())
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.unwrap(),
|
||||||
|
)),
|
||||||
_ => Err(Error::new_spanned(ty, "Invalid type").into()),
|
_ => Err(Error::new_spanned(ty, "Invalid type").into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
45
src/base.rs
45
src/base.rs
|
@ -1,4 +1,5 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::parser::types::Field;
|
use crate::parser::types::Field;
|
||||||
use crate::registry::Registry;
|
use crate::registry::Registry;
|
||||||
|
@ -77,6 +78,50 @@ impl<T: OutputType + Send + Sync + ?Sized> OutputType for &T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Type + Send + Sync + ?Sized> Type for Box<T> {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
T::type_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_type_info(registry: &mut Registry) -> String {
|
||||||
|
T::create_type_info(registry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<T: OutputType + Send + Sync + ?Sized> OutputType for Box<T> {
|
||||||
|
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||||
|
async fn resolve(
|
||||||
|
&self,
|
||||||
|
ctx: &ContextSelectionSet<'_>,
|
||||||
|
field: &Positioned<Field>,
|
||||||
|
) -> ServerResult<Value> {
|
||||||
|
T::resolve(&**self, ctx, field).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type + Send + Sync + ?Sized> Type for Arc<T> {
|
||||||
|
fn type_name() -> Cow<'static, str> {
|
||||||
|
T::type_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_type_info(registry: &mut Registry) -> String {
|
||||||
|
T::create_type_info(registry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<T: OutputType + Send + Sync + ?Sized> OutputType for Arc<T> {
|
||||||
|
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||||
|
async fn resolve(
|
||||||
|
&self,
|
||||||
|
ctx: &ContextSelectionSet<'_>,
|
||||||
|
field: &Positioned<Field>,
|
||||||
|
) -> ServerResult<Value> {
|
||||||
|
T::resolve(&**self, ctx, field).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Type> Type for Result<T> {
|
impl<T: Type> Type for Result<T> {
|
||||||
fn type_name() -> Cow<'static, str> {
|
fn type_name() -> Cow<'static, str> {
|
||||||
T::type_name()
|
T::type_name()
|
||||||
|
|
53
src/lib.rs
53
src/lib.rs
|
@ -316,6 +316,8 @@ pub type FieldResult<T> = Result<T>;
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
/// Implements GraphQL Object for struct.
|
||||||
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use async_graphql::*;
|
/// use async_graphql::*;
|
||||||
///
|
///
|
||||||
|
@ -363,6 +365,57 @@ pub type FieldResult<T> = Result<T>;
|
||||||
/// }));
|
/// }));
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Implements GraphQL Object for trait object.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use async_graphql::*;
|
||||||
|
///
|
||||||
|
/// trait MyTrait: Send + Sync {
|
||||||
|
/// fn name(&self) -> &str;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[Object]
|
||||||
|
/// impl dyn MyTrait {
|
||||||
|
/// #[graphql(name = "name")]
|
||||||
|
/// async fn gql_name(&self) -> &str {
|
||||||
|
/// self.name()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// struct MyObj(String);
|
||||||
|
///
|
||||||
|
/// impl MyTrait for MyObj {
|
||||||
|
/// fn name(&self) -> &str {
|
||||||
|
/// &self.0
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// struct QueryRoot;
|
||||||
|
///
|
||||||
|
/// #[Object]
|
||||||
|
/// impl QueryRoot {
|
||||||
|
/// async fn objs(&self) -> Vec<Box<dyn MyTrait>> {
|
||||||
|
/// vec![
|
||||||
|
/// Box::new(MyObj("a".to_string())),
|
||||||
|
/// Box::new(MyObj("b".to_string())),
|
||||||
|
/// ]
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// async_std::task::block_on(async move {
|
||||||
|
/// let schema = Schema::new(QueryRoot, EmptyMutation, EmptySubscription);
|
||||||
|
/// let res = schema.execute("{ objs { name } }").await.into_result().unwrap().data;
|
||||||
|
/// assert_eq!(res, value!({
|
||||||
|
/// "objs": [
|
||||||
|
/// { "name": "a" },
|
||||||
|
/// { "name": "b" },
|
||||||
|
/// ]
|
||||||
|
/// }));
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
pub use async_graphql_derive::Object;
|
pub use async_graphql_derive::Object;
|
||||||
|
|
||||||
/// Define a GraphQL object with fields
|
/// Define a GraphQL object with fields
|
||||||
|
|
|
@ -297,7 +297,7 @@ pub struct Registry {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Registry {
|
impl Registry {
|
||||||
pub fn create_type<T: crate::Type, F: FnMut(&mut Registry) -> MetaType>(
|
pub fn create_type<T: crate::Type + ?Sized, F: FnMut(&mut Registry) -> MetaType>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut f: F,
|
mut f: F,
|
||||||
) -> String {
|
) -> String {
|
||||||
|
|
|
@ -36,7 +36,7 @@ pub trait ContainerType: OutputType {
|
||||||
fields: &mut Fields<'a>,
|
fields: &mut Fields<'a>,
|
||||||
) -> ServerResult<()>
|
) -> ServerResult<()>
|
||||||
where
|
where
|
||||||
Self: Sized + Send + Sync,
|
Self: Send + Sync,
|
||||||
{
|
{
|
||||||
fields.add_set(ctx, self)
|
fields.add_set(ctx, self)
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ impl<T: ContainerType + Send + Sync> ContainerType for &T {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve an container by executing each of the fields concurrently.
|
/// Resolve an container by executing each of the fields concurrently.
|
||||||
pub async fn resolve_container<'a, T: ContainerType + Send + Sync>(
|
pub async fn resolve_container<'a, T: ContainerType + Send + Sync + ?Sized>(
|
||||||
ctx: &ContextSelectionSet<'a>,
|
ctx: &ContextSelectionSet<'a>,
|
||||||
root: &'a T,
|
root: &'a T,
|
||||||
) -> ServerResult<Value> {
|
) -> ServerResult<Value> {
|
||||||
|
@ -69,7 +69,7 @@ pub async fn resolve_container<'a, T: ContainerType + Send + Sync>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve an container by executing each of the fields serially.
|
/// Resolve an container by executing each of the fields serially.
|
||||||
pub async fn resolve_container_serial<'a, T: ContainerType + Send + Sync>(
|
pub async fn resolve_container_serial<'a, T: ContainerType + Send + Sync + ?Sized>(
|
||||||
ctx: &ContextSelectionSet<'a>,
|
ctx: &ContextSelectionSet<'a>,
|
||||||
root: &'a T,
|
root: &'a T,
|
||||||
) -> ServerResult<Value> {
|
) -> ServerResult<Value> {
|
||||||
|
@ -102,7 +102,7 @@ fn insert_value(target: &mut BTreeMap<Name, Value>, name: Name, value: Value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn resolve_container_inner<'a, T: ContainerType + Send + Sync>(
|
async fn resolve_container_inner<'a, T: ContainerType + Send + Sync + ?Sized>(
|
||||||
ctx: &ContextSelectionSet<'a>,
|
ctx: &ContextSelectionSet<'a>,
|
||||||
root: &'a T,
|
root: &'a T,
|
||||||
parallel: bool,
|
parallel: bool,
|
||||||
|
@ -134,7 +134,7 @@ pub struct Fields<'a>(Vec<BoxFieldFuture<'a>>);
|
||||||
|
|
||||||
impl<'a> Fields<'a> {
|
impl<'a> Fields<'a> {
|
||||||
/// Add another set of fields to this set of fields using the given container.
|
/// Add another set of fields to this set of fields using the given container.
|
||||||
pub fn add_set<T: ContainerType + Send + Sync>(
|
pub fn add_set<T: ContainerType + Send + Sync + ?Sized>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &ContextSelectionSet<'a>,
|
ctx: &ContextSelectionSet<'a>,
|
||||||
root: &'a T,
|
root: &'a T,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user