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
use crate::validation::context::ValidatorContext; use crate::validation::visitor::Visitor; use graphql_parser::query::{Definition, Document, FragmentSpread, InlineFragment, TypeCondition}; use std::collections::HashMap; #[derive(Default)] pub struct PossibleFragmentSpreads<'a> { fragment_types: HashMap<&'a str, &'a str>, } impl<'a> Visitor<'a> for PossibleFragmentSpreads<'a> { fn enter_document(&mut self, _ctx: &mut ValidatorContext<'a>, doc: &'a Document) { for d in &doc.definitions { if let Definition::Fragment(fragment) = d { let TypeCondition::On(type_name) = &fragment.type_condition; self.fragment_types .insert(fragment.name.as_str(), type_name); } } } fn enter_fragment_spread( &mut self, ctx: &mut ValidatorContext<'a>, fragment_spread: &'a FragmentSpread, ) { if let Some(fragment_type) = self .fragment_types .get(fragment_spread.fragment_name.as_str()) { if ctx.current_type().name() != *fragment_type { ctx.report_error( vec![fragment_spread.position], format!( "Fragment \"{}\" cannot be spread here as objects of type \"{}\" can never be of type \"{}\"", &fragment_spread.fragment_name, ctx.current_type().name(), fragment_type ), ) } } } fn enter_inline_fragment( &mut self, ctx: &mut ValidatorContext<'a>, inline_fragment: &'a InlineFragment, ) { if let Some(parent_type) = ctx.parent_type() { if let Some(TypeCondition::On(name)) = &inline_fragment.type_condition { if !parent_type.is_possible_type(&name) { ctx.report_error( vec![inline_fragment.position], format!( "Fragment cannot be spread here as objects of type \"{}\" \ can never be of type \"{}\"", parent_type.name(), name ), ) } } } } }