Skip to content

Commit 755c950

Browse files
committed
WIP
1 parent 808971b commit 755c950

File tree

3 files changed

+84
-24
lines changed

3 files changed

+84
-24
lines changed

graphql_client/tests/interfaces.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,33 +99,33 @@ fn fragment_in_interface() {
9999
response_data,
100100
ResponseData {
101101
everything: Some(vec![
102-
RustMyQueryEverything {
102+
RustInterfaceWithFragmentQueryEverything {
103103
name: "Audrey Lorde".to_string(),
104104
public_status: PublicStatus {
105105
display_name: false,
106106
},
107-
on: RustMyQueryEverythingOn::Person(RustMyQueryEverythingOnPerson {
107+
on: RustInterfaceWithFragmentQueryEverythingOn::Person(RustInterfaceWithFragmentQueryEverythingOnPerson {
108108
birthday: Some("1934-02-18".to_string()),
109109
})
110110
},
111-
RustMyQueryEverything {
111+
RustInterfaceWithFragmentQueryEverything {
112112
name: "Laïka".to_string(),
113113
public_status: PublicStatus { display_name: true },
114-
on: RustMyQueryEverythingOn::Dog(RustMyQueryEverythingOnDog {
114+
on: RustInterfaceWithFragmentQueryEverythingOn::Dog(RustInterfaceWithFragmentQueryEverythingOnDog {
115115
is_good_dog: true,
116116
})
117117
},
118-
RustMyQueryEverything {
118+
RustInterfaceWithFragmentQueryEverything {
119119
name: "Mozilla".to_string(),
120120
public_status: PublicStatus {
121121
display_name: false
122122
},
123-
on: RustMyQueryEverythingOn::Organization,
123+
on: RustInterfaceWithFragmentQueryEverythingOn::Organization,
124124
},
125-
RustMyQueryEverything {
125+
RustInterfaceWithFragmentQueryEverything {
126126
name: "Norbert".to_string(),
127127
public_status: PublicStatus { display_name: true },
128-
on: RustMyQueryEverythingOn::Dog(RustMyQueryEverythingOnDog {
128+
on: RustInterfaceWithFragmentQueryEverythingOn::Dog(RustInterfaceWithFragmentQueryEverythingOnDog {
129129
is_good_dog: true
130130
}),
131131
},

graphql_client/tests/interfaces/interface_with_fragment_query.graphql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ fragment PublicStatus on Named {
22
displayName
33
}
44

5-
query MyQuery {
5+
query InterfaceWithFragmentQuery {
66
everything {
7-
name
87
__typename
8+
name
99
...PublicStatus
1010
... on Dog {
1111
isGoodDog

graphql_client_codegen/src/interfaces.rs

Lines changed: 74 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ use failure;
22
use objects::GqlObjectField;
33
use proc_macro2::{Ident, Span, TokenStream};
44
use query::QueryContext;
5-
use selection::{Selection, SelectionFragmentSpread, SelectionItem};
5+
use selection::{Selection, SelectionField, SelectionFragmentSpread, SelectionItem};
66
use shared::*;
77
use std::borrow::Cow;
88
use std::cell::Cell;
99
use std::collections::HashSet;
1010
use unions::union_variants;
1111

12+
/// Represents an Interface type extracted from the schema.
1213
#[derive(Debug, Clone, PartialEq)]
1314
pub struct GqlInterface {
15+
/// The documentation for the interface. Extracted from the schema.
1416
pub description: Option<String>,
1517
/// The set of object types implementing this interface.
1618
pub implemented_by: HashSet<String>,
@@ -48,6 +50,32 @@ impl GqlInterface {
4850
)
4951
}
5052

53+
fn union_selection(&self, selection: &Selection, query_context: &QueryContext) -> Selection {
54+
Selection(
55+
selection
56+
.0
57+
.iter()
58+
// Only keep what we can handle
59+
.filter(|f| match f {
60+
SelectionItem::InlineFragment(_) => true,
61+
SelectionItem::FragmentSpread(SelectionFragmentSpread { fragment_name }) => {
62+
let fragment = query_context
63+
.fragments
64+
.get(fragment_name)
65+
.ok_or_else(|| format_err!("Unknown fragment: {}", &fragment_name))
66+
// TODO: fix this
67+
.unwrap();
68+
69+
// only the fragments _not_ on the interface
70+
fragment.on != self.name
71+
},
72+
SelectionItem::Field(SelectionField { name, .. }) => name == "__typename",
73+
}).map(|a| (*a).clone())
74+
.collect(),
75+
76+
)
77+
}
78+
5179
/// Create an empty interface. This needs to be mutated before it is useful.
5280
pub(crate) fn new(name: Cow<str>, description: Option<&str>) -> GqlInterface {
5381
GqlInterface {
@@ -102,24 +130,15 @@ impl GqlInterface {
102130

103131
selection
104132
.extract_typename()
105-
.ok_or_else(|| format_err!("Missing __typename in selection for {}", prefix))?;
106-
107-
let union_selection = Selection(
108-
selection
109-
.0
110-
.iter()
111-
// Only keep what we can handle
112-
.filter(|f| match f {
113-
SelectionItem::InlineFragment(_) | SelectionItem::FragmentSpread(_) => true,
114-
SelectionItem::Field(_) => false,
115-
}).map(|a| (*a).clone())
116-
.collect(),
117-
);
133+
.ok_or_else(|| format_err!("Missing __typename in selection for the {} interface (type: {})", prefix, self.name))?;
118134

119135
let object_fields =
120136
self.response_fields_for_selection(query_context, &selection, prefix)?;
121137

122138
let object_children = self.field_impls_for_selection(query_context, &selection, prefix)?;
139+
140+
let union_selection = self.union_selection(&selection, &query_context);
141+
123142
let (mut union_variants, union_children, used_variants) =
124143
union_variants(&union_selection, query_context, prefix)?;
125144

@@ -164,3 +183,44 @@ impl GqlInterface {
164183
})
165184
}
166185
}
186+
187+
#[cfg(test)]
188+
mod tests {
189+
use super::*;
190+
191+
// to be improved
192+
#[test]
193+
fn union_selection_works() {
194+
let iface = GqlInterface {
195+
description: None,
196+
implemented_by: HashSet::new(),
197+
name: "MyInterface".into(),
198+
fields: vec![],
199+
is_required: Cell::new(true),
200+
};
201+
202+
let context = QueryContext::new_empty();
203+
204+
let selection = Selection(vec![]);
205+
206+
assert_eq!(iface.union_selection(&selection, &context), Selection(vec![]));
207+
}
208+
209+
// to be improved
210+
#[test]
211+
fn object_selection_works() {
212+
let iface = GqlInterface {
213+
description: None,
214+
implemented_by: HashSet::new(),
215+
name: "MyInterface".into(),
216+
fields: vec![],
217+
is_required: Cell::new(true),
218+
};
219+
220+
let context = QueryContext::new_empty();
221+
222+
let selection = Selection(vec![]);
223+
224+
assert_eq!(iface.object_selection(&selection, &context), Selection(vec![]));
225+
}
226+
}

0 commit comments

Comments
 (0)