apollo_smith/
input_object.rs1use crate::description::Description;
2use crate::directive::Directive;
3use crate::directive::DirectiveLocation;
4use crate::input_value::InputValueDef;
5use crate::name::Name;
6use crate::DocumentBuilder;
7use apollo_compiler::ast;
8use apollo_compiler::Node;
9use arbitrary::Result as ArbitraryResult;
10use indexmap::IndexMap;
11use indexmap::IndexSet;
12
13#[derive(Debug, Clone)]
24pub struct InputObjectTypeDef {
25 pub(crate) name: Name,
26 pub(crate) description: Option<Description>,
27 pub(crate) fields: Vec<InputValueDef>,
29 pub(crate) directives: IndexMap<Name, Directive>,
31 pub(crate) extend: bool,
32}
33
34impl From<InputObjectTypeDef> for ast::Definition {
35 fn from(x: InputObjectTypeDef) -> Self {
36 if x.extend {
37 ast::InputObjectTypeExtension {
38 name: x.name.into(),
39 directives: Directive::to_ast(x.directives),
40 fields: x.fields.into_iter().map(|x| Node::new(x.into())).collect(),
41 }
42 .into()
43 } else {
44 ast::InputObjectTypeDefinition {
45 description: x.description.map(Into::into),
46 name: x.name.into(),
47 directives: Directive::to_ast(x.directives),
48 fields: x.fields.into_iter().map(|x| Node::new(x.into())).collect(),
49 }
50 .into()
51 }
52 }
53}
54
55impl TryFrom<apollo_parser::cst::InputObjectTypeDefinition> for InputObjectTypeDef {
56 type Error = crate::FromError;
57
58 fn try_from(
59 input_object: apollo_parser::cst::InputObjectTypeDefinition,
60 ) -> Result<Self, Self::Error> {
61 Ok(Self {
62 name: input_object
63 .name()
64 .expect("object type definition must have a name")
65 .into(),
66 description: input_object.description().map(Description::from),
67 directives: input_object
68 .directives()
69 .map(Directive::convert_directives)
70 .transpose()?
71 .unwrap_or_default(),
72 extend: false,
73 fields: input_object
74 .input_fields_definition()
75 .map(|input_fields| {
76 input_fields
77 .input_value_definitions()
78 .map(InputValueDef::try_from)
79 .collect::<Result<_, _>>()
80 })
81 .transpose()?
82 .unwrap_or_default(),
83 })
84 }
85}
86
87impl TryFrom<apollo_parser::cst::InputObjectTypeExtension> for InputObjectTypeDef {
88 type Error = crate::FromError;
89
90 fn try_from(
91 input_object: apollo_parser::cst::InputObjectTypeExtension,
92 ) -> Result<Self, Self::Error> {
93 Ok(Self {
94 name: input_object
95 .name()
96 .expect("object type definition must have a name")
97 .into(),
98 directives: input_object
99 .directives()
100 .map(Directive::convert_directives)
101 .transpose()?
102 .unwrap_or_default(),
103 extend: true,
104 fields: input_object
105 .input_fields_definition()
106 .map(|input_fields| {
107 input_fields
108 .input_value_definitions()
109 .map(InputValueDef::try_from)
110 .collect::<Result<Vec<_>, crate::FromError>>()
111 })
112 .transpose()?
113 .unwrap_or_default(),
114 description: None,
115 })
116 }
117}
118
119impl DocumentBuilder<'_> {
120 pub fn input_object_type_definition(&mut self) -> ArbitraryResult<InputObjectTypeDef> {
122 let extend = !self.input_object_type_defs.is_empty() && self.u.arbitrary().unwrap_or(false);
123 let name = if extend {
124 let available_input_objects: Vec<&Name> = self
125 .input_object_type_defs
126 .iter()
127 .filter_map(|input_object| {
128 if input_object.extend {
129 None
130 } else {
131 Some(&input_object.name)
132 }
133 })
134 .collect();
135 (*self.u.choose(&available_input_objects)?).clone()
136 } else {
137 self.type_name()?
138 };
139 let description = self
140 .u
141 .arbitrary()
142 .unwrap_or(false)
143 .then(|| self.description())
144 .transpose()?;
145 let exclude_fields: IndexSet<Name> = self
146 .input_object_type_defs
147 .iter()
148 .filter(|io| io.name == name)
149 .flat_map(|io| io.fields.iter().map(|f| f.name.clone()))
150 .collect();
151 let fields = self.input_values_def(
152 DirectiveLocation::InputFieldDefinition,
153 &exclude_fields,
154 Some(&name),
155 )?;
156
157 let directives = self.directives(DirectiveLocation::InputObject)?;
158
159 if extend && directives.is_empty() && fields.is_empty() {
160 return Err(arbitrary::Error::IncorrectFormat);
161 }
162
163 Ok(InputObjectTypeDef {
164 description,
165 directives,
166 name,
167 extend,
168 fields,
169 })
170 }
171}