Clean up crate root and improve context

This commit is contained in:
Koxiaet 2020-10-15 06:55:30 +01:00
parent 29080f16bd
commit 4eaa9cb86e
3 changed files with 91 additions and 47 deletions

View File

@ -1,10 +1,11 @@
use std::borrow::Cow;
use crate::parser::types::Field; use crate::parser::types::Field;
use crate::registry::Registry; use crate::registry::Registry;
use crate::{ use crate::{
registry, ContainerType, ContextSelectionSet, InputValueResult, Positioned, Result, registry, ContainerType, ContextSelectionSet, InputValueResult, Positioned, Result,
ServerResult, Value, ServerResult, Value,
}; };
use std::borrow::Cow;
/// Represents a GraphQL type. /// Represents a GraphQL type.
/// ///

View File

@ -1,3 +1,17 @@
//! Query context.
use std::any::{Any, TypeId};
use std::collections::{BTreeMap, HashMap};
use std::convert::TryFrom;
use std::fmt::{self, Debug, Display, Formatter};
use std::ops::Deref;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
use fnv::FnvHashMap;
use serde::ser::{SerializeSeq, Serializer};
use serde::{Deserialize, Serialize};
use crate::extensions::Extensions; use crate::extensions::Extensions;
use crate::parser::types::{ use crate::parser::types::{
Directive, Field, FragmentDefinition, OperationDefinition, SelectionSet, Directive, Field, FragmentDefinition, OperationDefinition, SelectionSet,
@ -8,16 +22,6 @@ use crate::{
UploadValue, Value, UploadValue, Value,
}; };
use async_graphql_value::{Name, Value as InputValue}; use async_graphql_value::{Name, Value as InputValue};
use fnv::FnvHashMap;
use serde::ser::{SerializeSeq, Serializer};
use serde::{Deserialize, Serialize};
use std::any::{Any, TypeId};
use std::collections::{BTreeMap, HashMap};
use std::convert::TryFrom;
use std::fmt::{self, Debug, Display, Formatter};
use std::ops::Deref;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
/// Variables of a query. /// Variables of a query.
#[derive(Debug, Clone, Default, Deserialize, Serialize)] #[derive(Debug, Clone, Default, Deserialize, Serialize)]
@ -119,22 +123,27 @@ pub type ContextSelectionSet<'a> = ContextBase<'a, &'a Positioned<SelectionSet>>
/// Context object for resolve field /// Context object for resolve field
pub type Context<'a> = ContextBase<'a, &'a Positioned<Field>>; pub type Context<'a> = ContextBase<'a, &'a Positioned<Field>>;
/// The query path segment /// A segment in the path to the current query.
#[derive(Clone)] ///
/// This is a borrowed form of [`PathSegment`](enum.PathSegment.html) used during execution instead
/// of passed back when errors occur.
#[derive(Debug, Clone, Copy)]
pub enum QueryPathSegment<'a> { pub enum QueryPathSegment<'a> {
/// Index /// We are currently resolving an element in a list.
Index(usize), Index(usize),
/// Field name /// We are currently resolving a field in an object.
Name(&'a str), Name(&'a str),
} }
/// The query path node /// A path to the current query.
#[derive(Clone)] ///
/// The path is stored as a kind of reverse linked list.
#[derive(Debug, Clone, Copy)]
pub struct QueryPathNode<'a> { pub struct QueryPathNode<'a> {
/// Parent node /// The parent node to this, if there is one.
pub parent: Option<&'a QueryPathNode<'a>>, pub parent: Option<&'a QueryPathNode<'a>>,
/// Current path segment /// The current path segment being resolved.
pub segment: QueryPathSegment<'a>, pub segment: QueryPathSegment<'a>,
} }
@ -176,26 +185,31 @@ impl<'a> Display for QueryPathNode<'a> {
impl<'a> QueryPathNode<'a> { impl<'a> QueryPathNode<'a> {
/// Get the current field name. /// Get the current field name.
///
/// This traverses all the parents of the node until it finds one that is a field name.
pub fn field_name(&self) -> &str { pub fn field_name(&self) -> &str {
let mut p = self; self.parents().find_map(|node| match node.segment {
loop { QueryPathSegment::Name(name) => Some(name),
if let QueryPathSegment::Name(name) = &p.segment { QueryPathSegment::Index(_) => None,
return name; }).unwrap()
}
p = p.parent.unwrap();
}
} }
/// Get the path represented by `Vec<String>`. /// Get the path represented by `Vec<String>`; numbers will be stringified.
#[must_use]
pub fn to_string_vec(&self) -> Vec<String> { pub fn to_string_vec(&self) -> Vec<String> {
let mut res = Vec::new(); let mut res = Vec::new();
self.for_each(|s| match s { self.for_each(|s| res.push(match s {
QueryPathSegment::Index(idx) => res.push(format!("{}", idx)), QueryPathSegment::Name(name) => name.to_string(),
QueryPathSegment::Name(name) => res.push(name.to_string()), QueryPathSegment::Index(idx) => idx.to_string(),
}); }));
res res
} }
/// Iterate over the parents of the node.
pub fn parents(&self) -> Parents<'_> {
Parents(self)
}
pub(crate) fn for_each<F: FnMut(&QueryPathSegment<'a>)>(&self, mut f: F) { pub(crate) fn for_each<F: FnMut(&QueryPathSegment<'a>)>(&self, mut f: F) {
self.for_each_ref(&mut f); self.for_each_ref(&mut f);
} }
@ -208,13 +222,39 @@ impl<'a> QueryPathNode<'a> {
} }
} }
/// Represents the unique id of the resolve /// An iterator over the parents of a [`QueryPathNode`](struct.QueryPathNode.html).
#[derive(Copy, Clone, Debug)] #[derive(Debug, Clone)]
pub struct Parents<'a>(&'a QueryPathNode<'a>);
impl<'a> Parents<'a> {
/// Get the current query path node, which the next call to `next` will get the parents of.
#[must_use]
pub fn current(&self) -> &'a QueryPathNode<'a> {
self.0
}
}
impl<'a> Iterator for Parents<'a> {
type Item = &'a QueryPathNode<'a>;
fn next(&mut self) -> Option<Self::Item> {
let parent = self.0.parent;
if let Some(parent) = parent {
self.0 = parent;
}
parent
}
}
impl<'a> std::iter::FusedIterator for Parents<'a> {}
/// The unique id of the current resolusion.
#[derive(Debug, Clone, Copy)]
pub struct ResolveId { pub struct ResolveId {
/// Parent id /// The unique ID of the parent resolution.
pub parent: Option<usize>, pub parent: Option<usize>,
/// Current id /// The current unique id.
pub current: usize, pub current: usize,
} }
@ -238,7 +278,9 @@ impl Display for ResolveId {
} }
} }
/// Query context /// Query context.
///
/// **This type is not stable and should not be used directly.**
#[derive(Clone)] #[derive(Clone)]
pub struct ContextBase<'a, T> { pub struct ContextBase<'a, T> {
#[allow(missing_docs)] #[allow(missing_docs)]
@ -338,7 +380,7 @@ impl<'a, T> ContextBase<'a, T> {
selection_set: &'a Positioned<SelectionSet>, selection_set: &'a Positioned<SelectionSet>,
) -> ContextBase<'a, &'a Positioned<SelectionSet>> { ) -> ContextBase<'a, &'a Positioned<SelectionSet>> {
ContextBase { ContextBase {
path_node: self.path_node.clone(), path_node: self.path_node,
item: selection_set, item: selection_set,
resolve_id: self.resolve_id, resolve_id: self.resolve_id,
inc_resolve_id: &self.inc_resolve_id, inc_resolve_id: &self.inc_resolve_id,

View File

@ -113,7 +113,6 @@
#![cfg_attr(feature = "nightly", feature(doc_cfg))] #![cfg_attr(feature = "nightly", feature(doc_cfg))]
mod base; mod base;
mod context;
mod error; mod error;
mod look_ahead; mod look_ahead;
mod model; mod model;
@ -124,6 +123,7 @@ mod subscription;
mod validation; mod validation;
pub mod extensions; pub mod extensions;
pub mod context;
pub mod guard; pub mod guard;
pub mod http; pub mod http;
pub mod resolver_utils; pub mod resolver_utils;
@ -156,9 +156,6 @@ pub use async_graphql_value::{
pub use base::{ pub use base::{
InputObjectType, InputValueType, InterfaceType, ObjectType, OutputValueType, Type, UnionType, InputObjectType, InputValueType, InterfaceType, ObjectType, OutputValueType, Type, UnionType,
}; };
pub use context::{
Context, ContextBase, Data, QueryEnv, QueryPathNode, QueryPathSegment, ResolveId, Variables,
};
pub use error::{ pub use error::{
Error, ErrorExtensionValues, ErrorExtensions, InputValueError, InputValueResult, Error, ErrorExtensionValues, ErrorExtensions, InputValueError, InputValueResult,
ParseRequestError, PathSegment, Result, ResultExt, ServerError, ServerResult, ParseRequestError, PathSegment, Result, ResultExt, ServerError, ServerResult,
@ -166,21 +163,25 @@ pub use error::{
pub use look_ahead::Lookahead; pub use look_ahead::Lookahead;
pub use registry::CacheControl; pub use registry::CacheControl;
pub use request::{BatchRequest, Request}; pub use request::{BatchRequest, Request};
#[doc(no_inline)]
pub use resolver_utils::{ContainerType, EnumType, ScalarType}; pub use resolver_utils::{ContainerType, EnumType, ScalarType};
pub use response::{BatchResponse, Response}; pub use response::{BatchResponse, Response};
pub use schema::{Schema, SchemaBuilder, SchemaEnv}; pub use schema::{Schema, SchemaBuilder, SchemaEnv};
pub use validation::ValidationMode; pub use validation::ValidationMode;
/// An alias of [async_graphql::Error](struct.Error.html).
pub type FieldError = Error;
/// An alias of [async_graphql::Result](type.Result.html).
pub type FieldResult<T> = Result<T>;
#[doc(no_inline)] #[doc(no_inline)]
pub use parser::{Pos, Positioned}; pub use parser::{Pos, Positioned};
pub use context::*;
pub use types::*; pub use types::*;
/// An alias of [async_graphql::Error](struct.Error.html). Present for backward compatibility
/// reasons.
pub type FieldError = Error;
/// An alias of [async_graphql::Result](type.Result.html). Present for backward compatibility
/// reasons.
pub type FieldResult<T> = Result<T>;
/// Define a GraphQL object with methods /// Define a GraphQL object with methods
/// ///
/// *[See also the Book](https://async-graphql.github.io/async-graphql/en/define_complex_object.html).* /// *[See also the Book](https://async-graphql.github.io/async-graphql/en/define_complex_object.html).*