apollo_smith/
interface.rs1use 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;
13
14#[derive(Debug, Clone)]
25pub struct InterfaceTypeDef {
26 pub(crate) description: Option<Description>,
27 pub(crate) name: Name,
28 pub(crate) interfaces: IndexSet<Name>,
29 pub(crate) directives: IndexMap<Name, Directive>,
30 pub(crate) fields_def: Vec<FieldDef>,
31 pub(crate) extend: bool,
32}
33
34impl From<InterfaceTypeDef> for ast::Definition {
35 fn from(x: InterfaceTypeDef) -> Self {
36 if x.extend {
37 ast::InterfaceTypeExtension {
38 name: x.name.into(),
39 implements_interfaces: x.interfaces.into_iter().map(Into::into).collect(),
40 directives: Directive::to_ast(x.directives),
41 fields: x
42 .fields_def
43 .into_iter()
44 .map(|x| Node::new(x.into()))
45 .collect(),
46 }
47 .into()
48 } else {
49 ast::InterfaceTypeDefinition {
50 description: x.description.map(Into::into),
51 name: x.name.into(),
52 implements_interfaces: x.interfaces.into_iter().map(Into::into).collect(),
53 directives: Directive::to_ast(x.directives),
54 fields: x
55 .fields_def
56 .into_iter()
57 .map(|x| Node::new(x.into()))
58 .collect(),
59 }
60 .into()
61 }
62 }
63}
64
65impl TryFrom<apollo_parser::cst::InterfaceTypeDefinition> for InterfaceTypeDef {
66 type Error = crate::FromError;
67
68 fn try_from(
69 interface_def: apollo_parser::cst::InterfaceTypeDefinition,
70 ) -> Result<Self, Self::Error> {
71 Ok(Self {
72 name: interface_def
73 .name()
74 .expect("object type definition must have a name")
75 .into(),
76 description: interface_def.description().map(Description::from),
77 directives: interface_def
78 .directives()
79 .map(Directive::convert_directives)
80 .transpose()?
81 .unwrap_or_default(),
82 extend: false,
83 fields_def: interface_def
84 .fields_definition()
85 .expect("object type definition must have fields definition")
86 .field_definitions()
87 .map(FieldDef::try_from)
88 .collect::<Result<Vec<_>, _>>()?,
89 interfaces: interface_def
90 .implements_interfaces()
91 .map(|itfs| {
92 itfs.named_types()
93 .map(|named_type| named_type.name().unwrap().into())
94 .collect()
95 })
96 .unwrap_or_default(),
97 })
98 }
99}
100
101impl TryFrom<apollo_parser::cst::InterfaceTypeExtension> for InterfaceTypeDef {
102 type Error = crate::FromError;
103
104 fn try_from(
105 interface_def: apollo_parser::cst::InterfaceTypeExtension,
106 ) -> Result<Self, Self::Error> {
107 Ok(Self {
108 name: interface_def
109 .name()
110 .expect("object type definition must have a name")
111 .into(),
112 description: None,
113 directives: interface_def
114 .directives()
115 .map(Directive::convert_directives)
116 .transpose()?
117 .unwrap_or_default(),
118 extend: true,
119 fields_def: interface_def
120 .fields_definition()
121 .expect("object type definition must have fields definition")
122 .field_definitions()
123 .map(FieldDef::try_from)
124 .collect::<Result<Vec<_>, _>>()?,
125 interfaces: interface_def
126 .implements_interfaces()
127 .map(|itfs| {
128 itfs.named_types()
129 .map(|named_type| named_type.name().unwrap().into())
130 .collect()
131 })
132 .unwrap_or_default(),
133 })
134 }
135}
136
137impl DocumentBuilder<'_> {
138 pub fn interface_type_definition(&mut self) -> ArbitraryResult<InterfaceTypeDef> {
140 let extend = !self.interface_type_defs.is_empty() && self.u.arbitrary().unwrap_or(false);
141 let description = self
142 .u
143 .arbitrary()
144 .unwrap_or(false)
145 .then(|| self.description())
146 .transpose()?;
147 let name = if extend {
148 let available_itfs: Vec<&Name> = self
149 .interface_type_defs
150 .iter()
151 .filter_map(|itf| if itf.extend { None } else { Some(&itf.name) })
152 .collect();
153 (*self.u.choose(&available_itfs)?).clone()
154 } else {
155 self.type_name()?
156 };
157 let fields_def = self.fields_definition(&[])?;
158 let directives = self.directives(DirectiveLocation::Interface)?;
159 let interfaces = self.implements_interfaces()?;
160
161 Ok(InterfaceTypeDef {
162 description,
163 name,
164 fields_def,
165 directives,
166 extend,
167 interfaces,
168 })
169 }
170
171 pub fn implements_interfaces(&mut self) -> ArbitraryResult<IndexSet<Name>> {
173 if self.interface_type_defs.is_empty() {
174 return Ok(IndexSet::new());
175 }
176
177 let num_itf = self
178 .u
179 .int_in_range(0..=(self.interface_type_defs.len() - 1))?;
180 let mut interface_impls = IndexSet::with_capacity(num_itf);
181
182 for _ in 0..num_itf {
183 interface_impls.insert(self.u.choose(&self.interface_type_defs)?.name.clone());
184 }
185
186 Ok(interface_impls)
187 }
188}
189
190impl StackedEntity for InterfaceTypeDef {
191 fn name(&self) -> &Name {
192 &self.name
193 }
194
195 fn fields_def(&self) -> &[FieldDef] {
196 &self.fields_def
197 }
198}