1use std::str::FromStr;
2
3use thiserror::Error;
4
5pub use crate::parser::common::{Directive, Text, Type, Value};
6use crate::parser::position::Pos;
7
8#[derive(Debug, Clone, Default, PartialEq)]
9pub struct Document<'a, T: Text<'a>> {
10 pub definitions: Vec<Definition<'a, T>>,
11}
12
13impl<'a, T: Text<'a>> Document<'a, T> {
14 pub fn new(definitions: Vec<Definition<'a, T>>) -> Self {
15 Document { definitions }
16 }
17
18 pub fn query_type_name(&self) -> Option<&T::Value> {
19 self.root_type_name("Query", |sd| &sd.query)
20 }
21
22 pub fn mutation_type_name(&self) -> Option<&T::Value> {
23 self.root_type_name("Mutation", |sd| &sd.mutation)
24 }
25
26 pub fn subscription_type_name(&self) -> Option<&T::Value> {
27 self.root_type_name("Subscription", |sd| &sd.subscription)
28 }
29
30 fn root_type_name(
31 &self,
32 default_name: &str,
33 schema_definition_field: impl for<'s> Fn(&'s SchemaDefinition<'a, T>) -> &'s Option<T::Value>,
34 ) -> Option<&T::Value> {
35 let mut fallback = None;
36
37 for definition in &self.definitions {
38 match definition {
39 Definition::SchemaDefinition(schema_definition) => {
40 if let Some(name) = schema_definition_field(schema_definition).as_ref() {
41 return Some(name);
42 }
43 }
44 Definition::TypeDefinition(TypeDefinition::Object(object))
45 if fallback.is_none() && object.name.as_ref() == default_name =>
46 {
47 fallback = Some(&object.name);
48 }
49 _ => {}
50 }
51 }
52
53 fallback
54 }
55}
56
57impl<'a> Document<'a, String> {
58 pub fn into_static(self) -> Document<'static, String> {
59 unsafe { std::mem::transmute::<_, Document<'static, String>>(self) }
73 }
74}
75
76#[derive(Debug, Clone, PartialEq)]
77pub enum Definition<'a, T: Text<'a>> {
78 SchemaDefinition(SchemaDefinition<'a, T>),
79 TypeDefinition(TypeDefinition<'a, T>),
80 TypeExtension(TypeExtension<'a, T>),
81 DirectiveDefinition(DirectiveDefinition<'a, T>),
82}
83
84#[derive(Debug, Clone, Default, PartialEq)]
85pub struct SchemaDefinition<'a, T: Text<'a>> {
86 pub position: Pos,
87 pub directives: Vec<Directive<'a, T>>,
88 pub query: Option<T::Value>,
89 pub mutation: Option<T::Value>,
90 pub subscription: Option<T::Value>,
91}
92
93#[derive(Debug, Clone, PartialEq)]
94pub enum TypeDefinition<'a, T: Text<'a>> {
95 Scalar(ScalarType<'a, T>),
96 Object(ObjectType<'a, T>),
97 Interface(InterfaceType<'a, T>),
98 Union(UnionType<'a, T>),
99 Enum(EnumType<'a, T>),
100 InputObject(InputObjectType<'a, T>),
101}
102
103#[derive(Debug, Clone, PartialEq)]
104pub enum TypeExtension<'a, T: Text<'a>> {
105 Scalar(ScalarTypeExtension<'a, T>),
106 Object(ObjectTypeExtension<'a, T>),
107 Interface(InterfaceTypeExtension<'a, T>),
108 Union(UnionTypeExtension<'a, T>),
109 Enum(EnumTypeExtension<'a, T>),
110 InputObject(InputObjectTypeExtension<'a, T>),
111}
112
113#[derive(Debug, Clone, PartialEq)]
114pub struct ScalarType<'a, T: Text<'a>> {
115 pub position: Pos,
116 pub description: Option<String>,
117 pub name: T::Value,
118 pub directives: Vec<Directive<'a, T>>,
119}
120
121impl<'a, T> ScalarType<'a, T>
122where
123 T: Text<'a>,
124{
125 pub fn new(name: T::Value) -> Self {
126 Self {
127 position: Pos::default(),
128 description: None,
129 name,
130 directives: vec![],
131 }
132 }
133}
134
135#[derive(Debug, Clone, PartialEq)]
136pub struct ScalarTypeExtension<'a, T: Text<'a>> {
137 pub position: Pos,
138 pub name: T::Value,
139 pub directives: Vec<Directive<'a, T>>,
140}
141
142impl<'a, T> ScalarTypeExtension<'a, T>
143where
144 T: Text<'a>,
145{
146 pub fn new(name: T::Value) -> Self {
147 Self {
148 position: Pos::default(),
149 name,
150 directives: vec![],
151 }
152 }
153}
154
155#[derive(Debug, Clone, PartialEq)]
156pub struct ObjectType<'a, T: Text<'a>> {
157 pub position: Pos,
158 pub description: Option<String>,
159 pub name: T::Value,
160 pub implements_interfaces: Vec<T::Value>,
161 pub directives: Vec<Directive<'a, T>>,
162 pub fields: Vec<Field<'a, T>>,
163}
164
165impl<'a, T> ObjectType<'a, T>
166where
167 T: Text<'a>,
168{
169 pub fn new(name: T::Value) -> Self {
170 Self {
171 position: Pos::default(),
172 description: None,
173 name,
174 implements_interfaces: vec![],
175 directives: vec![],
176 fields: vec![],
177 }
178 }
179}
180
181#[derive(Debug, Clone, PartialEq)]
182pub struct ObjectTypeExtension<'a, T: Text<'a>> {
183 pub position: Pos,
184 pub name: T::Value,
185 pub implements_interfaces: Vec<T::Value>,
186 pub directives: Vec<Directive<'a, T>>,
187 pub fields: Vec<Field<'a, T>>,
188}
189
190impl<'a, T> ObjectTypeExtension<'a, T>
191where
192 T: Text<'a>,
193{
194 pub fn new(name: T::Value) -> Self {
195 Self {
196 position: Pos::default(),
197 name,
198 implements_interfaces: vec![],
199 directives: vec![],
200 fields: vec![],
201 }
202 }
203}
204
205#[derive(Debug, Clone, PartialEq)]
206pub struct Field<'a, T: Text<'a>> {
207 pub position: Pos,
208 pub description: Option<String>,
209 pub name: T::Value,
210 pub arguments: Vec<InputValue<'a, T>>,
211 pub field_type: Type<'a, T>,
212 pub directives: Vec<Directive<'a, T>>,
213}
214
215#[derive(Debug, Clone, PartialEq)]
216pub struct InputValue<'a, T: Text<'a>> {
217 pub position: Pos,
218 pub description: Option<String>,
219 pub name: T::Value,
220 pub value_type: Type<'a, T>,
221 pub default_value: Option<Value<'a, T>>,
222 pub directives: Vec<Directive<'a, T>>,
223}
224
225#[derive(Debug, Clone, PartialEq)]
226pub struct InterfaceType<'a, T: Text<'a>> {
227 pub position: Pos,
228 pub description: Option<String>,
229 pub name: T::Value,
230 pub implements_interfaces: Vec<T::Value>,
231 pub directives: Vec<Directive<'a, T>>,
232 pub fields: Vec<Field<'a, T>>,
233}
234
235impl<'a, T> InterfaceType<'a, T>
236where
237 T: Text<'a>,
238{
239 pub fn new(name: T::Value) -> Self {
240 Self {
241 position: Pos::default(),
242 description: None,
243 name,
244 implements_interfaces: vec![],
245 directives: vec![],
246 fields: vec![],
247 }
248 }
249}
250
251#[derive(Debug, Clone, PartialEq)]
252pub struct InterfaceTypeExtension<'a, T: Text<'a>> {
253 pub position: Pos,
254 pub name: T::Value,
255 pub implements_interfaces: Vec<T::Value>,
256 pub directives: Vec<Directive<'a, T>>,
257 pub fields: Vec<Field<'a, T>>,
258}
259
260impl<'a, T> InterfaceTypeExtension<'a, T>
261where
262 T: Text<'a>,
263{
264 pub fn new(name: T::Value) -> Self {
265 Self {
266 position: Pos::default(),
267 name,
268 implements_interfaces: vec![],
269 directives: vec![],
270 fields: vec![],
271 }
272 }
273}
274
275#[derive(Debug, Clone, PartialEq)]
276pub struct UnionType<'a, T: Text<'a>> {
277 pub position: Pos,
278 pub description: Option<String>,
279 pub name: T::Value,
280 pub directives: Vec<Directive<'a, T>>,
281 pub types: Vec<T::Value>,
282}
283
284impl<'a, T> UnionType<'a, T>
285where
286 T: Text<'a>,
287{
288 pub fn new(name: T::Value) -> Self {
289 Self {
290 position: Pos::default(),
291 description: None,
292 name,
293 directives: vec![],
294 types: vec![],
295 }
296 }
297}
298
299#[derive(Debug, Clone, PartialEq)]
300pub struct UnionTypeExtension<'a, T: Text<'a>> {
301 pub position: Pos,
302 pub name: T::Value,
303 pub directives: Vec<Directive<'a, T>>,
304 pub types: Vec<T::Value>,
305}
306
307impl<'a, T> UnionTypeExtension<'a, T>
308where
309 T: Text<'a>,
310{
311 pub fn new(name: T::Value) -> Self {
312 Self {
313 position: Pos::default(),
314 name,
315 directives: vec![],
316 types: vec![],
317 }
318 }
319}
320
321#[derive(Debug, Clone, PartialEq)]
322pub struct EnumType<'a, T: Text<'a>> {
323 pub position: Pos,
324 pub description: Option<String>,
325 pub name: T::Value,
326 pub directives: Vec<Directive<'a, T>>,
327 pub values: Vec<EnumValue<'a, T>>,
328}
329
330impl<'a, T> EnumType<'a, T>
331where
332 T: Text<'a>,
333{
334 pub fn new(name: T::Value) -> Self {
335 Self {
336 position: Pos::default(),
337 description: None,
338 name,
339 directives: vec![],
340 values: vec![],
341 }
342 }
343}
344
345#[derive(Debug, Clone, PartialEq)]
346pub struct EnumValue<'a, T: Text<'a>> {
347 pub position: Pos,
348 pub description: Option<String>,
349 pub name: T::Value,
350 pub directives: Vec<Directive<'a, T>>,
351}
352
353impl<'a, T> EnumValue<'a, T>
354where
355 T: Text<'a>,
356{
357 pub fn new(name: T::Value) -> Self {
358 Self {
359 position: Pos::default(),
360 description: None,
361 name,
362 directives: vec![],
363 }
364 }
365}
366
367#[derive(Debug, Clone, PartialEq)]
368pub struct EnumTypeExtension<'a, T: Text<'a>> {
369 pub position: Pos,
370 pub name: T::Value,
371 pub directives: Vec<Directive<'a, T>>,
372 pub values: Vec<EnumValue<'a, T>>,
373}
374
375impl<'a, T> EnumTypeExtension<'a, T>
376where
377 T: Text<'a>,
378{
379 pub fn new(name: T::Value) -> Self {
380 Self {
381 position: Pos::default(),
382 name,
383 directives: vec![],
384 values: vec![],
385 }
386 }
387}
388
389#[derive(Debug, Clone, PartialEq)]
390pub struct InputObjectType<'a, T: Text<'a>> {
391 pub position: Pos,
392 pub description: Option<String>,
393 pub name: T::Value,
394 pub directives: Vec<Directive<'a, T>>,
395 pub fields: Vec<InputValue<'a, T>>,
396}
397
398impl<'a, T> InputObjectType<'a, T>
399where
400 T: Text<'a>,
401{
402 pub fn new(name: T::Value) -> Self {
403 Self {
404 position: Pos::default(),
405 description: None,
406 name,
407 directives: vec![],
408 fields: vec![],
409 }
410 }
411}
412
413#[derive(Debug, Clone, PartialEq)]
414pub struct InputObjectTypeExtension<'a, T: Text<'a>> {
415 pub position: Pos,
416 pub name: T::Value,
417 pub directives: Vec<Directive<'a, T>>,
418 pub fields: Vec<InputValue<'a, T>>,
419}
420
421impl<'a, T> InputObjectTypeExtension<'a, T>
422where
423 T: Text<'a>,
424{
425 pub fn new(name: T::Value) -> Self {
426 Self {
427 position: Pos::default(),
428 name,
429 directives: vec![],
430 fields: vec![],
431 }
432 }
433}
434
435#[derive(Debug, Clone, PartialEq, Eq)]
436pub enum DirectiveLocation {
437 Query,
439 Mutation,
440 Subscription,
441 Field,
442 FragmentDefinition,
443 FragmentSpread,
444 InlineFragment,
445
446 Schema,
448 Scalar,
449 Object,
450 FieldDefinition,
451 ArgumentDefinition,
452 Interface,
453 Union,
454 Enum,
455 EnumValue,
456 InputObject,
457 InputFieldDefinition,
458 VariableDefinition,
459}
460
461#[derive(Debug, Clone, PartialEq)]
462pub struct DirectiveDefinition<'a, T: Text<'a>> {
463 pub position: Pos,
464 pub description: Option<String>,
465 pub name: T::Value,
466 pub arguments: Vec<InputValue<'a, T>>,
467 pub repeatable: bool,
468 pub locations: Vec<DirectiveLocation>,
469}
470
471impl<'a, T> DirectiveDefinition<'a, T>
472where
473 T: Text<'a>,
474{
475 pub fn new(name: T::Value) -> Self {
476 Self {
477 position: Pos::default(),
478 description: None,
479 name,
480 arguments: vec![],
481 repeatable: false,
482 locations: vec![],
483 }
484 }
485}
486
487impl DirectiveLocation {
488 pub fn as_str(&self) -> &'static str {
490 use self::DirectiveLocation::*;
491 match *self {
492 Query => "QUERY",
493 Mutation => "MUTATION",
494 Subscription => "SUBSCRIPTION",
495 Field => "FIELD",
496 FragmentDefinition => "FRAGMENT_DEFINITION",
497 FragmentSpread => "FRAGMENT_SPREAD",
498 InlineFragment => "INLINE_FRAGMENT",
499 Schema => "SCHEMA",
500 Scalar => "SCALAR",
501 Object => "OBJECT",
502 FieldDefinition => "FIELD_DEFINITION",
503 ArgumentDefinition => "ARGUMENT_DEFINITION",
504 Interface => "INTERFACE",
505 Union => "UNION",
506 Enum => "ENUM",
507 EnumValue => "ENUM_VALUE",
508 InputObject => "INPUT_OBJECT",
509 InputFieldDefinition => "INPUT_FIELD_DEFINITION",
510 VariableDefinition => "VARIABLE_DEFINITION",
511 }
512 }
513
514 pub fn is_query(&self) -> bool {
516 use self::DirectiveLocation::*;
517 match *self {
518 Query | Mutation | Subscription | Field | FragmentDefinition | FragmentSpread
519 | InlineFragment => true,
520
521 Schema | Scalar | Object | FieldDefinition | ArgumentDefinition | Interface | Union
522 | Enum | EnumValue | InputObject | InputFieldDefinition | VariableDefinition => false,
523 }
524 }
525
526 pub fn is_schema(&self) -> bool {
528 !self.is_query()
529 }
530}
531
532#[derive(Debug, Error)]
533#[error("invalid directive location")]
534pub struct InvalidDirectiveLocation;
535
536impl FromStr for DirectiveLocation {
537 type Err = InvalidDirectiveLocation;
538 fn from_str(s: &str) -> Result<DirectiveLocation, InvalidDirectiveLocation> {
539 use self::DirectiveLocation::*;
540 let val = match s {
541 "QUERY" => Query,
542 "MUTATION" => Mutation,
543 "SUBSCRIPTION" => Subscription,
544 "FIELD" => Field,
545 "FRAGMENT_DEFINITION" => FragmentDefinition,
546 "FRAGMENT_SPREAD" => FragmentSpread,
547 "INLINE_FRAGMENT" => InlineFragment,
548 "SCHEMA" => Schema,
549 "SCALAR" => Scalar,
550 "OBJECT" => Object,
551 "FIELD_DEFINITION" => FieldDefinition,
552 "ARGUMENT_DEFINITION" => ArgumentDefinition,
553 "INTERFACE" => Interface,
554 "UNION" => Union,
555 "ENUM" => Enum,
556 "ENUM_VALUE" => EnumValue,
557 "INPUT_OBJECT" => InputObject,
558 "INPUT_FIELD_DEFINITION" => InputFieldDefinition,
559 "VARIABLE_DEFINITION" => VariableDefinition,
560 _ => return Err(InvalidDirectiveLocation),
561 };
562
563 Ok(val)
564 }
565}