graphql_parser/schema/
ast.rs

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