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::registry::Registry;
use crate::{
registry, ContainerType, ContextSelectionSet, InputValueResult, Positioned, Result,
ServerResult, Value,
};
use std::borrow::Cow;
/// 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::parser::types::{
Directive, Field, FragmentDefinition, OperationDefinition, SelectionSet,
@ -8,16 +22,6 @@ use crate::{
UploadValue, Value,
};
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.
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
@ -119,22 +123,27 @@ pub type ContextSelectionSet<'a> = ContextBase<'a, &'a Positioned<SelectionSet>>
/// Context object for resolve field
pub type Context<'a> = ContextBase<'a, &'a Positioned<Field>>;
/// The query path segment
#[derive(Clone)]
/// A segment in the path to the current query.
///
/// 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> {
/// Index
/// We are currently resolving an element in a list.
Index(usize),
/// Field name
/// We are currently resolving a field in an object.
Name(&'a str),
}
/// The query path node
#[derive(Clone)]
/// A path to the current query.
///
/// The path is stored as a kind of reverse linked list.
#[derive(Debug, Clone, Copy)]
pub struct QueryPathNode<'a> {
/// Parent node
/// The parent node to this, if there is one.
pub parent: Option<&'a QueryPathNode<'a>>,
/// Current path segment
/// The current path segment being resolved.
pub segment: QueryPathSegment<'a>,
}
@ -176,26 +185,31 @@ impl<'a> Display for QueryPathNode<'a> {
impl<'a> QueryPathNode<'a> {
/// 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 {
let mut p = self;
loop {
if let QueryPathSegment::Name(name) = &p.segment {
return name;
}
p = p.parent.unwrap();
}
self.parents().find_map(|node| match node.segment {
QueryPathSegment::Name(name) => Some(name),
QueryPathSegment::Index(_) => None,
}).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> {
let mut res = Vec::new();
self.for_each(|s| match s {
QueryPathSegment::Index(idx) => res.push(format!("{}", idx)),
QueryPathSegment::Name(name) => res.push(name.to_string()),
});
self.for_each(|s| res.push(match s {
QueryPathSegment::Name(name) => name.to_string(),
QueryPathSegment::Index(idx) => idx.to_string(),
}));
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) {
self.for_each_ref(&mut f);
}
@ -208,13 +222,39 @@ impl<'a> QueryPathNode<'a> {
}
}
/// Represents the unique id of the resolve
#[derive(Copy, Clone, Debug)]
/// An iterator over the parents of a [`QueryPathNode`](struct.QueryPathNode.html).
#[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 {
/// Parent id
/// The unique ID of the parent resolution.
pub parent: Option<usize>,
/// Current id
/// The current unique id.
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)]
pub struct ContextBase<'a, T> {
#[allow(missing_docs)]
@ -338,7 +380,7 @@ impl<'a, T> ContextBase<'a, T> {
selection_set: &'a Positioned<SelectionSet>,
) -> ContextBase<'a, &'a Positioned<SelectionSet>> {
ContextBase {
path_node: self.path_node.clone(),
path_node: self.path_node,
item: selection_set,
resolve_id: self.resolve_id,
inc_resolve_id: &self.inc_resolve_id,

View File

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