1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use crate::registry::Registry;
use crate::{ErrorWithPosition, GQLInputValue, QueryError, Result};
use fnv::FnvHasher;
use graphql_parser::query::{Field, SelectionSet, Value};
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use std::ops::{Deref, DerefMut};

#[derive(Default)]
pub struct Variables(HashMap<String, serde_json::Value>);

impl Deref for Variables {
    type Target = HashMap<String, serde_json::Value>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Variables {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

#[derive(Default)]
pub struct Data(HashMap<TypeId, Box<dyn Any + Sync + Send>, BuildHasherDefault<FnvHasher>>);

impl Data {
    pub fn insert<D: Any + Send + Sync>(&mut self, data: D) {
        self.0.insert(TypeId::of::<D>(), Box::new(data));
    }

    pub fn remove<D: Any + Send + Sync>(&mut self) {
        self.0.remove(&TypeId::of::<D>());
    }
}

pub type ContextSelectionSet<'a> = ContextBase<'a, &'a SelectionSet>;
pub type Context<'a> = ContextBase<'a, &'a Field>;

pub struct ContextBase<'a, T> {
    pub(crate) item: T,
    pub(crate) data: Option<&'a Data>,
    pub(crate) variables: Option<&'a Variables>,
    pub(crate) registry: &'a Registry,
}

impl<'a, T> Deref for ContextBase<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.item
    }
}

impl<'a, T> ContextBase<'a, T> {
    #[doc(hidden)]
    pub fn with_item<R>(&self, item: R) -> ContextBase<'a, R> {
        ContextBase {
            item,
            data: self.data,
            variables: self.variables,
            registry: self.registry.clone(),
        }
    }

    pub fn data<D: Any + Send + Sync>(&self) -> Option<&D> {
        self.data.and_then(|data| {
            data.0
                .get(&TypeId::of::<D>())
                .and_then(|d| d.downcast_ref::<D>())
        })
    }
}

impl<'a> ContextBase<'a, &'a Field> {
    #[doc(hidden)]
    pub fn param_value<T: GQLInputValue>(&self, name: &str) -> Result<T> {
        let value = self
            .arguments
            .iter()
            .find(|(n, _)| n == name)
            .map(|(_, v)| v)
            .cloned();

        if let Some(Value::Variable(var_name)) = &value {
            if let Some(vars) = &self.variables {
                if let Some(var_value) = vars.get(&*var_name).cloned() {
                    let res =
                        GQLInputValue::parse_from_json(var_value.clone()).ok_or_else(|| {
                            QueryError::ExpectedJsonType {
                                expect: T::qualified_type_name(),
                                actual: var_value,
                            }
                            .with_position(self.item.position)
                        })?;
                    return Ok(res);
                }
            }

            return Err(QueryError::VarNotDefined {
                var_name: var_name.clone(),
            }
            .into());
        };

        let value = value.unwrap_or(Value::Null);
        let res = GQLInputValue::parse(value.clone()).ok_or_else(|| {
            QueryError::ExpectedType {
                expect: T::qualified_type_name(),
                actual: value,
            }
            .with_position(self.item.position)
        })?;
        Ok(res)
    }
}