Skip to content

Commit a554885

Browse files
committed
Make type-refining fragments work
1 parent e2a5b46 commit a554885

File tree

5 files changed

+94
-35
lines changed

5 files changed

+94
-35
lines changed

graphql_client/tests/interfaces/interface_with_type_refining_fragment_query.graphql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
fragment Birthday on Person {
1+
fragment BirthdayFragment on Person {
22
birthday
33
}
44

@@ -9,7 +9,7 @@ query QueryOnInterface {
99
... on Dog {
1010
isGoodDog
1111
}
12-
...Birthday
12+
...BirthdayFragment
1313
... on Organization {
1414
industry
1515
}

graphql_client/tests/type_refining_fragments.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,19 @@ fn type_refining_fragment_on_union() {
2929
last_name: Some("Lorde".to_string()),
3030
}),
3131
query_on_union::QueryOnUnionNames::Dog(query_on_union::QueryOnUnionNamesOnDog {
32-
name: "Laïka".to_string(),
32+
dog_name: query_on_union::DogName {
33+
name: "Laïka".to_string(),
34+
},
3335
}),
3436
query_on_union::QueryOnUnionNames::Organization(
3537
query_on_union::QueryOnUnionNamesOnOrganization {
3638
title: "Mozilla".to_string(),
3739
},
3840
),
3941
query_on_union::QueryOnUnionNames::Dog(query_on_union::QueryOnUnionNamesOnDog {
40-
name: "Norbert".to_string(),
42+
dog_name: query_on_union::DogName {
43+
name: "Norbert".to_string(),
44+
},
4145
}),
4246
]),
4347
};
@@ -58,7 +62,9 @@ fn type_refining_fragment_on_interface() {
5862
QueryOnInterfaceEverything {
5963
name: "Audrey Lorde".to_string(),
6064
on: QueryOnInterfaceEverythingOn::Person(QueryOnInterfaceEverythingOnPerson {
61-
birthday: Some("1934-02-18".to_string()),
65+
birthday_fragment: BirthdayFragment {
66+
birthday: Some("1934-02-18".to_string())
67+
},
6268
}),
6369
},
6470
QueryOnInterfaceEverything {

graphql_client_codegen/src/codegen/selection.rs

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,11 @@ fn calculate_selection<'a>(
161161
})
162162
.peekable();
163163

