Introduce process_with for input object
This commit is contained in:
parent
aa15be435a
commit
ca1f9045cc
|
@ -372,6 +372,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,
|
||||
|
|
|
@ -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
|
||||
});
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ 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 |
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue