From 5ad9f497d89b31a5d76ce58b2a524a9ad70b44f1 Mon Sep 17 00:00:00 2001 From: Sunli Date: Sat, 7 May 2022 16:16:01 +0800 Subject: [PATCH] Remove code and tests related oneof fields. #915 --- derive/src/args.rs | 5 - derive/src/complex_object.rs | 194 ++++++----------- derive/src/interface.rs | 107 ++++------ derive/src/object.rs | 201 ++++++------------ derive/src/simple_object.rs | 1 - derive/src/subscription.rs | 196 ++++++----------- src/docs/complex_object.md | 1 - src/docs/interface.md | 1 - src/docs/object.md | 36 ---- src/docs/subscription.md | 1 - src/model/field.rs | 4 - src/registry/export_sdl.rs | 16 +- src/registry/mod.rs | 5 - src/types/query_root.rs | 2 - src/validation/mod.rs | 1 - src/validation/rules/mod.rs | 2 - .../oneof_fields_have_exactly_one_argument.rs | 101 --------- src/validation/test_harness.rs | 5 - tests/complex_object.rs | 84 -------- tests/interface.rs | 115 ---------- tests/object.rs | 77 ------- tests/subscription.rs | 43 ---- tests/validators.rs | 100 --------- 23 files changed, 250 insertions(+), 1048 deletions(-) delete mode 100644 src/validation/rules/oneof_fields_have_exactly_one_argument.rs diff --git a/derive/src/args.rs b/derive/src/args.rs index b189b29c..a9cca4a5 100644 --- a/derive/src/args.rs +++ b/derive/src/args.rs @@ -284,7 +284,6 @@ pub struct ObjectField { #[darling(default, multiple)] pub derived: Vec, pub flatten: bool, - pub oneof: bool, } #[derive(FromMeta, Default, Clone)] @@ -492,8 +491,6 @@ pub struct InterfaceField { pub requires: Option, #[darling(default)] pub visible: Option, - #[darling(default)] - pub oneof: bool, } #[derive(FromVariant)] @@ -573,7 +570,6 @@ pub struct SubscriptionField { pub guard: Option>, pub visible: Option, pub complexity: Option, - pub oneof: bool, } #[derive(FromField)] @@ -774,7 +770,6 @@ pub struct ComplexObjectField { #[darling(multiple)] pub derived: Vec, pub flatten: bool, - pub oneof: bool, } #[derive(FromMeta, Default)] diff --git a/derive/src/complex_object.rs b/derive/src/complex_object.rs index ae35124c..29c75864 100644 --- a/derive/src/complex_object.rs +++ b/derive/src/complex_object.rs @@ -191,102 +191,50 @@ pub fn generate( } }; - let mut args = extract_input_args::(&crate_name, method)?; + let args = extract_input_args::(&crate_name, method)?; let mut schema_args = Vec::new(); let mut use_params = Vec::new(); let mut get_params = Vec::new(); - let mut is_oneof_field = false; - if method_args.oneof { - is_oneof_field = true; - - if args.len() != 1 { - return Err(Error::new_spanned( - &method, - "The `oneof` field requires exactly one argument.", - ) - .into()); - } - let (ident, ty, argument) = args.pop().unwrap(); - schema_args.push(quote! { - #crate_name::static_assertions::assert_impl_one!(#ty: #crate_name::OneofObjectType); - if let #crate_name::registry::MetaType::InputObject { input_fields, .. } = registry.create_fake_input_type::<#ty>() { - args.extend(input_fields); - } + for ( + ident, + ty, + args::Argument { + name, + desc, + default, + default_with, + validator, + process_with, + visible, + secret, + .. + }, + ) in &args + { + let name = name.clone().unwrap_or_else(|| { + object_args + .rename_args + .rename(ident.ident.unraw().to_string(), RenameTarget::Argument) }); - use_params.push(quote! { #ident }); - - let param_ident = &ident.ident; - let process_with = match argument.process_with.as_ref() { - Some(fn_path) => { - let fn_path: syn::ExprPath = syn::parse_str(fn_path)?; + let desc = desc + .as_ref() + .map(|s| quote! {::std::option::Option::Some(#s)}) + .unwrap_or_else(|| quote! {::std::option::Option::None}); + let default = generate_default(default, default_with)?; + let schema_default = default + .as_ref() + .map(|value| { quote! { - #fn_path(&mut #param_ident); + ::std::option::Option::Some(::std::string::ToString::to_string( + &<#ty as #crate_name::InputType>::to_value(&#value) + )) } - } - None => Default::default(), - }; + }) + .unwrap_or_else(|| quote! {::std::option::Option::None}); - let validators = argument - .validator - .clone() - .unwrap_or_default() - .create_validators( - &crate_name, - quote!(&#ident), - quote!(#ty), - Some(quote!(.map_err(|err| err.into_server_error(__pos)))), - )?; - let mut non_mut_ident = ident.clone(); - non_mut_ident.mutability = None; - get_params.push(quote! { - #[allow(non_snake_case, unused_variables, unused_mut)] - let (__pos, mut #non_mut_ident) = ctx.oneof_param_value::<#ty>()?; - #process_with - #validators - #[allow(non_snake_case, unused_variables)] - let #ident = #non_mut_ident; - }); - } else { - for ( - ident, - ty, - args::Argument { - name, - desc, - default, - default_with, - validator, - process_with, - visible, - secret, - .. - }, - ) in &args - { - let name = name.clone().unwrap_or_else(|| { - object_args - .rename_args - .rename(ident.ident.unraw().to_string(), RenameTarget::Argument) - }); - let desc = desc - .as_ref() - .map(|s| quote! {::std::option::Option::Some(#s)}) - .unwrap_or_else(|| quote! {::std::option::Option::None}); - let default = generate_default(default, default_with)?; - let schema_default = default - .as_ref() - .map(|value| { - quote! { - ::std::option::Option::Some(::std::string::ToString::to_string( - &<#ty as #crate_name::InputType>::to_value(&#value) - )) - } - }) - .unwrap_or_else(|| quote! {::std::option::Option::None}); - - let visible = visible_fn(visible); - schema_args.push(quote! { + let visible = visible_fn(visible); + schema_args.push(quote! { args.insert(::std::borrow::ToOwned::to_owned(#name), #crate_name::registry::MetaInputValue { name: #name, description: #desc, @@ -297,45 +245,44 @@ pub fn generate( }); }); - let param_ident = &ident.ident; - use_params.push(quote! { #param_ident }); + let param_ident = &ident.ident; + use_params.push(quote! { #param_ident }); - let default = match default { - Some(default) => { - quote! { ::std::option::Option::Some(|| -> #ty { #default }) } + let default = match default { + Some(default) => { + quote! { ::std::option::Option::Some(|| -> #ty { #default }) } + } + None => quote! { ::std::option::Option::None }, + }; + + let param_ident = &ident.ident; + let process_with = match process_with.as_ref() { + Some(fn_path) => { + let fn_path: syn::ExprPath = syn::parse_str(fn_path)?; + quote! { + #fn_path(&mut #param_ident); } - None => quote! { ::std::option::Option::None }, - }; + } + None => Default::default(), + }; - let param_ident = &ident.ident; - let process_with = match process_with.as_ref() { - Some(fn_path) => { - let fn_path: syn::ExprPath = syn::parse_str(fn_path)?; - quote! { - #fn_path(&mut #param_ident); - } - } - None => Default::default(), - }; + let validators = validator.clone().unwrap_or_default().create_validators( + &crate_name, + quote!(&#ident), + quote!(ty), + Some(quote!(.map_err(|err| err.into_server_error(__pos)))), + )?; - let validators = validator.clone().unwrap_or_default().create_validators( - &crate_name, - quote!(&#ident), - quote!(ty), - Some(quote!(.map_err(|err| err.into_server_error(__pos)))), - )?; - - let mut non_mut_ident = ident.clone(); - non_mut_ident.mutability = None; - get_params.push(quote! { - #[allow(non_snake_case, unused_mut)] - let (__pos, mut #non_mut_ident) = ctx.param_value::<#ty>(#name, #default)?; - #process_with - #validators - #[allow(non_snake_case)] - let #ident = #non_mut_ident; - }); - } + let mut non_mut_ident = ident.clone(); + non_mut_ident.mutability = None; + get_params.push(quote! { + #[allow(non_snake_case, unused_mut)] + let (__pos, mut #non_mut_ident) = ctx.param_value::<#ty>(#name, #default)?; + #process_with + #validators + #[allow(non_snake_case)] + let #ident = #non_mut_ident; + }); } let ty = match &method.sig.output { @@ -420,7 +367,6 @@ pub fn generate( requires: #requires, visible: #visible, compute_complexity: #complexity, - oneof: #is_oneof_field, })); }); diff --git a/derive/src/interface.rs b/derive/src/interface.rs index a40107bf..a0261358 100644 --- a/derive/src/interface.rs +++ b/derive/src/interface.rs @@ -137,10 +137,8 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult GeneratorResult }); use_params.push(quote! { ctx }); - let mut is_oneof_field = false; - - if *oneof { - is_oneof_field = true; - - if args.len() != 1 { - return Err( - Error::new(name_span, "The `oneof` field requires one parameter.").into(), - ); - } - - let InterfaceFieldArgument { name, ty, .. } = &args[0]; + for InterfaceFieldArgument { + name, + desc, + ty, + default, + default_with, + visible, + secret, + } in args + { let ident = Ident::new(name, Span::call_site()); + let name = interface_args + .rename_args + .rename(name, RenameTarget::Argument); let ty = match syn::parse_str::(&ty.value()) { Ok(ty) => ty, Err(_) => return Err(Error::new_spanned(&ty, "Expect type").into()), }; - decl_params.push(quote! { #ident: #ty }); use_params.push(quote! { #ident }); + + let default = generate_default(default, default_with)?; + let get_default = match &default { + Some(default) => quote! { ::std::option::Option::Some(|| -> #ty { #default }) }, + None => quote! { ::std::option::Option::None }, + }; get_params.push(quote! { - #[allow(non_snake_case, unused_variables)] - let (_, #ident) = ctx.oneof_param_value::<#ty>()?; + let (_, #ident) = ctx.param_value::<#ty>(#name, #get_default)?; }); + + let desc = desc + .as_ref() + .map(|s| quote! {::std::option::Option::Some(#s)}) + .unwrap_or_else(|| quote! {::std::option::Option::None}); + let schema_default = default + .as_ref() + .map(|value| { + quote! { + ::std::option::Option::Some(::std::string::ToString::to_string( + &<#ty as #crate_name::InputType>::to_value(&#value) + )) + } + }) + .unwrap_or_else(|| quote! {::std::option::Option::None}); + let visible = visible_fn(visible); schema_args.push(quote! { - #crate_name::static_assertions::assert_impl_one!(#ty: #crate_name::OneofObjectType); - if let #crate_name::registry::MetaType::InputObject { input_fields, .. } = registry.create_fake_input_type::<#ty>() { - args.extend(input_fields); - } - }); - } else { - for InterfaceFieldArgument { - name, - desc, - ty, - default, - default_with, - visible, - secret, - } in args - { - let ident = Ident::new(name, Span::call_site()); - let name = interface_args - .rename_args - .rename(name, RenameTarget::Argument); - let ty = match syn::parse_str::(&ty.value()) { - Ok(ty) => ty, - Err(_) => return Err(Error::new_spanned(&ty, "Expect type").into()), - }; - decl_params.push(quote! { #ident: #ty }); - use_params.push(quote! { #ident }); - - let default = generate_default(default, default_with)?; - let get_default = match &default { - Some(default) => quote! { ::std::option::Option::Some(|| -> #ty { #default }) }, - None => quote! { ::std::option::Option::None }, - }; - get_params.push(quote! { - let (_, #ident) = ctx.param_value::<#ty>(#name, #get_default)?; - }); - - let desc = desc - .as_ref() - .map(|s| quote! {::std::option::Option::Some(#s)}) - .unwrap_or_else(|| quote! {::std::option::Option::None}); - let schema_default = default - .as_ref() - .map(|value| { - quote! { - ::std::option::Option::Some(::std::string::ToString::to_string( - &<#ty as #crate_name::InputType>::to_value(&#value) - )) - } - }) - .unwrap_or_else(|| quote! {::std::option::Option::None}); - let visible = visible_fn(visible); - schema_args.push(quote! { args.insert(::std::borrow::ToOwned::to_owned(#name), #crate_name::registry::MetaInputValue { name: #name, description: #desc, @@ -259,7 +226,6 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult GeneratorResult(&crate_name, method)?; let ty = match &method.sig.output { @@ -342,103 +334,50 @@ pub fn generate( } }; - let mut args = extract_input_args::(&crate_name, method)?; + let args = extract_input_args::(&crate_name, method)?; let mut schema_args = Vec::new(); let mut use_params = Vec::new(); let mut get_params = Vec::new(); - let mut is_oneof_field = false; - if method_args.oneof { - is_oneof_field = true; - - if args.len() != 1 { - return Err(Error::new_spanned( - &method, - "The `oneof` field requires exactly one argument.", - ) - .into()); - } - let (ident, ty, argument) = args.pop().unwrap(); - - schema_args.push(quote! { - #crate_name::static_assertions::assert_impl_one!(#ty: #crate_name::OneofObjectType); - if let #crate_name::registry::MetaType::InputObject { input_fields, .. } = registry.create_fake_input_type::<#ty>() { - args.extend(input_fields); - } + for ( + ident, + ty, + args::Argument { + name, + desc, + default, + default_with, + process_with, + validator, + visible, + secret, + .. + }, + ) in &args + { + let name = name.clone().unwrap_or_else(|| { + object_args + .rename_args + .rename(ident.ident.unraw().to_string(), RenameTarget::Argument) }); - use_params.push(quote! { #ident }); - - let param_ident = &ident.ident; - let process_with = match argument.process_with.as_ref() { - Some(fn_path) => { - let fn_path: syn::ExprPath = syn::parse_str(fn_path)?; + let desc = desc + .as_ref() + .map(|s| quote! {::std::option::Option::Some(#s)}) + .unwrap_or_else(|| quote! {::std::option::Option::None}); + let default = generate_default(default, default_with)?; + let schema_default = default + .as_ref() + .map(|value| { quote! { - #fn_path(&mut #param_ident); + ::std::option::Option::Some(::std::string::ToString::to_string( + &<#ty as #crate_name::InputType>::to_value(&#value) + )) } - } - None => Default::default(), - }; + }) + .unwrap_or_else(|| quote! {::std::option::Option::None}); - let validators = argument - .validator - .clone() - .unwrap_or_default() - .create_validators( - &crate_name, - quote!(&#ident), - quote!(#ty), - Some(quote!(.map_err(|err| err.into_server_error(__pos)))), - )?; - let mut non_mut_ident = ident.clone(); - non_mut_ident.mutability = None; - get_params.push(quote! { - #[allow(non_snake_case, unused_variables, unused_mut)] - let (__pos, mut #non_mut_ident) = ctx.oneof_param_value::<#ty>()?; - #process_with - #validators - #[allow(non_snake_case, unused_variables)] - let #ident = #non_mut_ident; - }); - } else { - for ( - ident, - ty, - args::Argument { - name, - desc, - default, - default_with, - process_with, - validator, - visible, - secret, - .. - }, - ) in &args - { - let name = name.clone().unwrap_or_else(|| { - object_args - .rename_args - .rename(ident.ident.unraw().to_string(), RenameTarget::Argument) - }); - let desc = desc - .as_ref() - .map(|s| quote! {::std::option::Option::Some(#s)}) - .unwrap_or_else(|| quote! {::std::option::Option::None}); - let default = generate_default(default, default_with)?; - let schema_default = default - .as_ref() - .map(|value| { - quote! { - ::std::option::Option::Some(::std::string::ToString::to_string( - &<#ty as #crate_name::InputType>::to_value(&#value) - )) - } - }) - .unwrap_or_else(|| quote! {::std::option::Option::None}); - - let visible = visible_fn(visible); - schema_args.push(quote! { + let visible = visible_fn(visible); + schema_args.push(quote! { args.insert(::std::borrow::ToOwned::to_owned(#name), #crate_name::registry::MetaInputValue { name: #name, description: #desc, @@ -449,44 +388,43 @@ pub fn generate( }); }); - let param_ident = &ident.ident; - use_params.push(quote! { #param_ident }); + let param_ident = &ident.ident; + use_params.push(quote! { #param_ident }); - let default = match default { - Some(default) => { - quote! { ::std::option::Option::Some(|| -> #ty { #default }) } + let default = match default { + Some(default) => { + quote! { ::std::option::Option::Some(|| -> #ty { #default }) } + } + None => quote! { ::std::option::Option::None }, + }; + + let process_with = match process_with.as_ref() { + Some(fn_path) => { + let fn_path: syn::ExprPath = syn::parse_str(fn_path)?; + quote! { + #fn_path(&mut #param_ident); } - None => quote! { ::std::option::Option::None }, - }; + } + None => Default::default(), + }; - let process_with = match process_with.as_ref() { - Some(fn_path) => { - let fn_path: syn::ExprPath = syn::parse_str(fn_path)?; - quote! { - #fn_path(&mut #param_ident); - } - } - None => Default::default(), - }; + let validators = validator.clone().unwrap_or_default().create_validators( + &crate_name, + quote!(&#ident), + quote!(#ty), + Some(quote!(.map_err(|err| err.into_server_error(__pos)))), + )?; - let validators = validator.clone().unwrap_or_default().create_validators( - &crate_name, - quote!(&#ident), - quote!(#ty), - Some(quote!(.map_err(|err| err.into_server_error(__pos)))), - )?; - - let mut non_mut_ident = ident.clone(); - non_mut_ident.mutability = None; - get_params.push(quote! { - #[allow(non_snake_case, unused_variables, unused_mut)] - let (__pos, mut #non_mut_ident) = ctx.param_value::<#ty>(#name, #default)?; - #process_with - #validators - #[allow(non_snake_case, unused_variables)] - let #ident = #non_mut_ident; - }); - } + let mut non_mut_ident = ident.clone(); + non_mut_ident.mutability = None; + get_params.push(quote! { + #[allow(non_snake_case, unused_variables, unused_mut)] + let (__pos, mut #non_mut_ident) = ctx.param_value::<#ty>(#name, #default)?; + #process_with + #validators + #[allow(non_snake_case, unused_variables)] + let #ident = #non_mut_ident; + }); } let ty = match &method.sig.output { @@ -571,7 +509,6 @@ pub fn generate( requires: #requires, visible: #visible, compute_complexity: #complexity, - oneof: #is_oneof_field, }); }); diff --git a/derive/src/simple_object.rs b/derive/src/simple_object.rs index 4d5d60b2..dc2bff44 100644 --- a/derive/src/simple_object.rs +++ b/derive/src/simple_object.rs @@ -176,7 +176,6 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult(&crate_name, method)?; + let args = extract_input_args::(&crate_name, method)?; - if field.oneof { - is_oneof_field = true; - - if args.len() != 1 { - return Err(Error::new_spanned( - &method, - "The `oneof` field requires exactly one argument.", - ) - .into()); - } - let (ident, ty, argument) = args.pop().unwrap(); - - schema_args.push(quote! { - #crate_name::static_assertions::assert_impl_one!(#ty: #crate_name::OneofObjectType); - if let #crate_name::registry::MetaType::InputObject { input_fields, .. } = registry.create_fake_input_type::<#ty>() { - args.extend(input_fields); - } - }); - use_params.push(quote! { #ident }); - - let param_ident = &ident.ident; - let process_with = match argument.process_with.as_ref() { - Some(fn_path) => { - let fn_path: syn::ExprPath = syn::parse_str(fn_path)?; - quote! { - #fn_path(&mut #param_ident); - } - } - None => Default::default(), - }; - - let validators = argument - .validator - .clone() - .unwrap_or_default() - .create_validators( - &crate_name, - quote!(&#ident), - quote!(#ty), - Some(quote!(.map_err(|err| err.into_server_error(__pos)))), - )?; - let mut non_mut_ident = ident.clone(); - non_mut_ident.mutability = None; - get_params.push(quote! { - #[allow(non_snake_case, unused_variables, unused_mut)] - let (__pos, mut #non_mut_ident) = ctx.oneof_param_value::<#ty>()?; - #process_with - #validators - #[allow(non_snake_case, unused_variables)] - let #ident = #non_mut_ident; + for ( + ident, + ty, + args::SubscriptionFieldArgument { + name, + desc, + default, + default_with, + validator, + process_with, + visible: arg_visible, + secret, + }, + ) in &args + { + let name = name.clone().unwrap_or_else(|| { + subscription_args + .rename_args + .rename(ident.ident.unraw().to_string(), RenameTarget::Argument) }); - } else { - for ( - ident, - ty, - args::SubscriptionFieldArgument { - name, - desc, - default, - default_with, - validator, - process_with, - visible: arg_visible, - secret, - }, - ) in &args - { - let name = name.clone().unwrap_or_else(|| { - subscription_args - .rename_args - .rename(ident.ident.unraw().to_string(), RenameTarget::Argument) - }); - let desc = desc - .as_ref() - .map(|s| quote! {::std::option::Option::Some(#s)}) - .unwrap_or_else(|| quote! {::std::option::Option::None}); - let default = generate_default(default, default_with)?; + let desc = desc + .as_ref() + .map(|s| quote! {::std::option::Option::Some(#s)}) + .unwrap_or_else(|| quote! {::std::option::Option::None}); + let default = generate_default(default, default_with)?; - let schema_default = default - .as_ref() - .map(|value| { - quote! { - ::std::option::Option::Some(::std::string::ToString::to_string( - &<#ty as #crate_name::InputType>::to_value(&#value) - )) - } - }) - .unwrap_or_else(|| quote! {::std::option::Option::None}); + let schema_default = default + .as_ref() + .map(|value| { + quote! { + ::std::option::Option::Some(::std::string::ToString::to_string( + &<#ty as #crate_name::InputType>::to_value(&#value) + )) + } + }) + .unwrap_or_else(|| quote! {::std::option::Option::None}); - let visible = visible_fn(arg_visible); - schema_args.push(quote! { + let visible = visible_fn(arg_visible); + schema_args.push(quote! { args.insert(::std::borrow::ToOwned::to_owned(#name), #crate_name::registry::MetaInputValue { name: #name, description: #desc, @@ -177,44 +123,43 @@ pub fn generate( }); }); - use_params.push(quote! { #ident }); + use_params.push(quote! { #ident }); - let default = match default { - Some(default) => { - quote! { ::std::option::Option::Some(|| -> #ty { #default }) } + let default = match default { + Some(default) => { + quote! { ::std::option::Option::Some(|| -> #ty { #default }) } + } + None => quote! { ::std::option::Option::None }, + }; + + let param_ident = &ident.ident; + let process_with = match process_with.as_ref() { + Some(fn_path) => { + let fn_path: syn::ExprPath = syn::parse_str(fn_path)?; + quote! { + #fn_path(&mut #param_ident); } - None => quote! { ::std::option::Option::None }, - }; + } + None => Default::default(), + }; - let param_ident = &ident.ident; - let process_with = match process_with.as_ref() { - Some(fn_path) => { - let fn_path: syn::ExprPath = syn::parse_str(fn_path)?; - quote! { - #fn_path(&mut #param_ident); - } - } - None => Default::default(), - }; + let validators = validator.clone().unwrap_or_default().create_validators( + &crate_name, + quote!(&#ident), + quote!(#ty), + Some(quote!(.map_err(|err| err.into_server_error(__pos)))), + )?; - let validators = validator.clone().unwrap_or_default().create_validators( - &crate_name, - quote!(&#ident), - quote!(#ty), - Some(quote!(.map_err(|err| err.into_server_error(__pos)))), - )?; - - let mut non_mut_ident = ident.clone(); - non_mut_ident.mutability = None; - get_params.push(quote! { - #[allow(non_snake_case, unused_mut)] - let (__pos, mut #non_mut_ident) = ctx.param_value::<#ty>(#name, #default)?; - #process_with - #validators - #[allow(non_snake_case)] - let #ident = #non_mut_ident; - }); - } + let mut non_mut_ident = ident.clone(); + non_mut_ident.mutability = None; + get_params.push(quote! { + #[allow(non_snake_case, unused_mut)] + let (__pos, mut #non_mut_ident) = ctx.param_value::<#ty>(#name, #default)?; + #process_with + #validators + #[allow(non_snake_case)] + let #ident = #non_mut_ident; + }); } let ty = match &method.sig.output { @@ -324,7 +269,6 @@ pub fn generate( provides: ::std::option::Option::None, visible: #visible, compute_complexity: #complexity, - oneof: #is_oneof_field, }); }); diff --git a/src/docs/complex_object.md b/src/docs/complex_object.md index 25dd991a..306cec47 100644 --- a/src/docs/complex_object.md +++ b/src/docs/complex_object.md @@ -37,7 +37,6 @@ some simple fields, and use the `ComplexObject` macro to define some other field | complexity | Custom field complexity. | string | Y | | derived | Generate derived fields *[See also the Book](https://async-graphql.github.io/async-graphql/en/derived_fields.html).* | object | Y | | flatten | Similar to serde (flatten) | boolean | Y | -| oneof | Oneof field | bool | Y | # Field argument attributes diff --git a/src/docs/interface.md b/src/docs/interface.md index 6a1953c8..d630af42 100644 --- a/src/docs/interface.md +++ b/src/docs/interface.md @@ -30,7 +30,6 @@ Define a GraphQL interface | 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. *[See also the Book](https://async-graphql.github.io/async-graphql/en/visibility.html).* | bool | Y | | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y | -| oneof | Oneof field | bool | Y | # Field argument attributes diff --git a/src/docs/object.md b/src/docs/object.md index 58134b92..fa86af8c 100644 --- a/src/docs/object.md +++ b/src/docs/object.md @@ -40,7 +40,6 @@ All methods are converted to camelCase. | complexity | Custom field complexity. | string | Y | | derived | Generate derived fields *[See also the Book](https://async-graphql.github.io/async-graphql/en/derived_fields.html).* | object | Y | | flatten | Similar to serde (flatten) | boolean | Y | -| oneof | Oneof field | bool | Y | # Field argument attributes @@ -192,38 +191,3 @@ assert_eq!(res, value!({ })); # }); ``` - -# Oneof field - -```rust -use async_graphql::*; - -#[derive(OneofObject)] -enum MyInputObject { - A(i32), - B(String), -} - -struct Query; - -#[Object] -impl Query { - #[graphql(oneof)] - async fn value(&self, input: MyInputObject) -> String { - match input { - MyInputObject::A(value) => format!("a:{}", value), - MyInputObject::B(value) => format!("b:{}", value), - } - } -} - -# tokio::runtime::Runtime::new().unwrap().block_on(async move { -let schema = Schema::new(Query, EmptyMutation, EmptySubscription); -let res = schema.execute(r#" -{ - value1: value(a:100) - value2: value(b:"abc") -}"#).await.into_result().unwrap().data; -assert_eq!(res, value!({ "value1": "a:100", "value2": "b:abc" })); -# }); -``` diff --git a/src/docs/subscription.md b/src/docs/subscription.md index bae85730..2e002195 100644 --- a/src/docs/subscription.md +++ b/src/docs/subscription.md @@ -33,7 +33,6 @@ The filter function should be synchronous. | complexity | Custom field complexity. *[See also the Book](https://async-graphql.github.io/async-graphql/en/depth_and_complexity.html).* | bool | Y | | complexity | Custom field complexity. | string | Y | | secret | Mark this field as a secret, it will not output the actual value in the log. | bool | Y | -| oneof | Oneof field | bool | Y | # Field argument attributes diff --git a/src/model/field.rs b/src/model/field.rs index c8979975..b47b0b76 100644 --- a/src/model/field.rs +++ b/src/model/field.rs @@ -54,8 +54,4 @@ impl<'a> __Field<'a> { async fn deprecation_reason(&self) -> Option<&str> { self.field.deprecation.reason() } - - async fn one_of(&self) -> bool { - self.field.oneof - } } diff --git a/src/registry/export_sdl.rs b/src/registry/export_sdl.rs index 24add5ca..5d9a8b85 100644 --- a/src/registry/export_sdl.rs +++ b/src/registry/export_sdl.rs @@ -66,15 +66,13 @@ impl Registry { pub(crate) fn export_sdl(&self, options: SDLExportOptions) -> String { let mut sdl = String::new(); - let has_oneof = self.types.values().any(|ty| match ty { - MetaType::InputObject { oneof: true, .. } => true, - MetaType::Object { fields, .. } => fields.values().any(|field| field.oneof), - _ => false, - }); + let has_oneof = self + .types + .values() + .any(|ty| matches!(ty, MetaType::InputObject { oneof: true, .. })); if has_oneof { - sdl.write_str("directive @oneOf on INPUT_OBJECT | FIELD_DEFINITION\n\n") - .ok(); + sdl.write_str("directive @oneOf on INPUT_OBJECT\n\n").ok(); } for ty in self.types.values() { @@ -154,10 +152,6 @@ impl Registry { write!(sdl, "\t{}: {}", field.name, field.ty).ok(); } - if field.oneof { - write!(sdl, " @oneof").ok(); - } - write_deprecated(sdl, &field.deprecation); if options.federation { diff --git a/src/registry/mod.rs b/src/registry/mod.rs index 5174f1ff..3afbc362 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -13,7 +13,6 @@ use indexmap::{map::IndexMap, set::IndexSet}; pub use crate::model::__DirectiveLocation; use crate::{ - model, parser::types::{BaseType as ParsedBaseType, Field, Type as ParsedType, VariableDefinition}, schema::IntrospectionMode, Any, Context, InputType, OutputType, Positioned, ServerResult, SubscriptionType, Value, @@ -168,7 +167,6 @@ pub struct MetaField { pub provides: Option<&'static str>, pub visible: Option, pub compute_complexity: Option, - pub oneof: bool, } #[derive(Clone)] @@ -634,7 +632,6 @@ impl Registry { provides: None, visible: None, compute_complexity: None, - oneof: false, }, ); @@ -666,7 +663,6 @@ impl Registry { provides: None, visible: None, compute_complexity: None, - oneof: false, }, ); } @@ -697,7 +693,6 @@ impl Registry { provides: None, visible: None, compute_complexity: None, - oneof: false, }, ); fields diff --git a/src/types/query_root.rs b/src/types/query_root.rs index 7d817e53..7dbf9526 100644 --- a/src/types/query_root.rs +++ b/src/types/query_root.rs @@ -133,7 +133,6 @@ impl OutputType for QueryRoot { provides: None, visible: None, compute_complexity: None, - oneof: false, }, ); @@ -165,7 +164,6 @@ impl OutputType for QueryRoot { provides: None, visible: None, compute_complexity: None, - oneof: false, }, ); } diff --git a/src/validation/mod.rs b/src/validation/mod.rs index 3b106f78..1f5f1a63 100644 --- a/src/validation/mod.rs +++ b/src/validation/mod.rs @@ -74,7 +74,6 @@ pub fn check_rules( .with(rules::KnownDirectives::default()) .with(rules::DirectivesUnique::default()) .with(rules::OverlappingFieldsCanBeMerged) - .with(rules::OneofFieldsHaveExactlyOneArgument) .with(rules::UploadFile) .with(visitors::CacheControlCalculate { cache_control: &mut cache_control, diff --git a/src/validation/rules/mod.rs b/src/validation/rules/mod.rs index b37d55f0..e36f0391 100644 --- a/src/validation/rules/mod.rs +++ b/src/validation/rules/mod.rs @@ -11,7 +11,6 @@ mod no_fragment_cycles; mod no_undefined_variables; mod no_unused_fragments; mod no_unused_variables; -mod oneof_fields_have_exactly_one_argument; mod overlapping_fields_can_be_merged; mod possible_fragment_spreads; mod provided_non_null_arguments; @@ -35,7 +34,6 @@ pub use no_fragment_cycles::NoFragmentCycles; pub use no_undefined_variables::NoUndefinedVariables; pub use no_unused_fragments::NoUnusedFragments; pub use no_unused_variables::NoUnusedVariables; -pub use oneof_fields_have_exactly_one_argument::OneofFieldsHaveExactlyOneArgument; pub use overlapping_fields_can_be_merged::OverlappingFieldsCanBeMerged; pub use possible_fragment_spreads::PossibleFragmentSpreads; pub use provided_non_null_arguments::ProvidedNonNullArguments; diff --git a/src/validation/rules/oneof_fields_have_exactly_one_argument.rs b/src/validation/rules/oneof_fields_have_exactly_one_argument.rs deleted file mode 100644 index 2fcce6fe..00000000 --- a/src/validation/rules/oneof_fields_have_exactly_one_argument.rs +++ /dev/null @@ -1,101 +0,0 @@ -use async_graphql_parser::{types::Field, Positioned}; - -use crate::{ - validation::visitor::{RuleError, Visitor}, - Value, VisitorContext, -}; - -pub struct OneofFieldsHaveExactlyOneArgument; - -impl<'a> Visitor<'a> for OneofFieldsHaveExactlyOneArgument { - fn enter_field(&mut self, ctx: &mut VisitorContext<'a>, field: &'a Positioned) { - if let Some(parent_type) = ctx.parent_type() { - if let Some(field_def) = parent_type - .fields() - .and_then(|fields| fields.get(field.node.name.node.as_str())) - { - if field_def.oneof { - if field.node.arguments.len() != 1 { - ctx.errors.push(RuleError::new( - vec![field.pos], - "Oneof fields requires have exactly one argument".to_string(), - )); - return; - } - - let value = field.node.arguments[0] - .1 - .node - .clone() - .into_const_with(|var_name| { - ctx.variables - .and_then(|variables| variables.get(&var_name)) - .map(Clone::clone) - .ok_or(()) - }) - .ok(); - if let Some(Value::Null) = value { - ctx.errors.push(RuleError::new( - vec![field.pos], - "Oneof Fields require that exactly one argument must be supplied and that argument must not be null".to_string(), - )); - } - } - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn factory() -> OneofFieldsHaveExactlyOneArgument { - OneofFieldsHaveExactlyOneArgument - } - - #[test] - fn oneof_field() { - expect_passes_rule!( - factory, - r#" - query Foo { - oneofField(a: 10) - } - "#, - ); - } - - #[test] - fn oneof_not_exactly_one_argument() { - expect_fails_rule!( - factory, - r#" - query Foo { - oneofField(a: 10, b: "abc") - } - "#, - ); - - expect_fails_rule!( - factory, - r#" - query Foo { - oneofField - } - "#, - ); - } - - #[test] - fn oneof_arguments_not_be_null() { - expect_fails_rule!( - factory, - r#" - query Foo { - oneofField(a: null) - } - "#, - ); - } -} diff --git a/src/validation/test_harness.rs b/src/validation/test_harness.rs index 1ef9d543..f024d959 100644 --- a/src/validation/test_harness.rs +++ b/src/validation/test_harness.rs @@ -352,11 +352,6 @@ impl Query { async fn oneof_opt(&self, arg: Option) -> String { unimplemented!() } - - #[graphql(oneof)] - async fn oneof_field(&self, arg: OneofArg) -> String { - unimplemented!() - } } pub struct Mutation; diff --git a/tests/complex_object.rs b/tests/complex_object.rs index 0709077e..74389e12 100644 --- a/tests/complex_object.rs +++ b/tests/complex_object.rs @@ -532,87 +532,3 @@ async fn test_flatten_with_result() { }) ); } - -#[tokio::test] -async fn test_oneof_field() { - #[derive(OneofObject)] - enum TestArg { - A(i32), - B(String), - } - - #[derive(SimpleObject)] - #[graphql(complex)] - struct Query { - a: i32, - } - - #[ComplexObject] - impl Query { - #[graphql(oneof)] - async fn test(&self, arg: TestArg) -> String { - match arg { - TestArg::A(a) => format!("a:{}", a), - TestArg::B(b) => format!("b:{}", b), - } - } - } - - let schema = Schema::new(Query { a: 10 }, EmptyMutation, EmptySubscription); - let query = "{ test(a: 10) }"; - assert_eq!( - schema.execute(query).await.into_result().unwrap().data, - value!({ - "test": "a:10" - }) - ); - - let query = r#"{ test(b: "abc") }"#; - assert_eq!( - schema.execute(query).await.into_result().unwrap().data, - value!({ - "test": "b:abc" - }) - ); - - let query = r#"{ - __type(name: "Query") { - fields { - name - args { - name - type { - kind - name - } - } - } - } - }"#; - assert_eq!( - schema.execute(query).await.into_result().unwrap().data, - value!({ - "__type": { - "fields": [{ - "name": "a", - "args": [] - }, { - "name": "test", - "args": [{ - "name": "a", - "type": { - "kind": "SCALAR", - "name": "Int" - } - }, { - "name": "b", - "type": { - "kind": "SCALAR", - "name": "String" - } - }] - }] - } - }) - ); -} diff --git a/tests/interface.rs b/tests/interface.rs index b57b1118..6d43a71b 100644 --- a/tests/interface.rs +++ b/tests/interface.rs @@ -473,118 +473,3 @@ pub async fn test_issue_330() { }) ); } - -#[tokio::test] -pub async fn test_oneof() { - #[derive(OneofObject)] - enum TestArg { - A(i32), - B(String), - } - - struct A; - - #[Object] - impl A { - async fn test(&self, arg: TestArg) -> String { - match arg { - TestArg::A(a) => format!("A:a:{}", a), - TestArg::B(b) => format!("A:b:{}", b), - } - } - } - - struct B; - - #[Object] - impl B { - async fn test(&self, arg: TestArg) -> String { - match arg { - TestArg::A(a) => format!("B:a:{}", a), - TestArg::B(b) => format!("B:b:{}", b), - } - } - } - - #[derive(Interface)] - #[graphql(field( - name = "test", - type = "String", - oneof, - arg(name = "arg", type = "TestArg") - ))] - enum Obj { - A(A), - B(B), - } - - struct Query; - - #[Object] - impl Query { - async fn a(&self) -> Obj { - A.into() - } - - async fn b(&self) -> Obj { - B.into() - } - } - - let schema = Schema::new(Query, EmptyMutation, EmptySubscription); - assert_eq!( - schema - .execute("{ a { test(a: 10) } }") - .await - .into_result() - .unwrap() - .data, - value!({ - "a": { - "test": "A:a:10" - } - }) - ); - - assert_eq!( - schema - .execute("{ a { test(b: \"abc\") } }") - .await - .into_result() - .unwrap() - .data, - value!({ - "a": { - "test": "A:b:abc" - } - }) - ); - - assert_eq!( - schema - .execute("{ b { test(a: 10) } }") - .await - .into_result() - .unwrap() - .data, - value!({ - "b": { - "test": "B:a:10" - } - }) - ); - - assert_eq!( - schema - .execute("{ b { test(b: \"def\") } }") - .await - .into_result() - .unwrap() - .data, - value!({ - "b": { - "test": "B:b:def" - } - }) - ); -} diff --git a/tests/object.rs b/tests/object.rs index 70394d3a..1c3d5189 100644 --- a/tests/object.rs +++ b/tests/object.rs @@ -141,80 +141,3 @@ async fn test_object_process_with_field() { }) ); } - -#[tokio::test] -async fn test_oneof_field() { - #[derive(OneofObject)] - enum TestArg { - A(i32), - B(String), - } - - struct Query; - - #[Object] - impl Query { - #[graphql(oneof)] - async fn test(&self, arg: TestArg) -> String { - match arg { - TestArg::A(a) => format!("a:{}", a), - TestArg::B(b) => format!("b:{}", b), - } - } - } - - let schema = Schema::new(Query, EmptyMutation, EmptySubscription); - let query = "{ test(a: 10) }"; - assert_eq!( - schema.execute(query).await.into_result().unwrap().data, - value!({ - "test": "a:10" - }) - ); - - let query = r#"{ test(b: "abc") }"#; - assert_eq!( - schema.execute(query).await.into_result().unwrap().data, - value!({ - "test": "b:abc" - }) - ); - - let query = r#"{ - __type(name: "Query") { - fields { - name - args { - name - type { - kind - name - } - } - } - } - }"#; - assert_eq!( - schema.execute(query).await.into_result().unwrap().data, - value!({ - "__type": { - "fields": [{ - "name": "test", - "args": [{ - "name": "a", - "type": { - "kind": "SCALAR", - "name": "Int" - } - }, { - "name": "b", - "type": { - "kind": "SCALAR", - "name": "String" - } - }] - }] - } - }) - ); -} diff --git a/tests/subscription.rs b/tests/subscription.rs index 4b07d30d..0958b6a1 100644 --- a/tests/subscription.rs +++ b/tests/subscription.rs @@ -420,46 +420,3 @@ pub async fn test_subscription_fieldresult() { assert!(stream.next().await.is_none()); } - -#[tokio::test] -pub async fn test_oneof_field() { - #[derive(OneofObject)] - enum TestArg { - A(i32), - B(String), - } - - struct Subscription; - - #[Subscription] - impl Subscription { - #[graphql(oneof)] - async fn test(&self, arg: TestArg) -> impl Stream { - let value = match arg { - TestArg::A(a) => format!("a:{}", a), - TestArg::B(b) => format!("b:{}", b), - }; - futures_util::stream::once(async move { value }) - } - } - - let schema = Schema::new(Query, EmptyMutation, Subscription); - - let mut stream = schema.execute_stream(r#"subscription { test(a: 10) }"#); - assert_eq!( - Response::new(value!({ - "test": "a:10" - })), - stream.next().await.unwrap() - ); - assert!(stream.next().await.is_none()); - - let mut stream = schema.execute_stream(r#"subscription { test(b: "abc") }"#); - assert_eq!( - Response::new(value!({ - "test": "b:abc" - })), - stream.next().await.unwrap() - ); - assert!(stream.next().await.is_none()); -} diff --git a/tests/validators.rs b/tests/validators.rs index 54940b97..84400dfb 100644 --- a/tests/validators.rs +++ b/tests/validators.rs @@ -790,103 +790,3 @@ pub async fn test_list_both_max_items_and_max_length() { }) ); } - -#[tokio::test] -pub async fn test_custom_validator_on_oneof_field() { - struct MyValidator; - - impl CustomValidator for MyValidator { - fn check(&self, value: &TestArg) -> Result<(), String> { - match value { - TestArg::A(a) => { - if *a < 100 { - Ok(()) - } else { - Err("invalid a".into()) - } - } - TestArg::B(b) => { - if b.len() < 5 { - Ok(()) - } else { - Err("invalid b".into()) - } - } - } - } - } - - #[derive(OneofObject)] - enum TestArg { - A(i32), - B(String), - } - - struct Query; - - #[Object] - impl Query { - #[graphql(oneof)] - async fn test(&self, #[graphql(validator(custom = "MyValidator"))] arg: TestArg) -> String { - match arg { - TestArg::A(a) => format!("a:{}", a), - TestArg::B(b) => format!("b:{}", b), - } - } - } - - let schema = Schema::new(Query, EmptyMutation, EmptySubscription); - assert_eq!( - schema - .execute("{ test(a: 10) }") - .await - .into_result() - .unwrap() - .data, - value!({ - "test": "a:10" - }) - ); - - assert_eq!( - schema - .execute("{ test(a: 200) }") - .await - .into_result() - .unwrap_err(), - vec![ServerError { - message: r#"Failed to parse "TestArg": invalid a"#.to_string(), - source: None, - locations: vec![Pos { column: 3, line: 1 }], - path: vec![PathSegment::Field("test".to_string())], - extensions: None - }] - ); - - assert_eq!( - schema - .execute(r#"{ test(b: "abcd") }"#) - .await - .into_result() - .unwrap() - .data, - value!({ - "test": "b:abcd" - }) - ); - - assert_eq!( - schema - .execute(r#"{ test(b: "abcde") }"#) - .await - .into_result() - .unwrap_err(), - vec![ServerError { - message: r#"Failed to parse "TestArg": invalid b"#.to_string(), - source: None, - locations: vec![Pos { column: 3, line: 1 }], - path: vec![PathSegment::Field("test".to_string())], - extensions: None - }] - ); -}