Add visible
attributes on types, fields, and parameters, allowing some content to be hidden based on conditions.
This commit is contained in:
parent
5c39d0197d
commit
ba23761cb4
|
@ -2,7 +2,7 @@ use darling::ast::{Data, Fields};
|
|||
use darling::util::Ignored;
|
||||
use darling::{FromDeriveInput, FromField, FromMeta, FromVariant};
|
||||
use inflector::Inflector;
|
||||
use syn::{Attribute, Generics, Ident, Lit, LitStr, Meta, Type, Visibility};
|
||||
use syn::{Attribute, Generics, Ident, Lit, LitBool, LitStr, Meta, Type, Visibility};
|
||||
|
||||
#[derive(FromMeta)]
|
||||
#[darling(default)]
|
||||
|
@ -44,6 +44,24 @@ impl FromMeta for DefaultValue {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Visible {
|
||||
None,
|
||||
HiddenAlways,
|
||||
FnName(String),
|
||||
}
|
||||
|
||||
impl FromMeta for Visible {
|
||||
fn from_value(value: &Lit) -> darling::Result<Self> {
|
||||
match value {
|
||||
Lit::Bool(LitBool { value: true, .. }) => Ok(Visible::None),
|
||||
Lit::Bool(LitBool { value: false, .. }) => Ok(Visible::HiddenAlways),
|
||||
Lit::Str(str) => Ok(Visible::FnName(str.value())),
|
||||
_ => Err(darling::Error::unexpected_lit_type(value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromField)]
|
||||
#[darling(attributes(graphql), forward_attrs(doc))]
|
||||
pub struct SimpleObjectField {
|
||||
|
@ -70,6 +88,8 @@ pub struct SimpleObjectField {
|
|||
pub requires: Option<String>,
|
||||
#[darling(default)]
|
||||
pub guard: Option<Meta>,
|
||||
#[darling(default)]
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromDeriveInput)]
|
||||
|
@ -94,6 +114,8 @@ pub struct SimpleObject {
|
|||
pub cache_control: CacheControl,
|
||||
#[darling(default)]
|
||||
pub extends: bool,
|
||||
#[darling(default)]
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromMeta, Default)]
|
||||
|
@ -105,6 +127,7 @@ pub struct Argument {
|
|||
pub default_with: Option<LitStr>,
|
||||
pub validator: Option<Meta>,
|
||||
pub key: bool, // for entity
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromMeta, Default)]
|
||||
|
@ -117,6 +140,7 @@ pub struct Object {
|
|||
pub cache_control: CacheControl,
|
||||
pub extends: bool,
|
||||
pub use_type_description: bool,
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromMeta, Default)]
|
||||
|
@ -131,6 +155,7 @@ pub struct ObjectField {
|
|||
pub provides: Option<String>,
|
||||
pub requires: Option<String>,
|
||||
pub guard: Option<Meta>,
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromDeriveInput)]
|
||||
|
@ -149,6 +174,8 @@ pub struct Enum {
|
|||
pub rename_items: Option<RenameRule>,
|
||||
#[darling(default)]
|
||||
pub remote: Option<String>,
|
||||
#[darling(default)]
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromVariant)]
|
||||
|
@ -162,6 +189,8 @@ pub struct EnumItem {
|
|||
pub name: Option<String>,
|
||||
#[darling(default)]
|
||||
pub deprecation: Option<String>,
|
||||
#[darling(default)]
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromDeriveInput)]
|
||||
|
@ -176,6 +205,8 @@ pub struct Union {
|
|||
pub internal: bool,
|
||||
#[darling(default)]
|
||||
pub name: Option<String>,
|
||||
#[darling(default)]
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromVariant)]
|
||||
|
@ -206,6 +237,8 @@ pub struct InputObjectField {
|
|||
pub validator: Option<Meta>,
|
||||
#[darling(default)]
|
||||
pub flatten: bool,
|
||||
#[darling(default)]
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromDeriveInput)]
|
||||
|
@ -222,6 +255,8 @@ pub struct InputObject {
|
|||
pub name: Option<String>,
|
||||
#[darling(default)]
|
||||
pub rename_fields: Option<RenameRule>,
|
||||
#[darling(default)]
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromMeta)]
|
||||
|
@ -235,6 +270,8 @@ pub struct InterfaceFieldArgument {
|
|||
pub default: Option<DefaultValue>,
|
||||
#[darling(default)]
|
||||
pub default_with: Option<LitStr>,
|
||||
#[darling(default)]
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromMeta)]
|
||||
|
@ -256,6 +293,8 @@ pub struct InterfaceField {
|
|||
pub provides: Option<String>,
|
||||
#[darling(default)]
|
||||
pub requires: Option<String>,
|
||||
#[darling(default)]
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromVariant)]
|
||||
|
@ -284,6 +323,8 @@ pub struct Interface {
|
|||
pub fields: Vec<InterfaceField>,
|
||||
#[darling(default)]
|
||||
pub extends: bool,
|
||||
#[darling(default)]
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromMeta, Default)]
|
||||
|
@ -292,6 +333,7 @@ pub struct Scalar {
|
|||
pub internal: bool,
|
||||
pub name: Option<String>,
|
||||
pub use_type_description: bool,
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromMeta, Default)]
|
||||
|
@ -312,6 +354,7 @@ pub struct SubscriptionFieldArgument {
|
|||
pub default: Option<DefaultValue>,
|
||||
pub default_with: Option<LitStr>,
|
||||
pub validator: Option<Meta>,
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromMeta, Default)]
|
||||
|
@ -321,6 +364,7 @@ pub struct SubscriptionField {
|
|||
pub name: Option<String>,
|
||||
pub deprecation: Option<String>,
|
||||
pub guard: Option<Meta>,
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromField)]
|
||||
|
@ -345,6 +389,8 @@ pub struct MergedObject {
|
|||
pub cache_control: CacheControl,
|
||||
#[darling(default)]
|
||||
pub extends: bool,
|
||||
#[darling(default)]
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(FromField)]
|
||||
|
@ -365,6 +411,8 @@ pub struct MergedSubscription {
|
|||
pub internal: bool,
|
||||
#[darling(default)]
|
||||
pub name: Option<String>,
|
||||
#[darling(default)]
|
||||
pub visible: Option<Visible>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, FromMeta)]
|
||||
|
|
|
@ -5,7 +5,7 @@ use syn::ext::IdentExt;
|
|||
use syn::Error;
|
||||
|
||||
use crate::args::{self, RenameRuleExt, RenameTarget};
|
||||
use crate::utils::{get_crate_name, get_rustdoc, GeneratorResult};
|
||||
use crate::utils::{get_crate_name, get_rustdoc, visible_fn, GeneratorResult};
|
||||
|
||||
pub fn generate(enum_args: &args::Enum) -> GeneratorResult<TokenStream> {
|
||||
let crate_name = get_crate_name(enum_args.internal);
|
||||
|
@ -62,11 +62,14 @@ pub fn generate(enum_args: &args::Enum) -> GeneratorResult<TokenStream> {
|
|||
value: #ident::#item_ident,
|
||||
}
|
||||
});
|
||||
|
||||
let visible = visible_fn(&variant.visible);
|
||||
schema_enum_items.push(quote! {
|
||||
enum_items.insert(#gql_item_name, #crate_name::registry::MetaEnumValue {
|
||||
name: #gql_item_name,
|
||||
description: #item_desc,
|
||||
deprecation: #item_deprecation,
|
||||
visible: #visible,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -119,6 +122,7 @@ pub fn generate(enum_args: &args::Enum) -> GeneratorResult<TokenStream> {
|
|||
.into());
|
||||
}
|
||||
|
||||
let visible = visible_fn(&enum_args.visible);
|
||||
let expanded = quote! {
|
||||
#[allow(clippy::all, clippy::pedantic)]
|
||||
impl #crate_name::resolver_utils::EnumType for #ident {
|
||||
|
@ -143,6 +147,7 @@ pub fn generate(enum_args: &args::Enum) -> GeneratorResult<TokenStream> {
|
|||
#(#schema_enum_items)*
|
||||
enum_items
|
||||
},
|
||||
visible: #visible,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use syn::Error;
|
|||
|
||||
use crate::args::{self, RenameRuleExt, RenameTarget};
|
||||
use crate::utils::{
|
||||
generate_default, generate_validator, get_crate_name, get_rustdoc, GeneratorResult,
|
||||
generate_default, generate_validator, get_crate_name, get_rustdoc, visible_fn, GeneratorResult,
|
||||
};
|
||||
|
||||
pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream> {
|
||||
|
@ -140,6 +140,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
|
|||
});
|
||||
|
||||
fields.push(ident);
|
||||
let visible = visible_fn(&field.visible);
|
||||
schema_fields.push(quote! {
|
||||
fields.insert(::std::borrow::ToOwned::to_owned(#name), #crate_name::registry::MetaInputValue {
|
||||
name: #name,
|
||||
|
@ -147,6 +148,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
|
|||
ty: <#ty as #crate_name::Type>::create_type_info(registry),
|
||||
default_value: #schema_default,
|
||||
validator: #validator,
|
||||
visible: #visible,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
@ -159,6 +161,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
|
|||
.into());
|
||||
}
|
||||
|
||||
let visible = visible_fn(&object_args.visible);
|
||||
let expanded = quote! {
|
||||
#[allow(clippy::all, clippy::pedantic)]
|
||||
impl #crate_name::Type for #ident {
|
||||
|
@ -174,7 +177,8 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
|
|||
let mut fields = #crate_name::indexmap::IndexMap::new();
|
||||
#(#schema_fields)*
|
||||
fields
|
||||
}
|
||||
},
|
||||
visible: #visible,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use syn::{visit_mut, Error, Lifetime, Type};
|
|||
|
||||
use crate::args::{self, InterfaceField, InterfaceFieldArgument, RenameRuleExt, RenameTarget};
|
||||
use crate::output_type::OutputType;
|
||||
use crate::utils::{generate_default, get_crate_name, get_rustdoc, GeneratorResult};
|
||||
use crate::utils::{generate_default, get_crate_name, get_rustdoc, visible_fn, GeneratorResult};
|
||||
|
||||
pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream> {
|
||||
let crate_name = get_crate_name(interface_args.internal);
|
||||
|
@ -139,6 +139,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
|
|||
external,
|
||||
provides,
|
||||
requires,
|
||||
visible,
|
||||
} in &interface_args.fields
|
||||
{
|
||||
let (name, method_name) = if let Some(method) = method {
|
||||
|
@ -179,6 +180,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
|
|||
ty,
|
||||
default,
|
||||
default_with,
|
||||
visible,
|
||||
} in args
|
||||
{
|
||||
let ident = Ident::new(name, Span::call_site());
|
||||
|
@ -215,6 +217,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
|
|||
}
|
||||
})
|
||||
.unwrap_or_else(|| quote! {::std::option::Option::None});
|
||||
let visible = visible_fn(&visible);
|
||||
schema_args.push(quote! {
|
||||
args.insert(#name, #crate_name::registry::MetaInputValue {
|
||||
name: #name,
|
||||
|
@ -222,6 +225,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
|
|||
ty: <#ty as #crate_name::Type>::create_type_info(registry),
|
||||
default_value: #schema_default,
|
||||
validator: ::std::option::Option::None,
|
||||
visible: #visible,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -257,6 +261,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
|
|||
}
|
||||
});
|
||||
|
||||
let visible = visible_fn(&visible);
|
||||
schema_fields.push(quote! {
|
||||
fields.insert(::std::string::ToString::to_string(#name), #crate_name::registry::MetaField {
|
||||
name: ::std::string::ToString::to_string(#name),
|
||||
|
@ -272,6 +277,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
|
|||
external: #external,
|
||||
provides: #provides,
|
||||
requires: #requires,
|
||||
visible: #visible,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -300,6 +306,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
|
|||
}
|
||||
};
|
||||
|
||||
let visible = visible_fn(&interface_args.visible);
|
||||
let expanded = quote! {
|
||||
#(#type_into_impls)*
|
||||
|
||||
|
@ -337,6 +344,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
|
|||
},
|
||||
extends: #extends,
|
||||
keys: ::std::option::Option::None,
|
||||
visible: #visible,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use quote::quote;
|
|||
use syn::{Error, LitInt};
|
||||
|
||||
use crate::args::{self, RenameTarget};
|
||||
use crate::utils::{get_crate_name, get_rustdoc, GeneratorResult};
|
||||
use crate::utils::{get_crate_name, get_rustdoc, visible_fn, GeneratorResult};
|
||||
|
||||
pub fn generate(object_args: &args::MergedObject) -> GeneratorResult<TokenStream> {
|
||||
let crate_name = get_crate_name(object_args.internal);
|
||||
|
@ -55,6 +55,7 @@ pub fn generate(object_args: &args::MergedObject) -> GeneratorResult<TokenStream
|
|||
obj
|
||||
};
|
||||
|
||||
let visible = visible_fn(&object_args.visible);
|
||||
let expanded = quote! {
|
||||
#[allow(clippy::all, clippy::pedantic)]
|
||||
impl #generics #crate_name::Type for #ident #generics #where_clause {
|
||||
|
@ -83,6 +84,7 @@ pub fn generate(object_args: &args::MergedObject) -> GeneratorResult<TokenStream
|
|||
cache_control,
|
||||
extends: #extends,
|
||||
keys: ::std::option::Option::None,
|
||||
visible: #visible,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use quote::quote;
|
|||
use syn::{Error, LitInt};
|
||||
|
||||
use crate::args::{self, RenameTarget};
|
||||
use crate::utils::{get_crate_name, get_rustdoc, GeneratorResult};
|
||||
use crate::utils::{get_crate_name, get_rustdoc, visible_fn, GeneratorResult};
|
||||
|
||||
pub fn generate(object_args: &args::MergedSubscription) -> GeneratorResult<TokenStream> {
|
||||
let crate_name = get_crate_name(object_args.internal);
|
||||
|
@ -44,6 +44,7 @@ pub fn generate(object_args: &args::MergedSubscription) -> GeneratorResult<Token
|
|||
|obj, ty| quote!(#crate_name::MergedObject::<#ty, #obj>),
|
||||
);
|
||||
|
||||
let visible = visible_fn(&object_args.visible);
|
||||
let expanded = quote! {
|
||||
#[allow(clippy::all, clippy::pedantic)]
|
||||
impl #crate_name::Type for #ident {
|
||||
|
@ -69,6 +70,7 @@ pub fn generate(object_args: &args::MergedSubscription) -> GeneratorResult<Token
|
|||
cache_control: ::std::default::Default::default(),
|
||||
extends: false,
|
||||
keys: ::std::option::Option::None,
|
||||
visible: #visible,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::output_type::OutputType;
|
|||
use crate::utils::{
|
||||
generate_default, generate_guards, generate_validator, get_cfg_attrs, get_crate_name,
|
||||
get_param_getter_ident, get_rustdoc, get_type_path_and_name, parse_graphql_attrs,
|
||||
remove_graphql_attrs, GeneratorResult,
|
||||
remove_graphql_attrs, visible_fn, GeneratorResult,
|
||||
};
|
||||
|
||||
pub fn generate(
|
||||
|
@ -319,6 +319,7 @@ pub fn generate(
|
|||
default,
|
||||
default_with,
|
||||
validator,
|
||||
visible,
|
||||
..
|
||||
},
|
||||
) in args
|
||||
|
@ -352,6 +353,7 @@ pub fn generate(
|
|||
None => quote!(::std::option::Option::None),
|
||||
};
|
||||
|
||||
let visible = visible_fn(&visible);
|
||||
schema_args.push(quote! {
|
||||
args.insert(#name, #crate_name::registry::MetaInputValue {
|
||||
name: #name,
|
||||
|
@ -359,6 +361,7 @@ pub fn generate(
|
|||
ty: <#ty as #crate_name::Type>::create_type_info(registry),
|
||||
default_value: #schema_default,
|
||||
validator: #validator,
|
||||
visible: #visible,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -381,6 +384,7 @@ pub fn generate(
|
|||
}
|
||||
|
||||
let schema_ty = ty.value_type();
|
||||
let visible = visible_fn(&method_args.visible);
|
||||
|
||||
schema_fields.push(quote! {
|
||||
#(#cfg_attrs)*
|
||||
|
@ -398,6 +402,7 @@ pub fn generate(
|
|||
external: #external,
|
||||
provides: #provides,
|
||||
requires: #requires,
|
||||
visible: #visible,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -473,6 +478,7 @@ pub fn generate(
|
|||
.into());
|
||||
}
|
||||
|
||||
let visible = visible_fn(&object_args.visible);
|
||||
let expanded = quote! {
|
||||
#item_impl
|
||||
|
||||
|
@ -494,6 +500,7 @@ pub fn generate(
|
|||
cache_control: #cache_control,
|
||||
extends: #extends,
|
||||
keys: ::std::option::Option::None,
|
||||
visible: #visible,
|
||||
});
|
||||
#(#create_entity_types)*
|
||||
#(#add_keys)*
|
||||
|
|
|
@ -3,7 +3,9 @@ use quote::quote;
|
|||
use syn::ItemImpl;
|
||||
|
||||
use crate::args::{self, RenameTarget};
|
||||
use crate::utils::{get_crate_name, get_rustdoc, get_type_path_and_name, GeneratorResult};
|
||||
use crate::utils::{
|
||||
get_crate_name, get_rustdoc, get_type_path_and_name, visible_fn, GeneratorResult,
|
||||
};
|
||||
|
||||
pub fn generate(
|
||||
scalar_args: &args::Scalar,
|
||||
|
@ -27,6 +29,7 @@ pub fn generate(
|
|||
let self_ty = &item_impl.self_ty;
|
||||
let generic = &item_impl.generics;
|
||||
let where_clause = &item_impl.generics.where_clause;
|
||||
let visible = visible_fn(&scalar_args.visible);
|
||||
let expanded = quote! {
|
||||
#item_impl
|
||||
|
||||
|
@ -41,6 +44,7 @@ pub fn generate(
|
|||
name: ::std::borrow::ToOwned::to_owned(#gql_typename),
|
||||
description: #desc,
|
||||
is_valid: |value| <#self_ty as #crate_name::ScalarType>::is_valid(value),
|
||||
visible: #visible,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use syn::ext::IdentExt;
|
|||
use syn::Error;
|
||||
|
||||
use crate::args::{self, RenameRuleExt, RenameTarget};
|
||||
use crate::utils::{generate_guards, get_crate_name, get_rustdoc, GeneratorResult};
|
||||
use crate::utils::{generate_guards, get_crate_name, get_rustdoc, visible_fn, GeneratorResult};
|
||||
|
||||
pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream> {
|
||||
let crate_name = get_crate_name(object_args.internal);
|
||||
|
@ -81,6 +81,8 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
|
|||
}
|
||||
};
|
||||
|
||||
let visible = visible_fn(&field.visible);
|
||||
|
||||
schema_fields.push(quote! {
|
||||
fields.insert(::std::borrow::ToOwned::to_owned(#field_name), #crate_name::registry::MetaField {
|
||||
name: ::std::borrow::ToOwned::to_owned(#field_name),
|
||||
|
@ -92,6 +94,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
|
|||
external: #external,
|
||||
provides: #provides,
|
||||
requires: #requires,
|
||||
visible: #visible,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -148,6 +151,8 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
|
|||
}
|
||||
};
|
||||
|
||||
let visible = visible_fn(&object_args.visible);
|
||||
|
||||
let expanded = quote! {
|
||||
#[allow(clippy::all, clippy::pedantic)]
|
||||
impl #generics #ident #generics #where_clause {
|
||||
|
@ -172,6 +177,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
|
|||
cache_control: #cache_control,
|
||||
extends: #extends,
|
||||
keys: ::std::option::Option::None,
|
||||
visible: #visible,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::output_type::OutputType;
|
|||
use crate::utils::{
|
||||
generate_default, generate_guards, generate_validator, get_cfg_attrs, get_crate_name,
|
||||
get_param_getter_ident, get_rustdoc, get_type_path_and_name, parse_graphql_attrs,
|
||||
remove_graphql_attrs, GeneratorResult,
|
||||
remove_graphql_attrs, visible_fn, GeneratorResult,
|
||||
};
|
||||
|
||||
pub fn generate(
|
||||
|
@ -150,6 +150,7 @@ pub fn generate(
|
|||
default,
|
||||
default_with,
|
||||
validator,
|
||||
visible: arg_visible,
|
||||
},
|
||||
) in args
|
||||
{
|
||||
|
@ -183,6 +184,7 @@ pub fn generate(
|
|||
})
|
||||
.unwrap_or_else(|| quote! {::std::option::Option::None});
|
||||
|
||||
let visible = visible_fn(&arg_visible);
|
||||
schema_args.push(quote! {
|
||||
args.insert(#name, #crate_name::registry::MetaInputValue {
|
||||
name: #name,
|
||||
|
@ -190,6 +192,7 @@ pub fn generate(
|
|||
ty: <#ty as #crate_name::Type>::create_type_info(registry),
|
||||
default_value: #schema_default,
|
||||
validator: #validator,
|
||||
visible: #visible,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -235,6 +238,7 @@ pub fn generate(
|
|||
.expect("invalid result type");
|
||||
}
|
||||
|
||||
let visible = visible_fn(&field.visible);
|
||||
schema_fields.push(quote! {
|
||||
#(#cfg_attrs)*
|
||||
fields.insert(::std::borrow::ToOwned::to_owned(#field_name), #crate_name::registry::MetaField {
|
||||
|
@ -251,6 +255,7 @@ pub fn generate(
|
|||
external: false,
|
||||
requires: ::std::option::Option::None,
|
||||
provides: ::std::option::Option::None,
|
||||
visible: #visible,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -388,6 +393,7 @@ pub fn generate(
|
|||
cache_control: ::std::default::Default::default(),
|
||||
extends: false,
|
||||
keys: ::std::option::Option::None,
|
||||
visible: ::std::option::Option::None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use syn::visit_mut::VisitMut;
|
|||
use syn::{visit_mut, Error, Lifetime, Type};
|
||||
|
||||
use crate::args::{self, RenameTarget};
|
||||
use crate::utils::{get_crate_name, get_rustdoc, GeneratorResult};
|
||||
use crate::utils::{get_crate_name, get_rustdoc, visible_fn, GeneratorResult};
|
||||
|
||||
pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
|
||||
let crate_name = get_crate_name(union_args.internal);
|
||||
|
@ -148,6 +148,7 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
|
|||
.into());
|
||||
}
|
||||
|
||||
let visible = visible_fn(&union_args.visible);
|
||||
let expanded = quote! {
|
||||
#(#type_into_impls)*
|
||||
|
||||
|
@ -174,7 +175,8 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
|
|||
let mut possible_types = #crate_name::indexmap::IndexSet::new();
|
||||
#(#possible_types)*
|
||||
possible_types
|
||||
}
|
||||
},
|
||||
visible: #visible,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ use syn::{
|
|||
use thiserror::Error;
|
||||
|
||||
use crate::args;
|
||||
use crate::args::Visible;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum GeneratorError {
|
||||
|
@ -389,3 +390,14 @@ pub fn get_type_path_and_name(ty: &Type) -> GeneratorResult<(&TypePath, String)>
|
|||
_ => Err(Error::new_spanned(ty, "Invalid type").into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visible_fn(visible: &Option<Visible>) -> TokenStream {
|
||||
match visible {
|
||||
None | Some(Visible::None) => quote! { ::std::option::Option::None },
|
||||
Some(Visible::HiddenAlways) => quote! { ::std::option::Option::Some(|_| false) },
|
||||
Some(Visible::FnName(name)) => {
|
||||
let ident = Ident::new(name, Span::call_site());
|
||||
quote! { ::std::option::Option::Some(#ident) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
32
src/lib.rs
32
src/lib.rs
|
@ -244,6 +244,8 @@ pub type FieldResult<T> = Result<T>;
|
|||
/// | cache_control | Object cache control | [`CacheControl`](struct.CacheControl.html) | Y |
|
||||
/// | extends | Add fields to an entity that's defined in another service | bool | Y |
|
||||
/// | use_type_description | Specifies that the description of the type is on the type declaration. [`Description`]()(derive.Description.html) | bool | Y |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Field parameters
|
||||
///
|
||||
|
@ -258,6 +260,8 @@ pub type FieldResult<T> = Result<T>;
|
|||
/// | 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 |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Field argument parameters
|
||||
///
|
||||
|
@ -270,6 +274,8 @@ pub type FieldResult<T> = Result<T>;
|
|||
/// | default_with | Expression to generate default value | code string | Y |
|
||||
/// | validator | Input value validator | [`InputValueValidator`](validators/trait.InputValueValidator.html) | Y |
|
||||
/// | key | Is entity key | bool | Y |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Valid field return types
|
||||
///
|
||||
|
@ -360,6 +366,8 @@ pub use async_graphql_derive::Object;
|
|||
/// | rename_fields | Rename all the fields according to the given case convention. The possible values are "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE".| string | Y |
|
||||
/// | cache_control | Object cache control | [`CacheControl`](struct.CacheControl.html) | Y |
|
||||
/// | extends | Add fields to an entity that's defined in another service | bool | Y |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Field parameters
|
||||
///
|
||||
|
@ -374,6 +382,8 @@ pub use async_graphql_derive::Object;
|
|||
/// | 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 |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -406,6 +416,8 @@ pub use async_graphql_derive::SimpleObject;
|
|||
/// | name | Enum name | string | Y |
|
||||
/// | rename_items | Rename all the fields according to the given case convention. The possible values are "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE".| string | Y |
|
||||
/// | remote | Derive a remote enum | string | Y |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Item parameters
|
||||
///
|
||||
|
@ -413,6 +425,8 @@ pub use async_graphql_derive::SimpleObject;
|
|||
/// |-------------|---------------------------|----------|----------|
|
||||
/// | name | Item name | string | Y |
|
||||
/// | deprecation | Item deprecation reason | string | Y |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -461,6 +475,8 @@ pub use async_graphql_derive::Enum;
|
|||
/// |---------------|---------------------------|----------|----------|
|
||||
/// | name | Object name | string | Y |
|
||||
/// | rename_fields | Rename all the fields according to the given case convention. The possible values are "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE".| string | Y |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Field parameters
|
||||
///
|
||||
|
@ -472,6 +488,8 @@ pub use async_graphql_derive::Enum;
|
|||
/// | default_with | Expression to generate default value | code string | Y |
|
||||
/// | validator | Input value validator | [`InputValueValidator`](validators/trait.InputValueValidator.html) | Y |
|
||||
/// | flatten | Similar to serde (flatten) | boolean | Y |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -520,6 +538,8 @@ pub use async_graphql_derive::InputObject;
|
|||
/// | rename_args | Rename all the arguments according to the given case convention. The possible values are "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE".| string | Y |
|
||||
/// | field | Fields of this Interface | [InterfaceField] | N |
|
||||
/// | extends | Add fields to an entity that's defined in another service | bool | Y |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Field parameters
|
||||
///
|
||||
|
@ -534,6 +554,8 @@ pub use async_graphql_derive::InputObject;
|
|||
/// | external | Mark a field as owned by another service. This allows service A to use fields from service B while also knowing at runtime the types of that field. | bool | Y |
|
||||
/// | 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 |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Field argument parameters
|
||||
///
|
||||
|
@ -545,6 +567,8 @@ pub use async_graphql_derive::InputObject;
|
|||
/// | default | Use `Default::default` for default value | none | Y |
|
||||
/// | default | Argument default value | literal | Y |
|
||||
/// | default_with | Expression to generate default value | code string | Y |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Define an interface
|
||||
///
|
||||
|
@ -650,6 +674,8 @@ pub use async_graphql_derive::Interface;
|
|||
/// | Attribute | description | Type | Optional |
|
||||
/// |-------------|---------------------------|----------|----------|
|
||||
/// | name | Object name | string | Y |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Item parameters
|
||||
///
|
||||
|
@ -737,6 +763,8 @@ pub use async_graphql_derive::Union;
|
|||
/// | name | Field name | string | Y |
|
||||
/// | deprecation | Field deprecation reason | string | Y |
|
||||
/// | guard | Field of guard | [`Guard`](guard/trait.Guard.html) | Y |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Field argument parameters
|
||||
///
|
||||
|
@ -748,6 +776,8 @@ pub use async_graphql_derive::Union;
|
|||
/// | default | Argument default value | literal | Y |
|
||||
/// | default_with | Expression to generate default value | code string | Y |
|
||||
/// | validator | Input value validator | [`InputValueValidator`](validators/trait.InputValueValidator.html) | Y |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -789,6 +819,8 @@ pub use async_graphql_derive::Scalar;
|
|||
/// | cache_control | Object cache control | [`CacheControl`](struct.CacheControl.html) | Y |
|
||||
/// | extends | Add fields to an entity that's defined in another service | bool | Y |
|
||||
/// | use_type_description | Specifies that the description of the type is on the type declaration. [`Description`]()(derive.Description.html) | bool | Y |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::model::{__InputValue, __Type};
|
||||
use crate::{registry, Object};
|
||||
use crate::{registry, Context, Object};
|
||||
|
||||
pub struct __Field<'a> {
|
||||
pub registry: &'a registry::Registry,
|
||||
|
@ -17,10 +17,14 @@ impl<'a> __Field<'a> {
|
|||
self.field.description.map(ToString::to_string)
|
||||
}
|
||||
|
||||
async fn args(&self) -> Vec<__InputValue<'a>> {
|
||||
async fn args(&self, ctx: &Context<'_>) -> Vec<__InputValue<'a>> {
|
||||
self.field
|
||||
.args
|
||||
.values()
|
||||
.filter(|input_value| match &input_value.visible {
|
||||
Some(f) => f(ctx),
|
||||
None => true,
|
||||
})
|
||||
.map(|input_value| __InputValue {
|
||||
registry: self.registry,
|
||||
input_value,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::model::{__Directive, __Type};
|
||||
use crate::{registry, Object};
|
||||
use crate::{registry, Context, Object};
|
||||
|
||||
pub struct __Schema<'a> {
|
||||
pub registry: &'a registry::Registry,
|
||||
|
@ -9,12 +9,18 @@ pub struct __Schema<'a> {
|
|||
#[Object(internal, name = "__Schema")]
|
||||
impl<'a> __Schema<'a> {
|
||||
/// A list of all types supported by this server.
|
||||
async fn types(&self) -> Vec<__Type<'a>> {
|
||||
async fn types(&self, ctx: &Context<'_>) -> Vec<__Type<'a>> {
|
||||
let mut types: Vec<_> = self
|
||||
.registry
|
||||
.types
|
||||
.values()
|
||||
.map(|ty| (ty.name(), __Type::new_simple(self.registry, ty)))
|
||||
.filter_map(|ty| {
|
||||
if ty.is_visible(ctx) {
|
||||
Some((ty.name(), __Type::new_simple(self.registry, ty)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
types.sort_by(|a, b| a.0.cmp(b.0));
|
||||
types.into_iter().map(|(_, ty)| ty).collect()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::model::{__EnumValue, __Field, __InputValue, __TypeKind};
|
||||
use crate::{registry, Object};
|
||||
use crate::{registry, Context, Object};
|
||||
|
||||
enum TypeDetail<'a> {
|
||||
Named(&'a registry::MetaType),
|
||||
|
@ -95,12 +95,17 @@ impl<'a> __Type<'a> {
|
|||
|
||||
async fn fields(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
#[graphql(default = false)] include_deprecated: bool,
|
||||
) -> Option<Vec<__Field<'a>>> {
|
||||
if let TypeDetail::Named(ty) = &self.detail {
|
||||
ty.fields().map(|fields| {
|
||||
fields
|
||||
.values()
|
||||
.filter(|field| match &field.visible {
|
||||
Some(f) => f(ctx),
|
||||
None => true,
|
||||
})
|
||||
.filter(|field| {
|
||||
(include_deprecated || field.deprecation.is_none())
|
||||
&& !field.name.starts_with("__")
|
||||
|
@ -158,13 +163,18 @@ impl<'a> __Type<'a> {
|
|||
|
||||
async fn enum_values(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
#[graphql(default = false)] include_deprecated: bool,
|
||||
) -> Option<Vec<__EnumValue<'a>>> {
|
||||
if let TypeDetail::Named(registry::MetaType::Enum { enum_values, .. }) = &self.detail {
|
||||
Some(
|
||||
enum_values
|
||||
.values()
|
||||
.filter(|field| include_deprecated || field.deprecation.is_none())
|
||||
.filter(|value| match &value.visible {
|
||||
Some(f) => f(ctx),
|
||||
None => true,
|
||||
})
|
||||
.filter(|value| include_deprecated || value.deprecation.is_none())
|
||||
.map(|value| __EnumValue {
|
||||
registry: self.registry,
|
||||
value,
|
||||
|
@ -176,13 +186,17 @@ impl<'a> __Type<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
async fn input_fields(&self) -> Option<Vec<__InputValue<'a>>> {
|
||||
async fn input_fields(&self, ctx: &Context<'_>) -> Option<Vec<__InputValue<'a>>> {
|
||||
if let TypeDetail::Named(registry::MetaType::InputObject { input_fields, .. }) =
|
||||
&self.detail
|
||||
{
|
||||
Some(
|
||||
input_fields
|
||||
.values()
|
||||
.filter(|input_value| match &input_value.visible {
|
||||
Some(f) => f(ctx),
|
||||
None => true,
|
||||
})
|
||||
.map(|input_value| __InputValue {
|
||||
registry: self.registry,
|
||||
input_value,
|
||||
|
|
|
@ -9,7 +9,7 @@ use indexmap::set::IndexSet;
|
|||
|
||||
use crate::parser::types::{BaseType as ParsedBaseType, Type as ParsedType};
|
||||
use crate::validators::InputValueValidator;
|
||||
use crate::{model, Any, Type, Value};
|
||||
use crate::{model, Any, Context, Type, Value};
|
||||
|
||||
pub use cache_control::CacheControl;
|
||||
|
||||
|
@ -92,6 +92,7 @@ pub struct MetaInputValue {
|
|||
pub ty: String,
|
||||
pub default_value: Option<String>,
|
||||
pub validator: Option<Arc<dyn InputValueValidator>>,
|
||||
pub visible: Option<MetaVisibleFn>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -105,6 +106,7 @@ pub struct MetaField {
|
|||
pub external: bool,
|
||||
pub requires: Option<&'static str>,
|
||||
pub provides: Option<&'static str>,
|
||||
pub visible: Option<MetaVisibleFn>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -112,13 +114,17 @@ pub struct MetaEnumValue {
|
|||
pub name: &'static str,
|
||||
pub description: Option<&'static str>,
|
||||
pub deprecation: Option<&'static str>,
|
||||
pub visible: Option<MetaVisibleFn>,
|
||||
}
|
||||
|
||||
type MetaVisibleFn = fn(&Context<'_>) -> bool;
|
||||
|
||||
pub enum MetaType {
|
||||
Scalar {
|
||||
name: String,
|
||||
description: Option<&'static str>,
|
||||
is_valid: fn(value: &Value) -> bool,
|
||||
visible: Option<MetaVisibleFn>,
|
||||
},
|
||||
Object {
|
||||
name: String,
|
||||
|
@ -127,6 +133,7 @@ pub enum MetaType {
|
|||
cache_control: CacheControl,
|
||||
extends: bool,
|
||||
keys: Option<Vec<String>>,
|
||||
visible: Option<MetaVisibleFn>,
|
||||
},
|
||||
Interface {
|
||||
name: String,
|
||||
|
@ -135,21 +142,25 @@ pub enum MetaType {
|
|||
possible_types: IndexSet<String>,
|
||||
extends: bool,
|
||||
keys: Option<Vec<String>>,
|
||||
visible: Option<MetaVisibleFn>,
|
||||
},
|
||||
Union {
|
||||
name: String,
|
||||
description: Option<&'static str>,
|
||||
possible_types: IndexSet<String>,
|
||||
visible: Option<MetaVisibleFn>,
|
||||
},
|
||||
Enum {
|
||||
name: String,
|
||||
description: Option<&'static str>,
|
||||
enum_values: IndexMap<&'static str, MetaEnumValue>,
|
||||
visible: Option<MetaVisibleFn>,
|
||||
},
|
||||
InputObject {
|
||||
name: String,
|
||||
description: Option<&'static str>,
|
||||
input_fields: IndexMap<String, MetaInputValue>,
|
||||
visible: Option<MetaVisibleFn>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -166,6 +177,21 @@ impl MetaType {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_visible(&self, ctx: &Context<'_>) -> bool {
|
||||
let visible = match self {
|
||||
MetaType::Scalar { visible, .. } => visible,
|
||||
MetaType::Object { visible, .. } => visible,
|
||||
MetaType::Interface { visible, .. } => visible,
|
||||
MetaType::Union { visible, .. } => visible,
|
||||
MetaType::Enum { visible, .. } => visible,
|
||||
MetaType::InputObject { visible, .. } => visible,
|
||||
};
|
||||
match visible {
|
||||
Some(f) => f(ctx),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
match self {
|
||||
MetaType::Scalar { name, .. } => &name,
|
||||
|
@ -281,6 +307,7 @@ impl Registry {
|
|||
cache_control: Default::default(),
|
||||
extends: false,
|
||||
keys: None,
|
||||
visible: None,
|
||||
},
|
||||
);
|
||||
let ty = f(self);
|
||||
|
@ -394,6 +421,7 @@ impl Registry {
|
|||
name: "_Entity".to_string(),
|
||||
description: None,
|
||||
possible_types,
|
||||
visible: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -420,6 +448,7 @@ impl Registry {
|
|||
external: false,
|
||||
requires: None,
|
||||
provides: None,
|
||||
visible: None,
|
||||
},
|
||||
);
|
||||
fields
|
||||
|
@ -427,6 +456,7 @@ impl Registry {
|
|||
cache_control: Default::default(),
|
||||
extends: false,
|
||||
keys: None,
|
||||
visible: None,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -446,6 +476,7 @@ impl Registry {
|
|||
external: false,
|
||||
requires: None,
|
||||
provides: None,
|
||||
visible: None,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -464,6 +495,7 @@ impl Registry {
|
|||
ty: "[_Any!]!".to_string(),
|
||||
default_value: None,
|
||||
validator: None,
|
||||
visible: None,
|
||||
},
|
||||
);
|
||||
args
|
||||
|
@ -474,6 +506,7 @@ impl Registry {
|
|||
external: false,
|
||||
requires: None,
|
||||
provides: None,
|
||||
visible: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -121,6 +121,7 @@ macro_rules! scalar_internal {
|
|||
name: ::std::borrow::ToOwned::to_owned($name),
|
||||
description: $desc,
|
||||
is_valid: |value| <$ty as $crate::ScalarType>::is_valid(value),
|
||||
visible: ::std::option::Option::None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -266,6 +266,7 @@ where
|
|||
ty: "Boolean!".to_string(),
|
||||
default_value: None,
|
||||
validator: None,
|
||||
visible: None,
|
||||
});
|
||||
args
|
||||
}
|
||||
|
@ -287,6 +288,7 @@ where
|
|||
ty: "Boolean!".to_string(),
|
||||
default_value: None,
|
||||
validator: None,
|
||||
visible: None,
|
||||
});
|
||||
args
|
||||
}
|
||||
|
|
|
@ -159,6 +159,7 @@ where
|
|||
external: false,
|
||||
requires: None,
|
||||
provides: None,
|
||||
visible: None,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -176,6 +177,7 @@ where
|
|||
external: false,
|
||||
requires: None,
|
||||
provides: None,
|
||||
visible: None,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -185,6 +187,7 @@ where
|
|||
cache_control: Default::default(),
|
||||
extends: false,
|
||||
keys: None,
|
||||
visible: None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ where
|
|||
external: false,
|
||||
requires: None,
|
||||
provides: None,
|
||||
visible: None,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -93,6 +94,7 @@ where
|
|||
external: false,
|
||||
requires: None,
|
||||
provides: None,
|
||||
visible: None,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -102,6 +104,7 @@ where
|
|||
cache_control: Default::default(),
|
||||
extends: false,
|
||||
keys: None,
|
||||
visible: None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ impl Type for EmptyMutation {
|
|||
cache_control: Default::default(),
|
||||
extends: false,
|
||||
keys: None,
|
||||
visible: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ impl Type for EmptySubscription {
|
|||
cache_control: Default::default(),
|
||||
extends: false,
|
||||
keys: None,
|
||||
visible: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ impl<T> Type for OutputJson<T> {
|
|||
name: Self::type_name().to_string(),
|
||||
description: None,
|
||||
is_valid: |_| true,
|
||||
visible: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ impl<A: Type, B: Type> Type for MergedObject<A, B> {
|
|||
cache_control: cc,
|
||||
extends: false,
|
||||
keys: None,
|
||||
visible: None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ impl<T: Type> Type for QueryRoot<T> {
|
|||
external: false,
|
||||
requires: None,
|
||||
provides: None,
|
||||
visible: None,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -63,6 +64,7 @@ impl<T: Type> Type for QueryRoot<T> {
|
|||
ty: "String!".to_string(),
|
||||
default_value: None,
|
||||
validator: None,
|
||||
visible: None,
|
||||
},
|
||||
);
|
||||
args
|
||||
|
@ -73,6 +75,7 @@ impl<T: Type> Type for QueryRoot<T> {
|
|||
external: false,
|
||||
requires: None,
|
||||
provides: None,
|
||||
visible: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -106,6 +109,7 @@ impl<T: ObjectType + Send + Sync> ContainerType for QueryRoot<T> {
|
|||
.registry
|
||||
.types
|
||||
.get(&type_name)
|
||||
.filter(|ty| ty.is_visible(ctx))
|
||||
.map(|ty| __Type::new_simple(&ctx.schema_env.registry, ty)),
|
||||
&ctx_obj,
|
||||
ctx.item,
|
||||
|
|
|
@ -110,6 +110,7 @@ impl Type for Upload {
|
|||
name: Self::type_name().to_string(),
|
||||
description: None,
|
||||
is_valid: |value| matches!(value, Value::String(_)),
|
||||
visible: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
254
tests/introspection_visible.rs
Normal file
254
tests/introspection_visible.rs
Normal file
|
@ -0,0 +1,254 @@
|
|||
use async_graphql::*;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[async_std::test]
|
||||
pub async fn test_type_visible() {
|
||||
#[derive(SimpleObject)]
|
||||
#[graphql(visible = false)]
|
||||
struct MyObj {
|
||||
a: i32,
|
||||
}
|
||||
|
||||
struct Query;
|
||||
|
||||
#[Object]
|
||||
impl Query {
|
||||
async fn obj(&self) -> MyObj {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
|
||||
assert_eq!(
|
||||
schema
|
||||
.execute(r#"{ __type(name: "MyObj") { name } }"#)
|
||||
.await
|
||||
.into_result()
|
||||
.unwrap()
|
||||
.data,
|
||||
value!({
|
||||
"__type": null,
|
||||
})
|
||||
);
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct QueryResponse {
|
||||
#[serde(rename = "__schema")]
|
||||
schema: SchemaResponse,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct SchemaResponse {
|
||||
types: Vec<TypeResponse>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct TypeResponse {
|
||||
name: String,
|
||||
}
|
||||
|
||||
let resp: QueryResponse = from_value(
|
||||
schema
|
||||
.execute(r#"{ __schema { types { name } } }"#)
|
||||
.await
|
||||
.into_result()
|
||||
.unwrap()
|
||||
.data,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(resp
|
||||
.schema
|
||||
.types
|
||||
.into_iter()
|
||||
.find(|ty| ty.name == "MyObj")
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
pub async fn test_field_visible() {
|
||||
#[derive(SimpleObject)]
|
||||
struct MyObj {
|
||||
a: i32,
|
||||
#[graphql(visible = false)]
|
||||
b: i32,
|
||||
}
|
||||
|
||||
struct Query;
|
||||
|
||||
#[Object]
|
||||
impl Query {
|
||||
async fn obj(&self) -> MyObj {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[graphql(visible = false)]
|
||||
async fn c(&self) -> i32 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct QueryResponse {
|
||||
#[serde(rename = "__type")]
|
||||
ty: TypeResponse,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct TypeResponse {
|
||||
fields: Vec<FieldResposne>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct FieldResposne {
|
||||
name: String,
|
||||
}
|
||||
|
||||
let resp: QueryResponse = from_value(
|
||||
schema
|
||||
.execute(r#"{ __type(name: "MyObj") { fields { name } } }"#)
|
||||
.await
|
||||
.into_result()
|
||||
.unwrap()
|
||||
.data,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
resp.ty
|
||||
.fields
|
||||
.iter()
|
||||
.map(|field| field.name.as_str())
|
||||
.collect::<Vec<_>>(),
|
||||
vec!["a"]
|
||||
);
|
||||
|
||||
let resp: QueryResponse = from_value(
|
||||
schema
|
||||
.execute(r#"{ __type(name: "Query") { fields { name } } }"#)
|
||||
.await
|
||||
.into_result()
|
||||
.unwrap()
|
||||
.data,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
resp.ty
|
||||
.fields
|
||||
.iter()
|
||||
.map(|field| field.name.as_str())
|
||||
.collect::<Vec<_>>(),
|
||||
vec!["obj"]
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
pub async fn test_enum_value_visible() {
|
||||
#[derive(Enum, Eq, PartialEq, Copy, Clone)]
|
||||
enum MyEnum {
|
||||
A,
|
||||
B,
|
||||
#[graphql(visible = false)]
|
||||
C,
|
||||
}
|
||||
|
||||
struct Query;
|
||||
|
||||
#[Object]
|
||||
impl Query {
|
||||
async fn e(&self) -> MyEnum {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct QueryResponse {
|
||||
#[serde(rename = "__type")]
|
||||
ty: TypeResponse,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct TypeResponse {
|
||||
enum_values: Vec<EnumValueResponse>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct EnumValueResponse {
|
||||
name: String,
|
||||
}
|
||||
|
||||
let resp: QueryResponse = from_value(
|
||||
schema
|
||||
.execute(r#"{ __type(name: "MyEnum") { enumValues { name } } }"#)
|
||||
.await
|
||||
.into_result()
|
||||
.unwrap()
|
||||
.data,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
resp.ty
|
||||
.enum_values
|
||||
.iter()
|
||||
.map(|value| value.name.as_str())
|
||||
.collect::<Vec<_>>(),
|
||||
vec!["A", "B"]
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
pub async fn test_visible_fn() {
|
||||
struct IsAdmin(bool);
|
||||
|
||||
#[derive(SimpleObject)]
|
||||
#[graphql(visible = "is_admin")]
|
||||
struct MyObj {
|
||||
a: i32,
|
||||
}
|
||||
|
||||
fn is_admin(ctx: &Context<'_>) -> bool {
|
||||
ctx.data_unchecked::<IsAdmin>().0
|
||||
}
|
||||
|
||||
struct Query;
|
||||
|
||||
#[Object]
|
||||
impl Query {
|
||||
async fn obj(&self) -> MyObj {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
|
||||
assert_eq!(
|
||||
schema
|
||||
.execute(Request::new(r#"{ __type(name: "MyObj") { name } }"#).data(IsAdmin(false)))
|
||||
.await
|
||||
.into_result()
|
||||
.unwrap()
|
||||
.data,
|
||||
value!({
|
||||
"__type": null,
|
||||
})
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
schema
|
||||
.execute(Request::new(r#"{ __type(name: "MyObj") { name } }"#).data(IsAdmin(true)))
|
||||
.await
|
||||
.into_result()
|
||||
.unwrap()
|
||||
.data,
|
||||
value!({
|
||||
"__type": {
|
||||
"name": "MyObj",
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user