Skip to main content

async_graphql/
context.rs

1//! Query context.
2
3use std::{
4    any::{Any, TypeId},
5    collections::HashMap,
6    fmt::{self, Debug, Display, Formatter},
7    ops::Deref,
8    sync::{Arc, Mutex},
9};
10
11use async_graphql_parser::types::ConstDirective;
12use async_graphql_value::{Value as InputValue, Variables};
13use indexmap::IndexMap;
14use rustc_hash::FxHashMap;
15use serde::{
16    Serialize,
17    ser::{SerializeSeq, Serializer},
18};
19
20use crate::{
21    Error, InputType, Lookahead, Name, OneofObjectType, PathSegment, Pos, Positioned, Result,
22    ServerError, ServerResult, UploadValue, Value,
23    extensions::Extensions,
24    parser::types::{
25        Directive, Field, FragmentDefinition, OperationDefinition, Selection, SelectionSet,
26    },
27    schema::{IntrospectionMode, SchemaEnv},
28};
29
30/// Data related functions of the context.
31pub trait DataContext<'a> {
32    /// Gets the global data defined in the `Context` or `Schema`.
33    ///
34    /// If both `Schema` and `Query` have the same data type, the data in the
35    /// `Query` is obtained.
36    ///
37    /// # Errors
38    ///
39    /// Returns a `Error` if the specified type data does not exist.
40    fn data<D: Any + Send + Sync>(&self) -> Result<&'a D>;
41
42    /// Gets the global data defined in the `Context` or `Schema`.
43    ///
44    /// # Panics
45    ///
46    /// It will panic if the specified data type does not exist.
47    fn data_unchecked<D: Any + Send + Sync>(&self) -> &'a D;
48
49    /// Gets the global data defined in the `Context` or `Schema` or `None` if
50    /// the specified type data does not exist.
51    fn data_opt<D: Any + Send + Sync>(&self) -> Option<&'a D>;
52}
53
54/// Schema/Context data.
55///
56/// This is a type map, allowing you to store anything inside it.
57#[derive(Default)]
58pub struct Data(FxHashMap<TypeId, Box<dyn Any + Sync + Send>>);
59
60impl Deref for Data {
61    type Target = FxHashMap<TypeId, Box<dyn Any + Sync + Send>>;
62
63    fn deref(&self) -> &Self::Target {
64        &self.0
65    }
66}
67
68impl Data {
69    /// Insert data.
70    pub fn insert<D: Any + Send + Sync>(&mut self, data: D) {
71        self.0.insert(TypeId::of::<D>(), Box::new(data));
72    }
73
74    pub(crate) fn merge(&mut self, other: Data) {
75        self.0.extend(other.0);
76    }
77}
78
79impl Debug for Data {
80    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
81        f.debug_tuple("Data").finish()
82    }
83}
84
85/// Context for `SelectionSet`
86pub type ContextSelectionSet<'a> = ContextBase<'a, &'a Positioned<SelectionSet>>;
87
88/// Context object for resolve field
89pub type Context<'a> = ContextBase<'a, &'a Positioned<Field>>;
90
91/// Context object for execute directive.
92pub type ContextDirective<'a> = ContextBase<'a, &'a Positioned<Directive>>;
93
94/// A segment in the path to the current query.
95///
96/// This is a borrowed form of [`PathSegment`](enum.PathSegment.html) used
97/// during execution instead of passed back when errors occur.
98#[derive(Debug, Clone, Copy, Serialize)]
99#[serde(untagged)]
100pub enum QueryPathSegment<'a> {
101    /// We are currently resolving an element in a list.
102    Index(usize),
103    /// We are currently resolving a field in an object.
104    Name(&'a str),
105}
106
107/// A path to the current query.
108///
109/// The path is stored as a kind of reverse linked list.
110#[derive(Debug, Clone, Copy)]
111pub struct QueryPathNode<'a> {
112    /// The parent node to this, if there is one.
113    pub parent: Option<&'a QueryPathNode<'a>>,
114
115    /// The current path segment being resolved.
116    pub segment: QueryPathSegment<'a>,
117}
118
119impl serde::Serialize for QueryPathNode<'_> {
120    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
121        let mut seq = serializer.serialize_seq(None)?;
122        self.try_for_each(|segment| seq.serialize_element(segment))?;
123        seq.end()
124    }
125}
126
127impl Display for QueryPathNode<'_> {
128    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
129        let mut first = true;
130        self.try_for_each(|segment| {
131            if !first {
132                write!(f, ".")?;
133            }
134            first = false;
135
136            match segment {
137                QueryPathSegment::Index(idx) => write!(f, "{}", *idx),
138                QueryPathSegment::Name(name) => write!(f, "{}", name),
139            }
140        })
141    }
142}
143
144impl<'a> QueryPathNode<'a> {
145    /// Get the current field name.
146    ///
147    /// This traverses all the parents of the node until it finds one that is a
148    /// field name.
149    pub fn field_name(&self) -> &str {
150        std::iter::once(self)
151            .chain(self.parents())
152            .find_map(|node| match node.segment {
153                QueryPathSegment::Name(name) => Some(name),
154                QueryPathSegment::Index(_) => None,
155            })
156            .unwrap()
157    }
158
159    /// Get the path represented by `Vec<String>`; numbers will be stringified.
160    #[must_use]
161    pub fn to_string_vec(self) -> Vec<String> {
162        let mut res = Vec::new();
163        self.for_each(|s| {
164            res.push(match s {
165                QueryPathSegment::Name(name) => (*name).to_string(),
166                QueryPathSegment::Index(idx) => idx.to_string(),
167            });
168        });
169        res
170    }
171
172    /// Iterate over the parents of the node.
173    pub fn parents(&self) -> Parents<'_> {
174        Parents(self)
175    }
176
177    pub(crate) fn for_each<F: FnMut(&QueryPathSegment<'a>)>(&self, mut f: F) {
178        let _ = self.try_for_each::<std::convert::Infallible, _>(|segment| {
179            f(segment);
180            Ok(())
181        });
182    }
183
184    pub(crate) fn try_for_each<E, F: FnMut(&QueryPathSegment<'a>) -> Result<(), E>>(
185        &self,
186        mut f: F,
187    ) -> Result<(), E> {
188        self.try_for_each_ref(&mut f)
189    }
190
191    fn try_for_each_ref<E, F: FnMut(&QueryPathSegment<'a>) -> Result<(), E>>(
192        &self,
193        f: &mut F,
194    ) -> Result<(), E> {
195        if let Some(parent) = &self.parent {
196            parent.try_for_each_ref(f)?;
197        }
198        f(&self.segment)
199    }
200}
201
202/// An iterator over the parents of a
203/// [`QueryPathNode`](struct.QueryPathNode.html).
204#[derive(Debug, Clone)]
205pub struct Parents<'a>(&'a QueryPathNode<'a>);
206
207impl<'a> Parents<'a> {
208    /// Get the current query path node, which the next call to `next` will get
209    /// the parents of.
210    #[must_use]
211    pub fn current(&self) -> &'a QueryPathNode<'a> {
212        self.0
213    }
214}
215
216impl<'a> Iterator for Parents<'a> {
217    type Item = &'a QueryPathNode<'a>;
218
219    fn next(&mut self) -> Option<Self::Item> {
220        let parent = self.0.parent;
221        if let Some(parent) = parent {
222            self.0 = parent;
223        }
224        parent
225    }
226}
227
228impl std::iter::FusedIterator for Parents<'_> {}
229
230/// Query context.
231///
232/// **This type is not stable and should not be used directly.**
233#[derive(Clone)]
234pub struct ContextBase<'a, T> {
235    /// The current path node being resolved.
236    pub path_node: Option<QueryPathNode<'a>>,
237    /// If `true` means the current field is for introspection.
238    pub(crate) is_for_introspection: bool,
239    #[doc(hidden)]
240    pub item: T,
241    #[doc(hidden)]
242    pub schema_env: &'a SchemaEnv,
243    #[doc(hidden)]
244    pub query_env: &'a QueryEnv,
245    #[doc(hidden)]
246    pub execute_data: Option<&'a Data>,
247}
248
249#[doc(hidden)]
250pub struct QueryEnvInner {
251    pub extensions: Extensions,
252    pub variables: Variables,
253    pub operation_name: Option<String>,
254    pub operation: Positioned<OperationDefinition>,
255    pub fragments: HashMap<Name, Positioned<FragmentDefinition>>,
256    pub uploads: Vec<UploadValue>,
257    pub session_data: Arc<Data>,
258    pub query_data: Arc<Data>,
259    pub http_headers: Mutex<http::HeaderMap>,
260    pub introspection_mode: IntrospectionMode,
261    pub errors: Mutex<Vec<ServerError>>,
262}
263
264#[doc(hidden)]
265#[derive(Clone)]
266pub struct QueryEnv(Arc<QueryEnvInner>);
267
268impl Deref for QueryEnv {
269    type Target = QueryEnvInner;
270
271    fn deref(&self) -> &Self::Target {
272        &self.0
273    }
274}
275
276impl QueryEnv {
277    #[doc(hidden)]
278    pub fn new(inner: QueryEnvInner) -> QueryEnv {
279        QueryEnv(Arc::new(inner))
280    }
281
282    #[doc(hidden)]
283    pub fn create_context<'a, T>(
284        &'a self,
285        schema_env: &'a SchemaEnv,
286        path_node: Option<QueryPathNode<'a>>,
287        item: T,
288        execute_data: Option<&'a Data>,
289    ) -> ContextBase<'a, T> {
290        ContextBase {
291            path_node,
292            is_for_introspection: false,
293            item,
294            schema_env,
295            query_env: self,
296            execute_data,
297        }
298    }
299}
300
301impl<'a, T> DataContext<'a> for ContextBase<'a, T> {
302    fn data<D: Any + Send + Sync>(&self) -> Result<&'a D> {
303        ContextBase::data::<D>(self)
304    }
305
306    fn data_unchecked<D: Any + Send + Sync>(&self) -> &'a D {
307        ContextBase::data_unchecked::<D>(self)
308    }
309
310    fn data_opt<D: Any + Send + Sync>(&self) -> Option<&'a D> {
311        ContextBase::data_opt::<D>(self)
312    }
313}
314
315impl<'a, T> ContextBase<'a, T> {
316    #[doc(hidden)]
317    pub fn with_field(
318        &'a self,
319        field: &'a Positioned<Field>,
320    ) -> ContextBase<'a, &'a Positioned<Field>> {
321        ContextBase {
322            path_node: Some(QueryPathNode {
323                parent: self.path_node.as_ref(),
324                segment: QueryPathSegment::Name(&field.node.response_key().node),
325            }),
326            is_for_introspection: self.is_for_introspection,
327            item: field,
328            schema_env: self.schema_env,
329            query_env: self.query_env,
330            execute_data: self.execute_data,
331        }
332    }
333
334    #[doc(hidden)]
335    pub fn with_selection_set(
336        &self,
337        selection_set: &'a Positioned<SelectionSet>,
338    ) -> ContextBase<'a, &'a Positioned<SelectionSet>> {
339        ContextBase {
340            path_node: self.path_node,
341            is_for_introspection: self.is_for_introspection,
342            item: selection_set,
343            schema_env: self.schema_env,
344            query_env: self.query_env,
345            execute_data: self.execute_data,
346        }
347    }
348
349    #[doc(hidden)]
350    pub fn set_error_path(&self, error: ServerError) -> ServerError {
351        if let Some(node) = self.path_node {
352            let mut path = Vec::new();
353            node.for_each(|current_node| {
354                path.push(match current_node {
355                    QueryPathSegment::Name(name) => PathSegment::Field((*name).to_string()),
356                    QueryPathSegment::Index(idx) => PathSegment::Index(*idx),
357                })
358            });
359            ServerError { path, ..error }
360        } else {
361            error
362        }
363    }
364
365    /// Report a resolver error.
366    ///
367    /// When implementing `OutputType`, if an error occurs, call this function
368    /// to report this error and return `Value::Null`.
369    pub fn add_error(&self, error: ServerError) {
370        self.query_env.errors.lock().unwrap().push(error);
371    }
372
373    /// Gets the global data defined in the `Context` or `Schema`.
374    ///
375    /// If both `Schema` and `Query` have the same data type, the data in the
376    /// `Query` is obtained.
377    ///
378    /// # Errors
379    ///
380    /// Returns a `Error` if the specified type data does not exist.
381    pub fn data<D: Any + Send + Sync>(&self) -> Result<&'a D> {
382        self.data_opt::<D>().ok_or_else(|| {
383            Error::new(format!(
384                "Data `{}` does not exist.",
385                std::any::type_name::<D>()
386            ))
387        })
388    }
389
390    /// Gets the global data defined in the `Context` or `Schema`.
391    ///
392    /// # Panics
393    ///
394    /// It will panic if the specified data type does not exist.
395    pub fn data_unchecked<D: Any + Send + Sync>(&self) -> &'a D {
396        self.data_opt::<D>()
397            .unwrap_or_else(|| panic!("Data `{}` does not exist.", std::any::type_name::<D>()))
398    }
399
400    /// Gets the global data defined in the `Context` or `Schema` or `None` if
401    /// the specified type data does not exist.
402    pub fn data_opt<D: Any + Send + Sync>(&self) -> Option<&'a D> {
403        self.execute_data
404            .as_ref()
405            .and_then(|execute_data| execute_data.get(&TypeId::of::<D>()))
406            .or_else(|| self.query_env.query_data.0.get(&TypeId::of::<D>()))
407            .or_else(|| self.query_env.session_data.0.get(&TypeId::of::<D>()))
408            .or_else(|| self.schema_env.data.0.get(&TypeId::of::<D>()))
409            .and_then(|d| d.downcast_ref::<D>())
410    }
411
412    /// Returns whether the HTTP header `key` is currently set on the response
413    ///
414    /// # Examples
415    ///
416    /// ```no_run
417    /// use ::http::header::ACCESS_CONTROL_ALLOW_ORIGIN;
418    /// use async_graphql::*;
419    ///
420    /// struct Query;
421    ///
422    /// #[Object]
423    /// impl Query {
424    ///     async fn greet(&self, ctx: &Context<'_>) -> String {
425    ///         let header_exists = ctx.http_header_contains("Access-Control-Allow-Origin");
426    ///         assert!(!header_exists);
427    ///
428    ///         ctx.insert_http_header(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
429    ///
430    ///         let header_exists = ctx.http_header_contains("Access-Control-Allow-Origin");
431    ///         assert!(header_exists);
432    ///
433    ///         String::from("Hello world")
434    ///     }
435    /// }
436    /// ```
437    pub fn http_header_contains(&self, key: impl http::header::AsHeaderName) -> bool {
438        self.query_env
439            .http_headers
440            .lock()
441            .unwrap()
442            .contains_key(key)
443    }
444
445    /// Sets a HTTP header to response.
446    ///
447    /// If the header was not currently set on the response, then `None` is
448    /// returned.
449    ///
450    /// If the response already contained this header then the new value is
451    /// associated with this key and __all the previous values are
452    /// removed__, however only a the first previous value is returned.
453    ///
454    /// See [`http::HeaderMap`] for more details on the underlying
455    /// implementation
456    ///
457    /// # Examples
458    ///
459    /// ```no_run
460    /// use ::http::{HeaderValue, header::ACCESS_CONTROL_ALLOW_ORIGIN};
461    /// use async_graphql::*;
462    ///
463    /// struct Query;
464    ///
465    /// #[Object]
466    /// impl Query {
467    ///     async fn greet(&self, ctx: &Context<'_>) -> String {
468    ///         // Headers can be inserted using the `http` constants
469    ///         let was_in_headers = ctx.insert_http_header(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
470    ///         assert_eq!(was_in_headers, None);
471    ///
472    ///         // They can also be inserted using &str
473    ///         let was_in_headers = ctx.insert_http_header("Custom-Header", "1234");
474    ///         assert_eq!(was_in_headers, None);
475    ///
476    ///         // If multiple headers with the same key are `inserted` then the most recent
477    ///         // one overwrites the previous. If you want multiple headers for the same key, use
478    ///         // `append_http_header` for subsequent headers
479    ///         let was_in_headers = ctx.insert_http_header("Custom-Header", "Hello World");
480    ///         assert_eq!(was_in_headers, Some(HeaderValue::from_static("1234")));
481    ///
482    ///         String::from("Hello world")
483    ///     }
484    /// }
485    /// ```
486    pub fn insert_http_header(
487        &self,
488        name: impl http::header::IntoHeaderName,
489        value: impl TryInto<http::HeaderValue>,
490    ) -> Option<http::HeaderValue> {
491        if let Ok(value) = value.try_into() {
492            self.query_env
493                .http_headers
494                .lock()
495                .unwrap()
496                .insert(name, value)
497        } else {
498            None
499        }
500    }
501
502    /// Sets a HTTP header to response.
503    ///
504    /// If the header was not currently set on the response, then `false` is
505    /// returned.
506    ///
507    /// If the response did have this header then the new value is appended to
508    /// the end of the list of values currently associated with the key,
509    /// however the key is not updated _(which is important for types that
510    /// can be `==` without being identical)_.
511    ///
512    /// See [`http::HeaderMap`] for more details on the underlying
513    /// implementation
514    ///
515    /// # Examples
516    ///
517    /// ```no_run
518    /// use ::http::header::SET_COOKIE;
519    /// use async_graphql::*;
520    ///
521    /// struct Query;
522    ///
523    /// #[Object]
524    /// impl Query {
525    ///     async fn greet(&self, ctx: &Context<'_>) -> String {
526    ///         // Insert the first instance of the header
527    ///         ctx.insert_http_header(SET_COOKIE, "Chocolate Chip");
528    ///
529    ///         // Subsequent values should be appended
530    ///         let header_already_exists = ctx.append_http_header("Set-Cookie", "Macadamia");
531    ///         assert!(header_already_exists);
532    ///
533    ///         String::from("Hello world")
534    ///     }
535    /// }
536    /// ```
537    pub fn append_http_header(
538        &self,
539        name: impl http::header::IntoHeaderName,
540        value: impl TryInto<http::HeaderValue>,
541    ) -> bool {
542        if let Ok(value) = value.try_into() {
543            self.query_env
544                .http_headers
545                .lock()
546                .unwrap()
547                .append(name, value)
548        } else {
549            false
550        }
551    }
552
553    fn var_value(&self, name: &str, pos: Pos) -> ServerResult<Option<Value>> {
554        let def = self
555            .query_env
556            .operation
557            .node
558            .variable_definitions
559            .iter()
560            .find(|def| def.node.name.node == name)
561            .ok_or_else(|| {
562                ServerError::new(format!("Variable {} is not defined.", name), Some(pos))
563            })?;
564
565        // Preserve omitted variables as `None`; only explicit variable defaults become
566        // values.
567        Ok(self
568            .query_env
569            .variables
570            .get(&def.node.name.node)
571            .cloned()
572            .or_else(|| {
573                def.node
574                    .default_value
575                    .as_ref()
576                    .map(|value| value.node.clone())
577            }))
578    }
579
580    fn resolve_input_value_inner(
581        &self,
582        value: InputValue,
583        pos: Pos,
584    ) -> ServerResult<Option<Value>> {
585        Ok(match value {
586            InputValue::Variable(name) => self.var_value(&name, pos)?,
587            InputValue::Null => Some(Value::Null),
588            InputValue::Number(num) => Some(Value::Number(num)),
589            InputValue::String(value) => Some(Value::String(value)),
590            InputValue::Boolean(value) => Some(Value::Boolean(value)),
591            InputValue::Binary(value) => Some(Value::Binary(value)),
592            InputValue::Enum(value) => Some(Value::Enum(value)),
593            InputValue::List(items) => {
594                let mut resolved_items = Vec::with_capacity(items.len());
595                for item in items {
596                    // Lists still need a concrete slot value, so omitted entries become `null`.
597                    resolved_items.push(
598                        self.resolve_input_value_inner(item, pos)?
599                            .unwrap_or(Value::Null),
600                    );
601                }
602                Some(Value::List(resolved_items))
603            }
604            InputValue::Object(object) => {
605                let mut resolved_object = IndexMap::with_capacity(object.len());
606                for (name, value) in object {
607                    // Omit object fields whose variables were not provided.
608                    if let Some(value) = self.resolve_input_value_inner(value, pos)? {
609                        resolved_object.insert(name, value);
610                    }
611                }
612                Some(Value::Object(resolved_object))
613            }
614        })
615    }
616
617    pub(crate) fn resolve_input_value(
618        &self,
619        value: Positioned<InputValue>,
620    ) -> ServerResult<Option<Value>> {
621        self.resolve_input_value_inner(value.node, value.pos)
622    }
623
624    #[doc(hidden)]
625    fn get_param_value<Q: InputType>(
626        &self,
627        arguments: &[(Positioned<Name>, Positioned<InputValue>)],
628        name: &str,
629        default: Option<fn() -> Q>,
630    ) -> ServerResult<(Pos, Q)> {
631        let value = arguments
632            .iter()
633            .find(|(n, _)| n.node.as_str() == name)
634            .map(|(_, value)| value)
635            .cloned();
636        if value.is_none()
637            && let Some(default) = default
638        {
639            return Ok((Pos::default(), default()));
640        }
641        let (pos, value) = match value {
642            Some(value) => (value.pos, self.resolve_input_value(value)?),
643            None => (Pos::default(), None),
644        };
645        InputType::parse(value)
646            .map(|value| (pos, value))
647            .map_err(|e| e.into_server_error(pos))
648    }
649
650    #[doc(hidden)]
651    #[must_use]
652    pub fn with_index(&'a self, idx: usize) -> ContextBase<'a, T>
653    where
654        T: Copy,
655    {
656        ContextBase {
657            path_node: Some(QueryPathNode {
658                parent: self.path_node.as_ref(),
659                segment: QueryPathSegment::Index(idx),
660            }),
661            is_for_introspection: self.is_for_introspection,
662            item: self.item,
663            schema_env: self.schema_env,
664            query_env: self.query_env,
665            execute_data: self.execute_data,
666        }
667    }
668}
669
670impl<'a> ContextBase<'a, &'a Positioned<Field>> {
671    #[doc(hidden)]
672    pub fn param_value<T: InputType>(
673        &self,
674        name: &str,
675        default: Option<fn() -> T>,
676    ) -> ServerResult<(Pos, T)> {
677        self.get_param_value(&self.item.node.arguments, name, default)
678    }
679
680    #[doc(hidden)]
681    pub fn oneof_param_value<T: OneofObjectType>(&self) -> ServerResult<(Pos, T)> {
682        use indexmap::IndexMap;
683
684        let mut map = IndexMap::new();
685
686        for (name, value) in &self.item.node.arguments {
687            // Skip omitted variable-backed arguments so input objects can observe
688            // `Undefined`.
689            if let Some(value) = self.resolve_input_value(value.clone())? {
690                map.insert(name.node.clone(), value);
691            }
692        }
693
694        InputType::parse(Some(Value::Object(map)))
695            .map(|value| (self.item.pos, value))
696            .map_err(|e| e.into_server_error(self.item.pos))
697    }
698
699    /// Creates a uniform interface to inspect the forthcoming selections.
700    ///
701    /// # Examples
702    ///
703    /// ```no_run
704    /// use async_graphql::*;
705    ///
706    /// #[derive(SimpleObject)]
707    /// struct Detail {
708    ///     c: i32,
709    ///     d: i32,
710    /// }
711    ///
712    /// #[derive(SimpleObject)]
713    /// struct MyObj {
714    ///     a: i32,
715    ///     b: i32,
716    ///     detail: Detail,
717    /// }
718    ///
719    /// struct Query;
720    ///
721    /// #[Object]
722    /// impl Query {
723    ///     async fn obj(&self, ctx: &Context<'_>) -> MyObj {
724    ///         if ctx.look_ahead().field("a").exists() {
725    ///             // This is a query like `obj { a }`
726    ///         } else if ctx.look_ahead().field("detail").field("c").exists() {
727    ///             // This is a query like `obj { detail { c } }`
728    ///         } else {
729    ///             // This query doesn't have `a`
730    ///         }
731    ///         unimplemented!()
732    ///     }
733    /// }
734    /// ```
735    pub fn look_ahead(&self) -> Lookahead<'_> {
736        Lookahead::new(&self.query_env.fragments, &self.item.node, self)
737    }
738
739    /// Get the current field.
740    ///
741    /// # Examples
742    ///
743    /// ```rust
744    /// use async_graphql::*;
745    ///
746    /// #[derive(SimpleObject)]
747    /// struct MyObj {
748    ///     a: i32,
749    ///     b: i32,
750    ///     c: i32,
751    /// }
752    ///
753    /// pub struct Query;
754    ///
755    /// #[Object]
756    /// impl Query {
757    ///     async fn obj(&self, ctx: &Context<'_>) -> MyObj {
758    ///         let fields = ctx
759    ///             .field()
760    ///             .selection_set()
761    ///             .map(|field| field.name())
762    ///             .collect::<Vec<_>>();
763    ///         assert_eq!(fields, vec!["a", "b", "c"]);
764    ///         MyObj { a: 1, b: 2, c: 3 }
765    ///     }
766    /// }
767    ///
768    /// # tokio::runtime::Runtime::new().unwrap().block_on(async move {
769    /// let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
770    /// assert!(schema.execute("{ obj { a b c }}").await.is_ok());
771    /// assert!(schema.execute("{ obj { a ... { b c } }}").await.is_ok());
772    /// assert!(
773    ///     schema
774    ///         .execute("{ obj { a ... BC }} fragment BC on MyObj { b c }")
775    ///         .await
776    ///         .is_ok()
777    /// );
778    /// # });
779    /// ```
780    pub fn field(&self) -> SelectionField<'_> {
781        SelectionField {
782            fragments: &self.query_env.fragments,
783            field: &self.item.node,
784            context: self,
785        }
786    }
787}
788
789impl<'a> ContextBase<'a, &'a Positioned<Directive>> {
790    #[doc(hidden)]
791    pub fn param_value<T: InputType>(
792        &self,
793        name: &str,
794        default: Option<fn() -> T>,
795    ) -> ServerResult<(Pos, T)> {
796        self.get_param_value(&self.item.node.arguments, name, default)
797    }
798}
799
800/// Selection field.
801#[derive(Clone, Copy)]
802pub struct SelectionField<'a> {
803    pub(crate) fragments: &'a HashMap<Name, Positioned<FragmentDefinition>>,
804    pub(crate) field: &'a Field,
805    pub(crate) context: &'a Context<'a>,
806}
807
808impl<'a> SelectionField<'a> {
809    /// Get the name of this field.
810    #[inline]
811    pub fn name(&self) -> &'a str {
812        self.field.name.node.as_str()
813    }
814
815    /// Get the alias of this field.
816    #[inline]
817    pub fn alias(&self) -> Option<&'a str> {
818        self.field.alias.as_ref().map(|alias| alias.node.as_str())
819    }
820
821    /// Get the directives of this field.
822    pub fn directives(&self) -> ServerResult<Vec<ConstDirective>> {
823        let mut directives = Vec::with_capacity(self.field.directives.len());
824
825        for directive in &self.field.directives {
826            let directive = &directive.node;
827
828            let mut arguments = Vec::with_capacity(directive.arguments.len());
829            for (name, value) in &directive.arguments {
830                // Preserve omission when exposing directive arguments through the context API.
831                if let Some(resolved_value) = self.context.resolve_input_value(value.clone())? {
832                    arguments.push((name.clone(), value.position_node(resolved_value)));
833                }
834            }
835
836            directives.push(ConstDirective {
837                name: directive.name.clone(),
838                arguments,
839            });
840        }
841
842        Ok(directives)
843    }
844
845    /// Get the arguments of this field.
846    pub fn arguments(&self) -> ServerResult<Vec<(Name, Value)>> {
847        let mut arguments = Vec::with_capacity(self.field.arguments.len());
848        for (name, value) in &self.field.arguments {
849            // Preserve omission when exposing field arguments through the context API.
850            if let Some(value) = self.context.resolve_input_value(value.clone())? {
851                arguments.push((name.node.clone(), value));
852            }
853        }
854        Ok(arguments)
855    }
856
857    /// Get all subfields of the current selection set.
858    pub fn selection_set(&self) -> impl Iterator<Item = SelectionField<'a>> {
859        SelectionFieldsIter {
860            fragments: self.fragments,
861            iter: vec![self.field.selection_set.node.items.iter()],
862            context: self.context,
863        }
864    }
865}
866
867impl Debug for SelectionField<'_> {
868    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
869        struct DebugSelectionSet<'a>(Vec<SelectionField<'a>>);
870
871        impl Debug for DebugSelectionSet<'_> {
872            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
873                f.debug_list().entries(&self.0).finish()
874            }
875        }
876
877        f.debug_struct(self.name())
878            .field("name", &self.name())
879            .field(
880                "selection_set",
881                &DebugSelectionSet(self.selection_set().collect()),
882            )
883            .finish()
884    }
885}
886
887struct SelectionFieldsIter<'a> {
888    fragments: &'a HashMap<Name, Positioned<FragmentDefinition>>,
889    iter: Vec<std::slice::Iter<'a, Positioned<Selection>>>,
890    context: &'a Context<'a>,
891}
892
893impl<'a> Iterator for SelectionFieldsIter<'a> {
894    type Item = SelectionField<'a>;
895
896    fn next(&mut self) -> Option<Self::Item> {
897        loop {
898            let it = self.iter.last_mut()?;
899            let item = it.next();
900
901            match item {
902                Some(selection) => match &selection.node {
903                    Selection::Field(field) => {
904                        return Some(SelectionField {
905                            fragments: self.fragments,
906                            field: &field.node,
907                            context: self.context,
908                        });
909                    }
910                    Selection::FragmentSpread(fragment_spread) => {
911                        if let Some(fragment) =
912                            self.fragments.get(&fragment_spread.node.fragment_name.node)
913                        {
914                            self.iter
915                                .push(fragment.node.selection_set.node.items.iter());
916                        }
917                    }
918                    Selection::InlineFragment(inline_fragment) => {
919                        self.iter
920                            .push(inline_fragment.node.selection_set.node.items.iter());
921                    }
922                },
923                None => {
924                    self.iter.pop();
925                }
926            }
927        }
928    }
929}