bluejay_validator/executable/document/rules/
field_selections.rs

1use crate::executable::{
2    document::{Error, Rule, Visitor},
3    Cache,
4};
5use bluejay_core::definition::{FieldsDefinition, SchemaDefinition, TypeDefinitionReference};
6use bluejay_core::executable::{ExecutableDocument, Field, Selection, SelectionReference};
7use bluejay_core::AsIter;
8use std::ops::Not;
9
10pub struct FieldSelections<'a, E: ExecutableDocument, S: SchemaDefinition> {
11    errors: Vec<Error<'a, E, S>>,
12}
13
14impl<'a, E: ExecutableDocument + 'a, S: SchemaDefinition + 'a> Visitor<'a, E, S>
15    for FieldSelections<'a, E, S>
16{
17    fn new(_: &'a E, _: &'a S, _: &'a Cache<'a, E, S>) -> Self {
18        Self { errors: Vec::new() }
19    }
20
21    fn visit_selection_set(
22        &mut self,
23        selection_set: &'a E::SelectionSet,
24        r#type: TypeDefinitionReference<'a, S::TypeDefinition>,
25    ) {
26        if let Some(fields_definition) = r#type.fields_definition() {
27            self.errors
28                .extend(selection_set.iter().filter_map(|selection| {
29                    if let SelectionReference::Field(field) = selection.as_ref() {
30                        let name = field.name();
31                        fields_definition
32                            .contains_field(name)
33                            .not()
34                            .then_some(Error::FieldDoesNotExistOnType { field, r#type })
35                    } else {
36                        None
37                    }
38                }));
39        }
40    }
41}
42
43impl<'a, E: ExecutableDocument + 'a, S: SchemaDefinition + 'a> Rule<'a, E, S>
44    for FieldSelections<'a, E, S>
45{
46    type Error = Error<'a, E, S>;
47    type Errors = std::vec::IntoIter<Error<'a, E, S>>;
48
49    fn into_errors(self) -> Self::Errors {
50        self.errors.into_iter()
51    }
52}