Skip to content

Commit 0230a28

Browse files
committed
Use selection ids to resolve selections
1 parent c15a7ab commit 0230a28

File tree

3 files changed

+94
-52
lines changed

3 files changed

+94
-52
lines changed

graphql_client/tests/union_query.rs

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,19 @@ fn union_query_deserialization() {
3232

3333
let expected = union_query::ResponseData {
3434
names: Some(vec![
35-
union_query::UnionQueryNames::Person(union_query::UnionQueryNamesOnPerson {
35+
union_query::UnionQueryNames::Person {
3636
first_name: "Audrey".to_string(),
3737
last_name: Some("Lorde".to_string()),
38-
}),
39-
union_query::UnionQueryNames::Dog(union_query::UnionQueryNamesOnDog {
38+
},
39+
union_query::UnionQueryNames::Dog {
4040
name: "Laïka".to_string(),
41-
}),
42-
union_query::UnionQueryNames::Organization(
43-
union_query::UnionQueryNamesOnOrganization {
44-
title: "Mozilla".to_string(),
45-
},
46-
),
47-
union_query::UnionQueryNames::Dog(union_query::UnionQueryNamesOnDog {
41+
},
42+
union_query::UnionQueryNames::Organization {
43+
title: "Mozilla".to_string(),
44+
},
45+
union_query::UnionQueryNames::Dog {
4846
name: "Norbert".to_string(),
49-
}),
47+
},
5048
]),
5149
};
5250

@@ -61,27 +59,25 @@ fn fragment_on_union() {
6159

6260
let expected = fragment_on_union::ResponseData {
6361
names: Some(vec![
64-
fragment_on_union::FragmentOnUnionNames::Person(
65-
fragment_on_union::FragmentOnUnionNamesOnPerson {
62+
fragment_on_union::FragmentOnUnionNames {
63+
names_fragment: fragment_on_union::NamesFragment::Person {
6664
first_name: "Audrey".to_string(),
6765
},
68-
),
69-
fragment_on_union::FragmentOnUnionNames::Dog(
70-
fragment_on_union::FragmentOnUnionNamesOnDog {
66+
},
67+
fragment_on_union::FragmentOnUnionNames {
68+
names_fragment: fragment_on_union::NamesFragment::Dog {
7169
name: "Laïka".to_string(),
7270
},
73-
),
74-
fragment_on_union::FragmentOnUnionNames::Organization(
75-
fragment_on_union::FragmentOnUnionNamesOnOrganization {
71+
},
72+
fragment_on_union::FragmentOnUnionNames {
73+
names_fragment: fragment_on_union::NamesFragment::Organization {
7674
title: "Mozilla".to_string(),
7775
},
78-
),
76+
},
7977
fragment_on_union::FragmentOnUnionNames {
80-
names_fragment: fragment_on_union::NamesFragment::Dog(
81-
fragment_on_union::NamesFragmentOnDog {
82-
name: "Norbert".to_string(),
83-
},
84-
),
78+
names_fragment: fragment_on_union::NamesFragment::Dog {
79+
name: "Norbert".to_string(),
80+
},
8581
},
8682
]),
8783
};
@@ -91,5 +87,21 @@ fn fragment_on_union() {
9187

9288
#[test]
9389
fn fragment_and_more_on_union() {
94-
todo!()
90+
let _expected = fragment_and_more_on_union::ResponseData {
91+
names: Some(vec![
92+
fragment_and_more_on_union::FragmentAndMoreOnUnionNames::Person {
93+
first_name: "Audrey".to_string(),
94+
last_name: Some("Lorde".to_string()),
95+
},
96+
fragment_and_more_on_union::FragmentAndMoreOnUnionNames::Dog {
97+
name: "Laïka".to_string(),
98+
},
99+
fragment_and_more_on_union::FragmentAndMoreOnUnionNames::Organization {
100+
title: "Mozilla".to_string(),
101+
},
102+
fragment_and_more_on_union::FragmentAndMoreOnUnionNames::Dog {
103+
name: "Norbert".to_string(),
104+
},
105+
]),
106+
};
95107
}

graphql_client_codegen/src/codegen.rs

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ fn render_response_data_fields<'a>(
244244
let mut variants = Vec::new();
245245

246246
render_selection(
247-
operation.selection(),
247+
operation.refocus(()),
248+
operation.selection_ids(),
248249
&mut fields,
249250
&mut variants,
250251
&mut response_types,
@@ -256,7 +257,8 @@ fn render_response_data_fields<'a>(
256257
}
257258

258259
fn render_selection<'a>(
259-
selection: impl Iterator<Item = WithQuery<'a, SelectionId>>,
260+
q: WithQuery<'a, ()>,
261+
selection: &[SelectionId],
260262
field_buffer: &mut Vec<TokenStream>,
261263
variants_buffer: &mut Vec<TokenStream>,
262264
response_type_buffer: &mut Vec<TokenStream>,
@@ -266,9 +268,9 @@ fn render_selection<'a>(
266268
// TODO: if the selection has one item, we can sometimes generate fewer structs (e.g. single fragment spread)
267269

268270
for select in selection {
269-
match &select.get() {
271+
match q.refocus(*select).get() {
270272
Selection::Field(field) => {
271-
let field = select.refocus(field);
273+
let field = q.refocus(field);
272274

273275
let deprecation_annotation = match (
274276
field.schema_field().is_deprecated(),
@@ -305,7 +307,7 @@ fn render_selection<'a>(
305307
field_buffer.push(quote!(#deprecation_annotation #ident: #type_name));
306308
}
307309
TypeId::Object(_) | TypeId::Interface(_) => {
308-
let struct_name_string = select.full_path_prefix();
310+
let struct_name_string = q.refocus(*select).full_path_prefix();
309311
let struct_name = Ident::new(&struct_name_string, Span::call_site());
310312
let field_type =
311313
decorate_type(&struct_name, field.schema_field().type_qualifiers());
@@ -315,7 +317,8 @@ fn render_selection<'a>(
315317
let mut fields = Vec::new();
316318
let mut variants = Vec::new();
317319
render_selection(
318-
select.subselection(),
320+
q,
321+
q.refocus(*select).subselection_ids(),
319322
&mut fields,
320323
&mut variants,
321324
response_type_buffer,
@@ -338,7 +341,7 @@ fn render_selection<'a>(
338341
// We want a struct, because we want to preserve fragments in the output,
339342
// and there can be fragment and inline spreads for a given selection set
340343
// on an enum.
341-
let struct_name = select.full_path_prefix();
344+
let struct_name = q.refocus(*select).full_path_prefix();
342345
let struct_name_ident = Ident::new(&struct_name, Span::call_site());
343346
let field_type = decorate_type(
344347
&struct_name_ident,
@@ -350,21 +353,18 @@ fn render_selection<'a>(
350353
let mut fields = Vec::new();
351354
let mut variants = Vec::new();
352355
render_selection(
353-
select.subselection(),
356+
q,
357+
q.refocus(*select).subselection_ids(),
354358
&mut fields,
355359
&mut variants,
356360
response_type_buffer,
357361
response_derives,
358362
options,
359363
);
360364

361-
let struct_definition = render_object_like_struct(
362-
response_derives,
363-
&struct_name,
364-
&fields,
365-
&variants,
366-
);
367-
response_type_buffer.push(struct_definition);
365+
let enum_definition =
366+
render_union_enum(response_derives, &struct_name, &variants);
367+
response_type_buffer.push(enum_definition);
368368
}
369369
TypeId::Input(_) => unreachable!("field selection on input type"),
370370
};
@@ -376,29 +376,46 @@ fn render_selection<'a>(
376376
));
377377
}
378378
Selection::InlineFragment(inline) => {
379-
let variant_name = select.refocus(inline).on().name();
380-
let variant_name = Ident::new(variant_name, Span::call_site());
381-
let variant_struct_name = select.full_path_prefix();
382-
let variant_struct_name = Ident::new(&variant_struct_name, Span::call_site());
383-
384-
let variant = quote!(#variant_name(#variant_struct_name));
385-
variants_buffer.push(variant);
379+
let variant_name_str = q.refocus(inline).on().name();
380+
let variant_name = Ident::new(variant_name_str, Span::call_site());
381+
let variant_struct_name_str = q.refocus(*select).full_path_prefix();
382+
let variant_struct_name = Ident::new(&variant_struct_name_str, Span::call_site());
386383

387384
// Render the struct for the selection
388385

389-
todo!("We have to do more here");
386+
let mut fields = Vec::new();
387+
let mut variants = Vec::new();
390388

391389
render_selection(
392-
select.subselection(),
390+
q,
391+
q.refocus(*select).subselection_ids(),
393392
&mut fields,
394393
&mut variants,
395394
response_type_buffer,
396395
response_derives,
397396
options,
398397
);
398+
399+
let variant = quote!(#variant_name { });
400+
variants_buffer.push(variant);
401+
402+
match q.refocus(inline).on().item {
403+
TypeId::Object(_) | TypeId::Interface(_) => {
404+
let struct_definition = render_object_like_struct(
405+
response_derives,
406+
&variant_struct_name_str,
407+
&fields,
408+
&variants,
409+
);
410+
411+
response_type_buffer.push(struct_definition);
412+
}
413+
TypeId::Union(_) => todo!("inline fragment on union"),
414+
other => unreachable!("Inline fragment on non composite type ({:?})", other),
415+
}
399416
}
400417
Selection::FragmentSpread(frag) => {
401-
let frag = select.refocus(*frag);
418+
let frag = q.refocus(*frag);
402419
let original_field_name = frag.name().to_snake_case();
403420
let final_field_name = keyword_replace(&original_field_name);
404421
let annotation = field_rename_annotation(&original_field_name, &final_field_name);
@@ -494,7 +511,8 @@ fn generate_fragment_definitions(
494511
let mut variants = Vec::new();
495512

496513
render_selection(
497-
fragment.selection(),
514+
fragment.refocus(()),
515+
fragment.selection_ids(),
498516
&mut fields,
499517
&mut variants,
500518
&mut response_type_buffer,

graphql_client_codegen/src/resolution.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ impl<'a> SelectionRef<'a> {
136136
.map(move |s| self.refocus(*s))
137137
}
138138

139+
pub(crate) fn subselection_ids(&self) -> &'a [SelectionId] {
140+
self.get().subselection()
141+
}
142+
139143
pub(crate) fn collect_used_types(&self, used_types: &mut UsedTypes) {
140144
let selection = self.get();
141145
match selection {
@@ -640,6 +644,10 @@ impl<'a> OperationRef<'a> {
640644
.map(move |selection_id| self.refocus(*selection_id))
641645
}
642646

647+
pub(crate) fn selection_ids(&self) -> &[SelectionId] {
648+
&self.get().selection
649+
}
650+
643651
pub(crate) fn variables<'b>(&'b self) -> impl Iterator<Item = VariableRef<'a>> + 'b {
644652
self.query
645653
.variables
@@ -722,6 +730,10 @@ impl<'a> FragmentRef<'a> {
722730
.map(move |item| self.refocus(*item))
723731
}
724732

733+
pub(crate) fn selection_ids(&self) -> &[SelectionId] {
734+
&self.get().selection
735+
}
736+
725737
fn to_path_segment(&self) -> String {
726738
self.get().name.to_camel_case()
727739
}

0 commit comments

Comments
 (0)