1use crate::description::Description;
2use crate::directive::Directive;
3use crate::directive::DirectiveLocation;
4use crate::field::FieldDef;
5use crate::name::Name;
6use crate::DocumentBuilder;
7use crate::StackedEntity;
8use apollo_compiler::ast;
9use apollo_compiler::Node;
10use arbitrary::Result as ArbitraryResult;
11use indexmap::IndexMap;
12use indexmap::IndexSet;
13use std::collections::HashMap;
14
15#[derive(Debug, Clone)]
26pub struct InterfaceTypeDef {
27 pub(crate) description: Option<Description>,
28 pub(crate) name: Name,
29 pub(crate) interfaces: IndexSet<Name>,
30 pub(crate) directives: IndexMap<Name, Directive>,
31 pub(crate) fields_def: Vec<FieldDef>,
32 pub(crate) extend: bool,
33}
34
35impl From<InterfaceTypeDef> for ast::Definition {
36 fn from(x: InterfaceTypeDef) -> Self {
37 if x.extend {
38 ast::InterfaceTypeExtension {
39 name: x.name.into(),
40 implements_interfaces: x.interfaces.into_iter().map(Into::into).collect(),
41 directives: Directive::to_ast(x.directives),
42 fields: x
43 .fields_def
44 .into_iter()
45 .map(|x| Node::new(x.into()))
46 .collect(),
47 }
48 .into()
49 } else {
50 ast::InterfaceTypeDefinition {
51 description: x.description.map(Into::into),
52 name: x.name.into(),
53 implements_interfaces: x.interfaces.into_iter().map(Into::into).collect(),
54 directives: Directive::to_ast(x.directives),
55 fields: x
56 .fields_def
57 .into_iter()
58 .map(|x| Node::new(x.into()))
59 .collect(),
60 }
61 .into()
62 }
63 }
64}
65
66impl TryFrom<apollo_parser::cst::InterfaceTypeDefinition> for InterfaceTypeDef {
67 type Error = crate::FromError;
68
69 fn try_from(
70 interface_def: apollo_parser::cst::InterfaceTypeDefinition,
71 ) -> Result<Self, Self::Error> {
72 Ok(Self {
73 name: interface_def
74 .name()
75 .expect("object type definition must have a name")
76 .into(),
77 description: interface_def.description().map(Description::from),
78 directives: interface_def
79 .directives()
80 .map(Directive::convert_directives)
81 .transpose()?
82 .unwrap_or_default(),
83 extend: false,
84 fields_def: interface_def
85 .fields_definition()
86 .expect("object type definition must have fields definition")
87 .field_definitions()
88 .map(FieldDef::try_from)
89 .collect::<Result<Vec<_>, _>>()?,
90 interfaces: interface_def
91 .implements_interfaces()
92 .map(|itfs| {
93 itfs.named_types()
94 .map(|named_type| named_type.name().unwrap().into())
95 .collect()
96 })
97 .unwrap_or_default(),
98 })
99 }
100}
101
102impl TryFrom<apollo_parser::cst::InterfaceTypeExtension> for InterfaceTypeDef {
103 type Error = crate::FromError;
104
105 fn try_from(
106 interface_def: apollo_parser::cst::InterfaceTypeExtension,
107 ) -> Result<Self, Self::Error> {
108 Ok(Self {
109 name: interface_def
110 .name()
111 .expect("object type definition must have a name")
112 .into(),
113 description: None,
114 directives: interface_def
115 .directives()
116 .map(Directive::convert_directives)
117 .transpose()?
118 .unwrap_or_default(),
119 extend: true,
120 fields_def: interface_def
121 .fields_definition()
122 .expect("object type definition must have fields definition")
123 .field_definitions()
124 .map(FieldDef::try_from)
125 .collect::<Result<Vec<_>, _>>()?,
126 interfaces: interface_def
127 .implements_interfaces()
128 .map(|itfs| {
129 itfs.named_types()
130 .map(|named_type| named_type.name().unwrap().into())
131 .collect()
132 })
133 .unwrap_or_default(),
134 })
135 }
136}
137
138impl DocumentBuilder<'_> {
139 pub fn interface_type_definition(&mut self) -> ArbitraryResult<InterfaceTypeDef> {
141 let extend = !self.interface_type_defs.is_empty() && self.u.arbitrary().unwrap_or(false);
142 let description = self
143 .u
144 .arbitrary()
145 .unwrap_or(false)
146 .then(|| self.description())
147 .transpose()?;
148 let name = if extend {
149 let available_itfs: Vec<&Name> = self
150 .interface_type_defs
151 .iter()
152 .filter_map(|itf| if itf.extend { None } else { Some(&itf.name) })
153 .collect();
154 (*self.u.choose(&available_itfs)?).clone()
155 } else {
156 self.type_name()?
157 };
158 let existing_field_signatures = field_signatures_for(&self.interface_type_defs, &name);
163 let interfaces = self.additional_implements(&existing_field_signatures, Some(&name))?;
164 let exclude_fields: IndexSet<Name> = existing_field_signatures
165 .keys()
166 .map(|k| Name::new(k.clone()))
167 .collect();
168 let fields_def = self.fields_definition(&exclude_fields)?;
169 let directives = self.directives(DirectiveLocation::Interface)?;
170
171 if extend && directives.is_empty() && fields_def.is_empty() && interfaces.is_empty() {
172 return Err(arbitrary::Error::IncorrectFormat);
173 }
174
175 Ok(InterfaceTypeDef {
176 description,
177 name,
178 fields_def,
179 directives,
180 extend,
181 interfaces,
182 })
183 }
184
185 pub fn implements_interfaces(&mut self) -> ArbitraryResult<IndexSet<Name>> {
190 self.additional_implements(&IndexMap::new(), None)
191 }
192
193 pub(crate) fn additional_implements(
204 &mut self,
205 existing_field_signatures: &IndexMap<String, FieldDef>,
206 self_name: Option<&Name>,
207 ) -> ArbitraryResult<IndexSet<Name>> {
208 if self.interface_type_defs.is_empty() {
209 return Ok(IndexSet::new());
210 }
211 let num_itf = self
212 .u
213 .int_in_range(0..=(self.interface_type_defs.len() - 1))?;
214 let fields_by_type_name = fields_from_all_definitions(&self.interface_type_defs);
215
216 let already_implemented_parents = match self_name {
217 Some(n) => self.implements_graph.direct_parents(n),
218 None => IndexSet::new(),
219 };
220 let mut accepted = already_implemented_parents.clone();
221 let mut accumulated_signatures = existing_field_signatures.clone();
225 for parent in &already_implemented_parents {
226 if let Some(fields) = fields_by_type_name.get(parent) {
227 for (fname, fdef) in fields {
228 accumulated_signatures
229 .entry(fname.clone())
230 .or_insert_with(|| fdef.clone());
231 }
232 }
233 }
234
235 for _ in 0..num_itf {
236 let candidate = self.u.choose(&self.interface_type_defs)?.name.clone();
237 try_accept_candidate(
238 &candidate,
239 &self.implements_graph,
240 &fields_by_type_name,
241 &mut accepted,
242 &mut accumulated_signatures,
243 self_name,
244 );
245 }
246
247 accepted.retain(|n| !already_implemented_parents.contains(n));
248 Ok(accepted)
249 }
250
251 pub(crate) fn backfill_inherited_interface_fields(&mut self) {
257 let order = self.implements_graph.topo_order_parents_first();
258 for name in order {
259 let Some(base_idx) = base_def_index(&self.interface_type_defs, &name) else {
260 continue;
261 };
262 self.expand_transitive_interface_implementations(&name, base_idx);
263
264 let parents = self.implements_graph.direct_parents(&name);
265 let mut inherited_fields = parent_fields_from_defs(&parents, &self.interface_type_defs);
266 for i in def_indices_with_name(&self.interface_type_defs, &name) {
270 for f in self.interface_type_defs[i].fields_def.iter_mut() {
271 if let Some(parent_fdef) = inherited_fields.shift_remove(&f.name.name) {
272 *f = parent_fdef;
273 }
274 }
275 }
276 self.interface_type_defs[base_idx]
278 .fields_def
279 .extend(inherited_fields.into_values());
280 }
281 }
282
283 fn expand_transitive_interface_implementations(&mut self, name: &Name, base_idx: usize) {
285 let mut all_implemented_interfaces = self.implements_graph.closure(name);
286 all_implemented_interfaces.shift_remove(name);
288
289 let interfaces_declared_by_extensions: IndexSet<Name> = self
290 .interface_type_defs
291 .iter()
292 .filter(|i| i.extend && &i.name == name)
293 .flat_map(|i| i.interfaces.iter().cloned())
294 .collect();
295 let interfaces_to_add = all_implemented_interfaces
296 .into_iter()
297 .filter(|p| !interfaces_declared_by_extensions.contains(p));
298 self.interface_type_defs[base_idx]
299 .interfaces
300 .extend(interfaces_to_add);
301 }
302}
303
304pub(crate) trait NamedDef {
307 fn name(&self) -> &Name;
308 fn is_extend(&self) -> bool;
309 fn fields(&self) -> &[FieldDef];
310}
311
312impl NamedDef for InterfaceTypeDef {
313 fn name(&self) -> &Name {
314 &self.name
315 }
316 fn is_extend(&self) -> bool {
317 self.extend
318 }
319 fn fields(&self) -> &[FieldDef] {
320 &self.fields_def
321 }
322}
323
324impl NamedDef for crate::ObjectTypeDef {
325 fn name(&self) -> &Name {
326 &self.name
327 }
328 fn is_extend(&self) -> bool {
329 self.extend
330 }
331 fn fields(&self) -> &[FieldDef] {
332 &self.fields_def
333 }
334}
335
336fn try_accept_candidate(
345 candidate: &Name,
346 graph: &crate::implements_graph::ImplementsGraph,
347 fields_by_type_name: &HashMap<Name, IndexMap<String, FieldDef>>,
348 accepted: &mut IndexSet<Name>,
349 accumulated_signatures: &mut IndexMap<String, FieldDef>,
350 self_name: Option<&Name>,
351) {
352 let closure = graph.closure(candidate);
353
354 let would_cycle = self_name.is_some_and(|n| closure.contains(n));
355 let would_conflict = closure.iter().any(|name| {
356 fields_by_type_name
357 .get(name)
358 .into_iter()
359 .flatten()
360 .any(|(fname, fdef)| {
361 accumulated_signatures.get(fname).is_some_and(|existing| {
362 existing.ty != fdef.ty
363 || existing.arguments_definition != fdef.arguments_definition
364 })
365 })
366 });
367 if would_cycle || would_conflict {
368 return;
369 }
370
371 for name in closure {
372 if !accepted.insert(name.clone()) {
373 continue;
374 }
375 for (fname, fdef) in fields_by_type_name.get(&name).into_iter().flatten() {
376 accumulated_signatures
377 .entry(fname.clone())
378 .or_insert_with(|| fdef.clone());
379 }
380 }
381}
382
383pub(crate) fn fields_from_all_definitions<T: NamedDef>(
386 defs: &[T],
387) -> HashMap<Name, IndexMap<String, FieldDef>> {
388 unique_names(defs)
389 .into_iter()
390 .map(|n| {
391 let fields = field_signatures_for(defs, &n);
392 (n, fields)
393 })
394 .collect()
395}
396
397pub(crate) fn unique_names<T: NamedDef>(defs: &[T]) -> Vec<Name> {
399 let mut seen: IndexSet<Name> = IndexSet::new();
400 for d in defs {
401 seen.insert(d.name().clone());
402 }
403 seen.into_iter().collect()
404}
405
406pub(crate) fn base_def_index<T: NamedDef>(defs: &[T], name: &Name) -> Option<usize> {
409 defs.iter()
410 .position(|d| !d.is_extend() && d.name() == name)
411 .or_else(|| defs.iter().position(|d| d.name() == name))
412}
413
414pub(crate) fn def_indices_with_name<T: NamedDef>(defs: &[T], name: &Name) -> Vec<usize> {
416 defs.iter()
417 .enumerate()
418 .filter_map(|(i, d)| (d.name() == name).then_some(i))
419 .collect()
420}
421
422pub(crate) fn field_signatures_for<T: NamedDef>(
427 defs: &[T],
428 name: &Name,
429) -> IndexMap<String, FieldDef> {
430 let mut out: IndexMap<String, FieldDef> = IndexMap::new();
431 for def in defs {
432 if def.name() == name {
433 for f in def.fields() {
434 out.entry(f.name.name.clone()).or_insert_with(|| f.clone());
435 }
436 }
437 }
438 out
439}
440
441pub(crate) fn parent_fields_from_defs<T: NamedDef>(
445 parents: &IndexSet<Name>,
446 defs: &[T],
447) -> IndexMap<String, FieldDef> {
448 let mut out: IndexMap<String, FieldDef> = IndexMap::new();
449 for parent in parents {
450 for def in defs {
451 if def.name() == parent {
452 for f in def.fields() {
453 out.entry(f.name.name.clone()).or_insert_with(|| f.clone());
454 }
455 }
456 }
457 }
458 out
459}
460
461impl StackedEntity for InterfaceTypeDef {
462 fn name(&self) -> &Name {
463 &self.name
464 }
465
466 fn fields_def(&self) -> &[FieldDef] {
467 &self.fields_def
468 }
469}