grafbase_sdk/types/elements/
query.rs

1use std::iter::Enumerate;
2
3use crate::{
4    types::{authorization::private::QueryElementOrResponseItem, DirectiveSite},
5    wit, SdkError,
6};
7use serde::Deserialize;
8
9/// A list of elements present in the query on which one of the extension's directive was applied on their definition.
10#[derive(Clone, Copy)]
11pub struct QueryElements<'a>(&'a wit::QueryElements);
12
13impl<'a> From<&'a wit::QueryElements> for QueryElements<'a> {
14    fn from(value: &'a wit::QueryElements) -> Self {
15        Self(value)
16    }
17}
18
19// is never empty, otherwise we wouldn't call the extension at all
20#[allow(clippy::len_without_is_empty)]
21impl<'a> QueryElements<'a> {
22    /// Number of elements within the query
23    pub fn len(&self) -> usize {
24        self.0.elements.len()
25    }
26
27    /// Iterate over all elements, regardless of the directive they're associated with. Useful if
28    /// expect only one directive to be used.
29    pub fn iter(&self) -> impl ExactSizeIterator<Item = QueryElement<'a>> + 'a {
30        (*self).into_iter()
31    }
32
33    /// Iterate over all elements grouped by the directive name.
34    pub fn iter_grouped_by_directive_name(
35        &self,
36    ) -> impl ExactSizeIterator<Item = (&'a str, impl ExactSizeIterator<Item = QueryElement<'a>> + 'a)> + 'a {
37        let query = self.0;
38        self.0.directive_names.iter().map(|(name, start, end)| {
39            let start = *start;
40            (
41                name.as_str(),
42                query.elements[start as usize..*end as usize]
43                    .iter()
44                    .enumerate()
45                    .map(move |(i, element)| QueryElement {
46                        element,
47                        ix: start + i as u32,
48                    }),
49            )
50        })
51    }
52}
53
54impl<'a> IntoIterator for QueryElements<'a> {
55    type Item = QueryElement<'a>;
56    type IntoIter = QueryElementsIterator<'a>;
57    fn into_iter(self) -> Self::IntoIter {
58        QueryElementsIterator(self.0.elements.iter().enumerate())
59    }
60}
61
62/// Iterator over the elements of the query on which a directive was applied.
63pub struct QueryElementsIterator<'a>(Enumerate<std::slice::Iter<'a, wit::QueryElement>>);
64
65impl ExactSizeIterator for QueryElementsIterator<'_> {}
66
67impl<'a> Iterator for QueryElementsIterator<'a> {
68    type Item = QueryElement<'a>;
69    fn next(&mut self) -> Option<Self::Item> {
70        self.0
71            .next()
72            .map(move |(ix, element)| QueryElement { element, ix: ix as u32 })
73    }
74    fn size_hint(&self) -> (usize, Option<usize>) {
75        self.0.size_hint()
76    }
77}
78
79impl crate::sealed::Sealed for QueryElement<'_> {}
80impl QueryElementOrResponseItem for QueryElement<'_> {
81    fn ix(&self) -> u32 {
82        self.ix
83    }
84}
85
86/// An element of the query on which a directive was applied.
87#[derive(Clone, Copy)]
88pub struct QueryElement<'a> {
89    element: &'a wit::QueryElement,
90    ix: u32,
91}
92
93/// An identifier for a query element. Only relevant for response authorization as data provided in
94/// `authorize_query` won't be re-sent in `authorize_response`. So this ID allows finding the
95/// relevant data in the custom state.
96#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize)]
97pub struct QueryElementId(pub(super) u32);
98
99impl From<QueryElementId> for u32 {
100    fn from(value: QueryElementId) -> u32 {
101        value.0
102    }
103}
104
105impl std::fmt::Display for QueryElementId {
106    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107        write!(f, "{}", self.0)
108    }
109}
110
111impl<'a> QueryElement<'a> {
112    /// ID of the query element, only relevant for response authorization.
113    pub fn id(&self) -> QueryElementId {
114        QueryElementId(self.element.id)
115    }
116
117    /// Directive site, where and with which arguments, of the directive associated with this element.
118    /// The provided arguments will exclude anything that depend on response data such as
119    /// `FieldSet`.
120    pub fn directive_site(&self) -> DirectiveSite<'a> {
121        (&self.element.site).into()
122    }
123
124    /// Arguments of the directive with any query data injected. Any argument that depends on
125    /// response data will not be present here and be provided separately.
126    pub fn directive_arguments<T>(&self) -> Result<T, SdkError>
127    where
128        T: Deserialize<'a>,
129    {
130        minicbor_serde::from_slice(&self.element.arguments).map_err(Into::into)
131    }
132}