async_graphql/validation/rules/
fragments_on_composite_types.rs

1use crate::{
2    Name, Positioned,
3    parser::types::{FragmentDefinition, InlineFragment},
4    validation::visitor::{Visitor, VisitorContext},
5};
6
7#[derive(Default)]
8pub struct FragmentsOnCompositeTypes;
9
10impl<'a> Visitor<'a> for FragmentsOnCompositeTypes {
11    fn enter_fragment_definition(
12        &mut self,
13        ctx: &mut VisitorContext<'a>,
14        name: &'a Name,
15        fragment_definition: &'a Positioned<FragmentDefinition>,
16    ) {
17        if let Some(current_type) = ctx.current_type() {
18            if !current_type.is_composite() {
19                ctx.report_error(
20                    vec![fragment_definition.pos],
21                    format!(
22                        "Fragment \"{}\" cannot condition non composite type \"{}\"",
23                        name, fragment_definition.node.type_condition.node.on.node,
24                    ),
25                );
26            }
27        }
28    }
29
30    fn enter_inline_fragment(
31        &mut self,
32        ctx: &mut VisitorContext<'a>,
33        inline_fragment: &'a Positioned<InlineFragment>,
34    ) {
35        if let Some(current_type) = ctx.current_type() {
36            if !current_type.is_composite() {
37                ctx.report_error(
38                    vec![inline_fragment.pos],
39                    format!(
40                        "Fragment cannot condition non composite type \"{}\"",
41                        current_type.name()
42                    ),
43                );
44            }
45        }
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    fn factory() -> FragmentsOnCompositeTypes {
54        FragmentsOnCompositeTypes
55    }
56
57    #[test]
58    fn on_object() {
59        expect_passes_rule!(
60            factory,
61            r#"
62          fragment validFragment on Dog {
63            barks
64          }
65          { __typename }
66        "#,
67        );
68    }
69
70    #[test]
71    fn on_interface() {
72        expect_passes_rule!(
73            factory,
74            r#"
75          fragment validFragment on Pet {
76            name
77          }
78          { __typename }
79        "#,
80        );
81    }
82
83    #[test]
84    fn on_object_inline() {
85        expect_passes_rule!(
86            factory,
87            r#"
88          fragment validFragment on Pet {
89            ... on Dog {
90              barks
91            }
92          }
93          { __typename }
94        "#,
95        );
96    }
97
98    #[test]
99    fn on_inline_without_type_cond() {
100        expect_passes_rule!(
101            factory,
102            r#"
103          fragment validFragment on Pet {
104            ... {
105              name
106            }
107          }
108          { __typename }
109        "#,
110        );
111    }
112
113    #[test]
114    fn on_union() {
115        expect_passes_rule!(
116            factory,
117            r#"
118          fragment validFragment on CatOrDog {
119            __typename
120          }
121          { __typename }
122        "#,
123        );
124    }
125
126    #[test]
127    fn not_on_scalar() {
128        expect_fails_rule!(
129            factory,
130            r#"
131          fragment scalarFragment on Boolean {
132            bad
133          }
134          { __typename }
135        "#,
136        );
137    }
138
139    #[test]
140    fn not_on_enum() {
141        expect_fails_rule!(
142            factory,
143            r#"
144          fragment scalarFragment on FurColor {
145            bad
146          }
147          { __typename }
148        "#,
149        );
150    }
151
152    #[test]
153    fn not_on_input_object() {
154        expect_fails_rule!(
155            factory,
156            r#"
157          fragment inputFragment on ComplexInput {
158            stringField
159          }
160          { __typename }
161        "#,
162        );
163    }
164
165    #[test]
166    fn not_on_scalar_inline() {
167        expect_fails_rule!(
168            factory,
169            r#"
170          fragment invalidFragment on Pet {
171            ... on String {
172              barks
173            }
174          }
175          { __typename }
176        "#,
177        );
178    }
179}