Impl reflect
traits for objects and interfaces fields, vol.1 [skip ci]
This commit is contained in:
parent
23e01956b3
commit
1819ab6e12
7 changed files with 132 additions and 0 deletions
|
@ -16,6 +16,7 @@ use syn::{
|
|||
|
||||
use crate::{
|
||||
common::{
|
||||
behavior,
|
||||
parse::{
|
||||
attr::{err, OptionExt as _},
|
||||
ParseBufferExt as _, TypeExt as _,
|
||||
|
@ -58,6 +59,19 @@ pub(crate) struct Attr {
|
|||
/// [2]: https://spec.graphql.org/June2018/#sec-Required-Arguments
|
||||
pub(crate) default: Option<SpanContainer<Option<syn::Expr>>>,
|
||||
|
||||
/// Explicitly specified type of the custom [`Behavior`] this
|
||||
/// [GraphQL argument][0] implementation is parametrized with, to [coerce]
|
||||
/// in the generated code from.
|
||||
///
|
||||
/// If [`None`], then [`behavior::Standard`] will be used for the generated
|
||||
/// code.
|
||||
///
|
||||
/// [`Behavior`]: juniper::behavior
|
||||
/// [`behavior::Standard`]: juniper::behavior::Standard
|
||||
/// [0]: https://spec.graphql.org/October2021#sec-Language.Arguments
|
||||
/// [coerce]: juniper::behavior::Coerce
|
||||
pub(crate) behavior: Option<SpanContainer<behavior::Type>>,
|
||||
|
||||
/// Explicitly specified marker indicating that this method argument doesn't
|
||||
/// represent a [GraphQL argument][1], but is a [`Context`] being injected
|
||||
/// into a [GraphQL field][2] resolving function.
|
||||
|
@ -121,6 +135,13 @@ impl Parse for Attr {
|
|||
))
|
||||
.none_or_else(|_| err::dup_arg(&ident))?
|
||||
}
|
||||
"behave" | "behavior" => {
|
||||
input.parse::<token::Eq>()?;
|
||||
let bh = input.parse::<behavior::Type>()?;
|
||||
out.behavior
|
||||
.replace(SpanContainer::new(ident.span(), Some(bh.span()), bh))
|
||||
.none_or_else(|_| err::dup_arg(&ident))?
|
||||
}
|
||||
"ctx" | "context" | "Context" => {
|
||||
let span = ident.span();
|
||||
out.context
|
||||
|
@ -151,6 +172,7 @@ impl Attr {
|
|||
name: try_merge_opt!(name: self, another),
|
||||
description: try_merge_opt!(description: self, another),
|
||||
default: try_merge_opt!(default: self, another),
|
||||
behavior: try_merge_opt!(behavior: self, another),
|
||||
context: try_merge_opt!(context: self, another),
|
||||
executor: try_merge_opt!(executor: self, another),
|
||||
})
|
||||
|
@ -253,6 +275,14 @@ pub(crate) struct OnField {
|
|||
/// [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments
|
||||
/// [2]: https://spec.graphql.org/June2018/#sec-Required-Arguments
|
||||
pub(crate) default: Option<Option<syn::Expr>>,
|
||||
|
||||
/// [`Behavior`] parametrization of this [GraphQL argument][0]
|
||||
/// implementation to [coerce] from in the generated code.
|
||||
///
|
||||
/// [`Behavior`]: juniper::behavior
|
||||
/// [0]: https://spec.graphql.org/October2021#sec-Language.Arguments
|
||||
/// [coerce]: juniper::behavior::Coerce
|
||||
pub(crate) behavior: behavior::Type,
|
||||
}
|
||||
|
||||
/// Possible kinds of Rust method arguments for code generation.
|
||||
|
@ -464,6 +494,7 @@ impl OnMethod {
|
|||
ty: argument.ty.as_ref().clone(),
|
||||
description: attr.description.as_ref().map(|d| d.as_ref().value()),
|
||||
default: attr.default.as_ref().map(|v| v.as_ref().clone()),
|
||||
behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ use syn::{
|
|||
|
||||
use crate::{
|
||||
common::{
|
||||
behavior,
|
||||
parse::{
|
||||
attr::{err, OptionExt as _},
|
||||
ParseBufferExt as _,
|
||||
|
@ -58,6 +59,19 @@ pub(crate) struct Attr {
|
|||
/// [2]: https://spec.graphql.org/June2018/#sec-Deprecation
|
||||
pub(crate) deprecated: Option<SpanContainer<Option<syn::LitStr>>>,
|
||||
|
||||
/// Explicitly specified type of the custom [`Behavior`] this
|
||||
/// [GraphQL field][0] implementation is parametrized with, to [coerce] in
|
||||
/// the generated code from.
|
||||
///
|
||||
/// If [`None`], then [`behavior::Standard`] will be used for the generated
|
||||
/// code.
|
||||
///
|
||||
/// [`Behavior`]: juniper::behavior
|
||||
/// [`behavior::Standard`]: juniper::behavior::Standard
|
||||
/// [0]: https://spec.graphql.org/October2021#sec-Language.Fields
|
||||
/// [coerce]: juniper::behavior::Coerce
|
||||
pub(crate) behavior: Option<SpanContainer<behavior::Type>>,
|
||||
|
||||
/// Explicitly specified marker indicating that this method (or struct
|
||||
/// field) should be omitted by code generation and not considered as the
|
||||
/// [GraphQL field][1] definition.
|
||||
|
@ -100,6 +114,13 @@ impl Parse for Attr {
|
|||
))
|
||||
.none_or_else(|_| err::dup_arg(&ident))?
|
||||
}
|
||||
"behave" | "behavior" => {
|
||||
input.parse::<token::Eq>()?;
|
||||
let bh = input.parse::<behavior::Type>()?;
|
||||
out.behavior
|
||||
.replace(SpanContainer::new(ident.span(), Some(bh.span()), bh))
|
||||
.none_or_else(|_| err::dup_arg(&ident))?
|
||||
}
|
||||
"ignore" | "skip" => out
|
||||
.ignore
|
||||
.replace(SpanContainer::new(ident.span(), None, ident.clone()))
|
||||
|
@ -122,6 +143,7 @@ impl Attr {
|
|||
name: try_merge_opt!(name: self, another),
|
||||
description: try_merge_opt!(description: self, another),
|
||||
deprecated: try_merge_opt!(deprecated: self, another),
|
||||
behavior: try_merge_opt!(behavior: self, another),
|
||||
ignore: try_merge_opt!(ignore: self, another),
|
||||
})
|
||||
}
|
||||
|
@ -199,6 +221,14 @@ pub(crate) struct Definition {
|
|||
/// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
|
||||
pub(crate) ident: syn::Ident,
|
||||
|
||||
/// [`Behavior`] parametrization of this [GraphQL field][0] implementation
|
||||
/// to [coerce] from in the generated code.
|
||||
///
|
||||
/// [`Behavior`]: juniper::behavior
|
||||
/// [0]: https://spec.graphql.org/October2021#sec-Language.Fields
|
||||
/// [coerce]: juniper::behavior::Coerce
|
||||
pub(crate) behavior: behavior::Type,
|
||||
|
||||
/// Rust [`MethodArgument`]s required to call the method representing this
|
||||
/// [GraphQL field][1].
|
||||
///
|
||||
|
|
|
@ -212,6 +212,7 @@ fn parse_trait_method(
|
|||
description,
|
||||
deprecated,
|
||||
ident: method_ident.clone(),
|
||||
behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
|
||||
arguments: Some(arguments),
|
||||
has_receiver: method.sig.receiver().is_some(),
|
||||
is_async: method.sig.asyncness.is_some(),
|
||||
|
@ -375,6 +376,7 @@ fn parse_struct_field(field: &mut syn::Field, renaming: &RenameRule) -> Option<f
|
|||
description,
|
||||
deprecated,
|
||||
ident: field_ident.clone(),
|
||||
behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
|
||||
arguments: None,
|
||||
has_receiver: false,
|
||||
is_async: false,
|
||||
|
|
|
@ -154,6 +154,7 @@ fn parse_field(field: &syn::Field, renaming: &RenameRule) -> Option<field::Defin
|
|||
description,
|
||||
deprecated,
|
||||
ident: field_ident.clone(),
|
||||
behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
|
||||
arguments: None,
|
||||
has_receiver: false,
|
||||
is_async: false,
|
||||
|
|
|
@ -229,6 +229,7 @@ fn parse_field(
|
|||
description,
|
||||
deprecated,
|
||||
ident: method_ident.clone(),
|
||||
behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
|
||||
arguments: Some(arguments),
|
||||
has_receiver: method.sig.receiver().is_some(),
|
||||
is_async: method.sig.asyncness.is_some(),
|
||||
|
|
|
@ -154,6 +154,7 @@ fn parse_field(field: &syn::Field, renaming: &RenameRule) -> Option<field::Defin
|
|||
description,
|
||||
deprecated,
|
||||
ident: field_ident.clone(),
|
||||
behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(),
|
||||
arguments: None,
|
||||
has_receiver: false,
|
||||
is_async: false,
|
||||
|
|
|
@ -519,6 +519,70 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns generated code implementing [`reflect::Field`] trait for each
|
||||
/// [field][1] of this [GraphQL object][0].
|
||||
///
|
||||
/// [`reflect::Field`]: juniper::reflect::Field
|
||||
/// [0]: https://spec.graphql.org/October2021#sec-Objects
|
||||
/// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
|
||||
#[must_use]
|
||||
pub(crate) fn impl_reflect_field(&self) -> TokenStream {
|
||||
let bh = &self.behavior;
|
||||
let (ty, generics) = self.ty_and_generics();
|
||||
let (impl_gens, _, where_clause) = generics.split_for_impl();
|
||||
|
||||
self.fields
|
||||
.iter()
|
||||
.map(|field| {
|
||||
let (f_name, f_ty, f_bh) = (&field.name, &field.ty, &field.behavior);
|
||||
|
||||
let arguments = field
|
||||
.arguments
|
||||
.as_ref()
|
||||
.iter()
|
||||
.flat_map(|vec| vec.iter().filter_map(field::MethodArgument::as_regular))
|
||||
.map(|arg| {
|
||||
let (a_name, a_ty, a_bh) = (&arg.name, &arg.ty, &arg.behavior);
|
||||
|
||||
quote! {(
|
||||
#a_name,
|
||||
<#a_ty as ::juniper::reflect::BaseType<#a_bh>>
|
||||
::NAME,
|
||||
<#a_ty as ::juniper::reflect::WrappedType<#a_bh>>
|
||||
::VALUE,
|
||||
)}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
#[allow(deprecated, non_snake_case)]
|
||||
#[automatically_derived]
|
||||
impl#impl_gens ::juniper::reflect::Field<
|
||||
{ ::juniper::reflect::fnv1a128(#f_name) }, #bh,
|
||||
> for #ty #where_clause {
|
||||
const TYPE: ::juniper::reflect::Type =
|
||||
<#f_ty as ::juniper::reflect::BaseType<#f_bh>>
|
||||
::NAME;
|
||||
|
||||
const SUB_TYPES: ::juniper::reflect::Types =
|
||||
<#f_ty as ::juniper::reflect::BaseSubTypes<#f_bh>>
|
||||
::NAMES;
|
||||
|
||||
const WRAPPED_VALUE: juniper::reflect::WrappedValue =
|
||||
<#f_ty as ::juniper::reflect::WrappedType<#f_bh>>
|
||||
::VALUE;
|
||||
|
||||
const ARGUMENTS: &'static [(
|
||||
::juniper::reflect::Name,
|
||||
::juniper::reflect::Type,
|
||||
::juniper::reflect::WrappedValue,
|
||||
)] = &[#( #arguments ),*];
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Returns generated code implementing [`GraphQLType`] trait for this
|
||||
/// [GraphQL object][1].
|
||||
///
|
||||
|
@ -602,6 +666,8 @@ impl ToTokens for Definition<Query> {
|
|||
self.impl_async_field_tokens().to_tokens(into);
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
self.impl_reflect().to_tokens(into);
|
||||
self.impl_reflect_field().to_tokens(into);
|
||||
//self.impl_resolve_field_static().to_tokens(into);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue