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_input_object;
|
||||
mod derive_object;
|
||||
mod derive_object_with_raw_idents;
|
||||
mod scalar_value_transparent;
|
||||
mod unions;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 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)
|
||||
|
||||
|
|
|
@ -99,12 +99,12 @@ where
|
|||
use futures::future::{ready, FutureExt};
|
||||
match field_name {
|
||||
"__schema" | "__type" => {
|
||||
let v = self.resolve_field(info, field_name, arguments, executor);
|
||||
Box::pin(ready(v))
|
||||
self.resolve_field(info, field_name, arguments, executor)
|
||||
}
|
||||
_ => self
|
||||
.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 => {
|
||||
// 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 {
|
||||
|
|
|
@ -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]
|
||||
pub fn object(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
|
|
|
@ -631,6 +631,11 @@ pub struct GraphQLTypeDefinitionField {
|
|||
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
|
||||
/// by various macros.
|
||||
/// The definition can be rendered to Rust code.
|
||||
|
@ -679,7 +684,7 @@ impl GraphQLTypeDefiniton {
|
|||
let field_definitions = self.fields.iter().map(|field| {
|
||||
let args = field.args.iter().map(|arg| {
|
||||
let arg_type = &arg._type;
|
||||
let arg_name = &arg.name;
|
||||
let arg_name = unraw(&arg.name);
|
||||
|
||||
let description = match arg.description.as_ref() {
|
||||
Some(value) => quote!( .description( #value ) ),
|
||||
|
@ -719,7 +724,7 @@ impl GraphQLTypeDefiniton {
|
|||
None => quote!(),
|
||||
};
|
||||
|
||||
let field_name = &field.name;
|
||||
let field_name = unraw(&field.name);
|
||||
|
||||
let _type = &field._type;
|
||||
quote! {
|
||||
|
|
Loading…
Reference in a new issue