Add process_with to methods

This commit is contained in:
Douman 2022-04-06 16:10:56 +09:00
parent ca1f9045cc
commit b0933b3475
11 changed files with 187 additions and 17 deletions

View File

@ -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,
@ -549,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,
}

View File

@ -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;
});
}
}

View File

@ -77,7 +77,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
let process_with = match field.process_with.as_ref() {
Some(fn_path) => {
let fn_path: syn::ExprPath = syn::parse_str(&fn_path)?;
let fn_path: syn::ExprPath = syn::parse_str(fn_path)?;
quote! {
#fn_path(&mut #ident);
}

View File

@ -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;
});
}
}

View File

@ -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;
});
}
}

View File

@ -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
}
}

View File

@ -24,8 +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 |
| 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 |

View File

@ -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

View File

@ -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

View File

@ -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)]

View File

@ -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)]