164-
if let Some((selection_ref, _)) = variant_selections.peek() {
165-
let variant_struct_name_str = selection_ref.full_path_prefix();
164+
if let Some((selection_ref, _variant)) = variant_selections.peek() {
165+
let mut variant_struct_name_str = selection_ref.full_path_prefix();
166+
variant_struct_name_str.reserve(2 + variant_name_str.len());
167+
variant_struct_name_str.push_str("On");
168+
variant_struct_name_str.push_str(variant_name_str);
166169

167170
context.push_variant(ExpandedVariant {
168171
name: variant_name_str.into(),
@@ -177,13 +180,28 @@ fn calculate_selection<'a>(
177180

178181
let struct_id = context.push_type(expanded_type);
179182

180-
calculate_selection(
181-
context,
182-
// FIXME should be all subselections
183-
selection_ref.subselection_ids(),
184-
struct_id,
185-
variant_schema_type,
186-
);
183+
for (_selection, variant_selection) in variant_selections {
184+
match variant_selection {
185+
VariantSelection::InlineFragment(_) => {
186+
calculate_selection(
187+
context,
188+
selection_ref.subselection_ids(),
189+
struct_id,
190+
variant_schema_type,
191+
);
192+
}
193+
VariantSelection::FragmentSpread(fragment_ref) => {
194+
context.push_field(ExpandedField {
195+
field_type: fragment_ref.name().into(),
196+
field_type_qualifiers: &[GraphqlTypeQualifier::Required],
197+
flatten: true,
198+
graphql_name: None,
199+
rust_name: fragment_ref.name().to_snake_case().into(),
200+
struct_id,
201+
})
202+
}
203+
}
204+
}
187205
} else {
188206
context.push_variant(ExpandedVariant {
189207
name: variant_name_str.into(),
@@ -207,7 +225,7 @@ fn calculate_selection<'a>(
207225
match field_type.type_id() {
208226
TypeId::Enum(enm) => {
209227
context.push_field(ExpandedField {
210-
graphql_name,
228+
graphql_name: Some(graphql_name),
211229
rust_name,
212230
struct_id,
213231
field_type: context.schema().r#enum(enm).name().into(),
@@ -221,7 +239,7 @@ fn calculate_selection<'a>(
221239
field_type_qualifiers: field
222240
.schema_field(context.schema())
223241
.type_qualifiers(),
224-
graphql_name,
242+
graphql_name: Some(graphql_name),
225243
struct_id,
226244
rust_name,
227245
flatten: false,
@@ -232,7 +250,7 @@ fn calculate_selection<'a>(
232250

233251
context.push_field(ExpandedField {
234252
struct_id,
235-
graphql_name,
253+
graphql_name: Some(graphql_name),
236254
rust_name,
237255
field_type_qualifiers: schema_field.type_qualifiers(),
238256
field_type: Cow::Owned(struct_name_string.clone()),
@@ -276,7 +294,7 @@ fn calculate_selection<'a>(
276294
context.push_field(ExpandedField {
277295
field_type: fragment.name().into(),
278296
field_type_qualifiers: &[GraphqlTypeQualifier::Required],
279-
graphql_name: fragment.name(),
297+
graphql_name: None,
280298
rust_name: final_field_name,
281299
struct_id,
282300
flatten: true,
@@ -293,7 +311,7 @@ fn calculate_selection<'a>(
293311
struct ResponseTypeId(u32);
294312

295313
struct ExpandedField<'a> {
296-
graphql_name: &'a str,
314+
graphql_name: Option<&'a str>,
297315
rust_name: Cow<'a, str>,
298316
field_type: Cow<'a, str>,
299317
field_type_qualifiers: &'a [GraphqlTypeQualifier],
@@ -309,7 +327,10 @@ impl<'a> ExpandedField<'a> {
309327
self.field_type_qualifiers,
310328
);
311329

312-
let optional_rename = field_rename_annotation(self.graphql_name, &self.rust_name);
330+
let optional_rename = self
331+
.graphql_name
332+
.as_ref()
333+
.map(|graphql_name| field_rename_annotation(graphql_name, &self.rust_name));
313334
let optional_flatten = if self.flatten {
314335
Some(quote!(#[serde(flatten)]))
315336
} else {

graphql_client_codegen/src/resolution.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ impl<'a, T> QueryWith<'a, T> {
3434
}
3535
}
3636

37-
pub(crate) struct SelectionRef<'a>(QueryWith<'a, (SelectionId, &'a Selection)>);
3837
pub(crate) struct OperationRef<'a>(QueryWith<'a, OperationId>);
3938
pub(crate) struct VariableRef<'a>(QueryWith<'a, (VariableId, &'a ResolvedVariable)>);
4039
pub(crate) struct InlineFragmentRef<'a>(QueryWith<'a, &'a InlineFragment>);
@@ -65,15 +64,17 @@ impl VariableId {
6564

6665
#[derive(Debug, Clone, Copy)]
6766
enum SelectionParent {
68-
Selection(SelectionId),
67+
Field(SelectionId),
68+
InlineFragment(SelectionId),
6969
Fragment(ResolvedFragmentId),
7070
Operation(OperationId),
7171
}
7272

7373
impl SelectionParent {
7474
fn add_to_selection_set(&self, q: &mut ResolvedQuery, selection_id: SelectionId) {
7575
match self {
76-
SelectionParent::Selection(parent_selection_id) => {
76+
SelectionParent::Field(parent_selection_id)
77+
| SelectionParent::InlineFragment(parent_selection_id) => {
7778
let parent_selection = q
7879
.selections
7980
.get_mut(parent_selection_id.0 as usize)
@@ -82,7 +83,7 @@ impl SelectionParent {
8283
match parent_selection {
8384
Selection::Field(f) => f.selection_set.push(selection_id),
8485
Selection::InlineFragment(inline) => inline.selection_set.push(selection_id),
85-
_ => unreachable!("impossible parent selection"),
86+
other => unreachable!("impossible parent selection: {:?}", other),
8687
}
8788
}
8889
SelectionParent::Fragment(fragment_id) => {
@@ -105,6 +106,8 @@ impl SelectionParent {
105106
}
106107
}
107108

109+
pub(crate) struct SelectionRef<'a>(QueryWith<'a, (SelectionId, &'a Selection)>);
110+
108111
impl<'a> SelectionRef<'a> {
109112
pub(crate) fn query(&self) -> &'a ResolvedQuery {
110113
self.0.query
@@ -167,15 +170,18 @@ impl<'a> SelectionRef<'a> {
167170
}
168171

169172
pub(crate) fn full_path_prefix(&self) -> String {
170-
let mut path = vec![self.to_path_segment()];
173+
let mut path = match self.selection() {
174+
Selection::FragmentSpread(_) | Selection::InlineFragment(_) => Vec::new(),
175+
_ => vec![self.to_path_segment()],
176+
};
171177

172178
let mut item = self.id();
173179

174180
while let Some(parent) = self.0.query.selection_parent_idx.get(&item) {
175181
path.push(self.0.refocus(*parent).to_path_segment());
176182

177183
match parent {
178-
SelectionParent::Selection(id) => {
184+
SelectionParent::Field(id) | SelectionParent::InlineFragment(id) => {
179185
item = *id;
180186
}
181187
_ => break,
@@ -209,7 +215,7 @@ impl<'a> SelectionRef<'a> {
209215
impl<'a> QueryWith<'a, SelectionParent> {
210216
pub(crate) fn to_path_segment(&self) -> String {
211217
match self.focus {
212-
SelectionParent::Selection(id) => {
218+
SelectionParent::Field(id) | SelectionParent::InlineFragment(id) => {
213219
SelectionRef(self.refocus((id, self.query.get_selection(id)))).to_path_segment()
214220
}
215221
SelectionParent::Operation(id) => OperationRef(self.refocus(id)).to_path_segment(),
@@ -467,7 +473,7 @@ fn resolve_object_selection<'a>(
467473
object.schema(),
468474
field_ref.type_id(),
469475
&field.selection_set,
470-
SelectionParent::Selection(id),
476+
SelectionParent::Field(id),
471477
)?;
472478

473479
parent.add_to_selection_set(query, id);
@@ -551,7 +557,7 @@ fn resolve_inline_fragment(
551557
schema,
552558
type_id,
553559
&inline_fragment.selection_set,
554-
SelectionParent::Selection(id),
560+
SelectionParent::InlineFragment(id),
555561
)?;
556562

557563
Ok(id)

graphql_client_codegen/src/schema/json_conversion.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,8 @@ fn inputs_mut(schema: &mut JsonSchema) -> impl Iterator<Item = &mut FullType> {
251251
fn scalars_mut(schema: &mut JsonSchema) -> impl Iterator<Item = &mut FullType> {
252252
types_mut(schema).filter(|t| {
253253
t.kind == Some(__TypeKind::SCALAR)
254-
&& !super::DEFAULT_SCALARS.contains(&t.name.as_ref().map(String::as_str).expect("FullType.name"))
254+
&& !super::DEFAULT_SCALARS
255+
.contains(&t.name.as_ref().map(String::as_str).expect("FullType.name"))
255256
})
256257
}
257258

@@ -273,7 +274,15 @@ fn ingest_enum(schema: &mut Schema, enm: &mut FullType) {
273274
.as_mut()
274275
.expect("enm.enum_values.as_mut()")
275276
.into_iter()
276-
.map(|v| std::mem::replace(v.name.as_mut().take().expect("variant.name.as_mut().take()"), String::new()))
277+
.map(|v| {
278+
std::mem::replace(
279+
v.name
280+
.as_mut()
281+
.take()
282+
.expect("variant.name.as_mut().take()"),
283+
String::new(),
284+
)
285+
})
277286
.collect();
278287

279288
let enm = super::StoredEnum { name, variants };
@@ -295,7 +304,10 @@ fn ingest_interface(schema: &mut Schema, iface: &mut FullType) {
295304
let field = super::StoredField {
296305
parent: super::StoredFieldParent::Interface(interface_id),
297306
name: field.name.take().expect("take field name"),
298-
r#type: resolve_field_type(schema, &mut field.type_.as_mut().expect("take field type").type_ref),
307+
r#type: resolve_field_type(
308+
schema,
309+
&mut field.type_.as_mut().expect("take field type").type_ref,
310+
),
299311
deprecation: Some(None)
300312
.filter(|_: &Option<()>| !field.is_deprecated.unwrap_or(false))
301313
.map(|_: Option<()>| field.deprecation_reason.clone()),
@@ -305,7 +317,10 @@ fn ingest_interface(schema: &mut Schema, iface: &mut FullType) {
305317
}
306318

307319
let interface = super::StoredInterface {
308-
name: std::mem::replace(iface.name.as_mut().expect("iface.name.as_mut"), String::new()),
320+
name: std::mem::replace(
321+
iface.name.as_mut().expect("iface.name.as_mut"),
322+
String::new(),
323+
),
309324
fields: field_ids,
310325
};
311326

@@ -325,7 +340,10 @@ fn ingest_object(schema: &mut Schema, object: &mut FullType) {
325340
let field = super::StoredField {
326341
parent: super::StoredFieldParent::Object(object_id),
327342
name: field.name.take().expect("take field name"),
328-
r#type: resolve_field_type(schema, &mut field.type_.as_mut().expect("take field type").type_ref),
343+
r#type: resolve_field_type(
344+
schema,
345+
&mut field.type_.as_mut().expect("take field type").type_ref,
346+
),
329347
deprecation: Some(None)
330348
.filter(|_: &Option<()>| !field.is_deprecated.unwrap_or(false))
331349
.map(|_: Option<()>| field.deprecation_reason.clone()),
@@ -349,7 +367,15 @@ fn ingest_union(schema: &mut Schema, union: &mut FullType) {
349367
.as_ref()
350368
.expect("union.possible_types")
351369
.iter()
352-
.map(|variant| schema.find_type_id(variant.type_ref.name.as_ref().expect("variant.type_ref.name")))
370+
.map(|variant| {
371+
schema.find_type_id(
372+
variant
373+
.type_ref
374+
.name
375+
.as_ref()
376+
.expect("variant.type_ref.name"),
377+
)
378+
})
353379
.collect();
354380
let un = super::StoredUnion {
355381
name: union.name.take().expect("union.name.take"),

0 commit comments

Comments
 (0)