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