diff --git a/derive/src/args.rs b/derive/src/args.rs index 250cf2ac..5be1c4c4 100644 --- a/derive/src/args.rs +++ b/derive/src/args.rs @@ -154,6 +154,8 @@ pub struct SimpleObjectField { pub shareable: bool, #[darling(default)] pub inaccessible: bool, + #[darling(default, multiple, rename = "tag")] + pub tags: Vec, #[darling(default)] pub override_from: Option, #[darling(default)] @@ -207,6 +209,8 @@ pub struct SimpleObject { pub shareable: bool, #[darling(default)] pub inaccessible: bool, + #[darling(default, multiple, rename = "tag")] + pub tags: Vec, #[darling(default)] pub visible: Option, #[darling(default, multiple, rename = "concrete")] @@ -233,6 +237,8 @@ pub struct Argument { pub key: bool, // for entity pub visible: Option, pub inaccessible: bool, + #[darling(multiple, rename = "tag")] + pub tags: Vec, pub secret: bool, } @@ -248,6 +254,8 @@ pub struct Object { pub extends: bool, pub shareable: bool, pub inaccessible: bool, + #[darling(multiple, rename = "tag")] + pub tags: Vec, pub use_type_description: bool, pub visible: Option, pub serial: bool, @@ -293,6 +301,8 @@ pub struct ObjectField { pub requires: Option, pub shareable: bool, pub inaccessible: bool, + #[darling(multiple, rename = "tag")] + pub tags: Vec, pub override_from: Option, pub guard: Option>, pub visible: Option, @@ -333,6 +343,8 @@ pub struct Enum { pub visible: Option, #[darling(default)] pub inaccessible: bool, + #[darling(default, multiple, rename = "tag")] + pub tags: Vec, } #[derive(FromVariant)] @@ -350,6 +362,8 @@ pub struct EnumItem { pub visible: Option, #[darling(default)] pub inaccessible: bool, + #[darling(default, multiple, rename = "tag")] + pub tags: Vec, } #[derive(FromDeriveInput)] @@ -368,6 +382,8 @@ pub struct Union { pub visible: Option, #[darling(default)] pub inaccessible: bool, + #[darling(default, multiple, rename = "tag")] + pub tags: Vec, } #[derive(FromVariant)] @@ -411,6 +427,8 @@ pub struct InputObjectField { pub visible: Option, #[darling(default)] pub inaccessible: bool, + #[darling(default, multiple, rename = "tag")] + pub tags: Vec, #[darling(default)] pub secret: bool, } @@ -435,6 +453,8 @@ pub struct InputObject { pub visible: Option, #[darling(default)] pub inaccessible: bool, + #[darling(default, multiple, rename = "tag")] + pub tags: Vec, #[darling(default, multiple, rename = "concrete")] pub concretes: Vec, // for SimpleObject @@ -457,6 +477,8 @@ pub struct OneofObjectField { pub visible: Option, #[darling(default)] pub inaccessible: bool, + #[darling(default, multiple, rename = "tag")] + pub tags: Vec, #[darling(default)] pub secret: bool, } @@ -479,6 +501,8 @@ pub struct OneofObject { pub visible: Option, #[darling(default)] pub inaccessible: bool, + #[darling(default, multiple, rename = "tag")] + pub tags: Vec, #[darling(default, multiple, rename = "concrete")] pub concretes: Vec, } @@ -498,6 +522,8 @@ pub struct InterfaceFieldArgument { pub visible: Option, #[darling(default)] pub inaccessible: bool, + #[darling(default, multiple, rename = "tag")] + pub tags: Vec, #[darling(default)] pub secret: bool, } @@ -525,6 +551,8 @@ pub struct InterfaceField { pub visible: Option, #[darling(default)] pub inaccessible: bool, + #[darling(default, multiple, rename = "tag")] + pub tags: Vec, #[darling(default)] pub shareable: bool, #[darling(default)] @@ -561,6 +589,8 @@ pub struct Interface { pub visible: Option, #[darling(default)] pub inaccessible: bool, + #[darling(default, multiple, rename = "tag")] + pub tags: Vec, } #[derive(FromMeta, Default)] @@ -571,6 +601,8 @@ pub struct Scalar { pub use_type_description: bool, pub visible: Option, pub inaccessible: bool, + #[darling(multiple, rename = "tag")] + pub tags: Vec, pub specified_by_url: Option, } @@ -638,6 +670,8 @@ pub struct MergedObject { pub shareable: bool, #[darling(default)] pub inaccessible: bool, + #[darling(default, multiple, rename = "tag")] + pub tags: Vec, #[darling(default)] pub visible: Option, #[darling(default)] @@ -787,6 +821,8 @@ pub struct NewType { pub visible: Option, #[darling(default)] pub inaccessible: bool, + #[darling(default, multiple, rename = "tag")] + pub tags: Vec, #[darling(default)] pub specified_by_url: Option, } @@ -813,6 +849,8 @@ pub struct ComplexObjectField { pub requires: Option, pub shareable: bool, pub inaccessible: bool, + #[darling(multiple, rename = "tag")] + pub tags: Vec, pub override_from: Option, pub guard: Option>, pub visible: Option, diff --git a/derive/src/complex_object.rs b/derive/src/complex_object.rs index 8630e2cb..51256b42 100644 --- a/derive/src/complex_object.rs +++ b/derive/src/complex_object.rs @@ -178,6 +178,7 @@ pub fn generate( None => quote! { ::std::option::Option::None }, }; let inaccessible = method_args.inaccessible; + let tags = &method_args.tags; let requires = match &method_args.requires { Some(requires) => quote! { ::std::option::Option::Some(#requires) }, None => quote! { ::std::option::Option::None }, @@ -214,6 +215,7 @@ pub fn generate( process_with, visible, inaccessible, + tags, secret, .. }, @@ -249,6 +251,7 @@ pub fn generate( default_value: #schema_default, visible: #visible, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], is_secret: #secret, }); }); @@ -375,6 +378,7 @@ pub fn generate( requires: #requires, shareable: #shareable, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], override_from: #override_from, visible: #visible, compute_complexity: #complexity, diff --git a/derive/src/directive.rs b/derive/src/directive.rs index 4b89a6d9..872c27e5 100644 --- a/derive/src/directive.rs +++ b/derive/src/directive.rs @@ -90,6 +90,7 @@ pub fn generate( default_value: #schema_default, visible: #visible, inaccessible: false, + tags: ::std::default::Default::default(), is_secret: #secret, }); }); diff --git a/derive/src/enum.rs b/derive/src/enum.rs index 3dee9199..27be692c 100644 --- a/derive/src/enum.rs +++ b/derive/src/enum.rs @@ -22,6 +22,7 @@ pub fn generate(enum_args: &args::Enum) -> GeneratorResult { .unwrap_or_else(|| RenameTarget::Type.rename(ident.to_string())); let inaccessible = enum_args.inaccessible; + let tags = &enum_args.tags; let desc = get_rustdoc(&enum_args.attrs)? .map(|s| quote! { ::std::option::Option::Some(#s) }) .unwrap_or_else(|| quote! {::std::option::Option::None}); @@ -49,6 +50,7 @@ pub fn generate(enum_args: &args::Enum) -> GeneratorResult { .rename(variant.ident.unraw().to_string(), RenameTarget::EnumItem) }); let inaccessible = variant.inaccessible; + let tags = &variant.tags; let item_deprecation = gen_deprecation(&variant.deprecation, &crate_name); let item_desc = get_rustdoc(&variant.attrs)? .map(|s| quote! { ::std::option::Option::Some(#s) }) @@ -70,6 +72,7 @@ pub fn generate(enum_args: &args::Enum) -> GeneratorResult { deprecation: #item_deprecation, visible: #visible, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], }); }); } @@ -145,6 +148,7 @@ pub fn generate(enum_args: &args::Enum) -> GeneratorResult { }, visible: #visible, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], rust_typename: ::std::any::type_name::(), } }) diff --git a/derive/src/input_object.rs b/derive/src/input_object.rs index 281bdddb..f0476b75 100644 --- a/derive/src/input_object.rs +++ b/derive/src/input_object.rs @@ -13,6 +13,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult let (impl_generics, ty_generics, where_clause) = object_args.generics.split_for_impl(); let ident = &object_args.ident; let inaccessible = object_args.inaccessible; + let tags = &object_args.tags; let s = match &object_args.data { Data::Struct(s) => s, _ => { @@ -67,6 +68,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult .rename(ident.unraw().to_string(), RenameTarget::Field) }); let inaccessible = field.inaccessible; + let tags = &field.tags; if field.skip || field.skip_input { get_fields.push(quote! { @@ -191,6 +193,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult default_value: #schema_default, visible: #visible, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], is_secret: #secret, }); }) @@ -244,6 +247,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult }, visible: #visible, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], rust_typename: ::std::any::type_name::(), oneof: false, }) @@ -292,6 +296,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult }, visible: #visible, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], rust_typename: ::std::any::type_name::(), oneof: false, }) diff --git a/derive/src/interface.rs b/derive/src/interface.rs index e14284ca..33a4bd03 100644 --- a/derive/src/interface.rs +++ b/derive/src/interface.rs @@ -32,6 +32,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult GeneratorResult GeneratorResult GeneratorResult GeneratorResult GeneratorResult(), } }) diff --git a/derive/src/merged_object.rs b/derive/src/merged_object.rs index b6108c76..a794eab8 100644 --- a/derive/src/merged_object.rs +++ b/derive/src/merged_object.rs @@ -16,6 +16,7 @@ pub fn generate(object_args: &args::MergedObject) -> GeneratorResult GeneratorResult GeneratorResult(), } diff --git a/derive/src/newtype.rs b/derive/src/newtype.rs index 24d56054..b99d3676 100644 --- a/derive/src/newtype.rs +++ b/derive/src/newtype.rs @@ -13,6 +13,7 @@ pub fn generate(newtype_args: &args::NewType) -> GeneratorResult { let ident = &newtype_args.ident; let (impl_generics, ty_generics, where_clause) = newtype_args.generics.split_for_impl(); let inaccessible = newtype_args.inaccessible; + let tags = &newtype_args.tags; let gql_typename = match &newtype_args.name { NewTypeName::New(name) => Some(name.clone()), NewTypeName::Rust => Some(RenameTarget::Type.rename(ident.to_string())), @@ -53,6 +54,7 @@ pub fn generate(newtype_args: &args::NewType) -> GeneratorResult { is_valid: |value| <#ident as #crate_name::ScalarType>::is_valid(value), visible: #visible, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], specified_by_url: #specified_by_url, }) } diff --git a/derive/src/object.rs b/derive/src/object.rs index 2831aec1..6f921d0d 100644 --- a/derive/src/object.rs +++ b/derive/src/object.rs @@ -28,6 +28,7 @@ pub fn generate( let extends = object_args.extends; let shareable = object_args.shareable; let inaccessible = object_args.inaccessible; + let tags = &object_args.tags; let gql_typename = if !object_args.name_type { object_args .name @@ -319,6 +320,7 @@ pub fn generate( let external = method_args.external; let shareable = method_args.shareable; let inaccessible = method_args.inaccessible; + let tags = &method_args.tags; let override_from = match &method_args.override_from { Some(from) => quote! { ::std::option::Option::Some(#from) }, None => quote! { ::std::option::Option::None }, @@ -360,6 +362,7 @@ pub fn generate( visible, secret, inaccessible, + tags, .. }, ) in &args @@ -394,6 +397,7 @@ pub fn generate( default_value: #schema_default, visible: #visible, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], is_secret: #secret, }); }); @@ -519,6 +523,7 @@ pub fn generate( requires: #requires, shareable: #shareable, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], override_from: #override_from, visible: #visible, compute_complexity: #complexity, @@ -655,6 +660,7 @@ pub fn generate( extends: #extends, shareable: #shareable, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], keys: ::std::option::Option::None, visible: #visible, is_subscription: false, @@ -696,6 +702,7 @@ pub fn generate( extends: #extends, shareable: #shareable, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], 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 72d16121..8f5192ef 100644 --- a/derive/src/oneof_object.rs +++ b/derive/src/oneof_object.rs @@ -17,6 +17,7 @@ pub fn generate(object_args: &args::OneofObject) -> GeneratorResult .map(|s| quote! { ::std::option::Option::Some(#s) }) .unwrap_or_else(|| quote! {::std::option::Option::None}); let inaccessible = object_args.inaccessible; + let tags = &object_args.tags; let gql_typename = object_args .name .clone() @@ -43,6 +44,7 @@ pub fn generate(object_args: &args::OneofObject) -> GeneratorResult .rename(enum_name.to_string(), RenameTarget::Field) }); let inaccessible = variant.inaccessible; + let tags = &variant.tags; let desc = get_rustdoc(&object_args.attrs)? .map(|s| quote! { ::std::option::Option::Some(#s) }) .unwrap_or_else(|| quote! {::std::option::Option::None}); @@ -83,6 +85,7 @@ pub fn generate(object_args: &args::OneofObject) -> GeneratorResult default_value: ::std::option::Option::None, visible: #visible, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], is_secret: #secret, }); }); @@ -137,6 +140,7 @@ pub fn generate(object_args: &args::OneofObject) -> GeneratorResult }, visible: #visible, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], rust_typename: ::std::any::type_name::(), oneof: true, }) @@ -188,6 +192,7 @@ pub fn generate(object_args: &args::OneofObject) -> GeneratorResult }, visible: #visible, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], rust_typename: ::std::any::type_name::(), oneof: true, }) diff --git a/derive/src/scalar.rs b/derive/src/scalar.rs index b11deb44..94325554 100644 --- a/derive/src/scalar.rs +++ b/derive/src/scalar.rs @@ -31,6 +31,7 @@ pub fn generate( let where_clause = &item_impl.generics.where_clause; let visible = visible_fn(&scalar_args.visible); let inaccessible = scalar_args.inaccessible; + let tags = &scalar_args.tags; 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 }, @@ -54,6 +55,7 @@ pub fn generate( is_valid: |value| <#self_ty as #crate_name::ScalarType>::is_valid(value), visible: #visible, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], specified_by_url: #specified_by_url, }) } @@ -85,6 +87,7 @@ pub fn generate( is_valid: |value| <#self_ty as #crate_name::ScalarType>::is_valid(value), visible: #visible, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], specified_by_url: #specified_by_url, }) } diff --git a/derive/src/simple_object.rs b/derive/src/simple_object.rs index 35f6b358..1949913c 100644 --- a/derive/src/simple_object.rs +++ b/derive/src/simple_object.rs @@ -32,6 +32,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult GeneratorResult quote! { ::std::option::Option::Some(#from) }, None => quote! { ::std::option::Option::None }, @@ -184,6 +186,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult GeneratorResult GeneratorResult(), }) diff --git a/derive/src/union.rs b/derive/src/union.rs index 05af9d61..a3f82aae 100644 --- a/derive/src/union.rs +++ b/derive/src/union.rs @@ -29,6 +29,7 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult { .unwrap_or_else(|| RenameTarget::Type.rename(ident.to_string())); let inaccessible = union_args.inaccessible; + let tags = &union_args.tags; let desc = get_rustdoc(&union_args.attrs)? .map(|s| quote! { ::std::option::Option::Some(#s) }) .unwrap_or_else(|| quote! {::std::option::Option::None}); @@ -195,6 +196,7 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult { }, visible: #visible, inaccessible: #inaccessible, + tags: &[ #(#tags),* ], rust_typename: ::std::any::type_name::(), } }) diff --git a/src/registry/export_sdl.rs b/src/registry/export_sdl.rs index 1a1bf945..21c5e57e 100644 --- a/src/registry/export_sdl.rs +++ b/src/registry/export_sdl.rs @@ -153,8 +153,14 @@ impl Registry { } sdl.push_str(&export_input_value(arg)); - if options.federation && arg.inaccessible { - write!(sdl, " @inaccessible").ok(); + if options.federation { + if arg.inaccessible { + write!(sdl, " @inaccessible").ok(); + } + + for tag in arg.tags { + write!(sdl, " @tag(name: \"{}\")", tag.replace("\"", "\\\"")).ok(); + } } } write!(sdl, "): {}", field.ty).ok(); @@ -180,6 +186,9 @@ impl Registry { if field.inaccessible { write!(sdl, " @inaccessible").ok(); } + for tag in field.tags { + write!(sdl, " @tag(name: \"{}\")", tag.replace("\"", "\\\"")).ok(); + } if let Some(from) = field.override_from { write!(sdl, " @override(from: \"{}\")", from).ok(); } @@ -195,6 +204,7 @@ impl Registry { name, description, inaccessible, + tags, .. } => { let mut export_scalar = !SYSTEM_SCALARS.contains(&name.as_str()); @@ -207,8 +217,13 @@ impl Registry { } write!(sdl, "scalar {} ", name).ok(); - if options.federation && *inaccessible { - write!(sdl, "@inaccessible ").ok(); + if options.federation { + if *inaccessible { + write!(sdl, "@inaccessible ").ok(); + } + for tag in *tags { + write!(sdl, "@tag(name: \"{}\") ", tag.replace("\"", "\\\"")).ok(); + } } writeln!(sdl).ok(); } @@ -221,6 +236,7 @@ impl Registry { description, shareable, inaccessible, + tags, .. } => { if Some(name.as_str()) == self.subscription_type.as_deref() @@ -271,6 +287,10 @@ impl Registry { if *inaccessible { write!(sdl, "@inaccessible ").ok(); } + + for tag in *tags { + write!(sdl, "@tag(name: \"{}\") ", tag.replace("\"", "\\\"")).ok(); + } } writeln!(sdl, "{{").ok(); @@ -284,6 +304,7 @@ impl Registry { keys, description, inaccessible, + tags, .. } => { if let Some(description) = description { @@ -304,6 +325,10 @@ impl Registry { if *inaccessible { write!(sdl, "@inaccessible ").ok(); } + + for tag in *tags { + write!(sdl, "@tag(name: \"{}\") ", tag.replace("\"", "\\\"")).ok(); + } } self.write_implements(sdl, name); @@ -316,6 +341,7 @@ impl Registry { enum_values, description, inaccessible, + tags, .. } => { if let Some(description) = description { @@ -323,8 +349,13 @@ impl Registry { } write!(sdl, "enum {} ", name).ok(); - if options.federation && *inaccessible { - write!(sdl, "@inaccessible ").ok(); + if options.federation { + if *inaccessible { + write!(sdl, "@inaccessible ").ok(); + } + for tag in *tags { + write!(sdl, "@tag(name: \"{}\") ", tag.replace("\"", "\\\"")).ok(); + } } writeln!(sdl, "{{").ok(); @@ -336,8 +367,15 @@ 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(); + + if options.federation { + if value.inaccessible { + write!(sdl, " @inaccessible").ok(); + } + + for tag in value.tags { + write!(sdl, " @tag(name: \"{}\")", tag.replace("\"", "\\\"")).ok(); + } } writeln!(sdl).ok(); } @@ -349,6 +387,7 @@ impl Registry { input_fields, description, inaccessible, + tags, oneof, .. } => { @@ -361,8 +400,13 @@ impl Registry { if *oneof { write!(sdl, "@oneof ").ok(); } - if options.federation && *inaccessible { - write!(sdl, "@inaccessible ").ok(); + if options.federation { + if *inaccessible { + write!(sdl, "@inaccessible ").ok(); + } + for tag in *tags { + write!(sdl, "@tag(name: \"{}\") ", tag.replace("\"", "\\\"")).ok(); + } } writeln!(sdl, "{{").ok(); @@ -376,8 +420,13 @@ impl Registry { export_description(sdl, options, false, description); } write!(sdl, "\t{} ", export_input_value(&field)).ok(); - if options.federation && field.inaccessible { - write!(sdl, "@inaccessible ").ok(); + if options.federation { + if field.inaccessible { + write!(sdl, "@inaccessible ").ok(); + } + for tag in field.tags { + write!(sdl, "@tag(name: \"{}\") ", tag.replace("\"", "\\\"")).ok(); + } } writeln!(sdl).ok(); } @@ -389,6 +438,7 @@ impl Registry { possible_types, description, inaccessible, + tags, .. } => { if let Some(description) = description { @@ -396,8 +446,13 @@ impl Registry { } write!(sdl, "union {} ", name).ok(); - if options.federation && *inaccessible { - write!(sdl, "@inaccessible ").ok(); + if options.federation { + if *inaccessible { + write!(sdl, "@inaccessible ").ok(); + } + for tag in *tags { + write!(sdl, "@tag(name: \"{}\") ", tag.replace("\"", "\\\"")).ok(); + } } write!(sdl, "=").ok(); diff --git a/src/registry/mod.rs b/src/registry/mod.rs index 4a392e8d..cf67b893 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -112,6 +112,7 @@ pub struct MetaInputValue { pub default_value: Option, pub visible: Option, pub inaccessible: bool, + pub tags: &'static [&'static str], pub is_secret: bool, } @@ -169,6 +170,7 @@ pub struct MetaField { pub visible: Option, pub shareable: bool, pub inaccessible: bool, + pub tags: &'static [&'static str], pub override_from: Option<&'static str>, pub compute_complexity: Option, } @@ -180,6 +182,7 @@ pub struct MetaEnumValue { pub deprecation: Deprecation, pub visible: Option, pub inaccessible: bool, + pub tags: &'static [&'static str], } type MetaVisibleFn = fn(&Context<'_>) -> bool; @@ -215,6 +218,7 @@ pub enum MetaType { is_valid: fn(value: &Value) -> bool, visible: Option, inaccessible: bool, + tags: &'static [&'static str], specified_by_url: Option<&'static str>, }, Object { @@ -227,6 +231,7 @@ pub enum MetaType { keys: Option>, visible: Option, inaccessible: bool, + tags: &'static [&'static str], is_subscription: bool, rust_typename: &'static str, }, @@ -239,6 +244,7 @@ pub enum MetaType { keys: Option>, visible: Option, inaccessible: bool, + tags: &'static [&'static str], rust_typename: &'static str, }, Union { @@ -247,6 +253,7 @@ pub enum MetaType { possible_types: IndexSet, visible: Option, inaccessible: bool, + tags: &'static [&'static str], rust_typename: &'static str, }, Enum { @@ -255,6 +262,7 @@ pub enum MetaType { enum_values: IndexMap<&'static str, MetaEnumValue>, visible: Option, inaccessible: bool, + tags: &'static [&'static str], rust_typename: &'static str, }, InputObject { @@ -263,6 +271,7 @@ pub enum MetaType { input_fields: IndexMap, visible: Option, inaccessible: bool, + tags: &'static [&'static str], rust_typename: &'static str, oneof: bool, }, @@ -506,6 +515,7 @@ impl Registry { extends: false, shareable: false, inaccessible: false, + tags: Default::default(), keys: None, visible: None, is_subscription: false, @@ -635,6 +645,7 @@ impl Registry { provides: None, shareable: false, inaccessible: false, + tags: Default::default(), override_from: None, visible: None, compute_complexity: None, @@ -651,6 +662,7 @@ impl Registry { possible_types, visible: None, inaccessible: false, + tags: Default::default(), rust_typename: "async_graphql::federation::Entity", }, ); @@ -672,6 +684,7 @@ impl Registry { default_value: None, visible: None, inaccessible: false, + tags: Default::default(), is_secret: false, }, ); @@ -686,6 +699,7 @@ impl Registry { shareable: false, visible: None, inaccessible: false, + tags: Default::default(), override_from: None, compute_complexity: None, }, @@ -719,6 +733,7 @@ impl Registry { shareable: false, visible: None, inaccessible: false, + tags: Default::default(), override_from: None, compute_complexity: None, }, @@ -731,6 +746,7 @@ impl Registry { keys: None, visible: None, inaccessible: false, + tags: Default::default(), is_subscription: false, rust_typename: "async_graphql::federation::Service", }, diff --git a/src/resolver_utils/scalar.rs b/src/resolver_utils/scalar.rs index 39c50866..1a7ad8a4 100644 --- a/src/resolver_utils/scalar.rs +++ b/src/resolver_utils/scalar.rs @@ -165,6 +165,7 @@ macro_rules! scalar_internal { is_valid: |value| <$ty as $crate::ScalarType>::is_valid(value), visible: ::std::option::Option::None, inaccessible: false, + tags: ::std::default::Default::default(), specified_by_url: $specified_by_url, } }) @@ -201,6 +202,7 @@ macro_rules! scalar_internal { is_valid: |value| <$ty as $crate::ScalarType>::is_valid(value), visible: ::std::option::Option::None, inaccessible: false, + tags: ::std::default::Default::default(), specified_by_url: $specified_by_url, } }) diff --git a/src/schema.rs b/src/schema.rs index cbc89529..39769ae3 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -400,6 +400,7 @@ where default_value: None, visible: None, inaccessible: false, + tags: Default::default(), is_secret: false, }); args @@ -425,6 +426,7 @@ where default_value: None, visible: None, inaccessible: false, + tags: Default::default(), is_secret: false, }); args diff --git a/src/types/empty_mutation.rs b/src/types/empty_mutation.rs index 96ad2fc1..0f907e20 100644 --- a/src/types/empty_mutation.rs +++ b/src/types/empty_mutation.rs @@ -58,6 +58,7 @@ impl OutputType for EmptyMutation { keys: None, visible: None, inaccessible: false, + tags: Default::default(), is_subscription: false, rust_typename: std::any::type_name::(), }) diff --git a/src/types/empty_subscription.rs b/src/types/empty_subscription.rs index a9a3f4d8..bc35ba79 100644 --- a/src/types/empty_subscription.rs +++ b/src/types/empty_subscription.rs @@ -27,6 +27,7 @@ impl SubscriptionType for EmptySubscription { keys: None, visible: None, inaccessible: false, + tags: Default::default(), 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 1034d7b7..f9c4789f 100644 --- a/src/types/external/json_object/btreemap.rs +++ b/src/types/external/json_object/btreemap.rs @@ -30,6 +30,7 @@ where is_valid: |_| true, visible: None, inaccessible: false, + tags: Default::default(), specified_by_url: None, }) } @@ -86,6 +87,7 @@ where is_valid: |_| true, visible: None, inaccessible: false, + tags: Default::default(), specified_by_url: None, }) } diff --git a/src/types/external/json_object/hashmap.rs b/src/types/external/json_object/hashmap.rs index cae73228..de908d55 100644 --- a/src/types/external/json_object/hashmap.rs +++ b/src/types/external/json_object/hashmap.rs @@ -37,6 +37,7 @@ where is_valid: |_| true, visible: None, inaccessible: false, + tags: Default::default(), specified_by_url: None, }) } @@ -94,6 +95,7 @@ where is_valid: |_| true, visible: None, inaccessible: false, + tags: Default::default(), specified_by_url: None, }) } diff --git a/src/types/json.rs b/src/types/json.rs index c5b05639..d33f3314 100644 --- a/src/types/json.rs +++ b/src/types/json.rs @@ -55,6 +55,7 @@ impl InputType for Json { is_valid: |_| true, visible: None, inaccessible: false, + tags: Default::default(), specified_by_url: None, }) } @@ -85,6 +86,7 @@ impl OutputType for Json { is_valid: |_| true, visible: None, inaccessible: false, + tags: Default::default(), specified_by_url: None, }) } @@ -113,6 +115,7 @@ impl InputType for serde_json::Value { is_valid: |_| true, visible: None, inaccessible: false, + tags: Default::default(), specified_by_url: None, } }) @@ -145,6 +148,7 @@ impl OutputType for serde_json::Value { is_valid: |_| true, visible: None, inaccessible: false, + tags: Default::default(), specified_by_url: None, } }) diff --git a/src/types/merged_object.rs b/src/types/merged_object.rs index 81d3dee6..f8747be4 100644 --- a/src/types/merged_object.rs +++ b/src/types/merged_object.rs @@ -81,6 +81,7 @@ where keys: None, visible: None, inaccessible: false, + tags: Default::default(), is_subscription: false, rust_typename: std::any::type_name::(), } @@ -141,6 +142,7 @@ where keys: None, visible: None, inaccessible: false, + tags: Default::default(), is_subscription: false, rust_typename: std::any::type_name::(), } @@ -176,6 +178,7 @@ impl SubscriptionType for MergedObjectTail { keys: None, visible: None, inaccessible: false, + tags: Default::default(), is_subscription: false, rust_typename: std::any::type_name::(), }) diff --git a/src/types/query_root.rs b/src/types/query_root.rs index 93d3d977..ac82f5dc 100644 --- a/src/types/query_root.rs +++ b/src/types/query_root.rs @@ -133,6 +133,7 @@ impl OutputType for QueryRoot { provides: None, shareable: false, inaccessible: false, + tags: Default::default(), visible: None, compute_complexity: None, override_from: None, @@ -155,6 +156,7 @@ impl OutputType for QueryRoot { default_value: None, visible: None, inaccessible: false, + tags: Default::default(), is_secret: false, }, ); @@ -168,6 +170,7 @@ impl OutputType for QueryRoot { provides: None, shareable: false, inaccessible: false, + tags: Default::default(), override_from: None, visible: None, compute_complexity: None, diff --git a/src/types/upload.rs b/src/types/upload.rs index 5733a121..f8b8dd62 100644 --- a/src/types/upload.rs +++ b/src/types/upload.rs @@ -114,6 +114,7 @@ impl InputType for Upload { is_valid: |value| matches!(value, Value::String(_)), visible: None, inaccessible: false, + tags: Default::default(), specified_by_url: Some("https://github.com/jaydenseric/graphql-multipart-request-spec"), }) } diff --git a/tests/federation.rs b/tests/federation.rs index 0a48bd27..f2193251 100644 --- a/tests/federation.rs +++ b/tests/federation.rs @@ -535,3 +535,202 @@ pub async fn test_entity_inaccessible() { // INPUT_FIELD_DEFINITION assert!(schema_sdl.contains("inputFieldInaccessibleA: Int! @inaccessible")); } + +#[tokio::test] +pub async fn test_entity_tag() { + struct MyCustomObjTagged; + + #[Object( + tag = "tagged", + tag = "object", + tag = "with", + tag = "multiple", + tag = "tags" + )] + impl MyCustomObjTagged { + async fn a(&self) -> i32 { + todo!() + } + + #[graphql(tag = "tagged_custom_object_field")] + async fn custom_object_tagged(&self) -> i32 { + todo!() + } + } + + #[derive(SimpleObject)] + struct MyObjFieldTagged { + #[graphql(tag = "tagged_field")] + obj_field_tagged_a: i32, + } + + #[derive(SimpleObject)] + #[graphql(tag = "tagged_simple_object")] + struct MyObjTagged { + a: i32, + } + + #[derive(InputObject)] + struct MyInputObjFieldTagged { + #[graphql(tag = "tagged_input_object_field")] + input_field_tagged_a: i32, + } + + #[derive(InputObject)] + #[graphql(tag = "input_object_tag")] + struct MyInputObjTagged { + a: i32, + } + + #[derive(Enum, PartialEq, Eq, Copy, Clone)] + enum MyEnumVariantTagged { + #[graphql(tag = "tagged_enum_option")] + OptionATagged, + OptionB, + OptionC, + } + + #[derive(Enum, PartialEq, Eq, Copy, Clone)] + #[graphql(tag = "tagged_num")] + enum MyEnumTagged { + OptionA, + OptionB, + OptionC, + } + + #[derive(SimpleObject)] + struct MyInterfaceObjA { + tagged_interface_value: String, + } + + #[derive(SimpleObject)] + #[graphql(tag = "interface_object")] + struct MyInterfaceObjB { + tagged_interface_value: String, + } + + #[derive(Interface)] + #[graphql(field( + name = "tagged_interface_value", + type = "String", + tag = "tagged_interface_field" + ))] + #[graphql(tag = "tagged_interface")] + enum MyInterfaceTagged { + MyInterfaceObjA(MyInterfaceObjA), + MyInterfaceObjB(MyInterfaceObjB), + } + + #[derive(Union)] + #[graphql(tag = "tagged_union")] + enum MyUnionTagged { + MyInterfaceObjA(MyInterfaceObjA), + MyInterfaceObjB(MyInterfaceObjB), + } + + struct MyNumberTagged(i32); + + #[Scalar(tag = "tagged_scalar")] + impl ScalarType for MyNumberTagged { + 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_tagged(&self, _id: i32) -> MyObjFieldTagged { + todo!() + } + + #[graphql(entity)] + async fn find_obj_tagged(&self, _id: i32) -> MyObjTagged { + todo!() + } + + async fn enum_variant_tagged(&self, _id: i32) -> MyEnumVariantTagged { + todo!() + } + + async fn enum_tagged(&self, _id: i32) -> MyEnumTagged { + todo!() + } + + #[graphql(tag = "tagged_\"field\"")] + async fn tagged_field(&self, _id: i32) -> i32 { + todo!() + } + + async fn tagged_argument(&self, #[graphql(tag = "tagged_argument")] _id: i32) -> i32 { + todo!() + } + + async fn tagged_interface(&self) -> MyInterfaceTagged { + todo!() + } + + async fn tagged_union(&self) -> MyUnionTagged { + todo!() + } + + async fn tagged_scalar(&self) -> MyNumberTagged { + todo!() + } + + async fn tagged_input_field(&self, _value: MyInputObjFieldTagged) -> i32 { + todo!() + } + + async fn tagged_input(&self, _value: MyInputObjTagged) -> i32 { + todo!() + } + + async fn tagged_custom_object(&self) -> MyCustomObjTagged { + todo!() + } + } + + let schema_sdl = Schema::new(Query, EmptyMutation, EmptySubscription) + .sdl_with_options(SDLExportOptions::new().federation()); + + // FIELD_DEFINITION + assert!(schema_sdl.contains(r#"taggedField(id: Int!): Int! @tag(name: "tagged_\"field\"")"#)); + assert!(schema_sdl.contains(r#"objFieldTaggedA: Int! @tag(name: "tagged_field")"#)); + assert!(schema_sdl + .contains(r#"taggedInterfaceValue: String! @tag(name: "tagged_interface_field")"#)); + assert!( + schema_sdl.contains(r#"customObjectTagged: Int! @tag(name: "tagged_custom_object_field")"#) + ); + // INTERFACE + assert!(schema_sdl.contains(r#"interface MyInterfaceTagged @tag(name: "tagged_interface")"#)); + // OBJECT + assert!(schema_sdl.contains(r#"type MyCustomObjTagged @tag(name: "tagged") @tag(name: "object") @tag(name: "with") @tag(name: "multiple") @tag(name: "tags") {"#)); + assert!(schema_sdl + .contains(r#"type MyObjTagged @key(fields: "id") @tag(name: "tagged_simple_object") {"#)); + assert!(schema_sdl.contains( + r#"type MyInterfaceObjB implements MyInterfaceTagged @tag(name: "interface_object")"# + )); + // UNION + assert!(schema_sdl.contains(r#"union MyUnionTagged @tag(name: "tagged_union") ="#)); + // ARGUMENT_DEFINITION + assert!(schema_sdl.contains(r#"taggedArgument(id: Int! @tag(name: "tagged_argument")): Int!"#)); + // SCALAR + assert!(schema_sdl.contains(r#"scalar MyNumberTagged @tag(name: "tagged_scalar")"#)); + // ENUM + assert!(schema_sdl.contains(r#"enum MyEnumTagged @tag(name: "tagged_num")"#)); + // ENUM_VALUE + assert!(schema_sdl.contains(r#"OPTION_A_TAGGED @tag(name: "tagged_enum_option")"#)); + // INPUT_OBJECT + assert!(schema_sdl.contains(r#"input MyInputObjTagged @tag(name: "input_object_tag")"#)); + // INPUT_FIELD_DEFINITION + assert!( + schema_sdl.contains(r#"inputFieldTaggedA: Int! @tag(name: "tagged_input_object_field")"#) + ); +}