Skip to content

Commit c9d30d7

Browse files
authored
Merge pull request #10 from tomhoule/test-union-generation
Finalize union codegen
2 parents 028a169 + a15b7e0 commit c9d30d7

15 files changed

+390
-158
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ graphql-parser = "0.2.0"
1414
serde = "1.0"
1515
serde_derive = "1.0"
1616

17+
[dev-dependencies]
18+
serde_json = "1.0"
19+
1720
[workspace]
1821
members = [
1922
".",

graphql_query_derive/src/constants.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use proc_macro2::{Ident, Span};
2+
3+
pub const TYPENAME_FIELD: &'static str = "__typename";
4+
5+
pub fn string_type() -> Ident {
6+
Ident::new("String", Span::call_site())
7+
}

graphql_query_derive/src/fragments.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use selection::Selection;
21
use proc_macro2::{Ident, Span, TokenStream};
32
use query::QueryContext;
3+
use selection::Selection;
44

55
#[derive(Debug, PartialEq)]
66
pub struct GqlFragment {

graphql_query_derive/src/interfaces.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use selection::Selection;
21
use objects::GqlObjectField;
32
use proc_macro2::{Ident, Span, TokenStream};
43
use query::QueryContext;
4+
use selection::Selection;
55

66
#[derive(Debug, PartialEq)]
77
pub struct GqlInterface {

graphql_query_derive/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ extern crate quote;
1616

1717
use proc_macro2::TokenStream;
1818

19+
mod constants;
1920
mod enums;
2021
mod field_type;
2122
mod fragments;

graphql_query_derive/src/objects.rs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
use constants::*;
12
use failure;
23
use field_type::FieldType;
34
use heck::{CamelCase, SnakeCase};
45
use proc_macro2::{Ident, Span, TokenStream};
56
use query::QueryContext;
6-
use shared::render_object_field;
77
use selection::*;
8+
use shared::render_object_field;
9+
use std::borrow::Cow;
810

911
#[derive(Debug, PartialEq)]
1012
pub struct GqlObject {
@@ -19,6 +21,42 @@ pub struct GqlObjectField {
1921
}
2022

2123
impl GqlObject {
24+
pub fn new(name: Cow<str>) -> GqlObject {
25+
GqlObject {
26+
name: name.into_owned(),
27+
fields: vec![GqlObjectField {
28+
name: TYPENAME_FIELD.to_string(),
29+
/// Non-nullable, see spec:
30+
/// https://github.com/facebook/graphql/blob/master/spec/Section%204%20--%20Introspection.md
31+
type_: FieldType::Named(string_type()),
32+
}],
33+
}
34+
}
35+
36+
pub fn from_graphql_parser_object(obj: ::graphql_parser::schema::ObjectType) -> Self {
37+
let mut item = GqlObject::new(obj.name.into());
38+
item.fields
39+
.extend(obj.fields.iter().map(|f| GqlObjectField {
40+
name: f.name.clone(),
41+
type_: FieldType::from(f.field_type.clone()),
42+
}));
43+
item
44+
}
45+
46+
pub fn from_introspected_schema_json(obj: &::introspection_response::FullType) -> Self {
47+
let mut item = GqlObject::new(obj.name.clone().expect("missing object name").into());
48+
let fields = obj.fields.clone().unwrap().into_iter().filter_map(|t| {
49+
t.map(|t| GqlObjectField {
50+
name: t.name.expect("field name"),
51+
type_: FieldType::from(t.type_.expect("field type")),
52+
})
53+
});
54+
55+
item.fields.extend(fields);
56+
57+
item
58+
}
59+
2260
pub fn response_for_selection(
2361
&self,
2462
query_context: &QueryContext,
@@ -81,6 +119,7 @@ impl GqlObject {
81119
match item {
82120
SelectionItem::Field(f) => {
83121
let name = &f.name;
122+
84123
let ty = &self
85124
.fields
86125
.iter()
@@ -102,9 +141,7 @@ impl GqlObject {
102141
#field_name: #type_name
103142
})
104143
}
105-
SelectionItem::InlineFragment(_) => {
106-
unreachable!("inline fragment on object field")
107-
}
144+
SelectionItem::InlineFragment(_) => unreachable!("inline fragment on object field"),
108145
}
109146
}
110147

graphql_query_derive/src/query.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use field_type::FieldType;
33
use fragments::GqlFragment;
44
use proc_macro2::TokenStream;
55
use schema::Schema;
6-
use std::collections::BTreeMap;
76
use selection::Selection;
7+
use std::collections::BTreeMap;
88

99
pub struct QueryContext {
1010
pub _subscription_root: Option<Vec<TokenStream>>,

graphql_query_derive/src/schema.rs

Lines changed: 28 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use interfaces::GqlInterface;
88
use objects::{GqlObject, GqlObjectField};
99
use proc_macro2::TokenStream;
1010
use query::QueryContext;
11-
use std::collections::{BTreeMap, BTreeSet};
1211
use selection::Selection;
12+
use std::collections::{BTreeMap, BTreeSet};
1313
use unions::GqlUnion;
1414

1515
pub const DEFAULT_SCALARS: &[&'static str] = &["ID", "String", "Int", "Float", "Boolean"];
@@ -60,16 +60,12 @@ impl Schema {
6060
let prefix = format!("RUST_{}", prefix);
6161
let selection = Selection::from(&q.selection_set);
6262

63-
definitions.extend(definition.field_impls_for_selection(
64-
&context,
65-
&selection,
66-
&prefix,
67-
)?);
68-
Some(definition.response_fields_for_selection(
69-
&context,
70-
&selection,
71-
&prefix,
72-
))
63+
definitions.extend(
64+
definition.field_impls_for_selection(&context, &selection, &prefix)?,
65+
);
66+
Some(
67+
definition.response_fields_for_selection(&context, &selection, &prefix),
68+
)
7369
};
7470
}
7571
query::Definition::Operation(query::OperationDefinition::Mutation(q)) => {
@@ -84,16 +80,12 @@ impl Schema {
8480
let prefix = format!("RUST_{}", prefix);
8581
let selection = Selection::from(&q.selection_set);
8682

87-
definitions.extend(definition.field_impls_for_selection(
88-
&context,
89-
&selection,
90-
&prefix,
91-
)?);
92-
Some(definition.response_fields_for_selection(
93-
&context,
94-
&selection,
95-
&prefix,
96-
))
83+
definitions.extend(
84+
definition.field_impls_for_selection(&context, &selection, &prefix)?,
85+
);
86+
Some(
87+
definition.response_fields_for_selection(&context, &selection, &prefix),
88+
)
9789
};
9890
}
9991
query::Definition::Operation(query::OperationDefinition::Subscription(q)) => {
@@ -110,16 +102,12 @@ impl Schema {
110102
let prefix = format!("RUST_{}", prefix);
111103
let selection = Selection::from(&q.selection_set);
112104

113-
definitions.extend(definition.field_impls_for_selection(
114-
&context,
115-
&selection,
116-
&prefix,
117-
)?);
118-
Some(definition.response_fields_for_selection(
119-
&context,
120-
&selection,
121-
&prefix,
122-
))
105+
definitions.extend(
106+
definition.field_impls_for_selection(&context, &selection, &prefix)?,
107+
);
108+
Some(
109+
definition.response_fields_for_selection(&context, &selection, &prefix),
110+
)
123111
};
124112
}
125113
query::Definition::Operation(query::OperationDefinition::SelectionSet(_)) => {
@@ -204,20 +192,9 @@ impl ::std::convert::From<graphql_parser::schema::Document> for Schema {
204192
.or_insert_with(|| vec![name.clone()]);
205193
}
206194

207-
schema.objects.insert(
208-
obj.name.clone(),
209-
GqlObject {
210-
name: obj.name.clone(),
211-
fields: obj
212-
.fields
213-
.iter()
214-
.map(|f| GqlObjectField {
215-
name: f.name.clone(),
216-
type_: FieldType::from(f.field_type.clone()),
217-
})
218-
.collect(),
219-
},
220-
);
195+
schema
196+
.objects
197+
.insert(obj.name.clone(), GqlObject::from_graphql_parser_object(obj));
221198
}
222199
schema::TypeDefinition::Enum(enm) => {
223200
schema.enums.insert(
@@ -337,21 +314,9 @@ impl ::std::convert::From<::introspection_response::IntrospectionResponse> for S
337314
.or_insert_with(|| vec![name.clone()]);
338315
}
339316

340-
let fields: Vec<GqlObjectField> = ty
341-
.fields
342-
.clone()
343-
.unwrap()
344-
.into_iter()
345-
.filter_map(|t| {
346-
t.map(|t| GqlObjectField {
347-
name: t.name.expect("field name"),
348-
type_: FieldType::from(t.type_.expect("field type")),
349-
})
350-
})
351-
.collect();
352317
schema
353318
.objects
354-
.insert(name.clone(), GqlObject { name, fields });
319+
.insert(name.clone(), GqlObject::from_introspected_schema_json(ty));
355320
}
356321
Some(__TypeKind::INTERFACE) => {
357322
let iface = GqlInterface {
@@ -385,6 +350,7 @@ impl ::std::convert::From<::introspection_response::IntrospectionResponse> for S
385350
#[cfg(test)]
386351
mod tests {
387352
use super::*;
353+
use constants::*;
388354
use proc_macro2::{Ident, Span};
389355

390356
#[test]
@@ -397,6 +363,10 @@ mod tests {
397363
Some(&GqlObject {
398364
name: "Droid".to_string(),
399365
fields: vec![
366+
GqlObjectField {
367+
name: TYPENAME_FIELD.to_string(),
368+
type_: FieldType::Named(string_type()),
369+
},
400370
GqlObjectField {
401371
name: "id".to_string(),
402372
type_: FieldType::Optional(Box::new(FieldType::Named(Ident::new(

graphql_query_derive/src/selection.rs

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -108,34 +108,32 @@ mod tests {
108108
Selection(vec![SelectionItem::Field(SelectionField {
109109
name: "animal".to_string(),
110110
fields: Selection(vec![
111-
SelectionItem::Field(SelectionField {
112-
name: "isCat".to_string(),
113-
fields: Selection(Vec::new()),
114-
}),
115-
SelectionItem::Field(SelectionField {
116-
name: "isHorse".to_string(),
117-
fields: Selection(Vec::new()),
118-
}),
119-
SelectionItem::FragmentSpread(SelectionFragmentSpread {
120-
fragment_name: "Timestamps".to_string(),
121-
}),
122-
SelectionItem::Field(SelectionField {
123-
name: "barks".to_string(),
124-
fields: Selection(Vec::new()),
125-
}),
126-
SelectionItem::InlineFragment(SelectionInlineFragment {
127-
on: "Dog".to_string(),
128-
fields: Selection(vec![
129-
SelectionItem::Field(SelectionField {
130-
name: "rating".to_string(),
131-
fields: Selection(Vec::new()),
132-
}),
133-
]),
134-
}),
135-
SelectionItem::Field(SelectionField {
136-
name: "pawsCount".to_string(),
137-
fields: Selection(Vec::new()),
138-
}),
111+
SelectionItem::Field(SelectionField {
112+
name: "isCat".to_string(),
113+
fields: Selection(Vec::new()),
114+
}),
115+
SelectionItem::Field(SelectionField {
116+
name: "isHorse".to_string(),
117+
fields: Selection(Vec::new()),
118+
}),
119+
SelectionItem::FragmentSpread(SelectionFragmentSpread {
120+
fragment_name: "Timestamps".to_string(),
121+
}),
122+
SelectionItem::Field(SelectionField {
123+
name: "barks".to_string(),
124+
fields: Selection(Vec::new()),
125+
}),
126+
SelectionItem::InlineFragment(SelectionInlineFragment {
127+
on: "Dog".to_string(),
128+
fields: Selection(vec![SelectionItem::Field(SelectionField {
129+
name: "rating".to_string(),
130+
fields: Selection(Vec::new()),
131+
})]),
132+
}),
133+
SelectionItem::Field(SelectionField {
134+
name: "pawsCount".to_string(),
135+
fields: Selection(Vec::new()),
136+
}),
139137
]),
140138
})])
141139
);

graphql_query_derive/src/shared.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ pub fn render_object_field(field_name: &str, field_type: TokenStream) -> TokenSt
55
let name_ident = Ident::new(&format!("{}_", field_name), Span::call_site());
66
return quote! {
77
#[serde(rename = #field_name)]
8-
#name_ident: #field_type
8+
pub #name_ident: #field_type
99
};
1010
}
1111

1212
let name_ident = Ident::new(field_name, Span::call_site());
1313

14-
quote!(#name_ident: #field_type)
14+
quote!(pub #name_ident: #field_type)
1515
}

0 commit comments

Comments
 (0)