bluejay_validator/executable/document/rules/
field_selections.rs1use 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}