graphql_tools/validation/rules/
unique_input_field_names.rs1use std::collections::HashSet;
2
3use super::ValidationRule;
4use crate::ast::{OperationVisitor, OperationVisitorContext};
5use crate::static_graphql::query::Value;
6use crate::validation::utils::{ValidationError, ValidationErrorContext};
7
8pub struct UniqueInputFieldNames;
15
16impl Default for UniqueInputFieldNames {
17 fn default() -> Self {
18 Self::new()
19 }
20}
21
22impl UniqueInputFieldNames {
23 pub fn new() -> Self {
24 UniqueInputFieldNames
25 }
26}
27
28impl<'doc> OperationVisitor<'doc, ValidationErrorContext> for UniqueInputFieldNames {
29 fn enter_object_value(
30 &mut self,
31 _: &mut OperationVisitorContext,
32 user_context: &mut ValidationErrorContext,
33 object_value: &[(String, Value)],
34 ) {
35 let mut seen = HashSet::new();
36 for (field_name, _) in object_value {
37 if !seen.insert(field_name) {
38 user_context.report_error(ValidationError {
39 error_code: self.error_code(),
40 message: format!(
41 "There can be only one input field named \"{}\".",
42 field_name
43 ),
44 locations: vec![],
45 });
46 }
47 }
48 }
49}
50
51impl ValidationRule for UniqueInputFieldNames {
52 fn error_code(&self) -> &'static str {
53 "UniqueInputFieldNames"
54 }
55
56 fn visitor<'doc>(&self) -> super::ValidationVisitor<'doc> {
57 Box::new(UniqueInputFieldNames::new())
58 }
59}
60
61#[test]
62fn input_object_with_fields() {
63 use crate::validation::test_utils::*;
64
65 let mut plan = create_plan_from_rule(Box::new(UniqueInputFieldNames {}));
66 let errors = test_operation_with_schema(
67 "{
68 complicatedArgs {
69 complexArgField(complexArg: { requiredField: true })
70 }
71 }",
72 TEST_SCHEMA,
73 &mut plan,
74 );
75
76 assert_eq!(get_messages(&errors).len(), 0);
77}
78
79#[test]
80fn input_object_with_two_fields() {
81 use crate::validation::test_utils::*;
82
83 let mut plan = create_plan_from_rule(Box::new(UniqueInputFieldNames {}));
84 let errors = test_operation_with_schema(
85 "{
86 complicatedArgs {
87 complexArgField(complexArg: { requiredField: true, intField: 5 })
88 }
89 }",
90 TEST_SCHEMA,
91 &mut plan,
92 );
93
94 assert_eq!(get_messages(&errors).len(), 0);
95}
96
97#[test]
98fn same_input_object_within_two_args() {
99 use crate::validation::test_utils::*;
100
101 let mut plan = create_plan_from_rule(Box::new(UniqueInputFieldNames {}));
102 let errors = test_operation_with_schema(
103 "{
104 complicatedArgs {
105 a: complexArgField(complexArg: { requiredField: true })
106 b: complexArgField(complexArg: { requiredField: true })
107 }
108 }",
109 TEST_SCHEMA,
110 &mut plan,
111 );
112
113 assert_eq!(get_messages(&errors).len(), 0);
114}
115
116#[test]
117fn multiple_input_object_fields() {
118 use crate::validation::test_utils::*;
119
120 let mut plan = create_plan_from_rule(Box::new(UniqueInputFieldNames {}));
121 let errors = test_operation_with_schema(
122 "{
123 complicatedArgs {
124 complexArgField(complexArg: { requiredField: true, intField: 5, stringField: \"hello\" })
125 }
126 }",
127 TEST_SCHEMA,
128 &mut plan,
129 );
130
131 assert_eq!(get_messages(&errors).len(), 0);
132}
133
134#[test]
135fn allows_for_nested_input_objects_with_similar_fields() {
136 use crate::validation::test_utils::*;
137
138 let mut plan = create_plan_from_rule(Box::new(UniqueInputFieldNames {}));
139 let errors = test_operation_with_schema(
140 "{
141 complicatedArgs {
142 complexArgField(complexArg: { requiredField: true, nested: { requiredField: false } })
143 }
144 }",
145 TEST_SCHEMA,
146 &mut plan,
147 );
148
149 assert_eq!(get_messages(&errors).len(), 0);
150}
151
152#[test]
153fn duplicate_input_object_fields() {
154 use crate::validation::test_utils::*;
155
156 let mut plan = create_plan_from_rule(Box::new(UniqueInputFieldNames {}));
157 let errors = test_operation_with_schema(
158 "{
159 complicatedArgs {
160 complexArgField(complexArg: { requiredField: true, requiredField: true })
161 }
162 }",
163 TEST_SCHEMA,
164 &mut plan,
165 );
166
167 let messages = get_messages(&errors);
168 assert_eq!(messages.len(), 1);
169 assert_eq!(
170 messages,
171 vec!["There can be only one input field named \"requiredField\"."]
172 );
173}
174#[test]
175fn many_duplicate_input_object_fields() {
176 use crate::validation::test_utils::*;
177
178 let mut plan = create_plan_from_rule(Box::new(UniqueInputFieldNames {}));
179 let errors = test_operation_with_schema(
180 "{
181 complicatedArgs {
182 complexArgField(complexArg: { intField: 5, intField: 6, intField: 7 })
183 }
184 }",
185 TEST_SCHEMA,
186 &mut plan,
187 );
188
189 let messages = get_messages(&errors);
190 assert_eq!(messages.len(), 2);
191 assert_eq!(
192 messages,
193 vec!["There can be only one input field named \"intField\"."; 2]
194 );
195}
196
197#[test]
198fn nested_duplicate_input_object_fields() {
199 use crate::validation::test_utils::*;
200
201 let mut plan = create_plan_from_rule(Box::new(UniqueInputFieldNames {}));
202 let errors = test_operation_with_schema(
203 "{
204 complicatedArgs {
205 complexArgField(complexArg: { stringField: \"a\", nested: { intField: 1, intField: 2 } })
206 }
207 }",
208 TEST_SCHEMA,
209 &mut plan,
210 );
211
212 let messages = get_messages(&errors);
213 assert_eq!(messages.len(), 1);
214 assert_eq!(
215 messages,
216 vec!["There can be only one input field named \"intField\"."]
217 );
218}