Remove code and tests related oneof fields. #915
This commit is contained in:
parent
96e423ff31
commit
5ad9f497d8
|
@ -284,7 +284,6 @@ pub struct ObjectField {
|
|||
#[darling(default, multiple)]
|
||||
pub derived: Vec<DerivedField>,
|
||||
pub flatten: bool,
|
||||
pub oneof: bool,
|
||||
}
|
||||
|
||||
#[derive(FromMeta, Default, Clone)]
|
||||
|
@ -492,8 +491,6 @@ pub struct InterfaceField {
|
|||
pub requires: Option<String>,
|
||||
#[darling(default)]
|
||||
pub visible: Option<Visible>,
|
||||
#[darling(default)]
|
||||
pub oneof: bool,
|
||||
}
|
||||
|
||||
#[derive(FromVariant)]
|
||||
|
@ -573,7 +570,6 @@ pub struct SubscriptionField {
|
|||
pub guard: Option<SpannedValue<String>>,
|
||||
pub visible: Option<Visible>,
|
||||
pub complexity: Option<ComplexityType>,
|
||||
pub oneof: bool,
|
||||
}
|
||||
|
||||
#[derive(FromField)]
|
||||
|
@ -774,7 +770,6 @@ pub struct ComplexObjectField {
|
|||
#[darling(multiple)]
|
||||
pub derived: Vec<DerivedField>,
|
||||
pub flatten: bool,
|
||||
pub oneof: bool,
|
||||
}
|
||||
|
||||
#[derive(FromMeta, Default)]
|
||||
|
|
|
@ -191,102 +191,50 @@ pub fn generate(
|
|||
}
|
||||
};
|
||||
|
||||
let mut args = extract_input_args::<args::Argument>(&crate_name, method)?;
|
||||
let args = extract_input_args::<args::Argument>(&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,
|
||||
}));
|
||||
});
|
||||
|
||||
|
|
|
@ -137,10 +137,8 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
|
|||
provides,
|
||||
requires,
|
||||
visible,
|
||||
oneof,
|
||||
} in &interface_args.fields
|
||||
{
|
||||
let name_span = name.span();
|
||||
let (name, method_name) = if let Some(method) = method {
|
||||
(name.to_string(), Ident::new(method, Span::call_site()))
|
||||
} else {
|
||||
|
@ -173,83 +171,52 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
|
|||
decl_params.push(quote! { ctx: &'ctx #crate_name::Context<'ctx> });
|
||||
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::<syn::Type>(&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::<syn::Type>(&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<TokenStream
|
|||
is_secret: #secret,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for enum_name in &enum_names {
|
||||
|
@ -310,7 +276,6 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
|
|||
requires: #requires,
|
||||
visible: #visible,
|
||||
compute_complexity: ::std::option::Option::None,
|
||||
oneof: #is_oneof_field,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -150,14 +150,6 @@ pub fn generate(
|
|||
return Err(Error::new_spanned(&method, "Must be asynchronous").into());
|
||||
}
|
||||
|
||||
if method_args.oneof {
|
||||
return Err(Error::new_spanned(
|
||||
&method,
|
||||
"The `entity` and `oneof` attributes cannot be specified at the same time.",
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let args = extract_input_args::<args::Argument>(&crate_name, method)?;
|
||||
|
||||
let ty = match &method.sig.output {
|
||||
|
@ -342,103 +334,50 @@ pub fn generate(
|
|||
}
|
||||
};
|
||||
|
||||
let mut args = extract_input_args::<args::Argument>(&crate_name, method)?;
|
||||
let args = extract_input_args::<args::Argument>(&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,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -176,7 +176,6 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
|
|||
requires: #requires,
|
||||
visible: #visible,
|
||||
compute_complexity: ::std::option::Option::None,
|
||||
oneof: false,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -72,101 +72,47 @@ pub fn generate(
|
|||
let mut schema_args = Vec::new();
|
||||
let mut use_params = Vec::new();
|
||||
let mut get_params = Vec::new();
|
||||
let mut is_oneof_field = false;
|
||||
let mut args =
|
||||
extract_input_args::<args::SubscriptionFieldArgument>(&crate_name, method)?;
|
||||
let args = extract_input_args::<args::SubscriptionFieldArgument>(&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,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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" }));
|
||||
# });
|
||||
```
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<MetaVisibleFn>,
|
||||
pub compute_complexity: Option<ComplexityType>,
|
||||
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
|
||||
|
|
|
@ -133,7 +133,6 @@ impl<T: ObjectType> OutputType for QueryRoot<T> {
|
|||
provides: None,
|
||||
visible: None,
|
||||
compute_complexity: None,
|
||||
oneof: false,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -165,7 +164,6 @@ impl<T: ObjectType> OutputType for QueryRoot<T> {
|
|||
provides: None,
|
||||
visible: None,
|
||||
compute_complexity: None,
|
||||
oneof: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<Field>) {
|
||||
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)
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -352,11 +352,6 @@ impl Query {
|
|||
async fn oneof_opt(&self, arg: Option<OneofArg>) -> String {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[graphql(oneof)]
|
||||
async fn oneof_field(&self, arg: OneofArg) -> String {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Mutation;
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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<Item = String> {
|
||||
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());
|
||||
}
|
||||
|
|
|
@ -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<TestArg> 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
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue