Skip to content

Commit 1e941ed

Browse files
committed
graphql_query_derive: only output required structures
This can help to massively reduce compile times. Fixes #114.
1 parent a82359b commit 1e941ed

File tree

13 files changed

+125
-7
lines changed

13 files changed

+125
-7
lines changed

graphql_client_codegen/src/codegen.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub fn response_for_query(
3737
name: fragment.name,
3838
selection: Selection::from(&fragment.selection_set),
3939
on,
40+
is_required: false.into(),
4041
},
4142
);
4243
}
@@ -97,11 +98,23 @@ pub fn response_for_query(
9798
.schema
9899
.enums
99100
.values()
100-
.map(|enm| enm.to_rust(&context));
101+
.filter_map(|enm| {
102+
if enm.is_required.get() {
103+
Some(enm.to_rust(&context))
104+
} else {
105+
None
106+
}
107+
});
101108
let fragment_definitions: Result<Vec<TokenStream>, _> = context
102109
.fragments
103110
.values()
104-
.map(|fragment| fragment.to_rust(&context))
111+
.filter_map(|fragment| {
112+
if fragment.is_required.get() {
113+
Some(fragment.to_rust(&context))
114+
} else {
115+
None
116+
}
117+
})
105118
.collect();
106119
let fragment_definitions = fragment_definitions?;
107120
let variables_struct = operation.expand_variables(&context);
@@ -110,15 +123,27 @@ pub fn response_for_query(
110123
.schema
111124
.inputs
112125
.values()
113-
.map(|i| i.to_rust(&context))
126+
.filter_map(|i| {
127+
if i.is_required.get() {
128+
Some(i.to_rust(&context))
129+
} else {
130+
None
131+
}
132+
})
114133
.collect();
115134
let input_object_definitions = input_object_definitions?;
116135

117136
let scalar_definitions: Vec<TokenStream> = context
118137
.schema
119138
.scalars
120139
.values()
121-
.map(|s| s.to_rust())
140+
.filter_map(|s| {
141+
if s.is_required.get() {
142+
Some(s.to_rust())
143+
} else {
144+
None
145+
}
146+
})
122147
.collect();
123148

124149
let response_derives = context.response_derives();

graphql_client_codegen/src/enums.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use proc_macro2::{Ident, Span, TokenStream};
2+
use std::cell::Cell;
23

34
pub const ENUMS_PREFIX: &str = "";
45

@@ -13,6 +14,7 @@ pub struct GqlEnum {
1314
pub description: Option<String>,
1415
pub name: String,
1516
pub variants: Vec<EnumVariant>,
17+
pub is_required: Cell<bool>,
1618
}
1719

1820
impl GqlEnum {

graphql_client_codegen/src/field_type.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ impl FieldType {
2222
};
2323
match &self {
2424
FieldType::Named(ref name) => {
25-
let full_name = if context.schema.scalars.contains_key(name) || DEFAULT_SCALARS
25+
let full_name = if context.schema.scalars.get(name).map(|s| s.is_required.set(true)).is_some() || DEFAULT_SCALARS
2626
.iter()
2727
.any(|elem| elem == name)
2828
{
2929
name.clone()
30-
} else if context.schema.enums.contains_key(name) {
30+
} else if context.schema.enums.get(name).map(|enm| enm.is_required.set(true)).is_some() {
3131
format!("{}{}", ENUMS_PREFIX, name)
3232
} else {
3333
if prefix.is_empty() {

graphql_client_codegen/src/fragments.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
use proc_macro2::{Ident, Span, TokenStream};
22
use query::QueryContext;
33
use selection::Selection;
4+
use std::cell::Cell;
45

56
#[derive(Debug, PartialEq)]
67
pub struct GqlFragment {
78
pub name: String,
89
pub on: String,
910
pub selection: Selection,
11+
pub is_required: Cell<bool>,
1012
}
1113

1214
impl GqlFragment {

graphql_client_codegen/src/inputs.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,39 @@ use introspection_response;
66
use objects::GqlObjectField;
77
use proc_macro2::{Ident, Span, TokenStream};
88
use query::QueryContext;
9+
use schema::Schema;
910
use std::collections::HashMap;
11+
use std::cell::Cell;
1012

1113
/// Represents an input object type from a GraphQL schema
1214
#[derive(Debug, Clone, PartialEq)]
1315
pub struct GqlInput {
1416
pub description: Option<String>,
1517
pub name: String,
1618
pub fields: HashMap<String, GqlObjectField>,
19+
pub is_required: Cell<bool>,
1720
}
1821

1922
impl GqlInput {
23+
pub(crate) fn require(&self, schema: &Schema) {
24+
if self.is_required.get() {
25+
return;
26+
}
27+
self.is_required.set(true);
28+
self.fields
29+
.values()
30+
.for_each(|field| {
31+
schema.require(&field.type_.inner_name_string());
32+
})
33+
}
34+
2035
pub(crate) fn to_rust(&self, context: &QueryContext) -> Result<TokenStream, failure::Error> {
2136
let name = Ident::new(&self.name, Span::call_site());
2237
let mut fields: Vec<&GqlObjectField> = self.fields.values().collect();
2338
fields.sort_unstable_by(|a, b| a.name.cmp(&b.name));
2439
let fields = fields.iter().map(|field| {
2540
let ty = field.type_.to_rust(&context, "");
41+
context.schema.require(&field.type_.inner_name_string());
2642
let original_name = &field.name;
2743
let snake_case_name = field.name.to_snake_case();
2844
let rename = ::shared::field_rename_annotation(&original_name, &snake_case_name);
@@ -59,6 +75,7 @@ impl ::std::convert::From<graphql_parser::schema::InputObjectType> for GqlInput
5975
};
6076
(name, field)
6177
}).collect(),
78+
is_required: false.into(),
6279
}
6380
}
6481
}
@@ -87,6 +104,7 @@ impl ::std::convert::From<introspection_response::FullType> for GqlInput {
87104
};
88105
(name, field)
89106
}).collect(),
107+
is_required: false.into(),
90108
}
91109
}
92110
}
@@ -132,6 +150,7 @@ mod tests {
132150
),
133151
].into_iter()
134152
.collect(),
153+
is_required: false.into(),
135154
};
136155

