async_graphql/validation/rules/
fragments_on_composite_types.rs1use 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}