fuel_indexer_graphql_parser/schema/
ast.rs

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