(codegen) Respect mut modifier on arguments in object proc macro

This commit forwards `mut` declaration of arguments in a #[juniper::object] macro invocation
to the generated code.

Closes #399
This commit is contained in:
Christoph Herzog 2019-07-22 21:46:55 +02:00 committed by theduke
parent 9e849fe512
commit 049ba0c9dc
3 changed files with 33 additions and 4 deletions

View file

@ -2,6 +2,8 @@
- No changes yet - No changes yet
- Allow `mut` arguments for resolver functions in `#[object]` macros [#402](https://github.com/graphql-rust/juniper/pull/402)
# [[0.13.0] 2019-07-19](https://github.com/graphql-rust/juniper/releases/tag/juniper-0.13.0) # [[0.13.0] 2019-07-19](https://github.com/graphql-rust/juniper/releases/tag/juniper-0.13.0)
### newtype ScalarValue derive ### newtype ScalarValue derive

View file

@ -101,6 +101,13 @@ impl<'a> Query {
fn with_lifetime_child(&self) -> WithLifetime<'a> { fn with_lifetime_child(&self) -> WithLifetime<'a> {
WithLifetime { value: "blub" } WithLifetime { value: "blub" }
} }
fn with_mut_arg(mut arg: bool) -> bool {
if arg {
arg = !arg;
}
arg
}
} }
#[derive(Default)] #[derive(Default)]
@ -216,6 +223,19 @@ fn object_introspect() {
"description": None, "description": None,
"args": [], "args": [],
}, },
{
"name": "withMutArg",
"description": None,
"args": [
{
"name": "arg",
"description": None,
"type": {
"name": None,
},
}
],
},
] ]
}) })
); );
@ -241,6 +261,7 @@ fn object_query() {
withLifetimeChild { withLifetimeChild {
value value
} }
withMutArg(arg: true)
} }
"#; "#;
let schema = RootNode::new(Query { b: true }, EmptyMutation::<Context>::new()); let schema = RootNode::new(Query { b: true }, EmptyMutation::<Context>::new());
@ -264,6 +285,7 @@ fn object_query() {
"argWithDescription": true, "argWithDescription": true,
"withContextChild": { "ctx": true }, "withContextChild": { "ctx": true },
"withLifetimeChild": { "value": "blub" }, "withLifetimeChild": { "value": "blub" },
"withMutArg": false,
}) })
); );
} }

View file

@ -129,8 +129,10 @@ pub fn build_object(args: TokenStream, body: TokenStream, is_internal: bool) ->
); );
} }
syn::FnArg::Captured(ref captured) => { syn::FnArg::Captured(ref captured) => {
let arg_ident = match &captured.pat { let (arg_ident, is_mut) = match &captured.pat {
syn::Pat::Ident(ref pat_ident) => &pat_ident.ident, syn::Pat::Ident(ref pat_ident) => {
(&pat_ident.ident, pat_ident.mutability.is_some())
}
_ => { _ => {
panic!("Invalid token for function argument"); panic!("Invalid token for function argument");
} }
@ -147,7 +149,7 @@ pub fn build_object(args: TokenStream, body: TokenStream, is_internal: bool) ->
else if util::type_is_identifier(&captured.ty, "Executor") { else if util::type_is_identifier(&captured.ty, "Executor") {
panic!("Invalid executor argument: to access the Executor, you need to specify the type as a reference.\nDid you mean &Executor?"); panic!("Invalid executor argument: to access the Executor, you need to specify the type as a reference.\nDid you mean &Executor?");
} }
// Check for executor arg. // Check for context arg.
else if context_type else if context_type
.clone() .clone()
.map(|ctx| util::type_is_ref_of(&captured.ty, ctx)) .map(|ctx| util::type_is_ref_of(&captured.ty, ctx))
@ -167,12 +169,15 @@ pub fn build_object(args: TokenStream, body: TokenStream, is_internal: bool) ->
quote!(captured.ty), quote!(captured.ty),
); );
} else { } else {
// Regular argument.
let ty = &captured.ty; let ty = &captured.ty;
// TODO: respect graphql attribute overwrite. // TODO: respect graphql attribute overwrite.
let final_name = util::to_camel_case(&arg_name); let final_name = util::to_camel_case(&arg_name);
let expect_text = format!("Internal error: missing argument {} - validation must have failed", &final_name); let expect_text = format!("Internal error: missing argument {} - validation must have failed", &final_name);
let mut_modifier = if is_mut { quote!(mut) } else { quote!() };
resolve_parts.push(quote!( resolve_parts.push(quote!(
let #arg_ident = args let #mut_modifier #arg_ident = args
.get::<#ty>(#final_name) .get::<#ty>(#final_name)
.expect(#expect_text); .expect(#expect_text);
)); ));