From 619013d90c716a3163d101668949f62001ebf723 Mon Sep 17 00:00:00 2001 From: Nicolas Moutschen Date: Thu, 18 Aug 2022 11:40:04 +0200 Subject: [PATCH] feat: @inaccessible support --- derive/src/args.rs | 33 +++++ derive/src/complex_object.rs | 4 + derive/src/directive.rs | 1 + derive/src/enum.rs | 4 + derive/src/input_object.rs | 5 + derive/src/interface.rs | 6 + derive/src/merged_object.rs | 2 + derive/src/merged_subscription.rs | 1 + derive/src/newtype.rs | 2 + derive/src/object.rs | 7 + derive/src/oneof_object.rs | 5 + derive/src/scalar.rs | 3 + derive/src/simple_object.rs | 5 + derive/src/subscription.rs | 3 + derive/src/union.rs | 2 + src/registry/export_sdl.rs | 53 ++++++- src/registry/mod.rs | 16 ++ src/resolver_utils/scalar.rs | 2 + src/schema.rs | 2 + src/types/connection/mod.rs | 2 +- src/types/empty_mutation.rs | 1 + src/types/empty_subscription.rs | 1 + src/types/external/json_object/btreemap.rs | 2 + src/types/external/json_object/hashmap.rs | 2 + src/types/json.rs | 4 + src/types/merged_object.rs | 3 + src/types/query_root.rs | 3 + src/types/upload.rs | 1 + tests/federation.rs | 164 +++++++++++++++++++++ 29 files changed, 334 insertions(+), 5 deletions(-) diff --git a/derive/src/args.rs b/derive/src/args.rs index 6a5f8cd0..88c154c2 100644 --- a/derive/src/args.rs +++ b/derive/src/args.rs @@ -153,6 +153,8 @@ pub struct SimpleObjectField { #[darling(default)] pub shareable: bool, #[darling(default)] + pub inaccessible: bool, + #[darling(default)] pub guard: Option>, #[darling(default)] pub visible: Option, @@ -202,6 +204,8 @@ pub struct SimpleObject { #[darling(default)] pub shareable: bool, #[darling(default)] + pub inaccessible: bool, + #[darling(default)] pub visible: Option, #[darling(default, multiple, rename = "concrete")] pub concretes: Vec, @@ -226,6 +230,7 @@ pub struct Argument { pub process_with: Option, pub key: bool, // for entity pub visible: Option, + pub inaccessible: bool, pub secret: bool, } @@ -240,6 +245,7 @@ pub struct Object { pub cache_control: CacheControl, pub extends: bool, pub shareable: bool, + pub inaccessible: bool, pub use_type_description: bool, pub visible: Option, pub serial: bool, @@ -284,6 +290,7 @@ pub struct ObjectField { pub provides: Option, pub requires: Option, pub shareable: bool, + pub inaccessible: bool, pub guard: Option>, pub visible: Option, pub complexity: Option, @@ -321,6 +328,8 @@ pub struct Enum { pub remote: Option, #[darling(default)] pub visible: Option, + #[darling(default)] + pub inaccessible: bool, } #[derive(FromVariant)] @@ -336,6 +345,8 @@ pub struct EnumItem { pub deprecation: Deprecation, #[darling(default)] pub visible: Option, + #[darling(default)] + pub inaccessible: bool, } #[derive(FromDeriveInput)] @@ -352,6 +363,8 @@ pub struct Union { pub name: Option, #[darling(default)] pub visible: Option, + #[darling(default)] + pub inaccessible: bool, } #[derive(FromVariant)] @@ -394,6 +407,8 @@ pub struct InputObjectField { #[darling(default)] pub visible: Option, #[darling(default)] + pub inaccessible: bool, + #[darling(default)] pub secret: bool, } @@ -415,6 +430,8 @@ pub struct InputObject { pub rename_fields: Option, #[darling(default)] pub visible: Option, + #[darling(default)] + pub inaccessible: bool, #[darling(default, multiple, rename = "concrete")] pub concretes: Vec, // for SimpleObject @@ -436,6 +453,8 @@ pub struct OneofObjectField { #[darling(default)] pub visible: Option, #[darling(default)] + pub inaccessible: bool, + #[darling(default)] pub secret: bool, } @@ -455,6 +474,8 @@ pub struct OneofObject { pub rename_fields: Option, #[darling(default)] pub visible: Option, + #[darling(default)] + pub inaccessible: bool, #[darling(default, multiple, rename = "concrete")] pub concretes: Vec, } @@ -473,6 +494,8 @@ pub struct InterfaceFieldArgument { #[darling(default)] pub visible: Option, #[darling(default)] + pub inaccessible: bool, + #[darling(default)] pub secret: bool, } @@ -498,6 +521,8 @@ pub struct InterfaceField { #[darling(default)] pub visible: Option, #[darling(default)] + pub inaccessible: bool, + #[darling(default)] pub shareable: bool, } @@ -529,6 +554,8 @@ pub struct Interface { pub extends: bool, #[darling(default)] pub visible: Option, + #[darling(default)] + pub inaccessible: bool, } #[derive(FromMeta, Default)] @@ -538,6 +565,7 @@ pub struct Scalar { pub name: Option, pub use_type_description: bool, pub visible: Option, + pub inaccessible: bool, pub specified_by_url: Option, } @@ -604,6 +632,8 @@ pub struct MergedObject { #[darling(default)] pub shareable: bool, #[darling(default)] + pub inaccessible: bool, + #[darling(default)] pub visible: Option, #[darling(default)] pub serial: bool, @@ -751,6 +781,8 @@ pub struct NewType { #[darling(default)] pub visible: Option, #[darling(default)] + pub inaccessible: bool, + #[darling(default)] pub specified_by_url: Option, } @@ -775,6 +807,7 @@ pub struct ComplexObjectField { pub provides: Option, pub requires: Option, pub shareable: bool, + pub inaccessible: bool, pub guard: Option>, pub visible: Option, pub complexity: Option, diff --git a/derive/src/complex_object.rs b/derive/src/complex_object.rs index 24e34cee..0329a2e6 100644 --- a/derive/src/complex_object.rs +++ b/derive/src/complex_object.rs @@ -173,6 +173,7 @@ pub fn generate( let field_deprecation = gen_deprecation(&method_args.deprecation, &crate_name); let external = method_args.external; let shareable = method_args.shareable; + let inaccessible = method_args.inaccessible; let requires = match &method_args.requires { Some(requires) => quote! { ::std::option::Option::Some(#requires) }, None => quote! { ::std::option::Option::None }, @@ -208,6 +209,7 @@ pub fn generate( validator, process_with, visible, + inaccessible, secret, .. }, @@ -242,6 +244,7 @@ pub fn generate( ty: <#ty as #crate_name::InputType>::create_type_info(registry), default_value: #schema_default, visible: #visible, + inaccessible: #inaccessible, is_secret: #secret, }); }); @@ -367,6 +370,7 @@ pub fn generate( provides: #provides, requires: #requires, shareable: #shareable, + inaccessible: #inaccessible, visible: #visible, compute_complexity: #complexity, })); diff --git a/derive/src/directive.rs b/derive/src/directive.rs index b0f79239..4b89a6d9 100644 --- a/derive/src/directive.rs +++ b/derive/src/directive.rs @@ -89,6 +89,7 @@ pub fn generate( ty: <#arg_ty as #crate_name::InputType>::create_type_info(registry), default_value: #schema_default, visible: #visible, + inaccessible: false, is_secret: #secret, }); }); diff --git a/derive/src/enum.rs b/derive/src/enum.rs index 433aa35e..3dee9199 100644 --- a/derive/src/enum.rs +++ b/derive/src/enum.rs @@ -21,6 +21,7 @@ pub fn generate(enum_args: &args::Enum) -> GeneratorResult { .clone() .unwrap_or_else(|| RenameTarget::Type.rename(ident.to_string())); + let inaccessible = enum_args.inaccessible; let desc = get_rustdoc(&enum_args.attrs)? .map(|s| quote! { ::std::option::Option::Some(#s) }) .unwrap_or_else(|| quote! {::std::option::Option::None}); @@ -47,6 +48,7 @@ pub fn generate(enum_args: &args::Enum) -> GeneratorResult { .rename_items .rename(variant.ident.unraw().to_string(), RenameTarget::EnumItem) }); + let inaccessible = variant.inaccessible; let item_deprecation = gen_deprecation(&variant.deprecation, &crate_name); let item_desc = get_rustdoc(&variant.attrs)? .map(|s| quote! { ::std::option::Option::Some(#s) }) @@ -67,6 +69,7 @@ pub fn generate(enum_args: &args::Enum) -> GeneratorResult { description: #item_desc, deprecation: #item_deprecation, visible: #visible, + inaccessible: #inaccessible, }); }); } @@ -141,6 +144,7 @@ pub fn generate(enum_args: &args::Enum) -> GeneratorResult { enum_items }, visible: #visible, + inaccessible: #inaccessible, rust_typename: ::std::any::type_name::(), } }) diff --git a/derive/src/input_object.rs b/derive/src/input_object.rs index 788428bb..281bdddb 100644 --- a/derive/src/input_object.rs +++ b/derive/src/input_object.rs @@ -12,6 +12,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult let crate_name = get_crate_name(object_args.internal); let (impl_generics, ty_generics, where_clause) = object_args.generics.split_for_impl(); let ident = &object_args.ident; + let inaccessible = object_args.inaccessible; let s = match &object_args.data { Data::Struct(s) => s, _ => { @@ -65,6 +66,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult .rename_fields .rename(ident.unraw().to_string(), RenameTarget::Field) }); + let inaccessible = field.inaccessible; if field.skip || field.skip_input { get_fields.push(quote! { @@ -188,6 +190,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult ty: <#ty as #crate_name::InputType>::create_type_info(registry), default_value: #schema_default, visible: #visible, + inaccessible: #inaccessible, is_secret: #secret, }); }) @@ -240,6 +243,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult fields }, visible: #visible, + inaccessible: #inaccessible, rust_typename: ::std::any::type_name::(), oneof: false, }) @@ -287,6 +291,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult fields }, visible: #visible, + inaccessible: #inaccessible, rust_typename: ::std::any::type_name::(), oneof: false, }) diff --git a/derive/src/interface.rs b/derive/src/interface.rs index 6a89798e..962a152a 100644 --- a/derive/src/interface.rs +++ b/derive/src/interface.rs @@ -31,6 +31,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult GeneratorResult GeneratorResult GeneratorResult::create_type_info(registry), default_value: #schema_default, visible: #visible, + inaccessible: #inaccessible, is_secret: #secret, }); }); @@ -276,6 +280,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult GeneratorResult(), } }) diff --git a/derive/src/merged_object.rs b/derive/src/merged_object.rs index 2da26995..b6108c76 100644 --- a/derive/src/merged_object.rs +++ b/derive/src/merged_object.rs @@ -15,6 +15,7 @@ pub fn generate(object_args: &args::MergedObject) -> GeneratorResult GeneratorResult GeneratorResult(), } diff --git a/derive/src/newtype.rs b/derive/src/newtype.rs index ba90573c..24d56054 100644 --- a/derive/src/newtype.rs +++ b/derive/src/newtype.rs @@ -12,6 +12,7 @@ pub fn generate(newtype_args: &args::NewType) -> GeneratorResult { let crate_name = get_crate_name(newtype_args.internal); let ident = &newtype_args.ident; let (impl_generics, ty_generics, where_clause) = newtype_args.generics.split_for_impl(); + let inaccessible = newtype_args.inaccessible; let gql_typename = match &newtype_args.name { NewTypeName::New(name) => Some(name.clone()), NewTypeName::Rust => Some(RenameTarget::Type.rename(ident.to_string())), @@ -51,6 +52,7 @@ pub fn generate(newtype_args: &args::NewType) -> GeneratorResult { description: #desc, is_valid: |value| <#ident as #crate_name::ScalarType>::is_valid(value), visible: #visible, + inaccessible: #inaccessible, specified_by_url: #specified_by_url, }) } diff --git a/derive/src/object.rs b/derive/src/object.rs index 3791c581..eb90d4f3 100644 --- a/derive/src/object.rs +++ b/derive/src/object.rs @@ -27,6 +27,7 @@ pub fn generate( let (impl_generics, _, where_clause) = item_impl.generics.split_for_impl(); let extends = object_args.extends; let shareable = object_args.shareable; + let inaccessible = object_args.inaccessible; let gql_typename = if !object_args.name_type { object_args .name @@ -317,6 +318,7 @@ pub fn generate( let field_deprecation = gen_deprecation(&method_args.deprecation, &crate_name); let external = method_args.external; let shareable = method_args.shareable; + let inaccessible = method_args.inaccessible; let requires = match &method_args.requires { Some(requires) => quote! { ::std::option::Option::Some(#requires) }, None => quote! { ::std::option::Option::None }, @@ -353,6 +355,7 @@ pub fn generate( validator, visible, secret, + inaccessible, .. }, ) in &args @@ -386,6 +389,7 @@ pub fn generate( ty: <#ty as #crate_name::InputType>::create_type_info(registry), default_value: #schema_default, visible: #visible, + inaccessible: #inaccessible, is_secret: #secret, }); }); @@ -510,6 +514,7 @@ pub fn generate( provides: #provides, requires: #requires, shareable: #shareable, + inaccessible: #inaccessible, visible: #visible, compute_complexity: #complexity, }); @@ -644,6 +649,7 @@ pub fn generate( cache_control: #cache_control, extends: #extends, shareable: #shareable, + inaccessible: #inaccessible, keys: ::std::option::Option::None, visible: #visible, is_subscription: false, @@ -684,6 +690,7 @@ pub fn generate( cache_control: #cache_control, extends: #extends, shareable: #shareable, + inaccessible: #inaccessible, keys: ::std::option::Option::None, visible: #visible, is_subscription: false, diff --git a/derive/src/oneof_object.rs b/derive/src/oneof_object.rs index 3b13021e..72d16121 100644 --- a/derive/src/oneof_object.rs +++ b/derive/src/oneof_object.rs @@ -16,6 +16,7 @@ pub fn generate(object_args: &args::OneofObject) -> GeneratorResult let desc = get_rustdoc(&object_args.attrs)? .map(|s| quote! { ::std::option::Option::Some(#s) }) .unwrap_or_else(|| quote! {::std::option::Option::None}); + let inaccessible = object_args.inaccessible; let gql_typename = object_args .name .clone() @@ -41,6 +42,7 @@ pub fn generate(object_args: &args::OneofObject) -> GeneratorResult .rename_fields .rename(enum_name.to_string(), RenameTarget::Field) }); + let inaccessible = variant.inaccessible; let desc = get_rustdoc(&object_args.attrs)? .map(|s| quote! { ::std::option::Option::Some(#s) }) .unwrap_or_else(|| quote! {::std::option::Option::None}); @@ -80,6 +82,7 @@ pub fn generate(object_args: &args::OneofObject) -> GeneratorResult ty: <::std::option::Option<#ty> as #crate_name::InputType>::create_type_info(registry), default_value: ::std::option::Option::None, visible: #visible, + inaccessible: #inaccessible, is_secret: #secret, }); }); @@ -133,6 +136,7 @@ pub fn generate(object_args: &args::OneofObject) -> GeneratorResult fields }, visible: #visible, + inaccessible: #inaccessible, rust_typename: ::std::any::type_name::(), oneof: true, }) @@ -183,6 +187,7 @@ pub fn generate(object_args: &args::OneofObject) -> GeneratorResult fields }, visible: #visible, + inaccessible: #inaccessible, rust_typename: ::std::any::type_name::(), oneof: true, }) diff --git a/derive/src/scalar.rs b/derive/src/scalar.rs index a8f99a18..b11deb44 100644 --- a/derive/src/scalar.rs +++ b/derive/src/scalar.rs @@ -30,6 +30,7 @@ pub fn generate( let generic = &item_impl.generics; let where_clause = &item_impl.generics.where_clause; let visible = visible_fn(&scalar_args.visible); + let inaccessible = scalar_args.inaccessible; let specified_by_url = match &scalar_args.specified_by_url { Some(specified_by_url) => quote! { ::std::option::Option::Some(#specified_by_url) }, None => quote! { ::std::option::Option::None }, @@ -52,6 +53,7 @@ pub fn generate( description: #desc, is_valid: |value| <#self_ty as #crate_name::ScalarType>::is_valid(value), visible: #visible, + inaccessible: #inaccessible, specified_by_url: #specified_by_url, }) } @@ -82,6 +84,7 @@ pub fn generate( description: #desc, is_valid: |value| <#self_ty as #crate_name::ScalarType>::is_valid(value), visible: #visible, + inaccessible: #inaccessible, specified_by_url: #specified_by_url, }) } diff --git a/derive/src/simple_object.rs b/derive/src/simple_object.rs index d274fc67..37088634 100644 --- a/derive/src/simple_object.rs +++ b/derive/src/simple_object.rs @@ -31,6 +31,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult GeneratorResult quote! { ::std::option::Option::Some(#requires) }, None => quote! { ::std::option::Option::None }, @@ -177,6 +179,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult GeneratorResult GeneratorResult::create_type_info(registry), default_value: #schema_default, visible: #visible, + inaccessible: false, is_secret: #secret, }); }); @@ -269,6 +270,7 @@ pub fn generate( provides: ::std::option::Option::None, shareable: false, visible: #visible, + inaccessible: false, compute_complexity: #complexity, }); }); @@ -410,6 +412,7 @@ pub fn generate( keys: ::std::option::Option::None, visible: #visible, shareable: false, + inaccessible: false, is_subscription: true, rust_typename: ::std::any::type_name::(), }) diff --git a/derive/src/union.rs b/derive/src/union.rs index dceb5a07..05af9d61 100644 --- a/derive/src/union.rs +++ b/derive/src/union.rs @@ -28,6 +28,7 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult { .clone() .unwrap_or_else(|| RenameTarget::Type.rename(ident.to_string())); + let inaccessible = union_args.inaccessible; let desc = get_rustdoc(&union_args.attrs)? .map(|s| quote! { ::std::option::Option::Some(#s) }) .unwrap_or_else(|| quote! {::std::option::Option::None}); @@ -193,6 +194,7 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult { possible_types }, visible: #visible, + inaccessible: #inaccessible, rust_typename: ::std::any::type_name::(), } }) diff --git a/src/registry/export_sdl.rs b/src/registry/export_sdl.rs index 472f144c..0b937c4f 100644 --- a/src/registry/export_sdl.rs +++ b/src/registry/export_sdl.rs @@ -152,6 +152,10 @@ impl Registry { sdl.push_str(", "); } sdl.push_str(&export_input_value(arg)); + + if options.federation && arg.inaccessible { + write!(sdl, " @inaccessible").ok(); + } } write!(sdl, "): {}", field.ty).ok(); } else { @@ -173,6 +177,9 @@ impl Registry { if field.shareable { write!(sdl, " @shareable").ok(); } + if field.inaccessible { + write!(sdl, " @inaccessible").ok(); + } } writeln!(sdl).ok(); @@ -182,7 +189,10 @@ impl Registry { fn export_type(&self, ty: &MetaType, sdl: &mut String, options: &SDLExportOptions) { match ty { MetaType::Scalar { - name, description, .. + name, + description, + inaccessible, + .. } => { let mut export_scalar = !SYSTEM_SCALARS.contains(&name.as_str()); if options.federation && FEDERATION_SCALARS.contains(&name.as_str()) { @@ -192,7 +202,12 @@ impl Registry { if let Some(description) = description { export_description(sdl, options, true, description); } - writeln!(sdl, "scalar {}", name).ok(); + write!(sdl, "scalar {} ", name).ok(); + + if options.federation && *inaccessible { + write!(sdl, "@inaccessible ").ok(); + } + writeln!(sdl).ok(); } } MetaType::Object { @@ -202,6 +217,7 @@ impl Registry { keys, description, shareable, + inaccessible, .. } => { if Some(name.as_str()) == self.subscription_type.as_deref() @@ -248,6 +264,10 @@ impl Registry { if *shareable { write!(sdl, "@shareable ").ok(); } + + if *inaccessible { + write!(sdl, "@inaccessible ").ok(); + } } writeln!(sdl, "{{").ok(); @@ -260,6 +280,7 @@ impl Registry { extends, keys, description, + inaccessible, .. } => { if let Some(description) = description { @@ -277,6 +298,9 @@ impl Registry { write!(sdl, "@key(fields: \"{}\") ", key).ok(); } } + if *inaccessible { + write!(sdl, "@inaccessible ").ok(); + } } self.write_implements(sdl, name); @@ -288,6 +312,7 @@ impl Registry { name, enum_values, description, + inaccessible, .. } => { if let Some(description) = description { @@ -295,6 +320,9 @@ impl Registry { } write!(sdl, "enum {} ", name).ok(); + if options.federation && *inaccessible { + write!(sdl, "@inaccessible ").ok(); + } writeln!(sdl, "{{").ok(); let mut values = enum_values.values().collect::>(); @@ -305,6 +333,9 @@ impl Registry { for value in values { write!(sdl, "\t{}", value.name).ok(); write_deprecated(sdl, &value.deprecation); + if options.federation && value.inaccessible { + write!(sdl, " @inaccessible").ok(); + } writeln!(sdl).ok(); } @@ -314,6 +345,7 @@ impl Registry { name, input_fields, description, + inaccessible, oneof, .. } => { @@ -326,6 +358,9 @@ impl Registry { if *oneof { write!(sdl, "@oneof ").ok(); } + if options.federation && *inaccessible { + write!(sdl, "@inaccessible ").ok(); + } writeln!(sdl, "{{").ok(); let mut fields = input_fields.values().collect::>(); @@ -337,7 +372,11 @@ impl Registry { if let Some(description) = field.description { export_description(sdl, options, false, description); } - writeln!(sdl, "\t{}", export_input_value(&field)).ok(); + write!(sdl, "\t{} ", export_input_value(&field)).ok(); + if options.federation && field.inaccessible { + write!(sdl, "@inaccessible ").ok(); + } + writeln!(sdl).ok(); } writeln!(sdl, "}}").ok(); @@ -346,13 +385,19 @@ impl Registry { name, possible_types, description, + inaccessible, .. } => { if let Some(description) = description { export_description(sdl, options, true, description); } - write!(sdl, "union {} =", name).ok(); + write!(sdl, "union {} ", name).ok(); + if options.federation && *inaccessible { + write!(sdl, "@inaccessible ").ok(); + } + write!(sdl, "=").ok(); + for (idx, ty) in possible_types.iter().enumerate() { if idx == 0 { write!(sdl, " {}", ty).ok(); diff --git a/src/registry/mod.rs b/src/registry/mod.rs index 44648602..42cba04f 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -111,6 +111,7 @@ pub struct MetaInputValue { pub ty: String, pub default_value: Option, pub visible: Option, + pub inaccessible: bool, pub is_secret: bool, } @@ -167,6 +168,7 @@ pub struct MetaField { pub provides: Option<&'static str>, pub visible: Option, pub shareable: bool, + pub inaccessible: bool, pub compute_complexity: Option, } @@ -176,6 +178,7 @@ pub struct MetaEnumValue { pub description: Option<&'static str>, pub deprecation: Deprecation, pub visible: Option, + pub inaccessible: bool, } type MetaVisibleFn = fn(&Context<'_>) -> bool; @@ -210,6 +213,7 @@ pub enum MetaType { description: Option<&'static str>, is_valid: fn(value: &Value) -> bool, visible: Option, + inaccessible: bool, specified_by_url: Option<&'static str>, }, Object { @@ -221,6 +225,7 @@ pub enum MetaType { shareable: bool, keys: Option>, visible: Option, + inaccessible: bool, is_subscription: bool, rust_typename: &'static str, }, @@ -232,6 +237,7 @@ pub enum MetaType { extends: bool, keys: Option>, visible: Option, + inaccessible: bool, rust_typename: &'static str, }, Union { @@ -239,6 +245,7 @@ pub enum MetaType { description: Option<&'static str>, possible_types: IndexSet, visible: Option, + inaccessible: bool, rust_typename: &'static str, }, Enum { @@ -246,6 +253,7 @@ pub enum MetaType { description: Option<&'static str>, enum_values: IndexMap<&'static str, MetaEnumValue>, visible: Option, + inaccessible: bool, rust_typename: &'static str, }, InputObject { @@ -253,6 +261,7 @@ pub enum MetaType { description: Option<&'static str>, input_fields: IndexMap, visible: Option, + inaccessible: bool, rust_typename: &'static str, oneof: bool, }, @@ -495,6 +504,7 @@ impl Registry { cache_control: Default::default(), extends: false, shareable: false, + inaccessible: false, keys: None, visible: None, is_subscription: false, @@ -623,6 +633,7 @@ impl Registry { requires: None, provides: None, shareable: false, + inaccessible: false, visible: None, compute_complexity: None, }, @@ -637,6 +648,7 @@ impl Registry { description: None, possible_types, visible: None, + inaccessible: false, rust_typename: "async_graphql::federation::Entity", }, ); @@ -657,6 +669,7 @@ impl Registry { ty: "[_Any!]!".to_string(), default_value: None, visible: None, + inaccessible: false, is_secret: false, }, ); @@ -670,6 +683,7 @@ impl Registry { provides: None, shareable: false, visible: None, + inaccessible: false, compute_complexity: None, }, ); @@ -701,6 +715,7 @@ impl Registry { provides: None, shareable: false, visible: None, + inaccessible: false, compute_complexity: None, }, ); @@ -711,6 +726,7 @@ impl Registry { shareable: false, keys: None, visible: None, + inaccessible: false, is_subscription: false, rust_typename: "async_graphql::federation::Service", }, diff --git a/src/resolver_utils/scalar.rs b/src/resolver_utils/scalar.rs index e46538f7..39c50866 100644 --- a/src/resolver_utils/scalar.rs +++ b/src/resolver_utils/scalar.rs @@ -164,6 +164,7 @@ macro_rules! scalar_internal { description: $desc, is_valid: |value| <$ty as $crate::ScalarType>::is_valid(value), visible: ::std::option::Option::None, + inaccessible: false, specified_by_url: $specified_by_url, } }) @@ -199,6 +200,7 @@ macro_rules! scalar_internal { description: $desc, is_valid: |value| <$ty as $crate::ScalarType>::is_valid(value), visible: ::std::option::Option::None, + inaccessible: false, specified_by_url: $specified_by_url, } }) diff --git a/src/schema.rs b/src/schema.rs index 096b50d7..36f46773 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -399,6 +399,7 @@ where ty: "Boolean!".to_string(), default_value: None, visible: None, + inaccessible: false, is_secret: false, }); args @@ -423,6 +424,7 @@ where ty: "Boolean!".to_string(), default_value: None, visible: None, + inaccessible: false, is_secret: false, }); args diff --git a/src/types/connection/mod.rs b/src/types/connection/mod.rs index 73592dd2..1b9d06f6 100644 --- a/src/types/connection/mod.rs +++ b/src/types/connection/mod.rs @@ -222,7 +222,7 @@ where /// # Examples /// /// ```rust -/// +/// /// use async_graphql::*; /// use async_graphql::types::connection::*; /// diff --git a/src/types/empty_mutation.rs b/src/types/empty_mutation.rs index 972040a8..96ad2fc1 100644 --- a/src/types/empty_mutation.rs +++ b/src/types/empty_mutation.rs @@ -57,6 +57,7 @@ impl OutputType for EmptyMutation { shareable: false, keys: None, visible: None, + inaccessible: false, is_subscription: false, rust_typename: std::any::type_name::(), }) diff --git a/src/types/empty_subscription.rs b/src/types/empty_subscription.rs index c9efc7ec..a9a3f4d8 100644 --- a/src/types/empty_subscription.rs +++ b/src/types/empty_subscription.rs @@ -26,6 +26,7 @@ impl SubscriptionType for EmptySubscription { shareable: false, keys: None, visible: None, + inaccessible: false, is_subscription: true, rust_typename: std::any::type_name::(), }) diff --git a/src/types/external/json_object/btreemap.rs b/src/types/external/json_object/btreemap.rs index 16328ea9..1034d7b7 100644 --- a/src/types/external/json_object/btreemap.rs +++ b/src/types/external/json_object/btreemap.rs @@ -29,6 +29,7 @@ where description: Some("A scalar that can represent any JSON Object value."), is_valid: |_| true, visible: None, + inaccessible: false, specified_by_url: None, }) } @@ -84,6 +85,7 @@ where description: Some("A scalar that can represent any JSON Object value."), is_valid: |_| true, visible: None, + inaccessible: false, specified_by_url: None, }) } diff --git a/src/types/external/json_object/hashmap.rs b/src/types/external/json_object/hashmap.rs index 2725fa82..cae73228 100644 --- a/src/types/external/json_object/hashmap.rs +++ b/src/types/external/json_object/hashmap.rs @@ -36,6 +36,7 @@ where description: Some("A scalar that can represent any JSON Object value."), is_valid: |_| true, visible: None, + inaccessible: false, specified_by_url: None, }) } @@ -92,6 +93,7 @@ where description: Some("A scalar that can represent any JSON Object value."), is_valid: |_| true, visible: None, + inaccessible: false, specified_by_url: None, }) } diff --git a/src/types/json.rs b/src/types/json.rs index 5f1873b1..c5b05639 100644 --- a/src/types/json.rs +++ b/src/types/json.rs @@ -54,6 +54,7 @@ impl InputType for Json { description: Some("A scalar that can represent any JSON value."), is_valid: |_| true, visible: None, + inaccessible: false, specified_by_url: None, }) } @@ -83,6 +84,7 @@ impl OutputType for Json { description: Some("A scalar that can represent any JSON value."), is_valid: |_| true, visible: None, + inaccessible: false, specified_by_url: None, }) } @@ -110,6 +112,7 @@ impl InputType for serde_json::Value { description: Some("A scalar that can represent any JSON value."), is_valid: |_| true, visible: None, + inaccessible: false, specified_by_url: None, } }) @@ -141,6 +144,7 @@ impl OutputType for serde_json::Value { description: Some("A scalar that can represent any JSON value."), is_valid: |_| true, visible: None, + inaccessible: false, specified_by_url: None, } }) diff --git a/src/types/merged_object.rs b/src/types/merged_object.rs index 94fb9556..81d3dee6 100644 --- a/src/types/merged_object.rs +++ b/src/types/merged_object.rs @@ -80,6 +80,7 @@ where shareable: false, keys: None, visible: None, + inaccessible: false, is_subscription: false, rust_typename: std::any::type_name::(), } @@ -139,6 +140,7 @@ where shareable: false, keys: None, visible: None, + inaccessible: false, is_subscription: false, rust_typename: std::any::type_name::(), } @@ -173,6 +175,7 @@ impl SubscriptionType for MergedObjectTail { shareable: false, keys: None, visible: None, + inaccessible: false, is_subscription: false, rust_typename: std::any::type_name::(), }) diff --git a/src/types/query_root.rs b/src/types/query_root.rs index 6043dd05..f38cdfb5 100644 --- a/src/types/query_root.rs +++ b/src/types/query_root.rs @@ -132,6 +132,7 @@ impl OutputType for QueryRoot { requires: None, provides: None, shareable: false, + inaccessible: false, visible: None, compute_complexity: None, }, @@ -152,6 +153,7 @@ impl OutputType for QueryRoot { ty: "String!".to_string(), default_value: None, visible: None, + inaccessible: false, is_secret: false, }, ); @@ -164,6 +166,7 @@ impl OutputType for QueryRoot { requires: None, provides: None, shareable: false, + inaccessible: false, visible: None, compute_complexity: None, }, diff --git a/src/types/upload.rs b/src/types/upload.rs index 2820dcf4..5733a121 100644 --- a/src/types/upload.rs +++ b/src/types/upload.rs @@ -113,6 +113,7 @@ impl InputType for Upload { description: None, is_valid: |value| matches!(value, Value::String(_)), visible: None, + inaccessible: false, specified_by_url: Some("https://github.com/jaydenseric/graphql-multipart-request-spec"), }) } diff --git a/tests/federation.rs b/tests/federation.rs index a3b82178..28febc4c 100644 --- a/tests/federation.rs +++ b/tests/federation.rs @@ -327,3 +327,167 @@ pub async fn test_entity_shareable() { true ); } + +#[tokio::test] +pub async fn test_entity_inaccessible() { + #[derive(SimpleObject)] + struct MyObjFieldInaccessible { + #[graphql(inaccessible)] + obj_field_inaccessible_a: i32, + } + + #[derive(SimpleObject)] + #[graphql(inaccessible)] + struct MyObjInaccessible { + a: i32, + } + + #[derive(InputObject)] + struct MyInputObjFieldInaccessible { + #[graphql(inaccessible)] + input_field_inaccessible_a: i32, + } + + #[derive(InputObject)] + #[graphql(inaccessible)] + struct MyInputObjInaccessible { + a: i32, + } + + #[derive(Enum, PartialEq, Eq, Copy, Clone)] + enum MyEnumVariantInaccessible { + #[graphql(inaccessible)] + OptionAInaccessible, + OptionB, + OptionC, + } + + #[derive(Enum, PartialEq, Eq, Copy, Clone)] + #[graphql(inaccessible)] + enum MyEnumInaccessible { + OptionA, + OptionB, + OptionC, + } + + #[derive(SimpleObject)] + struct MyInterfaceObjA { + inaccessible_interface_value: String, + } + + #[derive(SimpleObject)] + #[graphql(inaccessible)] + struct MyInterfaceObjB { + inaccessible_interface_value: String, + } + + #[derive(Interface)] + #[graphql(field(name = "inaccessible_interface_value", type = "String", inaccessible))] + #[graphql(inaccessible)] + enum MyInterfaceInaccessible { + MyInterfaceObjA(MyInterfaceObjA), + MyInterfaceObjB(MyInterfaceObjB), + } + + #[derive(Union)] + #[graphql(inaccessible)] + enum MyUnionInaccessible { + MyInterfaceObjA(MyInterfaceObjA), + MyInterfaceObjB(MyInterfaceObjB), + } + + struct MyNumberInaccessible(i32); + + #[Scalar(inaccessible)] + impl ScalarType for MyNumberInaccessible { + fn parse(_value: Value) -> InputValueResult { + todo!() + } + + fn to_value(&self) -> Value { + todo!() + } + } + + struct Query; + + #[Object(extends)] + impl Query { + #[graphql(entity)] + async fn find_obj_field_inaccessible(&self, _id: i32) -> MyObjFieldInaccessible { + todo!() + } + + #[graphql(entity)] + async fn find_obj_inaccessible(&self, _id: i32) -> MyObjInaccessible { + todo!() + } + + async fn enum_variant_inaccessible(&self, _id: i32) -> MyEnumVariantInaccessible { + todo!() + } + + async fn enum_inaccessible(&self, _id: i32) -> MyEnumInaccessible { + todo!() + } + + #[graphql(inaccessible)] + async fn inaccessible_field(&self, _id: i32) -> i32 { + todo!() + } + + async fn inaccessible_argument(&self, #[graphql(inaccessible)] _id: i32) -> i32 { + todo!() + } + + async fn inaccessible_interface(&self) -> MyInterfaceInaccessible { + todo!() + } + + async fn inaccessible_union(&self) -> MyUnionInaccessible { + todo!() + } + + async fn inaccessible_scalar(&self) -> MyNumberInaccessible { + todo!() + } + + async fn inaccessible_input_field(&self, _value: MyInputObjFieldInaccessible) -> i32 { + todo!() + } + + async fn inaccessible_input(&self, _value: MyInputObjInaccessible) -> i32 { + todo!() + } + } + + let schema_sdl = Schema::new(Query, EmptyMutation, EmptySubscription) + .sdl_with_options(SDLExportOptions::new().federation()); + + println!("{}", schema_sdl); + + // FIELD_DEFINITION + assert!(schema_sdl.contains("inaccessibleField(id: Int!): Int! @inaccessible")); + assert!(schema_sdl.contains("objFieldInaccessibleA: Int! @inaccessible")); + assert!(schema_sdl.contains("inaccessibleInterfaceValue: String! @inaccessible")); + // INTERFACE + assert!(schema_sdl.contains("interface MyInterfaceInaccessible @inaccessible")); + // OBJECT + assert!(schema_sdl.contains(r#"type MyObjInaccessible @key(fields: "id") @inaccessible"#)); + assert!(schema_sdl + .contains("type MyInterfaceObjB implements MyInterfaceInaccessible @inaccessible")); + // UNION + assert!(schema_sdl.contains("union MyUnionInaccessible @inaccessible =")); + // ARGUMENT_DEFINITION + assert!(schema_sdl.contains("inaccessibleArgument(id: Int! @inaccessible): Int!")); + // SCALAR + assert!(schema_sdl.contains("scalar MyNumberInaccessible @inaccessible")); + // ENUM + assert!(schema_sdl.contains("enum MyEnumInaccessible @inaccessible")); + // ENUM_VALUE + assert!(schema_sdl.contains("OPTION_A_INACCESSIBLE @inaccessible")); + // INPUT_OBJECT + assert!(schema_sdl.contains("input MyInputObjInaccessible @inaccessible")); + // INPUT_FIELD_DEFINITION + assert!(schema_sdl.contains("inputFieldInaccessibleA: Int! @inaccessible")); +}