Add derive macro GQLMergeObject. #231
This commit is contained in:
parent
b0bce9ec32
commit
d280a13b70
|
@ -19,7 +19,7 @@ mod utils;
|
|||
use crate::utils::{add_container_attrs, parse_derive};
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
use syn::parse_macro_input;
|
||||
use syn::{AttributeArgs, ItemImpl};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
|
@ -207,11 +207,25 @@ pub fn Scalar(args: TokenStream, input: TokenStream) -> TokenStream {
|
|||
#[proc_macro_attribute]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn MergedObject(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
add_container_attrs(
|
||||
quote!(GQLMergedObject),
|
||||
parse_macro_input!(args as AttributeArgs),
|
||||
input.into(),
|
||||
)
|
||||
.unwrap_or_else(|err| err.to_compile_error())
|
||||
.into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(GQLMergedObject, attributes(item, graphql))]
|
||||
pub fn derive_merged_object(input: TokenStream) -> TokenStream {
|
||||
let (args, input) = match parse_derive(input.into()) {
|
||||
Ok(r) => r,
|
||||
Err(err) => return err.to_compile_error().into(),
|
||||
};
|
||||
let object_args = match args::Object::parse(parse_macro_input!(args as AttributeArgs)) {
|
||||
Ok(object_args) => object_args,
|
||||
Err(err) => return err.to_compile_error().into(),
|
||||
};
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
match merged_object::generate(&object_args, &input) {
|
||||
Ok(expanded) => expanded,
|
||||
Err(err) => err.to_compile_error().into(),
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::args;
|
||||
use crate::utils::{get_crate_name, get_rustdoc};
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Span;
|
||||
use quote::quote;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{Data, DeriveInput, Error, Ident, Result};
|
||||
use syn::{Data, DeriveInput, Error, LitInt, Result};
|
||||
|
||||
pub fn generate(object_args: &args::Object, input: &DeriveInput) -> Result<TokenStream> {
|
||||
let crate_name = get_crate_name(object_args.internal);
|
||||
|
@ -13,8 +13,6 @@ pub fn generate(object_args: &args::Object, input: &DeriveInput) -> Result<Token
|
|||
.name
|
||||
.clone()
|
||||
.unwrap_or_else(|| ident.to_string());
|
||||
let vis = &input.vis;
|
||||
let attrs = &input.attrs;
|
||||
|
||||
let desc = object_args
|
||||
.desc
|
||||
|
@ -33,23 +31,14 @@ pub fn generate(object_args: &args::Object, input: &DeriveInput) -> Result<Token
|
|||
types.push(&field.ty);
|
||||
}
|
||||
|
||||
let new_args = {
|
||||
let mut new_args = Vec::new();
|
||||
for (i, ty) in types.iter().enumerate() {
|
||||
let name = Ident::new(&format!("obj{}", i + 1), ty.span());
|
||||
new_args.push(quote! { #name: #ty })
|
||||
}
|
||||
new_args
|
||||
};
|
||||
|
||||
let new_func = {
|
||||
let create_merged_obj = {
|
||||
let mut obj = quote! { #crate_name::MergedObjectTail };
|
||||
for (i, ty) in types.iter().enumerate() {
|
||||
let name = Ident::new(&format!("obj{}", i + 1), ty.span());
|
||||
obj = quote! { #crate_name::MergedObject(#name, #obj) };
|
||||
for i in 0..types.len() {
|
||||
let n = LitInt::new(&format!("{}", i), Span::call_site());
|
||||
obj = quote! { #crate_name::MergedObject(&self.#n, #obj) };
|
||||
}
|
||||
quote! {
|
||||
Self(#obj)
|
||||
#obj
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -62,15 +51,6 @@ pub fn generate(object_args: &args::Object, input: &DeriveInput) -> Result<Token
|
|||
};
|
||||
|
||||
let expanded = quote! {
|
||||
#(#attrs)*
|
||||
#vis struct #ident(#merged_type);
|
||||
|
||||
impl #ident {
|
||||
pub fn new(#(#new_args),*) -> Self {
|
||||
#new_func
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::all, clippy::pedantic)]
|
||||
impl #crate_name::Type for #ident {
|
||||
fn type_name() -> ::std::borrow::Cow<'static, str> {
|
||||
|
@ -109,7 +89,7 @@ pub fn generate(object_args: &args::Object, input: &DeriveInput) -> Result<Token
|
|||
#[#crate_name::async_trait::async_trait]
|
||||
impl #crate_name::ObjectType for #ident {
|
||||
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::Result<#crate_name::serde_json::Value> {
|
||||
self.0.resolve_field(ctx).await
|
||||
#create_merged_obj.resolve_field(ctx).await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -166,6 +166,13 @@ impl<T: OutputValueType + Send + Sync> OutputValueType for &T {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<T: ObjectType + Send + Sync> ObjectType for &T {
|
||||
async fn resolve_field(&self, ctx: &Context<'_>) -> Result<serde_json::Value> {
|
||||
T::resolve_field(*self, ctx).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type + Send + Sync> Type for Box<T> {
|
||||
fn type_name() -> Cow<'static, str> {
|
||||
T::type_name()
|
||||
|
|
|
@ -786,6 +786,9 @@ pub use async_graphql_derive::Scalar;
|
|||
/// #[MergedObject]
|
||||
/// struct MyObj(Object1, Object2, Object3);
|
||||
///
|
||||
/// let obj = MyObj::new(Object1 { a: 10 }, Object2 { b: 20 }, Object3 { c: 30 });
|
||||
/// let obj = MyObj(Object1 { a: 10 }, Object2 { b: 20 }, Object3 { c: 30 });
|
||||
/// ```
|
||||
pub use async_graphql_derive::MergedObject;
|
||||
|
||||
/// Derive a GraphQL Merged object
|
||||
pub use async_graphql_derive::GQLMergedObject;
|
||||
|
|
|
@ -64,7 +64,35 @@ pub async fn test_merged_object_macro() {
|
|||
#[Object]
|
||||
impl Query {
|
||||
async fn obj(&self) -> MyObj {
|
||||
MyObj::new(Object1 { a: 10 }, Object2 { b: 20 }, Object3 { c: 30 })
|
||||
MyObj(Object1 { a: 10 }, Object2 { b: 20 }, Object3 { c: 30 })
|
||||
}
|
||||
}
|
||||
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
let query = "{ obj { a b c } }";
|
||||
assert_eq!(
|
||||
schema.execute(&query).await.unwrap().data,
|
||||
serde_json::json!({
|
||||
"obj": {
|
||||
"a": 10,
|
||||
"b": 20,
|
||||
"c": 30,
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
pub async fn test_merged_object_derive() {
|
||||
#[derive(GQLMergedObject)]
|
||||
struct MyObj(Object1, Object2, Object3);
|
||||
|
||||
struct Query;
|
||||
|
||||
#[Object]
|
||||
impl Query {
|
||||
async fn obj(&self) -> MyObj {
|
||||
MyObj(Object1 { a: 10 }, Object2 { b: 20 }, Object3 { c: 30 })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user