grafbase_sdk/types/
schema.rs

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