Rebase async_await
onto master (#454)
* feat: Raw identifier support in object macro This commit implements raw identifier (`r#name`) support for field names (methods) and arguments in the `object` proc macro. Eg: ```rust impl T { fn r#type(r#trait: String) -> bool {} } ``` * Rebase onto master * Fix merge [skip ci]
This commit is contained in:
parent
b133a0f3c2
commit
237e69c036
7 changed files with 136 additions and 7 deletions
|
@ -0,0 +1,105 @@
|
||||||
|
#[cfg(test)]
|
||||||
|
use fnv::FnvHashMap;
|
||||||
|
#[cfg(test)]
|
||||||
|
use juniper::Object;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use juniper::{
|
||||||
|
self, execute, graphql_value, DefaultScalarValue, EmptyMutation, GraphQLInputObject,
|
||||||
|
GraphQLType, RootNode, Value, Variables,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Query;
|
||||||
|
|
||||||
|
#[juniper::object]
|
||||||
|
impl Query {
|
||||||
|
fn r#type(r#fn: MyInputType) -> Vec<String> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(GraphQLInputObject, Debug, PartialEq)]
|
||||||
|
struct MyInputType {
|
||||||
|
r#trait: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn supports_raw_idents_in_types_and_args() {
|
||||||
|
let doc = r#"
|
||||||
|
{
|
||||||
|
__type(name: "Query") {
|
||||||
|
fields {
|
||||||
|
name
|
||||||
|
args {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let value = run_type_info_query(&doc);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
value,
|
||||||
|
graphql_value!(
|
||||||
|
{
|
||||||
|
"__type": {
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "type",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "fn"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn supports_raw_idents_in_fields_of_input_types() {
|
||||||
|
let doc = r#"
|
||||||
|
{
|
||||||
|
__type(name: "MyInputType") {
|
||||||
|
inputFields {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let value = run_type_info_query(&doc);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
value,
|
||||||
|
graphql_value!(
|
||||||
|
{
|
||||||
|
"__type": {
|
||||||
|
"inputFields": [
|
||||||
|
{
|
||||||
|
"name": "trait",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn run_type_info_query(doc: &str) -> Value {
|
||||||
|
let schema = RootNode::new(Query, EmptyMutation::<()>::new());
|
||||||
|
|
||||||
|
let (result, errs) =
|
||||||
|
execute(doc, None, &schema, &Variables::new(), &()).expect("Execution failed");
|
||||||
|
|
||||||
|
assert_eq!(errs, []);
|
||||||
|
|
||||||
|
println!("Result: {:#?}", result);
|
||||||
|
result
|
||||||
|
}
|
|
@ -3,5 +3,6 @@ mod util;
|
||||||
mod derive_enum;
|
mod derive_enum;
|
||||||
mod derive_input_object;
|
mod derive_input_object;
|
||||||
mod derive_object;
|
mod derive_object;
|
||||||
|
mod derive_object_with_raw_idents;
|
||||||
mod scalar_value_transparent;
|
mod scalar_value_transparent;
|
||||||
mod unions;
|
mod unions;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# master
|
# master
|
||||||
|
|
||||||
- No changes yet
|
- Correctly handle raw identifiers in field and argument names.
|
||||||
|
|
||||||
# [[0.14.1] 2019-10-24](https://github.com/graphql-rust/juniper/releases/tag/juniper-0.14.1)
|
# [[0.14.1] 2019-10-24](https://github.com/graphql-rust/juniper/releases/tag/juniper-0.14.1)
|
||||||
|
|
||||||
|
|
|
@ -99,12 +99,12 @@ where
|
||||||
use futures::future::{ready, FutureExt};
|
use futures::future::{ready, FutureExt};
|
||||||
match field_name {
|
match field_name {
|
||||||
"__schema" | "__type" => {
|
"__schema" | "__type" => {
|
||||||
let v = self.resolve_field(info, field_name, arguments, executor);
|
self.resolve_field(info, field_name, arguments, executor)
|
||||||
Box::pin(ready(v))
|
|
||||||
}
|
}
|
||||||
_ => self
|
_ => self
|
||||||
.query_type
|
.query_type
|
||||||
.resolve_field_async(info, field_name, arguments, executor),
|
.resolve_field_async(info, field_name, arguments, executor)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,7 +170,7 @@ pub fn impl_input_object(ast: &syn::DeriveInput, is_internal: bool) -> TokenStre
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// Note: auto camel casing when no custom name specified.
|
// Note: auto camel casing when no custom name specified.
|
||||||
crate::util::to_camel_case(&field_ident.to_string())
|
crate::util::to_camel_case(&unraw(&field_ident.to_string()))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let field_description = match field_attrs.description {
|
let field_description = match field_attrs.description {
|
||||||
|
|
|
@ -354,6 +354,24 @@ impl Query {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Raw identifiers
|
||||||
|
|
||||||
|
You can use [raw identifiers](https://doc.rust-lang.org/stable/edition-guide/rust-2018/module-system/raw-identifiers.html)
|
||||||
|
if you want a GrahpQL field that happens to be a Rust keyword:
|
||||||
|
|
||||||
|
```
|
||||||
|
struct User {
|
||||||
|
r#type: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[juniper::object]
|
||||||
|
impl User {
|
||||||
|
fn r#type(&self) -> &str {
|
||||||
|
&self.r#type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn object(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn object(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
|
|
|
@ -631,6 +631,11 @@ pub struct GraphQLTypeDefinitionField {
|
||||||
pub is_async: bool,
|
pub is_async: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unraw(s: &str) -> String {
|
||||||
|
use syn::ext::IdentExt;
|
||||||
|
quote::format_ident!("{}", s).unraw().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
/// Definition of a graphql type based on information extracted
|
/// Definition of a graphql type based on information extracted
|
||||||
/// by various macros.
|
/// by various macros.
|
||||||
/// The definition can be rendered to Rust code.
|
/// The definition can be rendered to Rust code.
|
||||||
|
@ -679,7 +684,7 @@ impl GraphQLTypeDefiniton {
|
||||||
let field_definitions = self.fields.iter().map(|field| {
|
let field_definitions = self.fields.iter().map(|field| {
|
||||||
let args = field.args.iter().map(|arg| {
|
let args = field.args.iter().map(|arg| {
|
||||||
let arg_type = &arg._type;
|
let arg_type = &arg._type;
|
||||||
let arg_name = &arg.name;
|
let arg_name = unraw(&arg.name);
|
||||||
|
|
||||||
let description = match arg.description.as_ref() {
|
let description = match arg.description.as_ref() {
|
||||||
Some(value) => quote!( .description( #value ) ),
|
Some(value) => quote!( .description( #value ) ),
|
||||||
|
@ -719,7 +724,7 @@ impl GraphQLTypeDefiniton {
|
||||||
None => quote!(),
|
None => quote!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let field_name = &field.name;
|
let field_name = unraw(&field.name);
|
||||||
|
|
||||||
let _type = &field._type;
|
let _type = &field._type;
|
||||||
quote! {
|
quote! {
|
||||||
|
|
Loading…
Reference in a new issue