async_graphql/validation/rules/
known_type_names.rs

1use crate::{
2    Name, Pos, Positioned,
3    parser::types::{FragmentDefinition, InlineFragment, TypeCondition, VariableDefinition},
4    registry::MetaTypeName,
5    validation::visitor::{Visitor, VisitorContext},
6};
7
8#[derive(Default)]
9pub struct KnownTypeNames;
10
11impl<'a> Visitor<'a> for KnownTypeNames {
12    fn enter_fragment_definition(
13        &mut self,
14        ctx: &mut VisitorContext<'a>,
15        _name: &'a Name,
16        fragment_definition: &'a Positioned<FragmentDefinition>,
17    ) {
18        let TypeCondition { on: name } = &fragment_definition.node.type_condition.node;
19        validate_type(ctx, &name.node, fragment_definition.pos);
20    }
21
22    fn enter_variable_definition(
23        &mut self,
24        ctx: &mut VisitorContext<'a>,
25        variable_definition: &'a Positioned<VariableDefinition>,
26    ) {
27        validate_type(
28            ctx,
29            MetaTypeName::concrete_typename(&variable_definition.node.var_type.to_string()),
30            variable_definition.pos,
31        );
32    }
33
34    fn enter_inline_fragment(
35        &mut self,
36        ctx: &mut VisitorContext<'a>,
37        inline_fragment: &'a Positioned<InlineFragment>,
38    ) {
39        if let Some(TypeCondition { on: name }) = inline_fragment
40            .node
41            .type_condition
42            .as_ref()
43            .map(|c| &c.node)
44        {
45            validate_type(ctx, &name.node, inline_fragment.pos);
46        }
47    }
48}
49
50fn validate_type(ctx: &mut VisitorContext<'_>, type_name: &str, pos: Pos) {
51    if !ctx.registry.types.contains_key(type_name) {
52        ctx.report_error(vec![pos], format!(r#"Unknown type "{}""#, type_name));
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    pub fn factory() -> KnownTypeNames {
61        KnownTypeNames
62    }
63
64    #[test]
65    fn known_type_names_are_valid() {
66        expect_passes_rule!(
67            factory,
68            r#"
69          query Foo($var: String, $required: [String!]!) {
70            user(id: 4) {
71              pets { ... on Pet { name }, ...PetFields, ... { name } }
72            }
73          }
74          fragment PetFields on Pet {
75            name
76          }
77        "#,
78        );
79    }
80
81    #[test]
82    fn unknown_type_names_are_invalid() {
83        expect_fails_rule!(
84            factory,
85            r#"
86          query Foo($var: JumbledUpLetters) {
87            user(id: 4) {
88              name
89              pets { ... on Badger { name }, ...PetFields }
90            }
91          }
92          fragment PetFields on Peettt {
93            name
94          }
95        "#,
96        );
97    }
98}