add feature attribute to field attribute inside Object (#153)

* add feature support in field attribute
This commit is contained in:
Coenen Benjamin 2020-06-05 15:06:53 +02:00 committed by GitHub
parent 076ccf4708
commit 614fb89703
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 0 deletions

View File

@ -200,6 +200,7 @@ pub struct Field {
pub is_ref: bool,
pub guard: Option<TokenStream>,
pub post_guard: Option<TokenStream>,
pub features: Vec<String>,
}
impl Field {
@ -211,6 +212,7 @@ impl Field {
let mut external = false;
let mut provides = None;
let mut requires = None;
let mut features = Vec::new();
let mut is_ref = false;
let mut guard = None;
let mut post_guard = None;
@ -277,6 +279,21 @@ impl Field {
"Attribute 'requires' should be a string.",
));
}
} else if nv.path.is_ident("feature") {
if let syn::Lit::Str(lit) = &nv.lit {
features = lit
.value()
.to_string()
.split(',')
.into_iter()
.map(|s| s.trim().to_string())
.collect();
} else {
return Err(Error::new_spanned(
&nv.lit,
"Attribute 'feature' should be a string.",
));
}
}
}
NestedMeta::Meta(Meta::List(ls)) => {
@ -307,6 +324,7 @@ impl Field {
is_ref,
guard,
post_guard,
features,
}))
}
}

View File

@ -200,6 +200,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
.map(|s| quote! {Some(#s)})
.unwrap_or_else(|| quote! {None});
let external = field.external;
let features = field.features;
let requires = match &field.requires {
Some(requires) => quote! { Some(#requires) },
None => quote! { None },
@ -365,6 +366,26 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
)
.expect("invalid result type");
}
if !features.is_empty() {
let block = &method.block;
let error_message = format!(
"`{}` is only available if the features `{}` are enabled",
field_name,
features.join(",")
);
let new_block = quote!({
#[cfg(not(all(#(feature = #features),*)))]
{
return Err(#crate_name::FieldError::from(#error_message)).map_err(std::convert::Into::into);
}
#[cfg(all(#(feature = #features),*))]
{
#block
}
});
method.block = syn::parse2::<Block>(new_block).expect("invalid block");
}
let resolve_obj = quote! {
{
let res = self.#field_ident(ctx, #(#use_params),*).await;

View File

@ -59,6 +59,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
.as_ref()
.map(|s| quote! {Some(#s)})
.unwrap_or_else(|| quote! {None});
let features = field.features;
if method.sig.asyncness.is_none() {
return Err(Error::new_spanned(
@ -205,6 +206,27 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
.expect("invalid result type");
}
if !features.is_empty() {
let block = &method.block;
let error_message = format!(
"`{}` is only available if the features `{}` are enabled",
field_name,
features.join(",")
);
let new_block = quote!({
#[cfg(not(all(#(feature = #features),*)))]
{
return Err(#crate_name::FieldError::from(#error_message)).map_err(std::convert::Into::into);
}
#[cfg(all(#(feature = #features),*))]
{
#block
}
});
method.block = syn::parse2::<Block>(new_block).expect("invalid block");
}
schema_fields.push(quote! {
fields.insert(#field_name.to_string(), #crate_name::registry::MetaField {
name: #field_name.to_string(),

View File

@ -204,6 +204,7 @@ pub use types::{EnumItem, EnumType};
/// | provides | Annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. | string | Y |
/// | requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y |
/// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y |
/// | feature | It's like a `#[cfg(feature = "foo")]` attribute but instead of not compiling this field it will just return a proper `FieldError` to tell you this feature is not enabled | string ("feature1,feature2") | Y |
///
/// # Field argument parameters
///
@ -655,6 +656,7 @@ pub use async_graphql_derive::Union;
/// | desc | Field description | string | Y |
/// | deprecation | Field deprecation reason | string | Y |
/// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y |
/// | feature | It's like a `#[cfg(feature = "foo")]` attribute but instead of not compiling this field it will just return a proper `FieldError` to tell you this feature is not enabled | string ("feature1,feature2") | Y |
///
/// # Field argument parameters
///