Fix the generic SimpleObject can't define the lifetimes. #774

This commit is contained in:
Sunli 2022-01-05 11:52:02 +08:00
parent d1d0154ad8
commit b484a6104d
2 changed files with 101 additions and 5 deletions

View File

@ -3,7 +3,8 @@ use proc_macro::TokenStream;
use quote::quote;
use std::str::FromStr;
use syn::ext::IdentExt;
use syn::{Error, Ident, Path, Type};
use syn::visit::Visit;
use syn::{Error, Ident, LifetimeDef, Path, Type};
use crate::args::{self, RenameRuleExt, RenameTarget, SimpleObjectField};
use crate::utils::{
@ -320,6 +321,33 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
} else {
let mut code = Vec::new();
#[derive(Default)]
struct GetLifetimes<'a> {
lifetimes: Vec<&'a LifetimeDef>,
}
impl<'a> Visit<'a> for GetLifetimes<'a> {
fn visit_lifetime_def(&mut self, i: &'a LifetimeDef) {
self.lifetimes.push(i);
}
}
let mut visitor = GetLifetimes::default();
visitor.visit_generics(&object_args.generics);
let lifetimes = visitor.lifetimes;
let def_lifetimes = if !lifetimes.is_empty() {
Some(quote!(<#(#lifetimes),*>))
} else {
None
};
let type_lifetimes = if !lifetimes.is_empty() {
Some(quote!(#(#lifetimes,)*))
} else {
None
};
code.push(quote! {
impl #impl_generics #ident #ty_generics #where_clause {
#(#getters)*
@ -357,12 +385,12 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
for concrete in &object_args.concretes {
let gql_typename = &concrete.name;
let params = &concrete.params.0;
let concrete_type = quote! { #ident<#(#params),*> };
let concrete_type = quote! { #ident<#type_lifetimes #(#params),*> };
let expanded = quote! {
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #crate_name::resolver_utils::ContainerType for #concrete_type {
impl #def_lifetimes #crate_name::resolver_utils::ContainerType for #concrete_type {
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> {
#complex_resolver
self.__internal_resolve_field(ctx).await
@ -371,7 +399,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
#[allow(clippy::all, clippy::pedantic)]
#[#crate_name::async_trait::async_trait]
impl #crate_name::OutputType for #concrete_type {
impl #def_lifetimes #crate_name::OutputType for #concrete_type {
fn type_name() -> ::std::borrow::Cow<'static, ::std::primitive::str> {
::std::borrow::Cow::Borrowed(#gql_typename)
}
@ -387,7 +415,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
}
}
impl #crate_name::ObjectType for #concrete_type {}
impl #def_lifetimes #crate_name::ObjectType for #concrete_type {}
};
code.push(expanded);
}

View File

@ -348,3 +348,71 @@ pub async fn test_concrete_object() {
})
);
}
#[tokio::test]
pub async fn test_concrete_object_with_lifetime() {
#[derive(SimpleObject)]
#[graphql(concrete(name = "Bar0", params(i32)))]
#[graphql(concrete(name = "Bar1", params(i64)))]
struct Foo<'a, T>
where
T: Sync + OutputType + 'a,
{
data: &'a T,
}
struct Query {
value1: i32,
value2: i64,
}
#[Object]
impl Query {
async fn a(&self) -> Foo<'_, i32> {
Foo { data: &self.value1 }
}
async fn b(&self) -> Foo<'_, i64> {
Foo { data: &self.value2 }
}
async fn static_a(&self) -> Foo<'static, i32> {
Foo { data: &100 }
}
async fn static_b(&self) -> Foo<'static, i32> {
Foo { data: &200 }
}
}
let schema = Schema::new(
Query {
value1: 88,
value2: 99,
},
EmptyMutation,
EmptySubscription,
);
assert_eq!(
schema
.execute(
r#"{
a { data }
b { data }
staticA { data }
staticB { data }
}"#
)
.await
.into_result()
.unwrap()
.data,
value!({
"a": { "data": 88 },
"b": { "data": 99 },
"staticA": { "data": 100 },
"staticB": { "data": 200 },
})
);
}