graphql_query/schema/
schema.rs

1use crate::ast::{ASTContext, OperationKind};
2use bumpalo::collections::Vec;
3use hashbrown::hash_map::DefaultHashBuilder;
4use hashbrown::{HashMap, HashSet};
5
6/// Schema Definition
7///
8/// A schema is created from root types for each kind of operation and is then used against
9/// AST documents for validation and execution. In this library the schema is never executable and
10/// serves only for metadata and type information. It is hence a "Client Schema".
11/// [Reference](https://spec.graphql.org/October2021/#sec-Schema)
12#[derive(Debug, Clone)]
13pub struct Schema<'a> {
14    pub(crate) query_type: Option<&'a SchemaObject<'a>>,
15    pub(crate) mutation_type: Option<&'a SchemaObject<'a>>,
16    pub(crate) subscription_type: Option<&'a SchemaObject<'a>>,
17    pub(crate) types:
18        hashbrown::HashMap<&'a str, &'a SchemaType<'a>, DefaultHashBuilder, &'a bumpalo::Bump>,
19}
20
21impl<'a> Schema<'a> {
22    /// Returns whether the schema is a default, empty schema
23    pub fn is_empty(&self) -> bool {
24        self.types.is_empty()
25            && self.query_type.is_none()
26            && self.mutation_type.is_none()
27            && self.subscription_type.is_none()
28    }
29
30    /// Returns the root object type for query operations
31    #[inline]
32    pub fn query_type(&self) -> Option<&'a SchemaObject<'a>> {
33        self.query_type
34    }
35
36    /// Returns the root object type for mutation operations
37    #[inline]
38    pub fn mutation_type(&self) -> Option<&'a SchemaObject<'a>> {
39        self.mutation_type
40    }
41
42    /// Returns the root object type for subscription operations
43    #[inline]
44    pub fn subscription_type(&self) -> Option<&'a SchemaObject<'a>> {
45        self.subscription_type
46    }
47
48    /// Returns the appropriate object type depending on the passed operation kind
49    #[inline]
50    pub fn get_root_type(&self, operation_kind: OperationKind) -> Option<&'a SchemaObject<'a>> {
51        match operation_kind {
52            OperationKind::Query => self.query_type,
53            OperationKind::Mutation => self.mutation_type,
54            OperationKind::Subscription => self.subscription_type,
55        }
56    }
57
58    /// Retrieves a kind by name from known schema types.
59    #[inline]
60    pub fn get_type(&self, name: &'a str) -> Option<&'a SchemaType<'a>> {
61        self.types.get(name).map(|x| *x)
62    }
63
64    /// Checks whether a given type is a sub type of another.
65    ///
66    /// This is typically used for return types of fields. A return type may be any given sub type
67    /// of the return type of said field.
68    pub fn is_sub_type(&self, abstract_type: SchemaType<'a>, sub_type: SchemaType<'a>) -> bool {
69        match abstract_type {
70            SchemaType::Union(schema_union) => schema_union.is_sub_type(sub_type),
71            SchemaType::Interface(schema_interface) => schema_interface.is_sub_type(sub_type),
72            SchemaType::Object(schema_object) => {
73                if let SchemaType::Object(sub_object_type) = sub_type {
74                    sub_object_type == schema_object
75                } else {
76                    false
77                }
78            }
79            _ => false,
80        }
81    }
82}
83
84/// Generic trait for any schema type that implements fields
85pub trait SchemaFields<'a>: Sized {
86    /// Add a new [SchemaField] to the list of fields
87    fn add_field(&mut self, ctx: &'a ASTContext, field: SchemaField<'a>);
88
89    /// Get a [Map] of all fields
90    fn get_fields(
91        &self,
92    ) -> HashMap<&'a str, &'a SchemaField<'a>, DefaultHashBuilder, &'a bumpalo::Bump>;
93
94    /// Get a known field by name
95    fn get_field(&self, name: &'a str) -> Option<&SchemaField<'a>> {
96        self.get_fields().get(name).map(|x| *x)
97    }
98}
99
100/// Generic trait for any schema type that implements interfaces
101pub trait SchemaInterfaces<'a>: Sized {
102    /// Add a new [SchemaInterface] to the list of implemented interfaces
103    fn add_interface(&mut self, ctx: &'a ASTContext, interface: &'a str);
104
105    /// Get list of implemented [SchemaInterface]s
106    fn get_interfaces(&self) -> Vec<&'a str>;
107
108    /// Checks whether given [ObjectType] is a possible subtype
109    #[inline]
110    fn implements_interface(&self, schema_interface: &SchemaInterface<'a>) -> bool {
111        self.get_interfaces()
112            .into_iter()
113            .any(|interface| interface == schema_interface.name)
114    }
115}
116
117/// Generic trait for any schema type that implements interfaces
118pub trait SchemaPossibleTypes<'a>: Sized {
119    /// Add a new [SchemaObject] to the list of possible types
120    fn add_possible_type(&mut self, ctx: &'a ASTContext, object: &'a str);
121
122    /// Get list of possible [SchemaObject] types
123    fn get_possible_types(&self) -> Vec<'a, &'a str>;
124
125    /// Get a specific possible type by name if it exists on the type
126    #[inline]
127    fn get_possible_type(&self, name: &'a str) -> Option<&'a str> {
128        self.get_possible_types()
129            .into_iter()
130            .find(|&possible_type| possible_type == name)
131    }
132
133    /// Checks whether given [ObjectType] is a possible subtype
134    #[inline]
135    fn is_possible_type(&self, schema_object: &SchemaObject<'a>) -> bool {
136        self.get_possible_types()
137            .into_iter()
138            .any(|possible_type| possible_type == schema_object.name)
139    }
140}
141
142/// Generic trait for any schema type that may be a super type of other types
143pub trait SchemaSuperType<'a>: Sized {
144    /// Checks whether a given type is a sub type of the current super type.
145    fn is_sub_type(&self, subtype: SchemaType<'a>) -> bool;
146}
147
148/// An Object type definition.
149///
150/// Most types in GraphQL are objects and define a set of fields and the interfaces they implement.
151/// [Reference](https://spec.graphql.org/October2021/#sec-Objects)
152#[derive(Debug, Clone, PartialEq)]
153pub struct SchemaObject<'a> {
154    pub name: &'a str,
155    pub(crate) fields: HashMap<&'a str, &'a SchemaField<'a>, DefaultHashBuilder, &'a bumpalo::Bump>,
156    pub(crate) interfaces: Vec<'a, &'a str>,
157}
158
159impl<'a> SchemaObject<'a> {
160    #[inline]
161    pub fn new(ctx: &'a ASTContext, name: &'a str) -> Self {
162        SchemaObject {
163            name,
164            fields: HashMap::new_in(&ctx.arena),
165            interfaces: Vec::new_in(&ctx.arena),
166        }
167    }
168}
169
170impl<'a> SchemaFields<'a> for SchemaObject<'a> {
171    /// Add a new [SchemaField] to the list of fields
172    fn add_field(&mut self, ctx: &'a ASTContext, field: SchemaField<'a>) {
173        self.fields.insert(field.name, ctx.alloc(field));
174    }
175
176    /// Get a [Map] of all fields on the [SchemaObject]
177    fn get_fields(
178        &self,
179    ) -> HashMap<&'a str, &'a SchemaField<'a>, DefaultHashBuilder, &'a bumpalo::Bump> {
180        self.fields.clone()
181    }
182}
183
184impl<'a> SchemaInterfaces<'a> for SchemaObject<'a> {
185    /// Add a new [SchemaInterface] to the list of implemented interfaces
186    fn add_interface(&mut self, _ctx: &'a ASTContext, interface: &'a str) {
187        // TODO: this used to prepend
188        self.interfaces.push(interface);
189    }
190
191    /// Get list of implemented [SchemaInterface]s
192    #[inline]
193    fn get_interfaces(&self) -> Vec<'a, &'a str> {
194        self.interfaces.clone()
195    }
196}
197
198/// An Interface type definition.
199///
200/// Any object or other interfaces may implement one or more interfaces and must then adhere to the
201/// definition of this interface. A field that returns an interface as its return type may return
202/// any object that implements this interface.
203/// [Reference](https://spec.graphql.org/October2021/#sec-Interfaces)
204#[derive(Clone, Debug)]
205pub struct SchemaInterface<'a> {
206    pub name: &'a str,
207    pub(crate) fields: HashMap<&'a str, &'a SchemaField<'a>, DefaultHashBuilder, &'a bumpalo::Bump>,
208    pub(crate) interfaces: Vec<'a, &'a str>,
209    pub(crate) possible_interfaces: Vec<'a, &'a str>,
210    pub(crate) possible_types: Vec<'a, &'a str>,
211}
212
213impl<'a> PartialEq for SchemaInterface<'a> {
214    fn eq(&self, other: &Self) -> bool {
215        self.name == other.name
216            && maps_are_equal(self.fields.clone(), other.fields.clone())
217            && self.interfaces == other.interfaces
218            && self.possible_interfaces == other.possible_interfaces
219            && self.possible_types == other.possible_types
220    }
221}
222
223impl<'a> SchemaInterface<'a> {
224    #[inline]
225    pub fn new(ctx: &'a ASTContext, name: &'a str) -> Self {
226        SchemaInterface {
227            name,
228            fields: HashMap::new_in(&ctx.arena),
229            interfaces: Vec::new_in(&ctx.arena),
230            possible_interfaces: Vec::new_in(&ctx.arena),
231            possible_types: Vec::new_in(&ctx.arena),
232        }
233    }
234
235    /// Add a new [SchemaInterface] to the list that implements this [SchemaInterface]
236    pub fn add_possible_interface(&mut self, _ctx: &'a ASTContext, interface: &'a str) {
237        self.possible_interfaces.push(interface);
238    }
239
240    /// Get list of possible [SchemaInterface]s that implement this [SchemaInterface]
241    #[inline]
242    pub fn get_possible_interfaces(&self) -> Vec<'a, &'a str> {
243        self.possible_interfaces.clone()
244    }
245}
246
247impl<'a> SchemaFields<'a> for SchemaInterface<'a> {
248    /// Add a new [SchemaField] to the list of fields
249    fn add_field(&mut self, ctx: &'a ASTContext, field: SchemaField<'a>) {
250        self.fields.insert(field.name, ctx.alloc(field));
251    }
252
253    /// Get a [Map] of all fields on the [SchemaInterface]
254    fn get_fields(
255        &self,
256    ) -> HashMap<&'a str, &'a SchemaField<'a>, DefaultHashBuilder, &'a bumpalo::Bump> {
257        self.fields.clone()
258    }
259}
260
261impl<'a> SchemaInterfaces<'a> for SchemaInterface<'a> {
262    /// Add a new [SchemaInterface] to the list of implemented interfaces
263    fn add_interface(&mut self, _ctx: &'a ASTContext, interface: &'a str) {
264        self.interfaces.push(interface);
265    }
266
267    /// Get list of implemented [SchemaInterface]s
268    #[inline]
269    fn get_interfaces(&self) -> Vec<'a, &'a str> {
270        self.interfaces.clone()
271    }
272}
273
274impl<'a> SchemaPossibleTypes<'a> for SchemaInterface<'a> {
275    /// Add a new [SchemaObject] to the list of possible types
276    fn add_possible_type(&mut self, _ctx: &'a ASTContext, object: &'a str) {
277        self.possible_types.push(object);
278    }
279
280    /// Get list of possible [SchemaObject] types
281    #[inline]
282    fn get_possible_types(&self) -> Vec<'a, &'a str> {
283        self.possible_types.clone()
284    }
285}
286
287impl<'a> SchemaSuperType<'a> for SchemaInterface<'a> {
288    #[inline]
289    fn is_sub_type(&self, sub_type: SchemaType<'a>) -> bool {
290        match sub_type {
291            SchemaType::Object(schema_object) => schema_object.implements_interface(self),
292            SchemaType::Interface(schema_interface) => schema_interface.implements_interface(self),
293            _ => false,
294        }
295    }
296}
297
298/// An object Field type definition.
299///
300/// A field is like a function that given its arguments as input values produces an output value.
301/// [Reference](https://spec.graphql.org/October2021/#FieldsDefinition)
302#[derive(Debug, Clone, PartialEq)]
303pub struct SchemaField<'a> {
304    pub name: &'a str,
305    pub arguments: HashMap<&'a str, SchemaInputField<'a>, DefaultHashBuilder, &'a bumpalo::Bump>,
306    pub output_type: &'a TypeRef<'a>,
307}
308
309impl<'a> SchemaField<'a> {
310    #[inline]
311    pub fn new(ctx: &'a ASTContext, name: &'a str, output_type: &'a TypeRef<'a>) -> Self {
312        SchemaField {
313            name,
314            arguments: HashMap::new_in(&ctx.arena),
315            output_type,
316        }
317    }
318
319    pub fn add_argument(&mut self, _ctx: &'a ASTContext, arg: SchemaInputField<'a>) {
320        self.arguments.insert(arg.name, arg);
321    }
322
323    #[inline]
324    pub fn get_argument(&self, name: &'a str) -> Option<&SchemaInputField<'a>> {
325        self.arguments.get(name)
326    }
327}
328
329/// A Union type definition.
330///
331/// A union contains a list of possible types that can be returned in its stead when its defined as
332/// an output type.
333/// [Reference](https://spec.graphql.org/October2021/#sec-Unions)
334#[derive(Debug, Clone)]
335pub struct SchemaUnion<'a> {
336    pub name: &'a str,
337    possible_types: Vec<'a, &'a str>,
338}
339
340impl<'a> PartialEq for SchemaUnion<'a> {
341    fn eq(&self, other: &Self) -> bool {
342        self.name == other.name && self.possible_types == other.possible_types
343    }
344}
345
346impl<'a> SchemaUnion<'a> {
347    #[inline]
348    pub fn new(ctx: &'a ASTContext, name: &'a str) -> Self {
349        SchemaUnion {
350            name,
351            possible_types: Vec::new_in(&ctx.arena),
352        }
353    }
354
355    #[inline]
356    pub fn is_sub_type(&self, sub_type: SchemaType<'a>) -> bool {
357        match sub_type {
358            SchemaType::Object(schema_object) => self
359                .possible_types
360                .iter()
361                .any(|possible| possible == &schema_object.name),
362            _ => false,
363        }
364    }
365}
366
367impl<'a> SchemaPossibleTypes<'a> for SchemaUnion<'a> {
368    /// Add a new [SchemaObject] to the list of possible types
369    fn add_possible_type(&mut self, _ctx: &'a ASTContext, object: &'a str) {
370        self.possible_types.push(object);
371    }
372
373    /// Get list of possible [SchemaObject] types
374    #[inline]
375    fn get_possible_types(&self) -> Vec<'a, &'a str> {
376        self.possible_types.clone()
377    }
378}
379
380impl<'a> SchemaSuperType<'a> for SchemaUnion<'a> {
381    #[inline]
382    fn is_sub_type(&self, sub_type: SchemaType<'a>) -> bool {
383        if let SchemaType::Object(schema_object) = sub_type {
384            self.is_possible_type(schema_object)
385        } else {
386            false
387        }
388    }
389}
390
391/// A Scalar type definition.
392///
393/// Scalars represent primitive leaf values in GraphQL that are represented with a specific
394/// serializer and deserializer, which makes the values returnable to a GraphQL client or readable
395/// by a GraphQL API.
396/// [Reference](https://spec.graphql.org/October2021/#sec-Scalars)
397#[derive(Debug, Clone, PartialEq)]
398pub struct SchemaScalar<'a> {
399    pub name: &'a str,
400}
401
402impl<'a> SchemaScalar<'a> {
403    #[inline]
404    pub fn new(name: &'a str) -> Self {
405        SchemaScalar { name }
406    }
407}
408
409#[derive(Debug, PartialEq, Clone)]
410pub struct SchemaEnum<'a> {
411    pub name: &'a str,
412    pub values: HashSet<&'a str, DefaultHashBuilder, &'a bumpalo::Bump>,
413}
414
415impl<'a> SchemaEnum<'a> {
416    #[inline]
417    pub fn new(ctx: &'a ASTContext, name: &'a str) -> Self {
418        SchemaEnum {
419            name,
420            values: HashSet::new_in(&ctx.arena),
421        }
422    }
423
424    pub fn add_value(&mut self, _ctx: &'a ASTContext, value: &'a str) {
425        self.values.insert(value);
426    }
427}
428
429/// An Input Object type definition.
430///
431/// Inputs, such as arguments, may sometimes be nested and accept objects that must adhere to the
432/// shape of an Input Object definition. This is often used to represent more complex inputs.
433/// [Reference](https://spec.graphql.org/October2021/#sec-Input-Objects)
434#[derive(Debug, Clone, PartialEq)]
435pub struct SchemaInputObject<'a> {
436    pub name: &'a str,
437    pub fields: HashMap<&'a str, SchemaInputField<'a>, DefaultHashBuilder, &'a bumpalo::Bump>,
438}
439
440impl<'a> SchemaInputObject<'a> {
441    #[inline]
442    pub fn new(ctx: &'a ASTContext, name: &'a str) -> Self {
443        SchemaInputObject {
444            name,
445            fields: HashMap::new_in(&ctx.arena),
446        }
447    }
448
449    pub fn add_field(&mut self, _ctx: &'a ASTContext, field: SchemaInputField<'a>) {
450        self.fields.insert(field.name, field);
451    }
452}
453
454#[derive(Debug, PartialEq, Clone, Copy)]
455pub struct SchemaInputField<'a> {
456    pub name: &'a str,
457    pub input_type: &'a TypeRef<'a>,
458}
459
460impl<'a> SchemaInputField<'a> {
461    #[inline]
462    pub fn new(name: &'a str, input_type: &'a TypeRef<'a>) -> Self {
463        SchemaInputField { name, input_type }
464    }
465}
466
467/// A named type enum that represents all possible GraphQL definition types.
468///
469/// [Reference](https://spec.graphql.org/October2021/#sec-Types)
470#[derive(Debug, PartialEq, Clone, Copy)]
471pub enum SchemaType<'a> {
472    InputObject(&'a SchemaInputObject<'a>),
473    Object(&'a SchemaObject<'a>),
474    Union(&'a SchemaUnion<'a>),
475    Interface(&'a SchemaInterface<'a>),
476    Scalar(&'a SchemaScalar<'a>),
477    Enum(&'a SchemaEnum<'a>),
478}
479
480impl<'a> SchemaType<'a> {
481    #[inline]
482    pub fn name(&self) -> &'a str {
483        match self {
484            SchemaType::InputObject(x) => x.name,
485            SchemaType::Object(x) => x.name,
486            SchemaType::Union(x) => x.name,
487            SchemaType::Interface(x) => x.name,
488            SchemaType::Scalar(x) => x.name,
489            SchemaType::Enum(x) => x.name,
490        }
491    }
492
493    pub fn object(&self) -> Option<&'a SchemaObject<'a>> {
494        match self {
495            SchemaType::Object(x) => Some(x),
496            _ => None,
497        }
498    }
499
500    pub fn input_object(&self) -> Option<&'a SchemaInputObject<'a>> {
501        match self {
502            SchemaType::InputObject(x) => Some(x),
503            _ => None,
504        }
505    }
506
507    pub fn interface(&self) -> Option<&'a SchemaInterface<'a>> {
508        match self {
509            SchemaType::Interface(x) => Some(x),
510            _ => None,
511        }
512    }
513
514    pub fn union_type(&self) -> Option<&'a SchemaUnion<'a>> {
515        match self {
516            SchemaType::Union(x) => Some(x),
517            _ => None,
518        }
519    }
520
521    pub fn input_type(&self) -> Option<InputType<'a>> {
522        match self {
523            SchemaType::Scalar(x) => Some(InputType::Scalar(x)),
524            SchemaType::Enum(x) => Some(InputType::Enum(x)),
525            SchemaType::InputObject(x) => Some(InputType::InputObject(x)),
526            _ => None,
527        }
528    }
529
530    pub fn output_type(&self) -> Option<OutputType<'a>> {
531        match self {
532            SchemaType::Object(x) => Some(OutputType::Object(x)),
533            SchemaType::Union(x) => Some(OutputType::Union(x)),
534            SchemaType::Interface(x) => Some(OutputType::Interface(x)),
535            SchemaType::Scalar(x) => Some(OutputType::Scalar(x)),
536            SchemaType::Enum(x) => Some(OutputType::Enum(x)),
537            _ => None,
538        }
539    }
540}
541
542#[derive(Debug, PartialEq, Clone)]
543pub enum OwnedSchemaType<'a> {
544    InputObject(SchemaInputObject<'a>),
545    Object(SchemaObject<'a>),
546    Union(SchemaUnion<'a>),
547    Interface(SchemaInterface<'a>),
548    Scalar(SchemaScalar<'a>),
549    Enum(SchemaEnum<'a>),
550}
551
552impl<'a> OwnedSchemaType<'a> {
553    #[inline]
554    pub fn name(&self) -> &'a str {
555        match self {
556            OwnedSchemaType::InputObject(x) => x.name,
557            OwnedSchemaType::Object(x) => x.name,
558            OwnedSchemaType::Union(x) => x.name,
559            OwnedSchemaType::Interface(x) => x.name,
560            OwnedSchemaType::Scalar(x) => x.name,
561            OwnedSchemaType::Enum(x) => x.name,
562        }
563    }
564
565    pub fn object(&'a self) -> Option<&'a SchemaObject<'a>> {
566        match self {
567            OwnedSchemaType::Object(x) => Some(x),
568            _ => None,
569        }
570    }
571
572    pub fn input_object(&'a self) -> Option<&'a SchemaInputObject<'a>> {
573        match self {
574            OwnedSchemaType::InputObject(x) => Some(x),
575            _ => None,
576        }
577    }
578
579    pub fn interface(&'a self) -> Option<&'a SchemaInterface<'a>> {
580        match self {
581            OwnedSchemaType::Interface(x) => Some(x),
582            _ => None,
583        }
584    }
585
586    pub fn union_type(&'a self) -> Option<&'a SchemaUnion<'a>> {
587        match self {
588            OwnedSchemaType::Union(x) => Some(x),
589            _ => None,
590        }
591    }
592
593    pub fn input_type(&'a self) -> Option<InputType<'a>> {
594        match self {
595            OwnedSchemaType::Scalar(x) => Some(InputType::Scalar(x)),
596            OwnedSchemaType::Enum(x) => Some(InputType::Enum(x)),
597            OwnedSchemaType::InputObject(x) => Some(InputType::InputObject(x)),
598            _ => None,
599        }
600    }
601
602    pub fn output_type(&'a self) -> Option<OutputType<'a>> {
603        match self {
604            OwnedSchemaType::Object(x) => Some(OutputType::Object(x)),
605            OwnedSchemaType::Union(x) => Some(OutputType::Union(x)),
606            OwnedSchemaType::Interface(x) => Some(OutputType::Interface(x)),
607            OwnedSchemaType::Scalar(x) => Some(OutputType::Scalar(x)),
608            OwnedSchemaType::Enum(x) => Some(OutputType::Enum(x)),
609            _ => None,
610        }
611    }
612}
613
614impl<'a> From<&'a SchemaObject<'a>> for SchemaType<'a> {
615    #[inline]
616    fn from(schema_object: &'a SchemaObject<'a>) -> Self {
617        SchemaType::Object(schema_object)
618    }
619}
620
621impl<'a> From<&'a SchemaUnion<'a>> for SchemaType<'a> {
622    #[inline]
623    fn from(schema_union: &'a SchemaUnion<'a>) -> Self {
624        SchemaType::Union(schema_union)
625    }
626}
627
628impl<'a> From<&'a SchemaInterface<'a>> for SchemaType<'a> {
629    #[inline]
630    fn from(schema_interface: &'a SchemaInterface<'a>) -> Self {
631        SchemaType::Interface(schema_interface)
632    }
633}
634
635impl<'a> From<OutputType<'a>> for SchemaType<'a> {
636    #[inline]
637    fn from(type_ref: OutputType<'a>) -> Self {
638        match type_ref {
639            OutputType::Object(x) => SchemaType::Object(x),
640            OutputType::Union(x) => SchemaType::Union(x),
641            OutputType::Interface(x) => SchemaType::Interface(x),
642            OutputType::Scalar(x) => SchemaType::Scalar(x),
643            OutputType::Enum(x) => SchemaType::Enum(x),
644        }
645    }
646}
647
648impl<'a> From<InputType<'a>> for SchemaType<'a> {
649    #[inline]
650    fn from(type_ref: InputType<'a>) -> Self {
651        match type_ref {
652            InputType::InputObject(x) => SchemaType::InputObject(x),
653            InputType::Scalar(x) => SchemaType::Scalar(x),
654            InputType::Enum(x) => SchemaType::Enum(x),
655        }
656    }
657}
658
659/// An output type enum that represents all possible GraphQL definition types that a field may
660/// return.
661///
662/// [Reference](https://spec.graphql.org/October2021/#sec-Input-and-Output-Types)
663#[derive(Debug, PartialEq, Clone, Copy)]
664pub enum OutputType<'a> {
665    Object(&'a SchemaObject<'a>),
666    Union(&'a SchemaUnion<'a>),
667    Interface(&'a SchemaInterface<'a>),
668    Scalar(&'a SchemaScalar<'a>),
669    Enum(&'a SchemaEnum<'a>),
670}
671
672impl<'a> OutputType<'a> {
673    #[inline]
674    pub fn name(&self) -> &str {
675        match self {
676            OutputType::Object(x) => x.name,
677            OutputType::Union(x) => x.name,
678            OutputType::Interface(x) => x.name,
679            OutputType::Scalar(x) => x.name,
680            OutputType::Enum(x) => x.name,
681        }
682    }
683
684    #[inline]
685    pub fn into_schema_type(&self) -> SchemaType<'a> {
686        match self {
687            OutputType::Object(x) => SchemaType::Object(x),
688            OutputType::Union(x) => SchemaType::Union(x),
689            OutputType::Interface(x) => SchemaType::Interface(x),
690            OutputType::Scalar(x) => SchemaType::Scalar(x),
691            OutputType::Enum(x) => SchemaType::Enum(x),
692        }
693    }
694}
695
696/// An input type enum that represents all possible GraphQL definition types that an argument or
697/// input object field may accept.
698///
699/// [Reference](https://spec.graphql.org/October2021/#sec-Input-and-Output-Types)
700#[derive(Debug, PartialEq, Clone, Copy)]
701pub enum InputType<'a> {
702    InputObject(&'a SchemaInputObject<'a>),
703    Scalar(&'a SchemaScalar<'a>),
704    Enum(&'a SchemaEnum<'a>),
705}
706
707impl<'a> InputType<'a> {
708    #[inline]
709    pub fn name(&self) -> &str {
710        match self {
711            InputType::InputObject(o) => o.name,
712            InputType::Scalar(s) => s.name,
713            InputType::Enum(e) => e.name,
714        }
715    }
716
717    #[inline]
718    pub fn named_type(&self) -> SchemaType<'a> {
719        match self {
720            InputType::InputObject(x) => SchemaType::InputObject(x),
721            InputType::Scalar(x) => SchemaType::Scalar(x),
722            InputType::Enum(x) => SchemaType::Enum(x),
723        }
724    }
725}
726
727#[derive(Clone, Copy)]
728pub enum TypeRef<'a> {
729    Type(&'a str),
730    ListType(&'a TypeRef<'a>),
731    NonNullType(&'a TypeRef<'a>),
732}
733
734impl<'a> TypeRef<'a> {
735    #[inline]
736    pub fn of_type(&self, schema: &'a Schema<'a>) -> &'a SchemaType<'a> {
737        match self {
738            TypeRef::Type(of_type) => {
739                let schema_type = schema
740                    .get_type(of_type)
741                    .expect("Referenced type should exist in the schema.");
742                schema_type
743            }
744            TypeRef::ListType(of_type) => of_type.of_type(schema),
745            TypeRef::NonNullType(of_type) => of_type.of_type(schema),
746        }
747    }
748}
749
750/// This implementation is necessary to circuit break circular types.
751/// Without this impl, `Debug` would print on and on, overflowing the stack as it's bouncing between types over and over.
752impl<'a> std::fmt::Debug for TypeRef<'a> {
753    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
754        match self {
755            Self::Type(arg0) => f.debug_tuple("OutputTypeRef").field(&arg0).finish(),
756            Self::ListType(arg0) => f.debug_tuple("ListType").field(arg0).finish(),
757            Self::NonNullType(arg0) => f.debug_tuple("NonNullType").field(arg0).finish(),
758        }
759    }
760}
761
762/// This implementation is necessary to circuit break circular types.
763/// Without this impl, `PartialEq` would never stop comparing types referencing each other.
764/// We achieve this by only ever comparing type names, which is all we need for comparing references.
765impl<'a> PartialEq for TypeRef<'a> {
766    fn eq(&self, other: &Self) -> bool {
767        match (self, other) {
768            (Self::Type(left), Self::Type(right)) => left == right,
769            (Self::ListType(left), Self::ListType(right)) => left == right,
770            (Self::NonNullType(left), Self::NonNullType(right)) => left == right,
771            _ => false,
772        }
773    }
774}
775
776/// By default, Toolshed Maps also compare insertion order. This utility compares only entries, not ordering.
777fn maps_are_equal<'a, V>(
778    left: HashMap<&'a str, V, DefaultHashBuilder, &'a bumpalo::Bump>,
779    right: HashMap<&'a str, V, DefaultHashBuilder, &'a bumpalo::Bump>,
780) -> bool
781where
782    V: PartialEq + Copy,
783{
784    let length_matches = left.len() == right.len();
785
786    // If the length matches and all entries in `left` are contained in `right` and equal, we can consider the maps equal.
787    length_matches
788        && left.iter().all(|(k, left_val)| {
789            right
790                .get(k)
791                .map(|right_val| left_val == right_val)
792                .unwrap_or(false)
793        })
794}
795
796/// Helper trait to generalize comparisons (see `eq_named_lists`).
797trait Named {
798    fn name(&self) -> &str;
799}
800
801impl<'a> Named for &'a SchemaInterface<'a> {
802    fn name(&self) -> &str {
803        self.name
804    }
805}
806
807impl<'a> Named for &'a SchemaObject<'a> {
808    fn name(&self) -> &str {
809        self.name
810    }
811}
812
813impl<'a> Named for &'a SchemaUnion<'a> {
814    fn name(&self) -> &str {
815        self.name
816    }
817}