137156
let expected: String = vec![

graphql_client_codegen/src/interfaces.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use query::QueryContext;
55
use selection::{Selection, SelectionItem};
66
use shared::*;
77
use std::borrow::Cow;
8+
use std::cell::Cell;
89
use std::collections::HashSet;
910
use unions::union_variants;
1011

@@ -14,6 +15,7 @@ pub struct GqlInterface {
1415
pub implemented_by: HashSet<String>,
1516
pub name: String,
1617
pub fields: Vec<GqlObjectField>,
18+
pub is_required: Cell<bool>,
1719
}
1820

1921
impl GqlInterface {
@@ -23,6 +25,7 @@ impl GqlInterface {
2325
name: name.into_owned(),
2426
implemented_by: HashSet::new(),
2527
fields: vec![],
28+
is_required: false.into(),
2629
}
2730
}
2831

graphql_client_codegen/src/objects.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@ use field_type::FieldType;
55
use graphql_parser::schema;
66
use proc_macro2::{Ident, Span, TokenStream};
77
use query::QueryContext;
8+
use schema::Schema;
89
use selection::*;
910
use shared::{field_impls_for_selection, response_fields_for_selection};
1011
use std::borrow::Cow;
12+
use std::cell::Cell;
1113

1214
#[derive(Debug, Clone, PartialEq)]
1315
pub struct GqlObject {
1416
pub description: Option<String>,
1517
pub fields: Vec<GqlObjectField>,
1618
pub name: String,
19+
pub is_required: Cell<bool>,
1720
}
1821

1922
#[derive(Clone, Debug, PartialEq, Hash)]
@@ -60,6 +63,7 @@ impl GqlObject {
6063
description: description.map(|s| s.to_owned()),
6164
name: name.into_owned(),
6265
fields: vec![typename_field()],
66+
is_required: false.into(),
6367
}
6468
}
6569

@@ -105,6 +109,18 @@ impl GqlObject {
105109
item
106110
}
107111

112+
pub(crate) fn require(&self, schema: &Schema) {
113+
if self.is_required.get() {
114+
return;
115+
}
116+
self.is_required.set(true);
117+
self.fields
118+
.iter()
119+
.for_each(|field| {
120+
schema.require(&field.type_.inner_name_string());
121+
})
122+
}
123+
108124
pub(crate) fn response_for_selection(
109125
&self,
110126
query_context: &QueryContext,

graphql_client_codegen/src/query.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ impl QueryContext {
3333
}
3434
}
3535

