grafbase_sdk/types/
selection_set.rs

1use std::borrow::Cow;
2
3use crate::{SdkError, wit::selection_set_resolver_types as wit};
4use serde::{Deserialize, de::DeserializeSeed};
5
6use super::DefinitionId;
7
8/// A field within a GraphQL query
9#[derive(Clone, Copy)]
10pub struct Field<'a> {
11    pub(crate) fields: &'a [wit::Field],
12    pub(crate) field: &'a wit::Field,
13}
14
15impl<'a> Field<'a> {
16    /// Gets the alias of this field, if any
17    pub fn alias(&self) -> Option<&str> {
18        self.field.alias.as_deref()
19    }
20
21    /// Gets the arguments ID of this field, if any
22    pub fn arguments_id(&self) -> Option<ArgumentsId> {
23        self.field.arguments.map(ArgumentsId)
24    }
25
26    /// Field definition id.
27    pub fn definition_id(&self) -> DefinitionId {
28        DefinitionId(self.field.definition_id)
29    }
30
31    /// Deserializes the arguments of this field into the specified type
32    pub fn arguments<'de, T>(&self, values: ArgumentValues<'de>) -> Result<T, SdkError>
33    where
34        T: Deserialize<'de>,
35    {
36        match self.field.arguments {
37            Some(id) => values.get(id.into()),
38            None => Err(SdkError::from("Field has no arguments".to_string())),
39        }
40    }
41
42    /// Deserializes the arguments of this field into the specified type with the given seed.
43    pub fn arguments_seed<'de, Seed>(&self, seed: Seed, values: ArgumentValues<'de>) -> Result<Seed::Value, SdkError>
44    where
45        Seed: DeserializeSeed<'de>,
46    {
47        match self.field.arguments {
48            Some(id) => values.get_seed(id.into(), seed),
49            None => Err(SdkError::from("Field has no arguments".to_string())),
50        }
51    }
52
53    /// Gets the selection set of this field
54    pub fn selection_set(&self) -> SelectionSet<'a> {
55        self.field
56            .selection_set
57            .map(|selection_set| SelectionSet {
58                fields: self.fields,
59                selection_set,
60            })
61            .unwrap_or_else(|| SelectionSet {
62                fields: &[],
63                selection_set: wit::SelectionSet {
64                    fields_ordered_by_parent_entity: (0, 0),
65                    requires_typename: false,
66                },
67            })
68    }
69
70    /// Serialize the field and its selection set
71    pub fn into_bytes(&self) -> Vec<u8> {
72        postcard::to_stdvec(&Data {
73            fields: Cow::Borrowed(self.fields),
74            ix: element_offset(self.fields, self.field).unwrap(),
75        })
76        .unwrap()
77    }
78
79    /// Deserialize a field and its selection set
80    pub fn with_bytes<T>(data: &[u8], f: impl FnOnce(Field<'_>) -> T) -> Result<T, SdkError> {
81        match postcard::from_bytes(data) {
82            Ok(Data { fields, ix }) => {
83                let field = fields.get(ix).ok_or("Field index out of bounds")?;
84                Ok(f(Field {
85                    fields: fields.as_ref(),
86                    field,
87                }))
88            }
89            Err(err) => Err(format!("Failed to deserialize field data: {err}").into()),
90        }
91    }
92}
93
94// std::lice::element_offset which is unstable
95fn element_offset(slice: &[wit::Field], element: &wit::Field) -> Option<usize> {
96    let self_start = slice.as_ptr().addr();
97    let elem_start = std::ptr::from_ref(element).addr();
98
99    let byte_offset = elem_start.wrapping_sub(self_start);
100
101    if byte_offset % std::mem::size_of::<wit::Field>() != 0 {
102        return None;
103    }
104
105    let offset = byte_offset / std::mem::size_of::<wit::Field>();
106
107    if offset < slice.len() { Some(offset) } else { None }
108}
109
110#[derive(serde::Serialize, serde::Deserialize)]
111struct Data<'a> {
112    fields: Cow<'a, [wit::Field]>,
113    ix: usize,
114}
115
116/// Represents a selection set in a GraphQL query
117///
118/// A selection set is a group of fields selected together in a query.
119#[derive(Clone, Copy)]
120pub struct SelectionSet<'a> {
121    fields: &'a [wit::Field],
122    selection_set: wit::SelectionSet,
123}
124
125impl<'a> SelectionSet<'a> {
126    /// Whether this selection set is empty. Can only happen for scalars and enums.
127    pub fn is_empty(&self) -> bool {
128        self.fields().len() == 0
129    }
130
131    /// Iterator of the fields of this selection set. For best performance, you should respect the
132    /// field ordering in the resolver data.
133    pub fn fields(&self) -> impl ExactSizeIterator<Item = Field<'a>> + 'a {
134        self.fields_ordered_by_parent_entity()
135    }
136
137    /// Iterator over the fields in this selection set, ordered by their parent entity. However, how parent
138    /// entities are ordered (by id, name, etc.) is undefined. For best performance, you should respect the
139    /// field ordering in the resolver data.
140    pub fn fields_ordered_by_parent_entity(&self) -> impl ExactSizeIterator<Item = Field<'a>> + 'a {
141        let (start, end) = self.selection_set.fields_ordered_by_parent_entity;
142        let fields = self.fields;
143        fields[usize::from(start)..usize::from(end)]
144            .iter()
145            .map(move |field| Field { fields, field })
146    }
147
148    /// Whether this selection set requires a `__typename` field
149    /// The Gateway doesn't need the typename for objects and for various simple cases. But if
150    /// multiple type conditions are applied, it'll be required.
151    pub fn requires_typename(&self) -> bool {
152        self.selection_set.requires_typename
153    }
154}
155
156/// Identifier for arguments in a GraphQL query
157#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
158pub struct ArgumentsId(wit::ArgumentsId);
159
160impl From<wit::ArgumentsId> for ArgumentsId {
161    fn from(id: wit::ArgumentsId) -> Self {
162        Self(id)
163    }
164}
165
166/// All argument values for a given selection set, to be used with [Field].
167#[derive(Clone, Copy)]
168pub struct ArgumentValues<'a>(pub(crate) &'a [(wit::ArgumentsId, Vec<u8>)]);
169
170impl<'a> ArgumentValues<'a> {
171    /// Deserializes the arguments of this field into the specified type
172    pub fn get<T>(&self, id: ArgumentsId) -> Result<T, SdkError>
173    where
174        T: Deserialize<'a>,
175    {
176        let bytes = self.get_bytes(id);
177        crate::cbor::from_slice(bytes).map_err(Into::into)
178    }
179
180    /// Deserializes the arguments of this field into the specified type with the given seed.
181    pub fn get_seed<Seed>(&self, id: ArgumentsId, seed: Seed) -> Result<Seed::Value, SdkError>
182    where
183        Seed: DeserializeSeed<'a>,
184    {
185        let bytes = self.get_bytes(id);
186        crate::cbor::from_slice_with_seed(bytes, seed).map_err(Into::into)
187    }
188
189    fn get_bytes(&self, id: ArgumentsId) -> &'a [u8] {
190        self.0
191            .iter()
192            .find_map(|(args_id, args)| if *args_id == id.0 { Some(args.as_slice()) } else { None })
193            .unwrap()
194    }
195}