2020-03-10 06:14:09 +00:00
|
|
|
use crate::registry::TypeName;
|
2020-03-24 10:54:22 +00:00
|
|
|
use crate::validation::visitor::{Visitor, VisitorContext};
|
2020-03-10 06:14:09 +00:00
|
|
|
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,
|
2020-03-22 08:45:59 +00:00
|
|
|
ctx: &mut VisitorContext<'a>,
|
2020-03-10 06:14:09 +00:00
|
|
|
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,
|
2020-03-22 08:45:59 +00:00
|
|
|
_ctx: &mut VisitorContext<'a>,
|
2020-03-10 06:14:09 +00:00
|
|
|
_operation_definition: &'a OperationDefinition,
|
|
|
|
) {
|
|
|
|
self.var_types.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn enter_variable_definition(
|
|
|
|
&mut self,
|
2020-03-22 08:45:59 +00:00
|
|
|
_ctx: &mut VisitorContext<'a>,
|
2020-03-10 06:14:09 +00:00
|
|
|
variable_definition: &'a VariableDefinition,
|
|
|
|
) {
|
|
|
|
self.var_types.insert(
|
|
|
|
variable_definition.name.as_str(),
|
|
|
|
variable_definition.var_type.to_string(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-03-22 08:45:59 +00:00
|
|
|
fn enter_directive(&mut self, ctx: &mut VisitorContext<'a>, directive: &'a Directive) {
|
2020-03-10 06:14:09 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-22 08:45:59 +00:00
|
|
|
fn enter_field(&mut self, ctx: &mut VisitorContext<'a>, field: &'a Field) {
|
2020-03-10 06:14:09 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|