Skip to content

Commit a46a3a9

Browse files
authored
Merge pull request #18 from tomhoule/variables-default-values
Implement default values for scalar variables
2 parents 92e52b4 + 156dc93 commit a46a3a9

File tree

5 files changed

+106
-3
lines changed

5 files changed

+106
-3
lines changed

graphql_query_derive/src/field_type.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ impl FieldType {
1717
pub fn to_rust(&self, context: &QueryContext, prefix: &str) -> TokenStream {
1818
match &self {
1919
FieldType::Named(name) => {
20-
let just_the_prefix = Ident::new(prefix, Span::call_site());
2120
let name_string = name.to_string();
2221

2322
let name = if context.schema.scalars.contains(&name_string)
@@ -33,7 +32,7 @@ impl FieldType {
3332
Span::call_site(),
3433
)
3534
} else {
36-
just_the_prefix
35+
Ident::new(prefix, Span::call_site())
3736
};
3837

3938
quote!(#name)
@@ -56,6 +55,13 @@ impl FieldType {
5655
FieldType::Vector(inner) => inner.inner_name_string(),
5756
}
5857
}
58+
59+
pub fn is_optional(&self) -> bool {
60+
match self {
61+
FieldType::Optional(_) => true,
62+
_ => false,
63+
}
64+
}
5965
}
6066

6167
impl ::std::convert::From<graphql_parser::schema::Type> for FieldType {

graphql_query_derive/src/query.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,25 @@ impl QueryContext {
4242

4343
let fields = self.variables.iter().map(|variable| {
4444
let name = &variable.name;
45-
let ty = variable.ty.to_rust(self, name);
45+
let ty = variable.ty.to_rust(self, "");
4646
let name = Ident::new(name, Span::call_site());
4747
quote!(pub #name: #ty)
4848
});
4949

50+
let default_constructors = self
51+
.variables
52+
.iter()
53+
.map(|variable| variable.generate_default_value_constructor(self));
54+
5055
quote! {
5156
#[derive(Serialize)]
5257
pub struct Variables {
5358
#(#fields,)*
5459
}
60+
61+
impl Variables {
62+
#(#default_constructors)*
63+
}
5564
}
5665
}
5766

graphql_query_derive/src/variables.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use field_type::FieldType;
22
use graphql_parser;
3+
use proc_macro2::{Ident, Span, TokenStream};
4+
use query::QueryContext;
35

46
#[derive(Debug)]
57
pub struct Variable {
@@ -8,6 +10,25 @@ pub struct Variable {
810
pub default: Option<graphql_parser::query::Value>,
911
}
1012

13+
impl Variable {
14+
pub fn generate_default_value_constructor(&self, context: &QueryContext) -> TokenStream {
15+
match &self.default {
16+
Some(default) => {
17+
let fn_name = Ident::new(&format!("default_{}", self.name), Span::call_site());
18+
let ty = self.ty.to_rust(context, "");
19+
let value = graphql_parser_value_to_literal(default, self.ty.is_optional());
20+
quote! {
21+
pub fn #fn_name() -> #ty {
22+
#value
23+
}
24+
25+
}
26+
}
27+
None => quote!(),
28+
}
29+
}
30+
}
31+
1132
impl ::std::convert::From<graphql_parser::query::VariableDefinition> for Variable {
1233
fn from(def: graphql_parser::query::VariableDefinition) -> Variable {
1334
Variable {
@@ -17,3 +38,44 @@ impl ::std::convert::From<graphql_parser::query::VariableDefinition> for Variabl
1738
}
1839
}
1940
}
41+
42+
fn graphql_parser_value_to_literal(
43+
value: &graphql_parser::query::Value,
44+
is_optional: bool,
45+
) -> TokenStream {
46+
use graphql_parser::query::Value;
47+
48+
let inner = match value {
49+
Value::Boolean(b) => if *b {
50+
quote!(true)
51+
} else {
52+
quote!(false)
53+
},
54+
Value::String(s) => quote!(#s.to_string()),
55+
Value::Variable(_) => panic!("variable in variable"),
56+
Value::Null => panic!("null as default value"),
57+
Value::Float(f) => quote!(#f),
58+
Value::Int(i) => {
59+
let i = i.as_i64();
60+
quote!(#i)
61+
}
62+
Value::Enum(en) => quote!(#en),
63+
Value::List(inner) => {
64+
let elements = inner
65+
.iter()
66+
.map(|val| graphql_parser_value_to_literal(val, false));
67+
quote! {
68+
vec![
69+
#(#elements,)*
70+
]
71+
}
72+
}
73+
Value::Object(_) => unimplemented!("object literal as default for variable"),
74+
};
75+
76+
if is_optional {
77+
quote!(Some(#inner))
78+
} else {
79+
inner
80+
}
81+
}

tests/scalar_variables.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ extern crate graphql_client;
33
#[macro_use]
44
extern crate serde_derive;
55
extern crate serde;
6+
extern crate serde_json;
67

78
#[derive(GraphQLQuery)]
89
#[GraphQLQuery(
@@ -19,3 +20,23 @@ fn scalar_variables_query_variables_struct() {
1920
reps: Some(32),
2021
};
2122
}
23+
24+
#[derive(GraphQLQuery)]
25+
#[GraphQLQuery(
26+
query_path = "tests/scalar_variables_query_defaults.graphql",
27+
schema_path = "tests/scalar_variables_schema.graphql"
28+
)]
29+
#[allow(dead_code)]
30+
struct DefaultScalarVariablesQuery;
31+
32+
#[test]
33+
fn scalar_variables_default() {
34+
let variables = default_scalar_variables_query::Variables {
35+
msg: default_scalar_variables_query::Variables::default_msg(),
36+
reps: default_scalar_variables_query::Variables::default_reps(),
37+
};
38+
39+
let out = serde_json::to_string(&variables).unwrap();
40+
41+
assert_eq!(out, r#"{"msg":"o, hai","reps":3}"#);
42+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
query VariablesQuery($msg: String = "o, hai", $reps: Int = 3) {
2+
echo(message: $msg, repetitions: $reps) {
3+
result
4+
}
5+
}

0 commit comments

Comments
 (0)