grafbase_sdk/extension/
resolver.rs

1use crate::{
2    component::AnyExtension,
3    types::{Error, FieldDefinitionDirective, FieldInputs, FieldOutput},
4    Headers,
5};
6
7use super::Extension;
8
9/// A trait that extends `Extension` and provides functionality for resolving fields.
10///
11/// Implementors of this trait are expected to provide a method to resolve field values based on
12/// the given context, directive, and inputs. This is typically used in scenarios where field
13/// resolution logic needs to be encapsulated within a resolver object, allowing for modular
14/// and reusable code design.
15pub trait Resolver: Extension {
16    /// Resolves a field value based on the given context, directive, definition, and inputs.
17    ///
18    /// # Arguments
19    ///
20    /// * `headers` - The subgraph headers associated with this field resolution
21    /// * `subgraph_name` - The name of the subgraph associated with this field resolution
22    /// * `directive` - The directive associated with this field resolution
23    /// * `definition` - The field definition containing metadata
24    /// * `inputs` - The input values provided for this field
25    ///
26    /// # Returns
27    ///
28    /// Returns a `Result` containing either the resolved `FieldOutput` value or an `Error`
29    fn resolve_field(
30        &mut self,
31        headers: Headers,
32        subgraph_name: &str,
33        directive: FieldDefinitionDirective<'_>,
34        inputs: FieldInputs,
35    ) -> Result<FieldOutput, Error>;
36
37    /// Resolves a subscription field by setting up a subscription handler.
38    ///
39    /// # Arguments
40    ///
41    /// * `headers` - The subgraph headers associated with this field resolution
42    /// * `directive` - The directive associated with this subscription field
43    /// * `definition` - The field definition containing metadata about the subscription
44    ///
45    /// # Returns
46    ///
47    /// Returns a `Result` containing either a boxed `Subscriber` implementation or an `Error`
48    fn resolve_subscription(
49        &mut self,
50        headers: Headers,
51        subgraph_name: &str,
52        directive: FieldDefinitionDirective<'_>,
53    ) -> Result<Box<dyn Subscription>, Error>;
54
55    /// Returns a key for a subscription field.
56    ///
57    /// This method is used to identify unique subscription channels or connections
58    /// when managing multiple active subscriptions. The returned key can be
59    /// used to track, manage, or deduplicate subscriptions.
60    ///
61    /// # Arguments
62    ///
63    /// * `headers` - The subgraph headers associated with this subscription
64    /// * `subgraph_name` - The name of the subgraph associated with this subscription
65    /// * `directive` - The directive associated with this subscription field
66    ///
67    /// # Returns
68    ///
69    /// Returns an `Option<Vec<u8>>` containing either a unique key for this
70    /// subscription or `None` if no deduplication is desired.
71    #[allow(unused)]
72    fn subscription_key(
73        &mut self,
74        headers: &Headers,
75        subgraph_name: &str,
76        directive: FieldDefinitionDirective<'_>,
77    ) -> Option<Vec<u8>> {
78        None
79    }
80}
81
82/// A trait for consuming field outputs from streams.
83///
84/// This trait provides an abstraction over different implementations
85/// of subscriptions to field output streams. Implementors should handle
86/// the details of their specific transport mechanism while providing a
87/// consistent interface for consumers.
88pub trait Subscription {
89    /// Retrieves the next field output from the subscription.
90    ///
91    /// Returns:
92    /// - `Ok(Some(FieldOutput))` if a field output was available
93    /// - `Ok(None)` if the subscription has ended normally
94    /// - `Err(Error)` if an error occurred while retrieving the next field output
95    fn next(&mut self) -> Result<Option<FieldOutput>, Error>;
96}
97
98#[doc(hidden)]
99pub fn register<T: Resolver>() {
100    pub(super) struct Proxy<T: Resolver>(T);
101
102    impl<T: Resolver> AnyExtension for Proxy<T> {
103        fn resolve_field(
104            &mut self,
105            headers: Headers,
106            subgraph_name: &str,
107            directive: FieldDefinitionDirective<'_>,
108            inputs: FieldInputs,
109        ) -> Result<FieldOutput, Error> {
110            Resolver::resolve_field(&mut self.0, headers, subgraph_name, directive, inputs)
111        }
112        fn resolve_subscription(
113            &mut self,
114            headers: Headers,
115            subgraph_name: &str,
116            directive: FieldDefinitionDirective<'_>,
117        ) -> Result<Box<dyn Subscription>, Error> {
118            Resolver::resolve_subscription(&mut self.0, headers, subgraph_name, directive)
119        }
120
121        fn subscription_key(
122            &mut self,
123            headers: &Headers,
124            subgraph_name: &str,
125            directive: FieldDefinitionDirective<'_>,
126        ) -> Result<Option<Vec<u8>>, Error> {
127            Ok(Resolver::subscription_key(
128                &mut self.0,
129                headers,
130                subgraph_name,
131                directive,
132            ))
133        }
134    }
135
136    crate::component::register_extension(Box::new(|schema_directives, config| {
137        <T as Extension>::new(schema_directives, config)
138            .map(|extension| Box::new(Proxy(extension)) as Box<dyn AnyExtension>)
139    }))
140}