1use crate::description::Description;
2use crate::directive::Directive;
3use crate::directive::DirectiveLocation;
4use crate::name::Name;
5use crate::ty::Ty;
6use crate::DocumentBuilder;
7use apollo_compiler::ast;
8use apollo_compiler::Node;
9use arbitrary::Result as ArbitraryResult;
10use indexmap::IndexMap;
11
12#[derive(Debug, Clone)]
19pub struct SchemaDef {
20 pub(crate) description: Option<Description>,
21 pub(crate) directives: IndexMap<Name, Directive>,
22 pub(crate) query: Option<Ty>,
23 pub(crate) mutation: Option<Ty>,
24 pub(crate) subscription: Option<Ty>,
25 pub(crate) extend: bool,
26}
27
28impl From<SchemaDef> for ast::Definition {
29 fn from(x: SchemaDef) -> Self {
30 let root_operations = [
31 (ast::OperationType::Query, x.query),
32 (ast::OperationType::Mutation, x.mutation),
33 (ast::OperationType::Subscription, x.subscription),
34 ]
35 .into_iter()
36 .flat_map(|(ty, name)| name.map(|n| Node::new((ty, n.name().into()))))
37 .collect();
38 if x.extend {
39 ast::SchemaExtension {
40 directives: Directive::to_ast(x.directives),
41 root_operations,
42 }
43 .into()
44 } else {
45 ast::SchemaDefinition {
46 description: x.description.map(Into::into),
47 directives: Directive::to_ast(x.directives),
48 root_operations,
49 }
50 .into()
51 }
52 }
53}
54
55impl TryFrom<apollo_parser::cst::SchemaDefinition> for SchemaDef {
56 type Error = crate::FromError;
57
58 fn try_from(schema_def: apollo_parser::cst::SchemaDefinition) -> Result<Self, Self::Error> {
59 let mut query = None;
60 let mut mutation = None;
61 let mut subcription = None;
62 for root_op in schema_def.root_operation_type_definitions() {
63 let op_type = root_op.operation_type().unwrap();
64 let named_type = root_op.named_type().unwrap();
65 if op_type.query_token().is_some() {
66 query = named_type.into();
67 } else if op_type.mutation_token().is_some() {
68 mutation = named_type.into();
69 } else if op_type.subscription_token().is_some() {
70 subcription = named_type.into();
71 } else {
72 panic!("operation type must be one of query|mutation|subscription");
73 }
74 }
75 Ok(Self {
76 description: schema_def.description().map(Description::from),
77 directives: schema_def
78 .directives()
79 .map(Directive::convert_directives)
80 .transpose()?
81 .unwrap_or_default(),
82 query: query.map(Ty::from),
83 mutation: mutation.map(Ty::from),
84 subscription: subcription.map(Ty::from),
85 extend: false,
86 })
87 }
88}
89
90impl TryFrom<apollo_parser::cst::SchemaExtension> for SchemaDef {
91 type Error = crate::FromError;
92
93 fn try_from(schema_def: apollo_parser::cst::SchemaExtension) -> Result<Self, Self::Error> {
94 let mut query = None;
95 let mut mutation = None;
96 let mut subcription = None;
97 for root_op in schema_def.root_operation_type_definitions() {
98 let op_type = root_op.operation_type().unwrap();
99 let named_type = root_op.named_type().unwrap();
100 if op_type.query_token().is_some() {
101 query = named_type.into();
102 } else if op_type.mutation_token().is_some() {
103 mutation = named_type.into();
104 } else if op_type.subscription_token().is_some() {
105 subcription = named_type.into();
106 } else {
107 panic!("operation type must be one of query|mutation|subscription");
108 }
109 }
110 Ok(Self {
111 description: None,
112 directives: schema_def
113 .directives()
114 .map(Directive::convert_directives)
115 .transpose()?
116 .unwrap_or_default(),
117 query: query.map(Ty::from),
118 mutation: mutation.map(Ty::from),
119 subscription: subcription.map(Ty::from),
120 extend: true,
121 })
122 }
123}
124
125impl DocumentBuilder<'_> {
126 pub fn schema_definition(&mut self) -> ArbitraryResult<SchemaDef> {
128 let description = self
129 .u
130 .arbitrary()
131 .unwrap_or(false)
132 .then(|| self.description())
133 .transpose()?;
134 let directives = self.directives(DirectiveLocation::Schema)?;
135 let named_types: Vec<Ty> = self
136 .list_existing_object_types()
137 .into_iter()
138 .filter(|ty| ty.is_named() && !ty.is_builtin())
139 .collect();
140
141 let arbitrary_idx: usize = self.u.arbitrary::<usize>()?;
142
143 let query = Some(self.u.choose(&named_types)?.clone());
149 let mutation = arbitrary_idx
150 .is_multiple_of(3)
151 .then(|| self.u.choose(&named_types))
152 .transpose()?
153 .cloned();
154 let subscription = arbitrary_idx
155 .is_multiple_of(5)
156 .then(|| self.u.choose(&named_types))
157 .transpose()?
158 .cloned();
159
160 Ok(SchemaDef {
161 description,
162 directives,
163 query,
164 mutation,
165 subscription,
166 extend: false,
173 })
174 }
175}