36+
pub(crate) fn require(&self, typename_: &str) {
37+
self.fragments
38+
.get(typename_)
39+
.map(|fragment| fragment.is_required.set(true));
40+
}
41+
3642
/// For testing only. creates an empty QueryContext with an empty Schema.
3743
#[cfg(test)]
3844
pub(crate) fn new_empty() -> QueryContext {
@@ -52,13 +58,17 @@ impl QueryContext {
5258
selection: &Selection,
5359
prefix: &str,
5460
) -> Result<TokenStream, failure::Error> {
55-
if let Some(_enm) = self.schema.enums.get(ty) {
61+
if let Some(enm) = self.schema.enums.get(ty) {
62+
enm.is_required.set(true);
5663
Ok(quote!()) // we already expand enums separately
5764
} else if let Some(obj) = self.schema.objects.get(ty) {
65+
obj.is_required.set(true);
5866
obj.response_for_selection(self, &selection, prefix)
5967
} else if let Some(iface) = self.schema.interfaces.get(ty) {
68+
iface.is_required.set(true);
6069
iface.response_for_selection(self, &selection, prefix)
6170
} else if let Some(unn) = self.schema.unions.get(ty) {
71+
unn.is_required.set(true);
6272
unn.response_for_selection(self, &selection, prefix)
6373
} else {
6474
Ok(quote!())

graphql_client_codegen/src/scalars.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use proc_macro2;
2+
use std::cell::Cell;
23

34
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq)]
45
pub struct Scalar {
56
pub name: String,
67
pub description: Option<String>,
8+
pub is_required: Cell<bool>,
79
}
810

911
impl Scalar {

graphql_client_codegen/src/schema.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,28 @@ impl Schema {
5555
Ok(())
5656
}).collect()
5757
}
58+
59+
pub(crate) fn require(&self, typename_: &str) {
60+
DEFAULT_SCALARS.iter()
61+
.find(|&&s| s == typename_)
62+
.map(|_| ())
63+
.or_else(|| {
64+
self.enums.get(typename_)
65+
.map(|enm| enm.is_required.set(true))
66+
})
67+
.or_else(|| {
68+
self.inputs.get(typename_)
69+
.map(|input| input.require(self))
70+
})
71+
.or_else(|| {
72+
self.objects.get(typename_)
73+
.map(|object| object.require(self))
74+
})
75+
.or_else(|| {
76+
self.scalars.get(typename_)
77+
.map(|scalar| scalar.is_required.set(true))
78+
});
79+
}
5880
}
5981

6082
impl ::std::convert::From<graphql_parser::schema::Document> for Schema {
@@ -94,6 +116,7 @@ impl ::std::convert::From<graphql_parser::schema::Document> for Schema {
94116
description: v.description.clone(),
95117
name: v.name.clone(),
96118
}).collect(),
119+
is_required: false.into(),
97120
},
98121
);
99122
}
@@ -103,6 +126,7 @@ impl ::std::convert::From<graphql_parser::schema::Document> for Schema {
103126
Scalar {
104127
name: scalar.name,
105128
description: scalar.description,
129+
is_required: false.into(),
106130
},
107131
);
108132
}
@@ -113,6 +137,7 @@ impl ::std::convert::From<graphql_parser::schema::Document> for Schema {
113137
GqlUnion {
114138
variants,
115139
description: union.description,
140+
is_required: false.into(),
116141
},
117142
);
118143
}
@@ -196,6 +221,7 @@ impl ::std::convert::From<::introspection_response::IntrospectionResponse> for S
196221
name: name.clone(),
197222
description: ty.description.clone(),
198223
variants,
224+
is_required: false.into(),
199225
};
200226
schema.enums.insert(name, enm);
201227
}
@@ -210,6 +236,7 @@ impl ::std::convert::From<::introspection_response::IntrospectionResponse> for S
210236
Scalar {
211237
name,
212238
description: ty.description.as_ref().map(|d| d.clone()),
239+
is_required: false.into(),
213240
},
214241
);
215242
}
@@ -227,6 +254,7 @@ impl ::std::convert::From<::introspection_response::IntrospectionResponse> for S
227254
GqlUnion {
228255
description: ty.description.as_ref().map(|d| d.to_owned()),
229256
variants,
257+
is_required: false.into(),
230258
},
231259
);
232260
}
@@ -347,6 +375,7 @@ mod tests {
347375
deprecation: DeprecationStatus::Current,
348376
},
349377
],
378+
is_required: false.into(),
350379
})
351380
)
352381
}

0 commit comments

Comments
 (0)