From 4ffd276a5b33ae4423f295675f977ed6cc7fb88a Mon Sep 17 00:00:00 2001 From: Zak <19464008+zaksabeast@users.noreply.github.com> Date: Thu, 26 Nov 2020 04:46:06 -0600 Subject: [PATCH] Allow raw identifier for field arguments in #[graphql_object] macro (#812, #786) --- .../juniper_tests/src/codegen/impl_object.rs | 43 +++ juniper/src/macros/tests/args.rs | 244 +++++++++++++++++- juniper_codegen/src/util/mod.rs | 5 +- 3 files changed, 289 insertions(+), 3 deletions(-) diff --git a/integration_tests/juniper_tests/src/codegen/impl_object.rs b/integration_tests/juniper_tests/src/codegen/impl_object.rs index 6349f7aa..7a7245ff 100644 --- a/integration_tests/juniper_tests/src/codegen/impl_object.rs +++ b/integration_tests/juniper_tests/src/codegen/impl_object.rs @@ -94,3 +94,46 @@ mod fallible { } } } + +mod raw_argument { + use juniper::{ + graphql_object, graphql_value, EmptyMutation, EmptySubscription, RootNode, Variables, + }; + + struct Obj; + + #[graphql_object] + impl Obj { + #[graphql(arguments(r#arg(description = "The only argument")))] + fn test(&self, arg: String) -> String { + arg + } + } + + #[tokio::test] + async fn named_correctly() { + let doc = r#"{ + __type(name: "Obj") { + fields { + args { + name + } + } + } + }"#; + + let schema = RootNode::new( + Obj, + EmptyMutation::<()>::new(), + EmptySubscription::<()>::new(), + ); + + assert_eq!( + juniper::execute(&doc, None, &schema, &Variables::new(), &()).await, + Ok(( + graphql_value!({"__type": {"fields": [{"args": [{"name": "arg"}]}]}}), + vec![], + )), + ); + } +} diff --git a/juniper/src/macros/tests/args.rs b/juniper/src/macros/tests/args.rs index b98ebc32..9f5d038d 100644 --- a/juniper/src/macros/tests/args.rs +++ b/juniper/src/macros/tests/args.rs @@ -58,6 +58,11 @@ impl Root { arg } + #[graphql(arguments(r#arg(description = "The arg")))] + fn single_arg_descr_raw_idents(arg: i32) -> i32 { + arg + } + #[graphql(arguments( arg1(description = "The first arg",), arg2(description = "The second arg") @@ -66,9 +71,17 @@ impl Root { arg1 + arg2 } + #[graphql(arguments( + r#arg1(description = "The first arg",), + r#arg2(description = "The second arg") + ))] + fn multi_args_descr_raw_idents(arg1: i32, arg2: i32) -> i32 { + arg1 + arg2 + } + #[graphql(arguments( arg1(description = "The first arg",), - arg2(description = "The second arg") + arg2(description = "The second arg",) ))] fn multi_args_descr_trailing_comma(arg1: i32, arg2: i32) -> i32 { arg1 + arg2 @@ -106,6 +119,11 @@ impl Root { arg } + #[graphql(arguments(r#arg(default = 123, description = "The arg")))] + fn arg_with_default_descr_raw_ident(arg: i32) -> i32 { + arg + } + #[graphql(arguments( arg1(default = 123, description = "The first arg"), arg2(default = 456, description = "The second arg") @@ -114,6 +132,14 @@ impl Root { arg1 + arg2 } + #[graphql(arguments( + r#arg1(default = 123, description = "The first arg"), + r#arg2(default = 456, description = "The second arg") + ))] + fn multi_args_with_default_descr_raw_ident(arg1: i32, arg2: i32) -> i32 { + arg1 + arg2 + } + #[graphql(arguments( arg1(default = 123, description = "The first arg",), arg2(default = 456, description = "The second arg",) @@ -122,6 +148,14 @@ impl Root { arg1 + arg2 } + #[graphql(arguments( + r#arg1(default = 123, description = "The first arg",), + r#arg2(default = 456, description = "The second arg",) + ))] + fn multi_args_with_default_trailing_comma_descr_raw_ident(arg1: i32, arg2: i32) -> i32 { + arg1 + arg2 + } + #[graphql( arguments( arg1( @@ -460,6 +494,40 @@ async fn introspect_field_single_arg_descr() { .await; } +#[tokio::test] +async fn introspect_field_single_arg_descr_raw_idents() { + run_args_info_query("singleArgDescrRawIdents", |args| { + assert_eq!(args.len(), 1); + + assert!(args.contains(&Value::object( + vec![ + ("name", Value::scalar("arg")), + ("description", Value::scalar("The arg")), + ("defaultValue", Value::null()), + ( + "type", + Value::object( + vec![ + ("name", Value::null()), + ( + "ofType", + Value::object( + vec![("name", Value::scalar("Int"))].into_iter().collect(), + ), + ), + ] + .into_iter() + .collect(), + ), + ), + ] + .into_iter() + .collect(), + ))); + }) + .await; +} + #[tokio::test] async fn introspect_field_multi_args_descr() { run_args_info_query("multiArgsDescr", |args| { @@ -520,6 +588,66 @@ async fn introspect_field_multi_args_descr() { .await; } +#[tokio::test] +async fn introspect_field_multi_args_descr_raw_idents() { + run_args_info_query("multiArgsDescrRawIdents", |args| { + assert_eq!(args.len(), 2); + + assert!(args.contains(&Value::object( + vec![ + ("name", Value::scalar("arg1")), + ("description", Value::scalar("The first arg")), + ("defaultValue", Value::null()), + ( + "type", + Value::object( + vec![ + ("name", Value::null()), + ( + "ofType", + Value::object( + vec![("name", Value::scalar("Int"))].into_iter().collect(), + ), + ), + ] + .into_iter() + .collect(), + ), + ), + ] + .into_iter() + .collect(), + ))); + + assert!(args.contains(&Value::object( + vec![ + ("name", Value::scalar("arg2")), + ("description", Value::scalar("The second arg")), + ("defaultValue", Value::null()), + ( + "type", + Value::object( + vec![ + ("name", Value::null()), + ( + "ofType", + Value::object( + vec![("name", Value::scalar("Int"))].into_iter().collect(), + ), + ), + ] + .into_iter() + .collect(), + ), + ), + ] + .into_iter() + .collect(), + ))); + }) + .await; +} + #[tokio::test] async fn introspect_field_multi_args_descr_trailing_comma() { run_args_info_query("multiArgsDescrTrailingComma", |args| { @@ -786,6 +914,32 @@ async fn introspect_field_arg_with_default_descr() { .await; } +#[tokio::test] +async fn introspect_field_arg_with_default_descr_raw_ident() { + run_args_info_query("argWithDefaultDescrRawIdent", |args| { + assert_eq!(args.len(), 1); + + assert!(args.contains(&Value::object( + vec![ + ("name", Value::scalar("arg")), + ("description", Value::scalar("The arg")), + ("defaultValue", Value::scalar("123")), + ( + "type", + Value::object( + vec![("name", Value::scalar("Int")), ("ofType", Value::null())] + .into_iter() + .collect(), + ), + ), + ] + .into_iter() + .collect(), + ))); + }) + .await; +} + #[tokio::test] async fn introspect_field_multi_args_with_default_descr() { run_args_info_query("multiArgsWithDefaultDescr", |args| { @@ -830,6 +984,50 @@ async fn introspect_field_multi_args_with_default_descr() { .await; } +#[tokio::test] +async fn introspect_field_multi_args_with_default_descr_raw_ident() { + run_args_info_query("multiArgsWithDefaultDescrRawIdent", |args| { + assert_eq!(args.len(), 2); + + assert!(args.contains(&Value::object( + vec![ + ("name", Value::scalar("arg1")), + ("description", Value::scalar("The first arg")), + ("defaultValue", Value::scalar("123")), + ( + "type", + Value::object( + vec![("name", Value::scalar("Int")), ("ofType", Value::null())] + .into_iter() + .collect(), + ), + ), + ] + .into_iter() + .collect(), + ))); + + assert!(args.contains(&Value::object( + vec![ + ("name", Value::scalar("arg2")), + ("description", Value::scalar("The second arg")), + ("defaultValue", Value::scalar("456")), + ( + "type", + Value::object( + vec![("name", Value::scalar("Int")), ("ofType", Value::null())] + .into_iter() + .collect(), + ), + ), + ] + .into_iter() + .collect(), + ))); + }) + .await; +} + #[tokio::test] async fn introspect_field_multi_args_with_default_trailing_comma_descr() { run_args_info_query("multiArgsWithDefaultTrailingCommaDescr", |args| { @@ -874,6 +1072,50 @@ async fn introspect_field_multi_args_with_default_trailing_comma_descr() { .await; } +#[tokio::test] +async fn introspect_field_multi_args_with_default_trailing_comma_descr_raw_ident() { + run_args_info_query("multiArgsWithDefaultTrailingCommaDescrRawIdent", |args| { + assert_eq!(args.len(), 2); + + assert!(args.contains(&Value::object( + vec![ + ("name", Value::scalar("arg1")), + ("description", Value::scalar("The first arg")), + ("defaultValue", Value::scalar("123")), + ( + "type", + Value::object( + vec![("name", Value::scalar("Int")), ("ofType", Value::null())] + .into_iter() + .collect(), + ), + ), + ] + .into_iter() + .collect(), + ))); + + assert!(args.contains(&Value::object( + vec![ + ("name", Value::scalar("arg2")), + ("description", Value::scalar("The second arg")), + ("defaultValue", Value::scalar("456")), + ( + "type", + Value::object( + vec![("name", Value::scalar("Int")), ("ofType", Value::null())] + .into_iter() + .collect(), + ), + ), + ] + .into_iter() + .collect(), + ))); + }) + .await; +} + #[tokio::test] async fn introspect_field_args_with_complex_default() { run_args_info_query("argsWithComplexDefault", |args| { diff --git a/juniper_codegen/src/util/mod.rs b/juniper_codegen/src/util/mod.rs index 062b52b1..b636d280 100644 --- a/juniper_codegen/src/util/mod.rs +++ b/juniper_codegen/src/util/mod.rs @@ -11,11 +11,12 @@ use proc_macro_error::abort; use quote::quote; use span_container::SpanContainer; use syn::{ + ext::IdentExt as _, parse::{Parse, ParseStream}, parse_quote, punctuated::Punctuated, spanned::Spanned, - token, Attribute, Lit, Meta, MetaList, MetaNameValue, NestedMeta, + token, Attribute, Ident, Lit, Meta, MetaList, MetaNameValue, NestedMeta, }; use crate::common::parse::ParseBufferExt as _; @@ -450,7 +451,7 @@ pub struct FieldAttributeArgument { impl Parse for FieldAttributeArgument { fn parse(input: ParseStream) -> syn::Result { - let name = input.parse()?; + let name = input.parse::()?.unraw(); let mut arg = Self { name,