2020-03-26 03:34:28 +00:00
|
|
|
use crate::extensions::BoxExtension;
|
2020-05-12 08:27:06 +00:00
|
|
|
use crate::parser::ast::{Directive, Field, SelectionSet};
|
2020-03-03 11:15:18 +00:00
|
|
|
use crate::registry::Registry;
|
2020-05-09 09:55:04 +00:00
|
|
|
use crate::{InputValueType, QueryError, Result, Schema, Type};
|
2020-05-10 02:59:51 +00:00
|
|
|
use crate::{Pos, Positioned, Value};
|
2020-05-12 08:27:06 +00:00
|
|
|
use async_graphql_parser::ast::Document;
|
2020-05-11 13:47:24 +00:00
|
|
|
use async_graphql_parser::UploadValue;
|
2020-04-24 02:05:41 +00:00
|
|
|
use fnv::FnvHashMap;
|
2020-03-01 10:54:34 +00:00
|
|
|
use std::any::{Any, TypeId};
|
2020-05-12 08:27:06 +00:00
|
|
|
use std::borrow::Cow;
|
|
|
|
use std::collections::BTreeMap;
|
2020-05-11 13:47:24 +00:00
|
|
|
use std::fs::File;
|
2020-03-01 10:54:34 +00:00
|
|
|
use std::ops::{Deref, DerefMut};
|
2020-03-26 03:34:28 +00:00
|
|
|
use std::sync::atomic::AtomicUsize;
|
2020-04-23 02:26:16 +00:00
|
|
|
use std::sync::Arc;
|
2020-03-01 10:54:34 +00:00
|
|
|
|
2020-03-09 10:05:52 +00:00
|
|
|
/// Variables of query
|
2020-03-17 09:26:59 +00:00
|
|
|
#[derive(Debug, Clone)]
|
2020-03-14 03:46:20 +00:00
|
|
|
pub struct Variables(Value);
|
|
|
|
|
|
|
|
impl Default for Variables {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self(Value::Object(Default::default()))
|
|
|
|
}
|
|
|
|
}
|
2020-03-01 10:54:34 +00:00
|
|
|
|
|
|
|
impl Deref for Variables {
|
2020-05-12 08:27:06 +00:00
|
|
|
type Target = BTreeMap<Cow<'static, str>, Value>;
|
2020-03-01 10:54:34 +00:00
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
2020-03-14 03:46:20 +00:00
|
|
|
if let Value::Object(obj) = &self.0 {
|
|
|
|
obj
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
2020-03-01 10:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-05 00:39:56 +00:00
|
|
|
impl DerefMut for Variables {
|
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
2020-03-14 03:46:20 +00:00
|
|
|
if let Value::Object(obj) = &mut self.0 {
|
|
|
|
obj
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
2020-03-05 00:39:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-04 03:51:42 +00:00
|
|
|
impl Variables {
|
2020-03-20 03:56:08 +00:00
|
|
|
/// Parse variables from JSON object.
|
2020-03-17 09:26:59 +00:00
|
|
|
pub fn parse_from_json(value: serde_json::Value) -> Result<Self> {
|
2020-05-09 14:16:39 +00:00
|
|
|
if let Value::Object(obj) = value.into() {
|
2020-05-09 09:55:04 +00:00
|
|
|
Ok(Variables(Value::Object(obj)))
|
2020-03-04 03:51:42 +00:00
|
|
|
} else {
|
|
|
|
Ok(Default::default())
|
|
|
|
}
|
|
|
|
}
|
2020-03-14 03:46:20 +00:00
|
|
|
|
|
|
|
pub(crate) fn set_upload(
|
|
|
|
&mut self,
|
|
|
|
var_path: &str,
|
2020-05-11 13:47:24 +00:00
|
|
|
filename: String,
|
|
|
|
content_type: Option<String>,
|
|
|
|
content: File,
|
2020-03-14 03:46:20 +00:00
|
|
|
) {
|
2020-03-21 01:32:13 +00:00
|
|
|
let mut it = var_path.split('.').peekable();
|
2020-03-14 03:46:20 +00:00
|
|
|
|
|
|
|
if let Some(first) = it.next() {
|
|
|
|
if first != "variables" {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut current = &mut self.0;
|
|
|
|
while let Some(s) = it.next() {
|
|
|
|
let has_next = it.peek().is_some();
|
|
|
|
|
|
|
|
if let Ok(idx) = s.parse::<i32>() {
|
|
|
|
if let Value::List(ls) = current {
|
|
|
|
if let Some(value) = ls.get_mut(idx as usize) {
|
|
|
|
if !has_next {
|
2020-05-11 13:47:24 +00:00
|
|
|
*value = Value::Upload(UploadValue {
|
|
|
|
filename,
|
|
|
|
content_type,
|
|
|
|
content,
|
|
|
|
});
|
2020-03-14 03:46:20 +00:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
current = value;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2020-03-21 01:32:13 +00:00
|
|
|
} else if let Value::Object(obj) = current {
|
|
|
|
if let Some(value) = obj.get_mut(s) {
|
|
|
|
if !has_next {
|
2020-05-11 13:47:24 +00:00
|
|
|
*value = Value::Upload(UploadValue {
|
|
|
|
filename,
|
|
|
|
content_type,
|
|
|
|
content,
|
|
|
|
});
|
2020-03-14 03:46:20 +00:00
|
|
|
return;
|
2020-03-21 01:32:13 +00:00
|
|
|
} else {
|
|
|
|
current = value;
|
2020-03-14 03:46:20 +00:00
|
|
|
}
|
2020-03-21 01:32:13 +00:00
|
|
|
} else {
|
|
|
|
return;
|
2020-03-14 03:46:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-01 10:54:34 +00:00
|
|
|
#[derive(Default)]
|
2020-04-23 02:26:16 +00:00
|
|
|
/// Schema/Context data
|
2020-04-23 13:36:04 +00:00
|
|
|
pub struct Data(FnvHashMap<TypeId, Box<dyn Any + Sync + Send>>);
|
2020-03-01 10:54:34 +00:00
|
|
|
|
|
|
|
impl Data {
|
2020-04-23 02:26:16 +00:00
|
|
|
#[allow(missing_docs)]
|
2020-03-01 10:54:34 +00:00
|
|
|
pub fn insert<D: Any + Send + Sync>(&mut self, data: D) {
|
|
|
|
self.0.insert(TypeId::of::<D>(), Box::new(data));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-20 03:56:08 +00:00
|
|
|
/// Context for `SelectionSet`
|
2020-05-10 02:59:51 +00:00
|
|
|
pub type ContextSelectionSet<'a> = ContextBase<'a, &'a Positioned<SelectionSet>>;
|
2020-03-09 10:05:52 +00:00
|
|
|
|
2020-03-20 03:56:08 +00:00
|
|
|
/// Context object for resolve field
|
2020-05-10 02:59:51 +00:00
|
|
|
pub type Context<'a> = ContextBase<'a, &'a Positioned<Field>>;
|
2020-03-01 10:54:34 +00:00
|
|
|
|
2020-03-26 03:34:28 +00:00
|
|
|
/// The query path segment
|
|
|
|
#[derive(Clone)]
|
2020-03-26 10:30:29 +00:00
|
|
|
pub enum QueryPathSegment<'a> {
|
2020-03-26 03:34:28 +00:00
|
|
|
/// Index
|
|
|
|
Index(usize),
|
|
|
|
|
|
|
|
/// Field name
|
2020-03-26 10:30:29 +00:00
|
|
|
Name(&'a str),
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|
|
|
|
|
2020-03-26 10:30:29 +00:00
|
|
|
/// The query path node
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct QueryPathNode<'a> {
|
|
|
|
/// Parent node
|
|
|
|
pub parent: Option<&'a QueryPathNode<'a>>,
|
2020-03-26 03:34:28 +00:00
|
|
|
|
2020-03-26 10:30:29 +00:00
|
|
|
/// Current path segment
|
|
|
|
pub segment: QueryPathSegment<'a>,
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|
|
|
|
|
2020-03-30 02:45:41 +00:00
|
|
|
impl<'a> std::fmt::Display for QueryPathNode<'a> {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
let mut first = true;
|
|
|
|
self.for_each(|segment| {
|
|
|
|
if !first {
|
|
|
|
write!(f, ".").ok();
|
|
|
|
}
|
|
|
|
match segment {
|
|
|
|
QueryPathSegment::Index(idx) => {
|
|
|
|
write!(f, "{}", *idx).ok();
|
|
|
|
}
|
|
|
|
QueryPathSegment::Name(name) => {
|
|
|
|
write!(f, "{}", name).ok();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
first = false;
|
|
|
|
});
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-26 10:30:29 +00:00
|
|
|
impl<'a> QueryPathNode<'a> {
|
|
|
|
pub(crate) fn field_name(&self) -> &str {
|
|
|
|
let mut p = self;
|
|
|
|
loop {
|
|
|
|
if let QueryPathSegment::Name(name) = &p.segment {
|
|
|
|
return name;
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|
2020-03-26 10:30:29 +00:00
|
|
|
p = p.parent.unwrap();
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-26 10:30:29 +00:00
|
|
|
pub(crate) fn for_each<F: FnMut(&QueryPathSegment<'a>)>(&self, mut f: F) {
|
|
|
|
self.for_each_ref(&mut f);
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|
|
|
|
|
2020-03-26 10:30:29 +00:00
|
|
|
fn for_each_ref<F: FnMut(&QueryPathSegment<'a>)>(&self, f: &mut F) {
|
|
|
|
if let Some(parent) = &self.parent {
|
|
|
|
parent.for_each_ref(f);
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|
2020-03-26 10:30:29 +00:00
|
|
|
f(&self.segment);
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|
2020-04-02 02:21:04 +00:00
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub fn to_json(&self) -> serde_json::Value {
|
|
|
|
let mut path: Vec<serde_json::Value> = Vec::new();
|
|
|
|
self.for_each(|segment| {
|
|
|
|
path.push(match segment {
|
|
|
|
QueryPathSegment::Index(idx) => (*idx).into(),
|
|
|
|
QueryPathSegment::Name(name) => (*name).to_string().into(),
|
|
|
|
})
|
|
|
|
});
|
|
|
|
path.into()
|
|
|
|
}
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|
|
|
|
|
2020-04-28 07:01:19 +00:00
|
|
|
/// Represents the unique id of the resolve
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub struct ResolveId {
|
|
|
|
/// Parent id
|
|
|
|
pub parent: Option<usize>,
|
|
|
|
|
|
|
|
/// Current id
|
|
|
|
pub current: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ResolveId {
|
|
|
|
pub(crate) fn root() -> ResolveId {
|
|
|
|
ResolveId {
|
|
|
|
parent: None,
|
|
|
|
current: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Display for ResolveId {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
if let Some(parent) = self.parent {
|
|
|
|
write!(f, "{}:{}", parent, self.current)
|
|
|
|
} else {
|
|
|
|
write!(f, "{}", self.current)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-20 03:56:08 +00:00
|
|
|
/// Query context
|
2020-03-25 03:39:28 +00:00
|
|
|
#[derive(Clone)]
|
2020-03-03 03:48:00 +00:00
|
|
|
pub struct ContextBase<'a, T> {
|
2020-04-02 02:21:04 +00:00
|
|
|
#[allow(missing_docs)]
|
|
|
|
pub path_node: Option<QueryPathNode<'a>>,
|
2020-04-28 07:01:19 +00:00
|
|
|
pub(crate) resolve_id: ResolveId,
|
|
|
|
pub(crate) inc_resolve_id: &'a AtomicUsize,
|
2020-03-26 03:34:28 +00:00
|
|
|
pub(crate) extensions: &'a [BoxExtension],
|
2020-03-01 10:54:34 +00:00
|
|
|
pub(crate) item: T,
|
2020-03-14 03:46:20 +00:00
|
|
|
pub(crate) variables: &'a Variables,
|
2020-03-03 11:15:18 +00:00
|
|
|
pub(crate) registry: &'a Registry,
|
2020-03-05 00:39:56 +00:00
|
|
|
pub(crate) data: &'a Data,
|
2020-03-31 03:19:18 +00:00
|
|
|
pub(crate) ctx_data: Option<&'a Data>,
|
2020-05-12 08:27:06 +00:00
|
|
|
pub(crate) document: &'a Document,
|
2020-03-01 10:54:34 +00:00
|
|
|
}
|
|
|
|
|
2020-03-03 03:48:00 +00:00
|
|
|
impl<'a, T> Deref for ContextBase<'a, T> {
|
2020-03-01 10:54:34 +00:00
|
|
|
type Target = T;
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.item
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-06 05:49:39 +00:00
|
|
|
#[doc(hidden)]
|
|
|
|
pub struct Environment {
|
|
|
|
pub variables: Variables,
|
2020-05-12 08:27:06 +00:00
|
|
|
pub document: Box<Document>,
|
2020-04-23 02:26:16 +00:00
|
|
|
pub ctx_data: Arc<Data>,
|
2020-04-06 05:49:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Environment {
|
|
|
|
#[doc(hidden)]
|
2020-04-23 02:26:16 +00:00
|
|
|
pub fn create_context<'a, T, Query, Mutation, Subscription>(
|
2020-04-06 05:49:39 +00:00
|
|
|
&'a self,
|
2020-04-23 02:26:16 +00:00
|
|
|
schema: &'a Schema<Query, Mutation, Subscription>,
|
2020-04-06 05:49:39 +00:00
|
|
|
path_node: Option<QueryPathNode<'a>>,
|
2020-04-23 02:26:16 +00:00
|
|
|
item: T,
|
2020-04-28 07:01:19 +00:00
|
|
|
inc_resolve_id: &'a AtomicUsize,
|
2020-04-06 05:49:39 +00:00
|
|
|
) -> ContextBase<'a, T> {
|
|
|
|
ContextBase {
|
|
|
|
path_node,
|
2020-04-28 07:01:19 +00:00
|
|
|
resolve_id: ResolveId::root(),
|
|
|
|
inc_resolve_id,
|
2020-04-06 05:49:39 +00:00
|
|
|
extensions: &[],
|
|
|
|
item,
|
|
|
|
variables: &self.variables,
|
2020-04-23 02:26:16 +00:00
|
|
|
registry: &schema.0.registry,
|
|
|
|
data: &schema.0.data,
|
|
|
|
ctx_data: Some(&self.ctx_data),
|
2020-05-12 08:27:06 +00:00
|
|
|
document: &self.document,
|
2020-04-06 05:49:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-03 03:48:00 +00:00
|
|
|
impl<'a, T> ContextBase<'a, T> {
|
2020-04-28 07:01:19 +00:00
|
|
|
fn get_child_resolve_id(&self) -> ResolveId {
|
|
|
|
let id = self
|
|
|
|
.inc_resolve_id
|
2020-03-26 03:34:28 +00:00
|
|
|
.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
|
2020-04-28 07:01:19 +00:00
|
|
|
+ 1;
|
|
|
|
ResolveId {
|
|
|
|
parent: Some(self.resolve_id.current),
|
|
|
|
current: id,
|
|
|
|
}
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
2020-05-10 02:59:51 +00:00
|
|
|
pub fn with_field(
|
|
|
|
&'a self,
|
|
|
|
field: &'a Positioned<Field>,
|
|
|
|
) -> ContextBase<'a, &'a Positioned<Field>> {
|
2020-03-26 03:34:28 +00:00
|
|
|
ContextBase {
|
2020-03-26 10:30:29 +00:00
|
|
|
path_node: Some(QueryPathNode {
|
|
|
|
parent: self.path_node.as_ref(),
|
|
|
|
segment: QueryPathSegment::Name(
|
|
|
|
field
|
|
|
|
.alias
|
2020-05-09 09:55:04 +00:00
|
|
|
.as_ref()
|
2020-05-12 08:27:06 +00:00
|
|
|
.map(|alias| alias.node)
|
|
|
|
.unwrap_or_else(|| field.name.node),
|
2020-03-26 10:30:29 +00:00
|
|
|
),
|
|
|
|
}),
|
2020-03-26 03:34:28 +00:00
|
|
|
extensions: self.extensions,
|
|
|
|
item: field,
|
2020-04-28 07:01:19 +00:00
|
|
|
resolve_id: self.get_child_resolve_id(),
|
|
|
|
inc_resolve_id: self.inc_resolve_id,
|
2020-03-26 03:34:28 +00:00
|
|
|
variables: self.variables,
|
|
|
|
registry: self.registry,
|
|
|
|
data: self.data,
|
2020-03-31 03:19:18 +00:00
|
|
|
ctx_data: self.ctx_data,
|
2020-05-12 08:27:06 +00:00
|
|
|
document: self.document,
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub fn with_selection_set(
|
|
|
|
&self,
|
2020-05-10 02:59:51 +00:00
|
|
|
selection_set: &'a Positioned<SelectionSet>,
|
|
|
|
) -> ContextBase<'a, &'a Positioned<SelectionSet>> {
|
2020-03-03 03:48:00 +00:00
|
|
|
ContextBase {
|
2020-03-26 10:30:29 +00:00
|
|
|
path_node: self.path_node.clone(),
|
2020-03-26 03:34:28 +00:00
|
|
|
extensions: self.extensions,
|
|
|
|
item: selection_set,
|
|
|
|
resolve_id: self.resolve_id,
|
2020-04-28 07:01:19 +00:00
|
|
|
inc_resolve_id: &self.inc_resolve_id,
|
2020-03-01 10:54:34 +00:00
|
|
|
variables: self.variables,
|
2020-03-21 01:32:13 +00:00
|
|
|
registry: self.registry,
|
2020-03-05 00:39:56 +00:00
|
|
|
data: self.data,
|
2020-03-31 03:19:18 +00:00
|
|
|
ctx_data: self.ctx_data,
|
2020-05-12 08:27:06 +00:00
|
|
|
document: self.document,
|
2020-03-01 10:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 03:19:18 +00:00
|
|
|
/// Gets the global data defined in the `Context` or `Schema`.
|
2020-03-07 10:03:19 +00:00
|
|
|
pub fn data<D: Any + Send + Sync>(&self) -> &D {
|
2020-04-23 06:52:22 +00:00
|
|
|
self.data_opt::<D>()
|
|
|
|
.expect("The specified data type does not exist.")
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the global data defined in the `Context` or `Schema`, returns `None` if the specified type data does not exist.
|
|
|
|
pub fn data_opt<D: Any + Send + Sync>(&self) -> Option<&D> {
|
2020-03-31 03:19:18 +00:00
|
|
|
self.ctx_data
|
|
|
|
.and_then(|ctx_data| ctx_data.0.get(&TypeId::of::<D>()))
|
|
|
|
.or_else(|| self.data.0.get(&TypeId::of::<D>()))
|
2020-03-05 00:39:56 +00:00
|
|
|
.and_then(|d| d.downcast_ref::<D>())
|
2020-03-01 10:54:34 +00:00
|
|
|
}
|
2020-03-05 07:50:57 +00:00
|
|
|
|
2020-04-02 02:21:04 +00:00
|
|
|
fn var_value(&self, name: &str, pos: Pos) -> Result<Value> {
|
2020-03-10 06:14:09 +00:00
|
|
|
let def = self
|
2020-05-12 08:27:06 +00:00
|
|
|
.document
|
|
|
|
.current_operation()
|
2020-03-10 06:14:09 +00:00
|
|
|
.variable_definitions
|
2020-04-01 08:53:49 +00:00
|
|
|
.iter()
|
2020-05-12 08:27:06 +00:00
|
|
|
.find(|def| def.name.node == name);
|
2020-03-10 06:14:09 +00:00
|
|
|
if let Some(def) = def {
|
2020-05-12 08:27:06 +00:00
|
|
|
if let Some(var_value) = self.variables.get(def.name.node) {
|
2020-03-10 06:14:09 +00:00
|
|
|
return Ok(var_value.clone());
|
|
|
|
} else if let Some(default) = &def.default_value {
|
2020-05-09 09:55:04 +00:00
|
|
|
return Ok(default.clone_inner());
|
2020-03-10 06:14:09 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-21 01:32:13 +00:00
|
|
|
Err(QueryError::VarNotDefined {
|
2020-03-10 06:14:09 +00:00
|
|
|
var_name: name.to_string(),
|
|
|
|
}
|
2020-04-02 02:21:04 +00:00
|
|
|
.into_error(pos))
|
2020-03-10 06:14:09 +00:00
|
|
|
}
|
|
|
|
|
2020-04-02 02:21:04 +00:00
|
|
|
fn resolve_input_value(&self, mut value: Value, pos: Pos) -> Result<Value> {
|
2020-03-10 06:14:09 +00:00
|
|
|
match value {
|
2020-04-02 02:21:04 +00:00
|
|
|
Value::Variable(var_name) => self.var_value(&var_name, pos),
|
2020-03-10 06:14:09 +00:00
|
|
|
Value::List(ref mut ls) => {
|
|
|
|
for value in ls {
|
|
|
|
if let Value::Variable(var_name) = value {
|
2020-04-02 02:21:04 +00:00
|
|
|
*value = self.var_value(&var_name, pos)?;
|
2020-03-10 06:14:09 +00:00
|
|
|
}
|
2020-03-04 03:51:42 +00:00
|
|
|
}
|
2020-03-10 06:14:09 +00:00
|
|
|
Ok(value)
|
2020-03-04 03:51:42 +00:00
|
|
|
}
|
2020-03-10 06:14:09 +00:00
|
|
|
Value::Object(ref mut obj) => {
|
2020-03-21 01:32:13 +00:00
|
|
|
for value in obj.values_mut() {
|
2020-03-10 06:14:09 +00:00
|
|
|
if let Value::Variable(var_name) = value {
|
2020-04-02 02:21:04 +00:00
|
|
|
*value = self.var_value(&var_name, pos)?;
|
2020-03-10 06:14:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(value)
|
2020-03-04 03:51:42 +00:00
|
|
|
}
|
2020-03-10 06:14:09 +00:00
|
|
|
_ => Ok(value),
|
2020-03-04 03:51:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-04 06:24:44 +00:00
|
|
|
#[doc(hidden)]
|
2020-05-10 02:59:51 +00:00
|
|
|
pub fn is_skip(&self, directives: &[Positioned<Directive>]) -> Result<bool> {
|
2020-03-05 09:06:14 +00:00
|
|
|
for directive in directives {
|
2020-05-12 08:27:06 +00:00
|
|
|
if directive.name.node == "skip" {
|
2020-05-09 09:55:04 +00:00
|
|
|
if let Some(value) = directive.get_argument("if") {
|
2020-05-10 10:27:46 +00:00
|
|
|
match InputValueType::parse(
|
2020-05-11 13:47:24 +00:00
|
|
|
self.resolve_input_value(value.clone_inner(), value.position())?,
|
2020-05-10 10:27:46 +00:00
|
|
|
) {
|
|
|
|
Ok(true) => return Ok(true),
|
|
|
|
Ok(false) => {}
|
|
|
|
Err(err) => {
|
2020-05-11 13:47:24 +00:00
|
|
|
return Err(err.into_error(value.pos, bool::qualified_type_name()))
|
2020-03-04 06:24:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(QueryError::RequiredDirectiveArgs {
|
|
|
|
directive: "@skip",
|
|
|
|
arg_name: "if",
|
|
|
|
arg_type: "Boolean!",
|
|
|
|
}
|
2020-05-09 09:55:04 +00:00
|
|
|
.into_error(directive.position()));
|
2020-03-04 06:24:44 +00:00
|
|
|
}
|
2020-05-12 08:27:06 +00:00
|
|
|
} else if directive.name.node == "include" {
|
2020-05-09 09:55:04 +00:00
|
|
|
if let Some(value) = directive.get_argument("if") {
|
2020-05-10 10:27:46 +00:00
|
|
|
match InputValueType::parse(
|
2020-05-11 13:47:24 +00:00
|
|
|
self.resolve_input_value(value.clone_inner(), value.position())?,
|
2020-05-10 10:27:46 +00:00
|
|
|
) {
|
|
|
|
Ok(false) => return Ok(true),
|
|
|
|
Ok(true) => {}
|
|
|
|
Err(err) => {
|
2020-05-11 13:47:24 +00:00
|
|
|
return Err(err.into_error(value.pos, bool::qualified_type_name()))
|
2020-03-04 06:24:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(QueryError::RequiredDirectiveArgs {
|
|
|
|
directive: "@include",
|
|
|
|
arg_name: "if",
|
|
|
|
arg_type: "Boolean!",
|
|
|
|
}
|
2020-05-09 09:55:04 +00:00
|
|
|
.into_error(directive.position()));
|
2020-03-04 06:24:44 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(QueryError::UnknownDirective {
|
2020-05-12 08:27:06 +00:00
|
|
|
name: directive.name.to_string(),
|
2020-03-04 06:24:44 +00:00
|
|
|
}
|
2020-05-09 09:55:04 +00:00
|
|
|
.into_error(directive.position()));
|
2020-03-04 06:24:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(false)
|
|
|
|
}
|
2020-03-01 10:54:34 +00:00
|
|
|
}
|
2020-03-05 09:06:14 +00:00
|
|
|
|
2020-05-10 02:59:51 +00:00
|
|
|
impl<'a> ContextBase<'a, &'a Positioned<SelectionSet>> {
|
2020-03-26 03:34:28 +00:00
|
|
|
#[doc(hidden)]
|
2020-05-10 02:59:51 +00:00
|
|
|
pub fn with_index(&'a self, idx: usize) -> ContextBase<'a, &'a Positioned<SelectionSet>> {
|
2020-03-26 03:34:28 +00:00
|
|
|
ContextBase {
|
2020-03-26 10:30:29 +00:00
|
|
|
path_node: Some(QueryPathNode {
|
|
|
|
parent: self.path_node.as_ref(),
|
|
|
|
segment: QueryPathSegment::Index(idx),
|
|
|
|
}),
|
2020-03-26 03:34:28 +00:00
|
|
|
extensions: self.extensions,
|
|
|
|
item: self.item,
|
2020-04-28 07:01:19 +00:00
|
|
|
resolve_id: self.get_child_resolve_id(),
|
|
|
|
inc_resolve_id: self.inc_resolve_id,
|
2020-03-26 03:34:28 +00:00
|
|
|
variables: self.variables,
|
|
|
|
registry: self.registry,
|
|
|
|
data: self.data,
|
2020-03-31 03:19:18 +00:00
|
|
|
ctx_data: self.ctx_data,
|
2020-05-12 08:27:06 +00:00
|
|
|
document: self.document,
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-10 02:59:51 +00:00
|
|
|
impl<'a> ContextBase<'a, &'a Positioned<Field>> {
|
2020-03-05 09:06:14 +00:00
|
|
|
#[doc(hidden)]
|
2020-03-19 09:20:12 +00:00
|
|
|
pub fn param_value<T: InputValueType, F: FnOnce() -> Value>(
|
2020-03-05 09:06:14 +00:00
|
|
|
&self,
|
|
|
|
name: &str,
|
2020-03-05 13:34:31 +00:00
|
|
|
default: F,
|
2020-03-05 09:06:14 +00:00
|
|
|
) -> Result<T> {
|
2020-05-09 09:55:04 +00:00
|
|
|
match self.get_argument(name).cloned() {
|
2020-03-05 09:06:14 +00:00
|
|
|
Some(value) => {
|
2020-05-09 09:55:04 +00:00
|
|
|
let pos = value.position();
|
|
|
|
let value = self.resolve_input_value(value.into_inner(), pos)?;
|
2020-05-11 13:47:24 +00:00
|
|
|
match InputValueType::parse(value) {
|
2020-05-10 10:27:46 +00:00
|
|
|
Ok(res) => Ok(res),
|
2020-05-11 13:47:24 +00:00
|
|
|
Err(err) => Err(err.into_error(pos, T::qualified_type_name())),
|
2020-05-10 10:27:46 +00:00
|
|
|
}
|
2020-03-05 09:06:14 +00:00
|
|
|
}
|
2020-03-05 13:34:31 +00:00
|
|
|
None => {
|
2020-03-05 09:06:14 +00:00
|
|
|
let value = default();
|
2020-05-11 13:47:24 +00:00
|
|
|
match InputValueType::parse(value) {
|
2020-05-10 10:27:46 +00:00
|
|
|
Ok(res) => Ok(res),
|
|
|
|
Err(err) => {
|
|
|
|
// The default value has no valid location.
|
2020-05-11 13:47:24 +00:00
|
|
|
Err(err.into_error(Pos::default(), T::qualified_type_name()))
|
2020-03-05 09:06:14 +00:00
|
|
|
}
|
2020-05-10 10:27:46 +00:00
|
|
|
}
|
2020-03-05 09:06:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-06 15:58:43 +00:00
|
|
|
|
2020-03-07 03:27:44 +00:00
|
|
|
#[doc(hidden)]
|
2020-03-26 03:34:28 +00:00
|
|
|
pub fn result_name(&self) -> &str {
|
2020-03-26 10:30:29 +00:00
|
|
|
self.item
|
|
|
|
.alias
|
2020-05-09 09:55:04 +00:00
|
|
|
.as_ref()
|
2020-05-12 08:27:06 +00:00
|
|
|
.map(|alias| alias.node)
|
|
|
|
.unwrap_or_else(|| self.item.name.node)
|
2020-03-06 15:58:43 +00:00
|
|
|
}
|
2020-05-14 09:35:25 +00:00
|
|
|
|
|
|
|
/// Get the position of the current field in the query code.
|
|
|
|
pub fn position(&self) -> Pos {
|
|
|
|
self.pos
|
|
|
|
}
|
2020-03-05 09:06:14 +00:00
|
|
|
}
|