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 crate::utils::{add_container_attrs, parse_derive};
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{parse_macro_input, DeriveInput};
|
use syn::parse_macro_input;
|
||||||
use syn::{AttributeArgs, ItemImpl};
|
use syn::{AttributeArgs, ItemImpl};
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
|
@ -207,11 +207,25 @@ pub fn Scalar(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn MergedObject(args: TokenStream, input: TokenStream) -> TokenStream {
|
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)) {
|
let object_args = match args::Object::parse(parse_macro_input!(args as AttributeArgs)) {
|
||||||
Ok(object_args) => object_args,
|
Ok(object_args) => object_args,
|
||||||
Err(err) => return err.to_compile_error().into(),
|
Err(err) => return err.to_compile_error().into(),
|
||||||
};
|
};
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
|
||||||
match merged_object::generate(&object_args, &input) {
|
match merged_object::generate(&object_args, &input) {
|
||||||
Ok(expanded) => expanded,
|
Ok(expanded) => expanded,
|
||||||
Err(err) => err.to_compile_error().into(),
|
Err(err) => err.to_compile_error().into(),
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::args;
|
use crate::args;
|
||||||
use crate::utils::{get_crate_name, get_rustdoc};
|
use crate::utils::{get_crate_name, get_rustdoc};
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
use proc_macro2::Span;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::spanned::Spanned;
|
use syn::{Data, DeriveInput, Error, LitInt, Result};
|
||||||
use syn::{Data, DeriveInput, Error, Ident, Result};
|
|
||||||
|
|
||||||
pub fn generate(object_args: &args::Object, input: &DeriveInput) -> Result<TokenStream> {
|
pub fn generate(object_args: &args::Object, input: &DeriveInput) -> Result<TokenStream> {
|
||||||
let crate_name = get_crate_name(object_args.internal);
|
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
|
.name
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| ident.to_string());
|
.unwrap_or_else(|| ident.to_string());
|
||||||
let vis = &input.vis;
|
|
||||||
let attrs = &input.attrs;
|
|
||||||
|
|
||||||
let desc = object_args
|
let desc = object_args
|
||||||
.desc
|
.desc
|
||||||
|
@ -33,23 +31,14 @@ pub fn generate(object_args: &args::Object, input: &DeriveInput) -> Result<Token
|
||||||
types.push(&field.ty);
|
types.push(&field.ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_args = {
|
let create_merged_obj = {
|
||||||
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 mut obj = quote! { #crate_name::MergedObjectTail };
|
let mut obj = quote! { #crate_name::MergedObjectTail };
|
||||||
for (i, ty) in types.iter().enumerate() {
|
for i in 0..types.len() {
|
||||||
let name = Ident::new(&format!("obj{}", i + 1), ty.span());
|
let n = LitInt::new(&format!("{}", i), Span::call_site());
|
||||||
obj = quote! { #crate_name::MergedObject(#name, #obj) };
|
obj = quote! { #crate_name::MergedObject(&self.#n, #obj) };
|
||||||
}
|
}
|
||||||
quote! {
|
quote! {
|
||||||
Self(#obj)
|
#obj
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,15 +51,6 @@ pub fn generate(object_args: &args::Object, input: &DeriveInput) -> Result<Token
|
||||||
};
|
};
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
#(#attrs)*
|
|
||||||
#vis struct #ident(#merged_type);
|
|
||||||
|
|
||||||
impl #ident {
|
|
||||||
pub fn new(#(#new_args),*) -> Self {
|
|
||||||
#new_func
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::all, clippy::pedantic)]
|
#[allow(clippy::all, clippy::pedantic)]
|
||||||
impl #crate_name::Type for #ident {
|
impl #crate_name::Type for #ident {
|
||||||
fn type_name() -> ::std::borrow::Cow<'static, str> {
|
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]
|
#[#crate_name::async_trait::async_trait]
|
||||||
impl #crate_name::ObjectType for #ident {
|
impl #crate_name::ObjectType for #ident {
|
||||||
async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::Result<#crate_name::serde_json::Value> {
|
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> {
|
impl<T: Type + Send + Sync> Type for Box<T> {
|
||||||
fn type_name() -> Cow<'static, str> {
|
fn type_name() -> Cow<'static, str> {
|
||||||
T::type_name()
|
T::type_name()
|
||||||
|
|
|
@ -786,6 +786,9 @@ pub use async_graphql_derive::Scalar;
|
||||||
/// #[MergedObject]
|
/// #[MergedObject]
|
||||||
/// struct MyObj(Object1, Object2, Object3);
|
/// 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;
|
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]
|
#[Object]
|
||||||
impl Query {
|
impl Query {
|
||||||
async fn obj(&self) -> MyObj {
|
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