grafbase_sdk/types/
schema.rs

1use fxhash::FxHasher32;
2use serde::Deserialize;
3use std::collections::HashMap;
4use std::{fmt, hash::BuildHasherDefault};
5
6use crate::{SdkError, wit};
7
8#[derive(Clone)]
9pub(crate) struct IndexedSchema {
10    name: String,
11    directives: Vec<wit::Directive>,
12    type_definitions: HashMap<DefinitionId, wit::TypeDefinition, BuildHasherDefault<FxHasher32>>,
13    root_types: wit::RootTypes,
14}
15
16impl From<(String, wit::Schema)> for IndexedSchema {
17    fn from((name, schema): (String, wit::Schema)) -> Self {
18        Self {
19            name,
20            directives: schema.directives,
21            type_definitions: schema
22                .type_definitions
23                .into_iter()
24                .map(|def| {
25                    let id = match &def {
26                        wit::TypeDefinition::Scalar(scalar) => DefinitionId(scalar.id),
27                        wit::TypeDefinition::Object(object) => DefinitionId(object.id),
28                        wit::TypeDefinition::Interface(interface) => DefinitionId(interface.id),
29                        wit::TypeDefinition::Union(union) => DefinitionId(union.id),
30                        wit::TypeDefinition::Enum(enum_def) => DefinitionId(enum_def.id),
31                        wit::TypeDefinition::InputObject(input_object) => DefinitionId(input_object.id),
32                    };
33                    (id, def)
34                })
35                .collect(),
36            root_types: schema.root_types,
37        }
38    }
39}
40
41/// GraphQL schema
42pub struct SubgraphSchema<'a>(pub(crate) &'a IndexedSchema);
43
44impl fmt::Debug for SubgraphSchema<'_> {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        f.debug_struct("SubgraphSchema")
47            .field("name", &self.name())
48            .field(
49                "type_definitions",
50                &format!("<{} type definitions>", self.type_definitions().len()),
51            )
52            .field("directives", &self.directives().collect::<Vec<_>>())
53            .finish_non_exhaustive()
54    }
55}
56
57impl SubgraphSchema<'_> {
58    /// Name of the subgraph this schema belongs to
59    pub fn name(&self) -> &str {
60        &self.0.name
61    }
62
63    /// Iterator over the definitions in this schema
64    pub fn type_definitions(&self) -> impl ExactSizeIterator<Item = TypeDefinition<'_>> + '_ {
65        let schema = self.0;
66        self.0.type_definitions.values().map(move |def| (schema, def).into())
67    }
68
69    /// Retrieves a specific type definition by its unique identifier.
70    pub fn type_definition(&self, id: &DefinitionId) -> Option<TypeDefinition<'_>> {
71        let schema = self.0;
72        self.0.type_definitions.get(id).map(move |def| (schema, def).into())
73    }
74
75    /// Iterator over the directives applied to this schema
76    pub fn directives(&self) -> impl ExactSizeIterator<Item = Directive<'_>> + '_ {
77        self.0.directives.iter().map(Into::into)
78    }
79
80    /// Query type id definition if any. Subgraph schema may only contain mutations or add fields
81    /// to external objects.
82    pub fn query(&self) -> Option<ObjectDefinition<'_>> {
83        self.0.root_types.query_id.map(|id| {
84            let Some(wit::TypeDefinition::Object(def)) = self.0.type_definitions.get(&DefinitionId(id)) else {
85                unreachable!("Inconsitent schema");
86            };
87            (self.0, def).into()
88        })
89    }
90
91    /// Mutation type definition id if any
92    pub fn mutation(&self) -> Option<ObjectDefinition<'_>> {
93        self.0.root_types.mutation_id.map(|id| {
94            let Some(wit::TypeDefinition::Object(def)) = self.0.type_definitions.get(&DefinitionId(id)) else {
95                unreachable!("Inconsitent schema");
96            };
97            (self.0, def).into()
98        })
99    }
100
101    /// Subscription type definition id if any
102    pub fn subscription(&self) -> Option<ObjectDefinition<'_>> {
103        self.0.root_types.subscription_id.map(|id| {
104            let Some(wit::TypeDefinition::Object(def)) = self.0.type_definitions.get(&DefinitionId(id)) else {
105                unreachable!("Inconsitent schema");
106            };
107            (self.0, def).into()
108        })
109    }
110}
111
112/// Identifier for a GraphQL definition within a schema
113///
114/// Provides a unique reference to different types of schema definitions such as
115/// scalars, objects, interfaces, and other type definitions.
116///
117/// There is no particular guarantee on the nature of the u32, it could be a `u32::MAX`. It's only
118/// ensured to be unique. It's recommended to use the `fxhash::FxHasher32` with a hashmap for best
119/// performance.
120#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize)]
121pub struct DefinitionId(pub(crate) u32);
122
123impl From<DefinitionId> for u32 {
124    fn from(id: DefinitionId) -> u32 {
125        id.0
126    }
127}
128
129/// Enum representing the different types of GraphQL definitions
130#[derive(Clone, Copy)]
131pub enum TypeDefinition<'a> {
132    /// A scalar type definition (e.g., String, Int, custom scalars)
133    Scalar(ScalarDefinition<'a>),
134    /// An object type definition
135    Object(ObjectDefinition<'a>),
136    /// An interface type definition
137    Interface(InterfaceDefinition<'a>),
138    /// A union type definition
139    Union(UnionDefinition<'a>),
140    /// An enum type definition
141    Enum(EnumDefinition<'a>),
142    /// An input object type definition
143    InputObject(InputObjectDefinition<'a>),
144}
145
146impl fmt::Debug for TypeDefinition<'_> {
147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148        match self {
149            TypeDefinition::Scalar(def) => f.debug_tuple("Scalar").field(def).finish(),
150            TypeDefinition::Object(def) => f.debug_tuple("Object").field(def).finish(),
151            TypeDefinition::Interface(def) => f.debug_tuple("Interface").field(def).finish(),
152            TypeDefinition::Union(def) => f.debug_tuple("Union").field(def).finish(),
153            TypeDefinition::Enum(def) => f.debug_tuple("Enum").field(def).finish(),
154            TypeDefinition::InputObject(def) => f.debug_tuple("InputObject").field(def).finish(),
155        }
156    }
157}
158
159impl<'a> TypeDefinition<'a> {
160    /// Unique identifier for this type definition
161    pub fn id(&self) -> DefinitionId {
162        match self {
163            TypeDefinition::Scalar(def) => def.id(),
164            TypeDefinition::Object(def) => def.id(),
165            TypeDefinition::Interface(def) => def.id(),
166            TypeDefinition::Union(def) => def.id(),
167            TypeDefinition::Enum(def) => def.id(),
168            TypeDefinition::InputObject(def) => def.id(),
169        }
170    }
171
172    /// Name of the type definition
173    pub fn name(&self) -> &'a str {
174        match self {
175            TypeDefinition::Scalar(def) => def.name(),
176            TypeDefinition::Object(def) => def.name(),
177            TypeDefinition::Interface(def) => def.name(),
178            TypeDefinition::Union(def) => def.name(),
179            TypeDefinition::Enum(def) => def.name(),
180            TypeDefinition::InputObject(def) => def.name(),
181        }
182    }
183}
184
185impl<'a> From<(&'a IndexedSchema, &'a wit::TypeDefinition)> for TypeDefinition<'a> {
186    fn from((schema, definition): (&'a IndexedSchema, &'a wit::TypeDefinition)) -> Self {
187        match definition {
188            wit::TypeDefinition::Scalar(scalar) => TypeDefinition::Scalar((schema, scalar).into()),
189            wit::TypeDefinition::Object(object) => TypeDefinition::Object((schema, object).into()),
190            wit::TypeDefinition::Interface(interface) => TypeDefinition::Interface((schema, interface).into()),
191            wit::TypeDefinition::Union(union) => TypeDefinition::Union((schema, union).into()),
192            wit::TypeDefinition::Enum(enum_def) => TypeDefinition::Enum((schema, enum_def).into()),
193            wit::TypeDefinition::InputObject(input_object) => {
194                TypeDefinition::InputObject((schema, input_object).into())
195            }
196        }
197    }
198}
199
200/// GraphQL scalar type definition
201#[derive(Clone, Copy)]
202pub struct ScalarDefinition<'a> {
203    pub(crate) definition: &'a wit::ScalarDefinition,
204}
205
206impl fmt::Debug for ScalarDefinition<'_> {
207    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208        f.debug_struct("ScalarDefinition")
209            .field("id", &self.id())
210            .field("name", &self.name())
211            .field("specified_by_url", &self.specified_by_url())
212            .field("directives", &self.directives().collect::<Vec<_>>())
213            .finish()
214    }
215}
216
217impl<'a> From<(&'a IndexedSchema, &'a wit::ScalarDefinition)> for ScalarDefinition<'a> {
218    fn from((_, definition): (&'a IndexedSchema, &'a wit::ScalarDefinition)) -> Self {
219        Self { definition }
220    }
221}
222
223impl<'a> ScalarDefinition<'a> {
224    /// Unique identifier for this scalar definition
225    pub fn id(&self) -> DefinitionId {
226        DefinitionId(self.definition.id)
227    }
228
229    /// Name of the scalar type
230    pub fn name(&self) -> &'a str {
231        self.definition.name.as_str()
232    }
233
234    /// URL that specifies the behavior of this scalar, if any
235    ///
236    /// The specified by URL is used with custom scalars to point to
237    /// a specification for how the scalar should be validated and parsed.
238    pub fn specified_by_url(&self) -> Option<&'a str> {
239        self.definition.specified_by_url.as_deref()
240    }
241
242    /// Iterator over the directives applied to this scalar
243    pub fn directives(&self) -> impl ExactSizeIterator<Item = Directive<'a>> + 'a {
244        self.definition.directives.iter().map(Into::into)
245    }
246}
247
248/// GraphQL object type definition
249#[derive(Clone, Copy)]
250pub struct ObjectDefinition<'a> {
251    pub(crate) schema: &'a IndexedSchema,
252    pub(crate) definition: &'a wit::ObjectDefinition,
253}
254
255impl fmt::Debug for ObjectDefinition<'_> {
256    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257        f.debug_struct("ObjectDefinition")
258            .field("id", &self.id())
259            .field("name", &self.name())
260            .field("fields", &self.fields().collect::<Vec<_>>())
261            .field(
262                "interfaces",
263                &self.interfaces().map(|inf| inf.name()).collect::<Vec<_>>(),
264            )
265            .field("directives", &self.directives().collect::<Vec<_>>())
266            .finish()
267    }
268}
269
270impl<'a> From<(&'a IndexedSchema, &'a wit::ObjectDefinition)> for ObjectDefinition<'a> {
271    fn from((schema, definition): (&'a IndexedSchema, &'a wit::ObjectDefinition)) -> Self {
272        Self { schema, definition }
273    }
274}
275
276impl<'a> ObjectDefinition<'a> {
277    /// Unique identifier for this object definition
278    pub fn id(&self) -> DefinitionId {
279        DefinitionId(self.definition.id)
280    }
281
282    /// Name of the object type
283    pub fn name(&self) -> &'a str {
284        self.definition.name.as_str()
285    }
286
287    /// Iterator over the fields defined in this object
288    pub fn fields(&self) -> impl ExactSizeIterator<Item = FieldDefinition<'a>> + 'a {
289        self.definition.fields.iter().map(|field| FieldDefinition {
290            schema: self.schema,
291            definition: field,
292        })
293    }
294
295    /// Iterator over the interfaces implemented by this object
296    pub fn interfaces(&self) -> impl ExactSizeIterator<Item = InterfaceDefinition<'a>> + 'a {
297        let schema = self.schema;
298        self.definition.interfaces.iter().map(move |&id| {
299            let Some(wit::TypeDefinition::Interface(def)) = &schema.type_definitions.get(&DefinitionId(id)) else {
300                unreachable!("Inconsitent schema");
301            };
302            (schema, def).into()
303        })
304    }
305
306    /// Iterator over the directives applied to this object
307    pub fn directives(&self) -> impl ExactSizeIterator<Item = Directive<'a>> + 'a {
308        self.definition.directives.iter().map(Into::into)
309    }
310}
311
312/// Represents a GraphQL interface type definition
313///
314/// Interface types define a set of fields that multiple object types can implement.
315/// Interfaces can also implement other interfaces.
316#[derive(Clone, Copy)]
317pub struct InterfaceDefinition<'a> {
318    pub(crate) schema: &'a IndexedSchema,
319    pub(crate) definition: &'a wit::InterfaceDefinition,
320}
321
322impl fmt::Debug for InterfaceDefinition<'_> {
323    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324        f.debug_struct("InterfaceDefinition")
325            .field("id", &self.id())
326            .field("name", &self.name())
327            .field("fields", &self.fields().collect::<Vec<_>>())
328            .field(
329                "interfaces",
330                &self.interfaces().map(|inf| inf.name()).collect::<Vec<_>>(),
331            )
332            .field("directives", &self.directives().collect::<Vec<_>>())
333            .finish()
334    }
335}
336
337impl<'a> From<(&'a IndexedSchema, &'a wit::InterfaceDefinition)> for InterfaceDefinition<'a> {
338    fn from((schema, definition): (&'a IndexedSchema, &'a wit::InterfaceDefinition)) -> Self {
339        Self { schema, definition }
340    }
341}
342
343impl<'a> InterfaceDefinition<'a> {
344    /// Unique identifier for this interface definition
345    pub fn id(&self) -> DefinitionId {
346        DefinitionId(self.definition.id)
347    }
348
349    /// Name of the interface type
350    pub fn name(&self) -> &'a str {
351        self.definition.name.as_str()
352    }
353
354    /// Iterator over the fields defined in this interface
355    pub fn fields(&self) -> impl ExactSizeIterator<Item = FieldDefinition<'a>> + 'a {
356        self.definition.fields.iter().map(|field| FieldDefinition {
357            definition: field,
358            schema: self.schema,
359        })
360    }
361
362    /// Iterator over the interfaces implemented by this interface
363    pub fn interfaces(&self) -> impl ExactSizeIterator<Item = InterfaceDefinition<'a>> + 'a {
364        let schema = self.schema;
365        self.definition.interfaces.iter().map(move |&id| {
366            let Some(wit::TypeDefinition::Interface(def)) = &schema.type_definitions.get(&DefinitionId(id)) else {
367                unreachable!("Inconsitent schema");
368            };
369            (schema, def).into()
370        })
371    }
372
373    /// Iterator over the directives applied to this interface
374    pub fn directives(&self) -> impl ExactSizeIterator<Item = Directive<'a>> + 'a {
375        self.definition.directives.iter().map(Into::into)
376    }
377}
378
379/// Represents a GraphQL union type definition
380///
381/// Union types define a type that could be one of several object types.
382#[derive(Clone, Copy)]
383pub struct UnionDefinition<'a> {
384    pub(crate) schema: &'a IndexedSchema,
385    pub(crate) definition: &'a wit::UnionDefinition,
386}
387
388impl fmt::Debug for UnionDefinition<'_> {
389    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
390        f.debug_struct("UnionDefinition")
391            .field("id", &self.id())
392            .field("name", &self.name())
393            .field(
394                "member_types",
395                &self.member_types().map(|obj| obj.name()).collect::<Vec<_>>(),
396            )
397            .field("directives", &self.directives().collect::<Vec<_>>())
398            .finish()
399    }
400}
401
402impl<'a> From<(&'a IndexedSchema, &'a wit::UnionDefinition)> for UnionDefinition<'a> {
403    fn from((schema, definition): (&'a IndexedSchema, &'a wit::UnionDefinition)) -> Self {
404        Self { schema, definition }
405    }
406}
407
408impl<'a> UnionDefinition<'a> {
409    /// Unique identifier for this union definition
410    pub fn id(&self) -> DefinitionId {
411        DefinitionId(self.definition.id)
412    }
413
414    /// Name of the union type
415    pub fn name(&self) -> &'a str {
416        self.definition.name.as_str()
417    }
418
419    /// Iterator over the member types that are part of this union
420    pub fn member_types(&self) -> impl ExactSizeIterator<Item = ObjectDefinition<'a>> + 'a {
421        let schema = self.schema;
422        self.definition.member_types.iter().map(move |&id| {
423            let Some(wit::TypeDefinition::Object(def)) = &schema.type_definitions.get(&DefinitionId(id)) else {
424                unreachable!("Inconsitent schema");
425            };
426            (schema, def).into()
427        })
428    }
429
430    /// Iterator over the directives applied to this union
431    pub fn directives(&self) -> impl ExactSizeIterator<Item = Directive<'a>> + 'a {
432        self.definition.directives.iter().map(Into::into)
433    }
434}
435
436/// Represents a GraphQL enum type definition
437///
438/// Enum types restrict a field to a finite set of values.
439#[derive(Clone, Copy)]
440pub struct EnumDefinition<'a> {
441    pub(crate) definition: &'a wit::EnumDefinition,
442}
443
444impl fmt::Debug for EnumDefinition<'_> {
445    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
446        f.debug_struct("EnumDefinition")
447            .field("id", &self.id())
448            .field("name", &self.name())
449            .field("values", &self.values().collect::<Vec<_>>())
450            .field("directives", &self.directives().collect::<Vec<_>>())
451            .finish()
452    }
453}
454
455impl<'a> From<(&'a IndexedSchema, &'a wit::EnumDefinition)> for EnumDefinition<'a> {
456    fn from((_, definition): (&'a IndexedSchema, &'a wit::EnumDefinition)) -> Self {
457        Self { definition }
458    }
459}
460
461impl<'a> EnumDefinition<'a> {
462    /// Unique identifier for this enum definition
463    pub fn id(&self) -> DefinitionId {
464        DefinitionId(self.definition.id)
465    }
466
467    /// Name of the enum type
468    pub fn name(&self) -> &'a str {
469        self.definition.name.as_str()
470    }
471
472    /// Iterator over the possible values for this enum
473    pub fn values(&self) -> impl ExactSizeIterator<Item = EnumValue<'a>> + 'a {
474        self.definition.values.iter().map(Into::into)
475    }
476
477    /// Iterator over the directives applied to this enum
478    pub fn directives(&self) -> impl ExactSizeIterator<Item = Directive<'a>> + 'a {
479        self.definition.directives.iter().map(Into::into)
480    }
481}
482
483/// Represents a GraphQL input object type definition
484///
485/// Input objects are complex objects provided as arguments to fields,
486/// consisting of a set of input fields.
487#[derive(Clone, Copy)]
488pub struct InputObjectDefinition<'a> {
489    pub(crate) schema: &'a IndexedSchema,
490    pub(crate) definition: &'a wit::InputObjectDefinition,
491}
492
493impl fmt::Debug for InputObjectDefinition<'_> {
494    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495        f.debug_struct("InputObjectDefinition")
496            .field("id", &self.id())
497            .field("name", &self.name())
498            .field("input_fields", &self.input_fields().collect::<Vec<_>>())
499            .field("directives", &self.directives().collect::<Vec<_>>())
500            .finish()
501    }
502}
503
504impl<'a> From<(&'a IndexedSchema, &'a wit::InputObjectDefinition)> for InputObjectDefinition<'a> {
505    fn from((schema, definition): (&'a IndexedSchema, &'a wit::InputObjectDefinition)) -> Self {
506        Self { schema, definition }
507    }
508}
509
510impl<'a> InputObjectDefinition<'a> {
511    /// Unique identifier for this input object definition
512    pub fn id(&self) -> DefinitionId {
513        DefinitionId(self.definition.id)
514    }
515
516    /// Name of the input object type
517    pub fn name(&self) -> &'a str {
518        self.definition.name.as_str()
519    }
520
521    /// Iterator over the input fields defined in this input object
522    pub fn input_fields(&self) -> impl ExactSizeIterator<Item = InputValueDefinition<'a>> + 'a {
523        self.definition.input_fields.iter().map(|field| InputValueDefinition {
524            definition: field,
525            schema: self.schema,
526        })
527    }
528
529    /// Iterator over the directives applied to this input object
530    pub fn directives(&self) -> impl ExactSizeIterator<Item = Directive<'a>> + 'a {
531        self.definition.directives.iter().map(Into::into)
532    }
533}
534
535/// Represents a GraphQL field definition within an object or interface
536///
537/// Fields are the basic units of data in GraphQL. They define what data can be
538/// fetched from a particular object or interface.
539#[derive(Clone, Copy)]
540pub struct FieldDefinition<'a> {
541    pub(crate) schema: &'a IndexedSchema,
542    pub(crate) definition: &'a wit::FieldDefinition,
543}
544
545impl fmt::Debug for FieldDefinition<'_> {
546    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
547        f.debug_struct("FieldDefinition")
548            .field("id", &self.id())
549            .field("name", &self.name())
550            .field("type", &self.ty())
551            .field("arguments", &self.arguments().collect::<Vec<_>>())
552            .field("directives", &self.directives().collect::<Vec<_>>())
553            .finish()
554    }
555}
556
557impl<'a> From<(&'a IndexedSchema, &'a wit::FieldDefinition)> for FieldDefinition<'a> {
558    fn from((schema, definition): (&'a IndexedSchema, &'a wit::FieldDefinition)) -> Self {
559        Self { schema, definition }
560    }
561}
562
563impl<'a> FieldDefinition<'a> {
564    /// Unique identifier for this field definition
565    pub fn id(&self) -> DefinitionId {
566        DefinitionId(self.definition.id)
567    }
568
569    /// Name of the field
570    pub fn name(&self) -> &'a str {
571        self.definition.name.as_str()
572    }
573
574    /// Type of value this field returns
575    pub fn ty(&self) -> Type<'a> {
576        (self.schema, &self.definition.ty).into()
577    }
578
579    /// Iterator over the arguments that can be passed to this field
580    pub fn arguments(&self) -> impl ExactSizeIterator<Item = InputValueDefinition<'a>> + 'a {
581        self.definition.arguments.iter().map(|arg| InputValueDefinition {
582            definition: arg,
583            schema: self.schema,
584        })
585    }
586
587    /// Iterator over the directives applied to this field
588    pub fn directives(&self) -> impl ExactSizeIterator<Item = Directive<'a>> + 'a {
589        self.definition.directives.iter().map(Into::into)
590    }
591}
592
593/// Represents a GraphQL type with its wrapping information
594///
595/// This struct contains information about a type's definition and any non-null
596/// or list wrapping that may be applied to it.
597#[derive(Clone, Copy)]
598pub struct Type<'a> {
599    schema: &'a IndexedSchema,
600    ty: &'a wit::Ty,
601}
602
603impl fmt::Debug for Type<'_> {
604    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
605        f.debug_struct("Type")
606            .field("definition", &self.definition().name())
607            .field("wrapping", &self.wrapping().collect::<Vec<_>>())
608            .finish()
609    }
610}
611
612impl<'a> From<(&'a IndexedSchema, &'a wit::Ty)> for Type<'a> {
613    fn from((schema, ty): (&'a IndexedSchema, &'a wit::Ty)) -> Self {
614        Self { schema, ty }
615    }
616}
617
618impl<'a> Type<'a> {
619    /// Whether this type is non-null
620    pub fn is_non_null(&self) -> bool {
621        self.wrapping().last() == Some(WrappingType::NonNull)
622    }
623
624    /// Whether this type is a list
625    pub fn is_list(&self) -> bool {
626        self.wrapping().any(|w| matches!(w, WrappingType::List))
627    }
628
629    /// Iterator over the type wrappers applied to this type
630    /// From the innermost to the outermost
631    pub fn wrapping(&self) -> impl ExactSizeIterator<Item = WrappingType> + 'a {
632        self.ty.wrapping.iter().map(|&w| w.into())
633    }
634
635    /// Identifier for the base type definition
636    pub fn definition(&self) -> TypeDefinition<'a> {
637        let Some(def) = self.schema.type_definitions.get(&DefinitionId(self.ty.definition_id)) else {
638            unreachable!("Inconsitent schema");
639        };
640        (self.schema, def).into()
641    }
642}
643
644/// Represents the different ways a GraphQL type can be wrapped
645///
646/// Types in GraphQL can be wrapped to indicate they are non-null or
647/// represent a list of values.
648#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
649pub enum WrappingType {
650    /// Indicates that the wrapped type cannot be null
651    NonNull,
652    /// Indicates that the wrapped type is a list of elements
653    List,
654}
655
656impl From<wit::WrappingType> for WrappingType {
657    fn from(wrapping: wit::WrappingType) -> Self {
658        match wrapping {
659            wit::WrappingType::NonNull => WrappingType::NonNull,
660            wit::WrappingType::List => WrappingType::List,
661        }
662    }
663}
664
665/// Represents an input value definition in a GraphQL schema
666///
667/// Input values are used for arguments on fields and input object fields.
668#[derive(Clone, Copy)]
669pub struct InputValueDefinition<'a> {
670    pub(crate) schema: &'a IndexedSchema,
671    pub(crate) definition: &'a wit::InputValueDefinition,
672}
673
674impl fmt::Debug for InputValueDefinition<'_> {
675    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
676        f.debug_struct("InputValueDefinition")
677            .field("id", &self.id())
678            .field("name", &self.name())
679            .field("type", &self.ty())
680            .field("directives", &self.directives().collect::<Vec<_>>())
681            .finish()
682    }
683}
684
685impl<'a> From<(&'a IndexedSchema, &'a wit::InputValueDefinition)> for InputValueDefinition<'a> {
686    fn from((schema, definition): (&'a IndexedSchema, &'a wit::InputValueDefinition)) -> Self {
687        Self { schema, definition }
688    }
689}
690
691impl<'a> InputValueDefinition<'a> {
692    /// Unique identifier for this input value definition
693    pub fn id(&self) -> DefinitionId {
694        DefinitionId(self.definition.id)
695    }
696
697    /// Name of the input value
698    pub fn name(&self) -> &'a str {
699        self.definition.name.as_str()
700    }
701
702    /// Type of this input value
703    pub fn ty(&self) -> Type<'a> {
704        (self.schema, &self.definition.ty).into()
705    }
706
707    /// Iterator over the directives applied to this input value
708    pub fn directives(&self) -> impl ExactSizeIterator<Item = Directive<'a>> + 'a {
709        self.definition.directives.iter().map(Into::into)
710    }
711}
712
713/// Represents a single possible value in a GraphQL enum definition
714#[derive(Clone, Copy)]
715pub struct EnumValue<'a>(&'a wit::EnumValue);
716
717impl fmt::Debug for EnumValue<'_> {
718    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
719        f.debug_struct("EnumValue")
720            .field("name", &self.name())
721            .field("directives", &self.directives().collect::<Vec<_>>())
722            .finish()
723    }
724}
725
726impl<'a> From<&'a wit::EnumValue> for EnumValue<'a> {
727    fn from(enum_value: &'a wit::EnumValue) -> Self {
728        Self(enum_value)
729    }
730}
731
732impl<'a> EnumValue<'a> {
733    /// Name of this enum value
734    pub fn name(&self) -> &'a str {
735        self.0.name.as_str()
736    }
737
738    /// Iterator over the directives applied to this enum value
739    pub fn directives(&self) -> impl ExactSizeIterator<Item = Directive<'a>> + 'a {
740        self.0.directives.iter().map(Into::into)
741    }
742}
743
744/// Represents a GraphQL directive applied to a schema element
745///
746/// Directives provide a way to describe alternate runtime execution and type validation
747/// behavior in a GraphQL document.
748#[derive(Clone, Copy)]
749pub struct Directive<'a>(&'a wit::Directive);
750
751impl fmt::Debug for Directive<'_> {
752    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
753        f.debug_struct("Directive")
754            .field("name", &self.name())
755            .field("arguments", &"<binary arguments>")
756            .finish()
757    }
758}
759
760impl<'a> From<&'a wit::Directive> for Directive<'a> {
761    fn from(directive: &'a wit::Directive) -> Self {
762        Self(directive)
763    }
764}
765
766impl<'a> Directive<'a> {
767    /// Name of the directive
768    pub fn name(&self) -> &'a str {
769        self.0.name.as_str()
770    }
771
772    /// Deserializes the directive's arguments into the specified type.
773    pub fn arguments<T>(&self) -> Result<T, SdkError>
774    where
775        T: Deserialize<'a>,
776    {
777        minicbor_serde::from_slice(&self.0.arguments).map_err(Into::into)
778    }
779}