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
use crate::registry::TypeName; use crate::validation::context::ValidatorContext; use crate::validation::visitor::Visitor; use crate::Value; use graphql_parser::query::{Field, OperationDefinition, VariableDefinition}; use graphql_parser::schema::Directive; use graphql_parser::Pos; use std::collections::HashMap; #[derive(Default)] pub struct VariableInAllowedPosition<'a> { var_types: HashMap<&'a str, String>, } impl<'a> VariableInAllowedPosition<'a> { fn check_type( &mut self, ctx: &mut ValidatorContext<'a>, pos: Pos, except_type: &str, value: &Value, ) { let ty = TypeName::create(except_type); match (ty, value) { (_, Value::Variable(name)) => { if let Some(var_type) = self.var_types.get(name.as_str()) { if except_type != var_type { ctx.report_error( vec![pos], format!( "Variable \"{}\" of type \"{}\" used in position expecting type \"{}\"", name, var_type, except_type ), ); } } } (TypeName::List(elem_type), Value::List(values)) => { for value in values { self.check_type(ctx, pos, elem_type, value); } } (TypeName::NonNull(elem_type), value) => { self.check_type(ctx, pos, elem_type, value); } _ => {} } } } impl<'a> Visitor<'a> for VariableInAllowedPosition<'a> { fn enter_operation_definition( &mut self, _ctx: &mut ValidatorContext<'a>, _operation_definition: &'a OperationDefinition, ) { self.var_types.clear(); } fn enter_variable_definition( &mut self, _ctx: &mut ValidatorContext<'a>, variable_definition: &'a VariableDefinition, ) { self.var_types.insert( variable_definition.name.as_str(), variable_definition.var_type.to_string(), ); } fn enter_directive(&mut self, ctx: &mut ValidatorContext<'a>, directive: &'a Directive) { if let Some(schema_directive) = ctx.registry.directives.get(directive.name.as_str()) { for (name, value) in &directive.arguments { if let Some(input) = schema_directive.args.get(name.as_str()) { self.check_type(ctx, directive.position, &input.ty, value); } } } } fn enter_field(&mut self, ctx: &mut ValidatorContext<'a>, field: &'a Field) { if let Some(parent_type) = ctx.parent_type() { if let Some(schema_field) = parent_type.field_by_name(&field.name) { for (name, value) in &field.arguments { if let Some(arg) = schema_field.args.get(name.as_str()) { self.check_type(ctx, field.position, &arg.ty, value); } } } } } }