1use crate::{
2 error::GqlError, input::GqlInputType, operation::Operation, types::schema::Schema, GqlValue,
3 ResolverResult,
4};
5use graphql_parser::{
6 query::{Field, SelectionSet},
7 schema::{Directive, Value},
8};
9
10#[derive(Clone)]
11pub struct ExecutionContext<'a, T> {
12 pub schema: &'a Schema,
13 pub operation: &'a Operation<'a>,
14 pub item: T,
15}
16
17pub type Context<'a> = ExecutionContext<'a, &'a Field<'a, String>>;
18
19impl<'a> Context<'a> {
20 pub fn get_arg_value<T: GqlInputType>(&self, arg_name: &str) -> ResolverResult<T> {
21 let value = self
22 .item
23 .arguments
24 .iter()
25 .find(|(name, _)| name == arg_name)
26 .map(|(_, v)| v);
27 let gql_value = match value {
28 Some(v) => {
29 if let Value::Variable(var_name) = v {
30 self.resolve_variable_value(var_name)?
31 } else {
32 GqlValue::from(v.clone())
33 }
34 }
35 None => GqlValue::Null,
36 };
37 match T::from_gql_value(Some(gql_value)) {
38 Ok(v) => Ok(v),
39 Err(err) => Err(GqlError::new(err, None)),
40 }
41 }
42}
43
44pub type SelectionSetContext<'a> = ExecutionContext<'a, &'a SelectionSet<'a, String>>;
45
46impl<'a, T> ExecutionContext<'a, T> {
47 pub fn with_field(
48 &self,
49 field: &'a Field<'a, String>,
50 ) -> ExecutionContext<'a, &'a Field<'a, String>> {
51 ExecutionContext {
52 schema: self.schema,
53 operation: self.operation,
54 item: field,
55 }
56 }
57
58 pub fn with_selection_set(
59 &self,
60 selection_set: &'a SelectionSet<'a, String>,
61 ) -> ExecutionContext<'a, &'a SelectionSet<'a, String>> {
62 ExecutionContext {
63 schema: self.schema,
64 operation: self.operation,
65 item: selection_set,
66 }
67 }
68
69 pub fn is_skip(&self, directives: &'a [Directive<'a, String>]) -> bool {
70 for dir in directives {
71 let skip = match dir.name.as_str() {
72 "skip" => true,
73 "include" => false,
74 _ => continue,
75 };
76
77 for (key, value) in &dir.arguments {
78 if key != "if" {
79 continue;
80 } else if let Value::Boolean(cond) = value {
81 if skip && *cond {
82 return true;
83 }
84 }
85 }
86
87 return skip;
88 }
89
90 false
91 }
92 pub fn add_error(&self, error: &GqlError) {
93 self.operation.errors.lock().unwrap().push(error.clone());
94 }
95
96 pub fn resolve_variable_value(&self, name: &str) -> ResolverResult<GqlValue> {
97 let v = self
98 .operation
99 .variable_definitions
100 .iter()
101 .find(|var_def| var_def.name == name)
102 .and_then(|var_def| self.operation.variables.0.get(&var_def.name));
103 match v {
104 Some(value) => Ok(value.clone()),
105 None => Err(GqlError::new(
106 format!("Variable {} is not defined", name),
107 None,
108 )),
109 }
110 }
111}
112
113pub(crate) fn build_context<'a>(
114 schema: &'a Schema,
115 operation: &'a Operation<'a>,
116) -> ExecutionContext<'a, &'a SelectionSet<'a, String>> {
117 ExecutionContext {
118 schema,
119 operation,
120 item: &operation.selection_set,
121 }
122}