graphql_tools/parser/schema/
ast.rs

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> Document<'a, String> {
14    pub fn into_static(self) -> Document<'static, String> {
15        // To support both reference and owned values in the AST,
16        // all string data is represented with the ::common::Str<'a, T: Text<'a>>
17        // wrapper type.
18        // This type must carry the liftetime of the schema string,
19        // and is stored in a PhantomData value on the Str type.
20        // When using owned String types, the actual lifetime of
21        // the Ast nodes is 'static, since no references are kept,
22        // but the nodes will still carry the input lifetime.
23        // To continue working with Document<String> in a owned fasion
24        // the lifetime needs to be transmuted to 'static.
25        //
26        // This is safe because no references are present.
27        // Just the PhantomData lifetime reference is transmuted away.
28        unsafe { std::mem::transmute::<_, Document<'static, String>>(self) }
29    }
30}
31
32#[derive(Debug, Clone, PartialEq)]
33pub enum Definition<'a, T: Text<'a>> {
34    SchemaDefinition(SchemaDefinition<'a, T>),
35    TypeDefinition(TypeDefinition<'a, T>),
36    TypeExtension(TypeExtension<'a, T>),
37    DirectiveDefinition(DirectiveDefinition<'a, T>),
38}
39
40#[derive(Debug, Clone, Default, PartialEq)]
41pub struct SchemaDefinition<'a, T: Text<'a>> {
42    pub position: Pos,
43    pub directives: Vec<Directive<'a, T>>,
44    pub query: Option<T::Value>,
45    pub mutation: Option<T::Value>,
46    pub subscription: Option<T::Value>,
47}
48
49#[derive(Debug, Clone, PartialEq)]
50pub enum TypeDefinition<'a, T: Text<'a>> {
51    Scalar(ScalarType<'a, T>),
52    Object(ObjectType<'a, T>),
53    Interface(InterfaceType<'a, T>),
54    Union(UnionType<'a, T>),
55    Enum(EnumType<'a, T>),
56    InputObject(InputObjectType<'a, T>),
57}
58
59#[derive(Debug, Clone, PartialEq)]
60pub enum TypeExtension<'a, T: Text<'a>> {
61    Scalar(ScalarTypeExtension<'a, T>),
62    Object(ObjectTypeExtension<'a, T>),
63    Interface(InterfaceTypeExtension<'a, T>),
64    Union(UnionTypeExtension<'a, T>),
65    Enum(EnumTypeExtension<'a, T>),
66    InputObject(InputObjectTypeExtension<'a, T>),
67}
68
69#[derive(Debug, Clone, PartialEq)]
70pub struct ScalarType<'a, T: Text<'a>> {
71    pub position: Pos,
72    pub description: Option<String>,
73    pub name: T::Value,
74    pub directives: Vec<Directive<'a, T>>,
75}
76
77impl<'a, T> ScalarType<'a, T>
78where
79    T: Text<'a>,
80{
81    pub fn new(name: T::Value) -> Self {
82        Self {
83            position: Pos::default(),
84            description: None,
85            name,
86            directives: vec![],
87        }
88    }
89}
90
91#[derive(Debug, Clone, PartialEq)]
92pub struct ScalarTypeExtension<'a, T: Text<'a>> {
93    pub position: Pos,
94    pub name: T::Value,
95    pub directives: Vec<Directive<'a, T>>,
96}
97
98impl<'a, T> ScalarTypeExtension<'a, T>
99where
100    T: Text<'a>,
101{
102    pub fn new(name: T::Value) -> Self {
103        Self {
104            position: Pos::default(),
105            name,
106            directives: vec![],
107        }
108    }
109}
110
111#[derive(Debug, Clone, PartialEq)]
112pub struct ObjectType<'a, T: Text<'a>> {
113    pub position: Pos,
114    pub description: Option<String>,
115    pub name: T::Value,
116    pub implements_interfaces: Vec<T::Value>,
117    pub directives: Vec<Directive<'a, T>>,
118    pub fields: Vec<Field<'a, T>>,
119}
120
121impl<'a, T> ObjectType<'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            implements_interfaces: vec![],
131            directives: vec![],
132            fields: vec![],
133        }
134    }
135}
136
137#[derive(Debug, Clone, PartialEq)]
138pub struct ObjectTypeExtension<'a, T: Text<'a>> {
139    pub position: Pos,
140    pub name: T::Value,
141    pub implements_interfaces: Vec<T::Value>,
142    pub directives: Vec<Directive<'a, T>>,
143    pub fields: Vec<Field<'a, T>>,
144}
145
146impl<'a, T> ObjectTypeExtension<'a, T>
147where
148    T: Text<'a>,
149{
150    pub fn new(name: T::Value) -> Self {
151        Self {
152            position: Pos::default(),
153            name,
154            implements_interfaces: vec![],
155            directives: vec![],
156            fields: vec![],
157        }
158    }
159}
160
161#[derive(Debug, Clone, PartialEq)]
162pub struct Field<'a, T: Text<'a>> {
163    pub position: Pos,
164    pub description: Option<String>,
165    pub name: T::Value,
166    pub arguments: Vec<InputValue<'a, T>>,
167    pub field_type: Type<'a, T>,
168    pub directives: Vec<Directive<'a, T>>,
169}
170
171#[derive(Debug, Clone, PartialEq)]
172pub struct InputValue<'a, T: Text<'a>> {
173    pub position: Pos,
174    pub description: Option<String>,
175    pub name: T::Value,
176    pub value_type: Type<'a, T>,
177    pub default_value: Option<Value<'a, T>>,
178    pub directives: Vec<Directive<'a, T>>,
179}
180
181#[derive(Debug, Clone, PartialEq)]
182pub struct InterfaceType<'a, T: Text<'a>> {
183    pub position: Pos,
184    pub description: Option<String>,
185    pub name: T::Value,
186    pub implements_interfaces: Vec<T::Value>,
187    pub directives: Vec<Directive<'a, T>>,
188    pub fields: Vec<Field<'a, T>>,
189}
190
191impl<'a, T> InterfaceType<'a, T>
192where
193    T: Text<'a>,
194{
195    pub fn new(name: T::Value) -> Self {
196        Self {
197            position: Pos::default(),
198            description: None,
199            name,
200            implements_interfaces: vec![],
201            directives: vec![],
202            fields: vec![],
203        }
204    }
205}
206
207#[derive(Debug, Clone, PartialEq)]
208pub struct InterfaceTypeExtension<'a, T: Text<'a>> {
209    pub position: Pos,
210    pub name: T::Value,
211    pub implements_interfaces: Vec<T::Value>,
212    pub directives: Vec<Directive<'a, T>>,
213    pub fields: Vec<Field<'a, T>>,
214}
215
216impl<'a, T> InterfaceTypeExtension<'a, T>
217where
218    T: Text<'a>,
219{
220    pub fn new(name: T::Value) -> Self {
221        Self {
222            position: Pos::default(),
223            name,
224            implements_interfaces: vec![],
225            directives: vec![],
226            fields: vec![],
227        }
228    }
229}
230
231#[derive(Debug, Clone, PartialEq)]
232pub struct UnionType<'a, T: Text<'a>> {
233    pub position: Pos,
234    pub description: Option<String>,
235    pub name: T::Value,
236    pub directives: Vec<Directive<'a, T>>,
237    pub types: Vec<T::Value>,
238}
239
240impl<'a, T> UnionType<'a, T>
241where
242    T: Text<'a>,
243{
244    pub fn new(name: T::Value) -> Self {
245        Self {
246            position: Pos::default(),
247            description: None,
248            name,
249            directives: vec![],
250            types: vec![],
251        }
252    }
253}
254
255#[derive(Debug, Clone, PartialEq)]
256pub struct UnionTypeExtension<'a, T: Text<'a>> {
257    pub position: Pos,
258    pub name: T::Value,
259    pub directives: Vec<Directive<'a, T>>,
260    pub types: Vec<T::Value>,
261}
262
263impl<'a, T> UnionTypeExtension<'a, T>
264where
265    T: Text<'a>,
266{
267    pub fn new(name: T::Value) -> Self {
268        Self {
269            position: Pos::default(),
270            name,
271            directives: vec![],
272            types: vec![],
273        }
274    }
275}
276
277#[derive(Debug, Clone, PartialEq)]
278pub struct EnumType<'a, T: Text<'a>> {
279    pub position: Pos,
280    pub description: Option<String>,
281    pub name: T::Value,
282    pub directives: Vec<Directive<'a, T>>,
283    pub values: Vec<EnumValue<'a, T>>,
284}
285
286impl<'a, T> EnumType<'a, T>
287where
288    T: Text<'a>,
289{
290    pub fn new(name: T::Value) -> Self {
291        Self {
292            position: Pos::default(),
293            description: None,
294            name,
295            directives: vec![],
296            values: vec![],
297        }
298    }
299}
300
301#[derive(Debug, Clone, PartialEq)]
302pub struct EnumValue<'a, T: Text<'a>> {
303    pub position: Pos,
304    pub description: Option<String>,
305    pub name: T::Value,
306    pub directives: Vec<Directive<'a, T>>,
307}
308
309impl<'a, T> EnumValue<'a, T>
310where
311    T: Text<'a>,
312{
313    pub fn new(name: T::Value) -> Self {
314        Self {
315            position: Pos::default(),
316            description: None,
317            name,
318            directives: vec![],
319        }
320    }
321}
322
323#[derive(Debug, Clone, PartialEq)]
324pub struct EnumTypeExtension<'a, T: Text<'a>> {
325    pub position: Pos,
326    pub name: T::Value,
327    pub directives: Vec<Directive<'a, T>>,
328    pub values: Vec<EnumValue<'a, T>>,
329}
330
331impl<'a, T> EnumTypeExtension<'a, T>
332where
333    T: Text<'a>,
334{
335    pub fn new(name: T::Value) -> Self {
336        Self {
337            position: Pos::default(),
338            name,
339            directives: vec![],
340            values: vec![],
341        }
342    }
343}
344
345#[derive(Debug, Clone, PartialEq)]
346pub struct InputObjectType<'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    pub fields: Vec<InputValue<'a, T>>,
352}
353
354impl<'a, T> InputObjectType<'a, T>
355where
356    T: Text<'a>,
357{
358    pub fn new(name: T::Value) -> Self {
359        Self {
360            position: Pos::default(),
361            description: None,
362            name,
363            directives: vec![],
364            fields: vec![],
365        }
366    }
367}
368
369#[derive(Debug, Clone, PartialEq)]
370pub struct InputObjectTypeExtension<'a, T: Text<'a>> {
371    pub position: Pos,
372    pub name: T::Value,
373    pub directives: Vec<Directive<'a, T>>,
374    pub fields: Vec<InputValue<'a, T>>,
375}
376
377impl<'a, T> InputObjectTypeExtension<'a, T>
378where
379    T: Text<'a>,
380{
381    pub fn new(name: T::Value) -> Self {
382        Self {
383            position: Pos::default(),
384            name,
385            directives: vec![],
386            fields: vec![],
387        }
388    }
389}
390
391#[derive(Debug, Clone, PartialEq, Eq, Hash)]
392pub enum DirectiveLocation {
393    // executable
394    Query,
395    Mutation,
396    Subscription,
397    Field,
398    FragmentDefinition,
399    FragmentSpread,
400    InlineFragment,
401
402    // type_system
403    Schema,
404    Scalar,
405    Object,
406    FieldDefinition,
407    ArgumentDefinition,
408    Interface,
409    Union,
410    Enum,
411    EnumValue,
412    InputObject,
413    InputFieldDefinition,
414    VariableDefinition,
415}
416
417#[derive(Debug, Clone, PartialEq)]
418pub struct DirectiveDefinition<'a, T: Text<'a>> {
419    pub position: Pos,
420    pub description: Option<String>,
421    pub name: T::Value,
422    pub arguments: Vec<InputValue<'a, T>>,
423    pub repeatable: bool,
424    pub locations: Vec<DirectiveLocation>,
425}
426
427impl<'a, T> DirectiveDefinition<'a, T>
428where
429    T: Text<'a>,
430{
431    pub fn new(name: T::Value) -> Self {
432        Self {
433            position: Pos::default(),
434            description: None,
435            name,
436            arguments: vec![],
437            repeatable: false,
438            locations: vec![],
439        }
440    }
441}
442
443impl DirectiveLocation {
444    /// Returns GraphQL syntax compatible name of the directive
445    pub fn as_str(&self) -> &'static str {
446        use self::DirectiveLocation::*;
447        match *self {
448            Query => "QUERY",
449            Mutation => "MUTATION",
450            Subscription => "SUBSCRIPTION",
451            Field => "FIELD",
452            FragmentDefinition => "FRAGMENT_DEFINITION",
453            FragmentSpread => "FRAGMENT_SPREAD",
454            InlineFragment => "INLINE_FRAGMENT",
455            Schema => "SCHEMA",
456            Scalar => "SCALAR",
457            Object => "OBJECT",
458            FieldDefinition => "FIELD_DEFINITION",
459            ArgumentDefinition => "ARGUMENT_DEFINITION",
460            Interface => "INTERFACE",
461            Union => "UNION",
462            Enum => "ENUM",
463            EnumValue => "ENUM_VALUE",
464            InputObject => "INPUT_OBJECT",
465            InputFieldDefinition => "INPUT_FIELD_DEFINITION",
466            VariableDefinition => "VARIABLE_DEFINITION",
467        }
468    }
469
470    /// Returns `true` if this location is for queries (execution)
471    pub fn is_query(&self) -> bool {
472        use self::DirectiveLocation::*;
473        match *self {
474            Query | Mutation | Subscription | Field | FragmentDefinition | FragmentSpread
475            | InlineFragment => true,
476
477            Schema | Scalar | Object | FieldDefinition | ArgumentDefinition | Interface | Union
478            | Enum | EnumValue | InputObject | InputFieldDefinition | VariableDefinition => false,
479        }
480    }
481
482    /// Returns `true` if this location is for schema
483    pub fn is_schema(&self) -> bool {
484        !self.is_query()
485    }
486}
487
488#[derive(Debug, Error)]
489#[error("invalid directive location")]
490pub struct InvalidDirectiveLocation;
491
492impl FromStr for DirectiveLocation {
493    type Err = InvalidDirectiveLocation;
494    fn from_str(s: &str) -> Result<DirectiveLocation, InvalidDirectiveLocation> {
495        use self::DirectiveLocation::*;
496        let val = match s {
497            "QUERY" => Query,
498            "MUTATION" => Mutation,
499            "SUBSCRIPTION" => Subscription,
500            "FIELD" => Field,
501            "FRAGMENT_DEFINITION" => FragmentDefinition,
502            "FRAGMENT_SPREAD" => FragmentSpread,
503            "INLINE_FRAGMENT" => InlineFragment,
504            "SCHEMA" => Schema,
505            "SCALAR" => Scalar,
506            "OBJECT" => Object,
507            "FIELD_DEFINITION" => FieldDefinition,
508            "ARGUMENT_DEFINITION" => ArgumentDefinition,
509            "INTERFACE" => Interface,
510            "UNION" => Union,
511            "ENUM" => Enum,
512            "ENUM_VALUE" => EnumValue,
513            "INPUT_OBJECT" => InputObject,
514            "INPUT_FIELD_DEFINITION" => InputFieldDefinition,
515            "VARIABLE_DEFINITION" => VariableDefinition,
516            _ => return Err(InvalidDirectiveLocation),
517        };
518
519        Ok(val)
520    }
521}