Merge branch 'master' of github.com:async-graphql/async-graphql
This commit is contained in:
commit
38005b0de1
|
@ -154,6 +154,8 @@ pub struct SimpleObjectField {
|
|||
pub visible: Option<Visible>,
|
||||
#[darling(default, multiple)]
|
||||
pub derived: Vec<DerivedField>,
|
||||
#[darling(default)]
|
||||
pub process_with: Option<String>,
|
||||
// for InputObject
|
||||
#[darling(default)]
|
||||
pub default: Option<DefaultValue>,
|
||||
|
@ -212,6 +214,8 @@ pub struct Argument {
|
|||
pub default: Option<DefaultValue>,
|
||||
pub default_with: Option<LitStr>,
|
||||
pub validator: Option<Validators>,
|
||||
#[darling(default)]
|
||||
pub process_with: Option<String>,
|
||||
pub key: bool, // for entity
|
||||
pub visible: Option<Visible>,
|
||||
pub secret: bool,
|
||||
|
@ -372,6 +376,8 @@ pub struct InputObjectField {
|
|||
pub skip: bool,
|
||||
#[darling(default)]
|
||||
pub skip_input: bool,
|
||||
#[darling(default)]
|
||||
pub process_with: Option<String>,
|
||||
// for SimpleObject
|
||||
#[darling(default)]
|
||||
pub skip_output: bool,
|
||||
|
@ -547,6 +553,8 @@ pub struct SubscriptionFieldArgument {
|
|||
pub default: Option<DefaultValue>,
|
||||
pub default_with: Option<LitStr>,
|
||||
pub validator: Option<Validators>,
|
||||
#[darling(default)]
|
||||
pub process_with: Option<String>,
|
||||
pub visible: Option<Visible>,
|
||||
pub secret: bool,
|
||||
}
|
||||
|
|
|
@ -215,6 +215,17 @@ pub fn generate(
|
|||
});
|
||||
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()
|
||||
|
@ -225,10 +236,15 @@ pub fn generate(
|
|||
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)]
|
||||
let (__pos, #ident) = ctx.oneof_param_value::<#ty>()?;
|
||||
#[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 (
|
||||
|
@ -240,6 +256,7 @@ pub fn generate(
|
|||
default,
|
||||
default_with,
|
||||
validator,
|
||||
process_with,
|
||||
visible,
|
||||
secret,
|
||||
..
|
||||
|
@ -289,6 +306,17 @@ pub fn generate(
|
|||
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 => Default::default(),
|
||||
};
|
||||
|
||||
let validators = validator.clone().unwrap_or_default().create_validators(
|
||||
&crate_name,
|
||||
quote!(&#ident),
|
||||
|
@ -296,10 +324,15 @@ pub fn generate(
|
|||
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)]
|
||||
let (__pos, #ident) = ctx.param_value::<#ty>(#name, #default)?;
|
||||
#[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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,16 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
|
|||
|
||||
federation_fields.push((ty, name.clone()));
|
||||
|
||||
let process_with = match field.process_with.as_ref() {
|
||||
Some(fn_path) => {
|
||||
let fn_path: syn::ExprPath = syn::parse_str(fn_path)?;
|
||||
quote! {
|
||||
#fn_path(&mut #ident);
|
||||
}
|
||||
}
|
||||
None => Default::default(),
|
||||
};
|
||||
|
||||
let validators = field
|
||||
.validator
|
||||
.clone()
|
||||
|
@ -99,9 +109,11 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
|
|||
});
|
||||
|
||||
get_fields.push(quote! {
|
||||
let #ident: #ty = #crate_name::InputType::parse(
|
||||
#[allow(unused_mut)]
|
||||
let mut #ident: #ty = #crate_name::InputType::parse(
|
||||
::std::option::Option::Some(#crate_name::Value::Object(::std::clone::Clone::clone(&obj)))
|
||||
).map_err(#crate_name::InputValueError::propagate)?;
|
||||
#process_with
|
||||
#validators
|
||||
});
|
||||
|
||||
|
@ -137,8 +149,12 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
|
|||
let #ident: #ty = {
|
||||
match obj.get(#name) {
|
||||
::std::option::Option::Some(value) => {
|
||||
#crate_name::InputType::parse(::std::option::Option::Some(::std::clone::Clone::clone(&value)))
|
||||
.map_err(#crate_name::InputValueError::propagate)?
|
||||
#[allow(unused_mut)]
|
||||
let mut #ident = #crate_name::InputType::parse(::std::option::Option::Some(::std::clone::Clone::clone(&value)))
|
||||
.map_err(#crate_name::InputValueError::propagate)?;
|
||||
#process_with
|
||||
#ident
|
||||
|
||||
},
|
||||
::std::option::Option::None => #default,
|
||||
}
|
||||
|
@ -147,9 +163,10 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
|
|||
});
|
||||
} else {
|
||||
get_fields.push(quote! {
|
||||
#[allow(non_snake_case)]
|
||||
let #ident: #ty = #crate_name::InputType::parse(obj.get(#name).cloned())
|
||||
#[allow(non_snake_case, unused_mut)]
|
||||
let mut #ident: #ty = #crate_name::InputType::parse(obj.get(#name).cloned())
|
||||
.map_err(#crate_name::InputValueError::propagate)?;
|
||||
#process_with
|
||||
#validators
|
||||
});
|
||||
}
|
||||
|
|
|
@ -189,7 +189,7 @@ pub fn generate(
|
|||
if is_key {
|
||||
get_federation_key.push(quote! {
|
||||
if let Some(fields) = <#ty as #crate_name::InputType>::federation_fields() {
|
||||
key_str.push(format!("{} {}", #name, fields));
|
||||
key_str.push(format!("{} {}", #name, fields));
|
||||
} else {
|
||||
key_str.push(#name.to_string());
|
||||
}
|
||||
|
@ -360,6 +360,17 @@ pub fn generate(
|
|||
});
|
||||
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()
|
||||
|
@ -370,10 +381,15 @@ pub fn generate(
|
|||
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)]
|
||||
let (__pos, #ident) = ctx.oneof_param_value::<#ty>()?;
|
||||
#[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 (
|
||||
|
@ -384,6 +400,7 @@ pub fn generate(
|
|||
desc,
|
||||
default,
|
||||
default_with,
|
||||
process_with,
|
||||
validator,
|
||||
visible,
|
||||
secret,
|
||||
|
@ -434,6 +451,16 @@ pub fn generate(
|
|||
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 => Default::default(),
|
||||
};
|
||||
|
||||
let validators = validator.clone().unwrap_or_default().create_validators(
|
||||
&crate_name,
|
||||
quote!(&#ident),
|
||||
|
@ -441,10 +468,15 @@ pub fn generate(
|
|||
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)]
|
||||
let (__pos, #ident) = ctx.param_value::<#ty>(#name, #default)?;
|
||||
#[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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,6 +92,17 @@ pub fn generate(
|
|||
});
|
||||
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()
|
||||
|
@ -102,10 +113,15 @@ pub fn generate(
|
|||
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)]
|
||||
let (__pos, #ident) = ctx.oneof_param_value::<#ty>()?;
|
||||
#[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 (
|
||||
|
@ -117,6 +133,7 @@ pub fn generate(
|
|||
default,
|
||||
default_with,
|
||||
validator,
|
||||
process_with,
|
||||
visible: arg_visible,
|
||||
secret,
|
||||
},
|
||||
|
@ -164,6 +181,18 @@ pub fn generate(
|
|||
}
|
||||
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 => Default::default(),
|
||||
};
|
||||
|
||||
let validators = validator.clone().unwrap_or_default().create_validators(
|
||||
&crate_name,
|
||||
quote!(&#ident),
|
||||
|
@ -171,10 +200,15 @@ pub fn generate(
|
|||
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)]
|
||||
let (__pos, #ident) = ctx.param_value::<#ty>(#name, #default)?;
|
||||
#[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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,9 +60,14 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
|
|||
}
|
||||
};
|
||||
|
||||
if let Type::Path(p) = &ty {
|
||||
let mut ty = ty;
|
||||
while let Type::Group(group) = ty {
|
||||
ty = &*group.elem;
|
||||
}
|
||||
|
||||
if matches!(ty, Type::Path(_) | Type::Macro(_)) {
|
||||
// This validates that the field type wasn't already used
|
||||
if !enum_items.insert(p) {
|
||||
if !enum_items.insert(ty) {
|
||||
return Err(
|
||||
Error::new_spanned(&ty, "This type already used in another variant").into(),
|
||||
);
|
||||
|
@ -70,16 +75,16 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
|
|||
|
||||
enum_names.push(enum_name);
|
||||
|
||||
let mut assert_ty = p.clone();
|
||||
RemoveLifetime.visit_type_path_mut(&mut assert_ty);
|
||||
let mut assert_ty = ty.clone();
|
||||
RemoveLifetime.visit_type_mut(&mut assert_ty);
|
||||
|
||||
if !variant.flatten {
|
||||
type_into_impls.push(quote! {
|
||||
#crate_name::static_assertions::assert_impl_one!(#assert_ty: #crate_name::ObjectType);
|
||||
|
||||
#[allow(clippy::all, clippy::pedantic)]
|
||||
impl #impl_generics ::std::convert::From<#p> for #ident #ty_generics #where_clause {
|
||||
fn from(obj: #p) -> Self {
|
||||
impl #impl_generics ::std::convert::From<#ty> for #ident #ty_generics #where_clause {
|
||||
fn from(obj: #ty) -> Self {
|
||||
#ident::#enum_name(obj)
|
||||
}
|
||||
}
|
||||
|
@ -89,8 +94,8 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
|
|||
#crate_name::static_assertions::assert_impl_one!(#assert_ty: #crate_name::UnionType);
|
||||
|
||||
#[allow(clippy::all, clippy::pedantic)]
|
||||
impl #impl_generics ::std::convert::From<#p> for #ident #ty_generics #where_clause {
|
||||
fn from(obj: #p) -> Self {
|
||||
impl #impl_generics ::std::convert::From<#ty> for #ident #ty_generics #where_clause {
|
||||
fn from(obj: #ty) -> Self {
|
||||
#ident::#enum_name(obj)
|
||||
}
|
||||
}
|
||||
|
@ -99,15 +104,15 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
|
|||
|
||||
if !variant.flatten {
|
||||
registry_types.push(quote! {
|
||||
<#p as #crate_name::OutputType>::create_type_info(registry);
|
||||
<#ty as #crate_name::OutputType>::create_type_info(registry);
|
||||
});
|
||||
possible_types.push(quote! {
|
||||
possible_types.insert(<#p as #crate_name::OutputType>::type_name().into_owned());
|
||||
possible_types.insert(<#ty as #crate_name::OutputType>::type_name().into_owned());
|
||||
});
|
||||
} else {
|
||||
possible_types.push(quote! {
|
||||
if let #crate_name::registry::MetaType::Union { possible_types: possible_types2, .. } =
|
||||
registry.create_fake_output_type::<#p>() {
|
||||
registry.create_fake_output_type::<#ty>() {
|
||||
possible_types.extend(possible_types2);
|
||||
}
|
||||
});
|
||||
|
@ -115,11 +120,11 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
|
|||
|
||||
if !variant.flatten {
|
||||
get_introspection_typename.push(quote! {
|
||||
#ident::#enum_name(obj) => <#p as #crate_name::OutputType>::type_name()
|
||||
#ident::#enum_name(obj) => <#ty as #crate_name::OutputType>::type_name()
|
||||
});
|
||||
} else {
|
||||
get_introspection_typename.push(quote! {
|
||||
#ident::#enum_name(obj) => <#p as #crate_name::OutputType>::introspection_type_name(obj)
|
||||
#ident::#enum_name(obj) => <#ty as #crate_name::OutputType>::introspection_type_name(obj)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -25,3 +25,12 @@ impl Query {
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Errors in subscriptions
|
||||
|
||||
Errors can be returned from subscription resolvers as well, using a return type of the form:
|
||||
```rust
|
||||
async fn my_subscription_resolver(&self) -> impl Stream<Item = Result<MyItem, MyError>> { ... }
|
||||
```
|
||||
|
||||
Note however that the `MyError` struct must have `Clone` implemented, due to the restrictions placed by the `Subscription` macro. One way to accomplish this is by creating a custom error type, with `#[derive(Clone)]`, as [seen here](https://github.com/async-graphql/async-graphql/issues/845#issuecomment-1090933464).
|
||||
|
|
|
@ -52,6 +52,7 @@ some simple fields, and use the `ComplexObject` macro to define some other field
|
|||
| 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 |
|
||||
| secret | Mark this field as a secret, it will not output the actual value in the log. | bool | Y |
|
||||
| process_with | Upon successful parsing, invokes specified function. Its signature must be `fn(&mut T)`. | code path | Y |
|
||||
|
||||
# Examples
|
||||
|
||||
|
@ -68,7 +69,7 @@ struct MyObj {
|
|||
#[ComplexObject]
|
||||
impl MyObj {
|
||||
async fn c(&self) -> i32 {
|
||||
self.a + self.b
|
||||
self.a + self.b
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ Define a GraphQL input object
|
|||
| flatten | Similar to serde (flatten) | boolean | Y |
|
||||
| skip | Skip this field, use `Default::default` to get a default value for this field. | bool | Y |
|
||||
| skip_input | Skip this field, similar to `skip`, but avoids conflicts when this macro is used with `SimpleObject`. | bool | Y |
|
||||
| process_with | Upon successful parsing, invokes specified function. Its signature must be `fn(&mut T)`. | code path | 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 |
|
||||
| secret | Mark this field as a secret, it will not output the actual value in the log. | bool | Y |
|
||||
|
|
|
@ -56,6 +56,7 @@ All methods are converted to camelCase.
|
|||
| visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
| secret | Mark this field as a secret, it will not output the actual value in the log. | bool | Y |
|
||||
| key | Is entity key(for Federation) | bool | Y |
|
||||
| process_with | Upon successful parsing, invokes specified function. Its signature must be `fn(&mut T)`. | code path | Y |
|
||||
|
||||
# Derived argument attributes
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ The filter function should be synchronous.
|
|||
| validator | Input value validator *[See also the Book](https://async-graphql.github.io/async-graphql/en/input_value_validators.html)* | object | 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 |
|
||||
| process_with | Upon successful parsing, invokes specified function. Its signature must be `fn(&mut T)`. | code path | Y |
|
||||
|
||||
# Examples
|
||||
|
||||
|
|
|
@ -1,6 +1,45 @@
|
|||
use async_graphql::*;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_complex_object_process_with_method_field() {
|
||||
#[derive(SimpleObject)]
|
||||
#[graphql(complex)]
|
||||
struct MyObj {
|
||||
a: i32,
|
||||
}
|
||||
|
||||
#[ComplexObject]
|
||||
impl MyObj {
|
||||
async fn test(
|
||||
&self,
|
||||
#[graphql(process_with = "str::make_ascii_uppercase")] processed_complex_arg: String,
|
||||
) -> String {
|
||||
processed_complex_arg
|
||||
}
|
||||
}
|
||||
|
||||
struct Query;
|
||||
|
||||
#[Object]
|
||||
impl Query {
|
||||
async fn obj(&self) -> MyObj {
|
||||
MyObj { a: 10 }
|
||||
}
|
||||
}
|
||||
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
let query = "{ obj { test(processedComplexArg: \"smol\") } }";
|
||||
assert_eq!(
|
||||
schema.execute(query).await.into_result().unwrap().data,
|
||||
value!({
|
||||
"obj": {
|
||||
"test": "SMOL"
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
pub async fn test_complex_object() {
|
||||
#[derive(SimpleObject)]
|
||||
|
|
|
@ -546,3 +546,88 @@ pub async fn test_complex_output() {
|
|||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
pub async fn test_input_object_process_with() {
|
||||
mod processor {
|
||||
pub fn string(input: &mut String) {
|
||||
while let Some(ch) = input.pop() {
|
||||
if !ch.is_whitespace() {
|
||||
input.push(ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(InputObject)]
|
||||
struct MyInput {
|
||||
//processor does nothing on default value
|
||||
#[graphql(default = " ", process_with = "processor::string")]
|
||||
a: String,
|
||||
|
||||
#[graphql(process_with = "processor::string")]
|
||||
b: String,
|
||||
}
|
||||
|
||||
struct MyOutput {
|
||||
a: String,
|
||||
b: String,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl MyOutput {
|
||||
async fn a(&self) -> &String {
|
||||
&self.a
|
||||
}
|
||||
|
||||
async fn b(&self) -> &String {
|
||||
&self.b
|
||||
}
|
||||
}
|
||||
|
||||
struct Root;
|
||||
|
||||
#[Object]
|
||||
impl Root {
|
||||
async fn a(&self, input: MyInput) -> MyOutput {
|
||||
MyOutput {
|
||||
a: input.a,
|
||||
b: input.b,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let schema = Schema::new(Root, EmptyMutation, EmptySubscription);
|
||||
let query = r#"{
|
||||
a(input:{b: "test b "}) {
|
||||
a b
|
||||
}
|
||||
}"#
|
||||
.to_owned();
|
||||
assert_eq!(
|
||||
schema.execute(&query).await.data,
|
||||
value!({
|
||||
"a": {
|
||||
"a": " ",
|
||||
"b": "test b",
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
let schema = Schema::new(Root, EmptyMutation, EmptySubscription);
|
||||
let query = r#"{
|
||||
a(input:{a: "test a ", b: "test"}) {
|
||||
a b
|
||||
}
|
||||
}"#
|
||||
.to_owned();
|
||||
assert_eq!(
|
||||
schema.execute(&query).await.data,
|
||||
value!({
|
||||
"a": {
|
||||
"a": "test a",
|
||||
"b": "test",
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -118,6 +118,30 @@ async fn test_flatten_with_context() {
|
|||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_object_process_with_field() {
|
||||
struct Query;
|
||||
|
||||
#[Object]
|
||||
impl Query {
|
||||
async fn test(
|
||||
&self,
|
||||
#[graphql(process_with = "str::make_ascii_uppercase")] processed_arg: String,
|
||||
) -> String {
|
||||
processed_arg
|
||||
}
|
||||
}
|
||||
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
let query = "{ test(processedArg: \"smol\") }";
|
||||
assert_eq!(
|
||||
schema.execute(query).await.into_result().unwrap().data,
|
||||
value!({
|
||||
"test": "SMOL"
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_oneof_field() {
|
||||
#[derive(OneofObject)]
|
||||
|
|
|
@ -419,3 +419,24 @@ pub async fn test_trait_object_in_union() {
|
|||
})
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! generate_union {
|
||||
($name:ident, $variant_ty:ty) => {
|
||||
#[derive(Union)]
|
||||
pub enum $name {
|
||||
Val($variant_ty),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_macro_generated_union() {
|
||||
#[derive(SimpleObject)]
|
||||
pub struct IntObj {
|
||||
pub val: i32,
|
||||
}
|
||||
|
||||
generate_union!(MyEnum, IntObj);
|
||||
|
||||
let _ = MyEnum::Val(IntObj { val: 1 });
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue