grafbase_sdk/types/elements/
query.rs

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