1use crate::description::Description;
2use crate::directive::Directive;
3use crate::directive::DirectiveLocation;
4use crate::field::FieldDef;
5use crate::interface::base_def_index;
6use crate::interface::def_indices_with_name;
7use crate::interface::field_signatures_for;
8use crate::interface::parent_fields_from_defs;
9use crate::interface::unique_names;
10use crate::name::Name;
11use crate::DocumentBuilder;
12use crate::StackedEntity;
13use apollo_compiler::ast;
14use apollo_compiler::Node;
15use arbitrary::Result as ArbitraryResult;
16use indexmap::IndexMap;
17use indexmap::IndexSet;
18
19#[derive(Debug, Clone)]
29pub struct ObjectTypeDef {
30 pub(crate) description: Option<Description>,
31 pub(crate) name: Name,
32 pub(crate) implements_interfaces: IndexSet<Name>,
33 pub(crate) directives: IndexMap<Name, Directive>,
34 pub(crate) fields_def: Vec<FieldDef>,
35 pub(crate) extend: bool,
36}
37
38impl From<ObjectTypeDef> for ast::Definition {
39 fn from(x: ObjectTypeDef) -> Self {
40 if x.extend {
41 ast::ObjectTypeExtension {
42 name: x.name.into(),
43 implements_interfaces: x
44 .implements_interfaces
45 .into_iter()
46 .map(Into::into)
47 .collect(),
48 directives: Directive::to_ast(x.directives),
49 fields: x
50 .fields_def
51 .into_iter()
52 .map(|x| Node::new(x.into()))
53 .collect(),
54 }
55 .into()
56 } else {
57 ast::ObjectTypeDefinition {
58 description: x.description.map(Into::into),
59 name: x.name.into(),
60 implements_interfaces: x
61 .implements_interfaces
62 .into_iter()
63 .map(Into::into)
64 .collect(),
65 directives: Directive::to_ast(x.directives),
66 fields: x
67 .fields_def
68 .into_iter()
69 .map(|x| Node::new(x.into()))
70 .collect(),
71 }
72 .into()
73 }
74 }
75}
76
77impl TryFrom<apollo_parser::cst::ObjectTypeDefinition> for ObjectTypeDef {
78 type Error = crate::FromError;
79
80 fn try_from(object_def: apollo_parser::cst::ObjectTypeDefinition) -> Result<Self, Self::Error> {
81 Ok(Self {
82 name: object_def
83 .name()
84 .expect("object type definition must have a name")
85 .into(),
86 description: object_def.description().map(Description::from),
87 directives: object_def
88 .directives()
89 .map(Directive::convert_directives)
90 .transpose()?
91 .unwrap_or_default(),
92 implements_interfaces: object_def
93 .implements_interfaces()
94 .map(|impl_int| {
95 impl_int
96 .named_types()
97 .map(|n| n.name().unwrap().into())
98 .collect()
99 })
100 .unwrap_or_default(),
101 extend: false,
102 fields_def: object_def
103 .fields_definition()
104 .expect("object type definition must have fields definition")
105 .field_definitions()
106 .map(FieldDef::try_from)
107 .collect::<Result<Vec<_>, _>>()?,
108 })
109 }
110}
111
112impl TryFrom<apollo_parser::cst::ObjectTypeExtension> for ObjectTypeDef {
113 type Error = crate::FromError;
114
115 fn try_from(object_def: apollo_parser::cst::ObjectTypeExtension) -> Result<Self, Self::Error> {
116 Ok(Self {
117 name: object_def
118 .name()
119 .expect("object type definition must have a name")
120 .into(),
121 description: None,
122 directives: object_def
123 .directives()
124 .map(Directive::convert_directives)
125 .transpose()?
126 .unwrap_or_default(),
127 implements_interfaces: object_def
128 .implements_interfaces()
129 .map(|impl_int| {
130 impl_int
131 .named_types()
132 .map(|n| n.name().unwrap().into())
133 .collect()
134 })
135 .unwrap_or_default(),
136 extend: true,
137 fields_def: object_def
138 .fields_definition()
139 .expect("object type definition must have fields definition")
140 .field_definitions()
141 .map(FieldDef::try_from)
142 .collect::<Result<Vec<_>, _>>()?,
143 })
144 }
145}
146
147impl DocumentBuilder<'_> {
148 pub fn object_type_definition(&mut self) -> ArbitraryResult<ObjectTypeDef> {
150 let extend = !self.object_type_defs.is_empty() && self.u.arbitrary().unwrap_or(false);
151 let description = self
152 .u
153 .arbitrary()
154 .unwrap_or(false)
155 .then(|| self.description())
156 .transpose()?;
157 let name = if extend {
158 let available_objects: Vec<&Name> = self
159 .object_type_defs
160 .iter()
161 .filter_map(|object| {
162 if object.extend {
163 None
164 } else {
165 Some(&object.name)
166 }
167 })
168 .collect();
169 (*self.u.choose(&available_objects)?).clone()
170 } else {
171 self.type_name()?
172 };
173
174 let existing_field_signatures = field_signatures_for(&self.object_type_defs, &name);
179 let implements_interfaces = self.additional_implements(&existing_field_signatures, None)?;
180 let exclude_fields: IndexSet<Name> = existing_field_signatures
181 .keys()
182 .map(|k| Name::new(k.clone()))
183 .collect();
184 let fields_def = self.fields_definition(&exclude_fields)?;
185 let directives = self.directives(DirectiveLocation::Object)?;
186
187 if extend
188 && directives.is_empty()
189 && fields_def.is_empty()
190 && implements_interfaces.is_empty()
191 {
192 return Err(arbitrary::Error::IncorrectFormat);
193 }
194
195 Ok(ObjectTypeDef {
196 description,
197 directives,
198 implements_interfaces,
199 name,
200 fields_def,
201 extend,
202 })
203 }
204
205 pub(crate) fn backfill_inherited_object_fields(&mut self) {
210 for name in unique_names(&self.object_type_defs) {
211 let Some(base_idx) = base_def_index(&self.object_type_defs, &name) else {
212 continue;
213 };
214 self.expand_transitive_object_implementations(&name, base_idx);
215
216 let parents = self.implements_graph.direct_parents(&name);
217 let mut inherited_fields = parent_fields_from_defs(&parents, &self.interface_type_defs);
218 let def_indices = def_indices_with_name(&self.object_type_defs, &name);
222 for &i in &def_indices {
223 for f in self.object_type_defs[i].fields_def.iter_mut() {
224 if let Some(parent_fdef) = inherited_fields.shift_remove(&f.name.name) {
225 *f = parent_fdef;
226 }
227 }
228 }
229 self.object_type_defs[base_idx]
231 .fields_def
232 .extend(inherited_fields.into_values());
233 }
234 }
235
236 fn expand_transitive_object_implementations(&mut self, name: &Name, base_idx: usize) {
238 let mut all_implemented_interfaces = self.implements_graph.closure(name);
239 all_implemented_interfaces.shift_remove(name);
241
242 let interfaces_declared_by_extensions: IndexSet<Name> = self
243 .object_type_defs
244 .iter()
245 .filter(|o| o.extend && &o.name == name)
246 .flat_map(|o| o.implements_interfaces.iter().cloned())
247 .collect();
248 let interfaces_to_add = all_implemented_interfaces
249 .into_iter()
250 .filter(|p| !interfaces_declared_by_extensions.contains(p));
251 self.object_type_defs[base_idx]
252 .implements_interfaces
253 .extend(interfaces_to_add);
254 }
255}
256
257impl StackedEntity for ObjectTypeDef {
258 fn name(&self) -> &Name {
259 &self.name
260 }
261
262 fn fields_def(&self) -> &[FieldDef] {
263 &self.fields_def
264 }
265}