graphql_query/validate/rules/
unique_argument_names.rs1use super::super::{ValidationContext, ValidationRule};
2use crate::{ast::*, visit::*};
3
4#[derive(Default)]
9pub struct UniqueArgumentNames<'a> {
10 used_argument_names: Vec<&'a str>,
11}
12
13impl<'a> ValidationRule<'a> for UniqueArgumentNames<'a> {}
14
15impl<'a> Visitor<'a, ValidationContext<'a>> for UniqueArgumentNames<'a> {
16 fn enter_field(
17 &mut self,
18 _ctx: &mut ValidationContext<'a>,
19 _field: &'a Field<'a>,
20 _info: &VisitInfo,
21 ) -> VisitFlow {
22 self.used_argument_names.clear();
23 VisitFlow::Next
24 }
25
26 fn enter_directive(
27 &mut self,
28 _ctx: &mut ValidationContext<'a>,
29 _directive: &'a Directive<'a>,
30 _info: &VisitInfo,
31 ) -> VisitFlow {
32 self.used_argument_names.clear();
33 VisitFlow::Next
34 }
35
36 fn enter_argument(
37 &mut self,
38 ctx: &mut ValidationContext<'a>,
39 argument: &'a Argument<'a>,
40 _info: &VisitInfo,
41 ) -> VisitFlow {
42 if self.used_argument_names.contains(&argument.name) {
43 ctx.add_error("All passed arguments per field must only be passed once");
44 VisitFlow::Break
45 } else {
46 self.used_argument_names.push(argument.name);
47 VisitFlow::Skip
48 }
49 }
50
51 fn enter_variable_definition(
52 &mut self,
53 _ctx: &mut ValidationContext<'a>,
54 _var_def: &'a VariableDefinition,
55 _info: &VisitInfo,
56 ) -> VisitFlow {
57 VisitFlow::Skip
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn valid_args() {
67 let ctx = ASTContext::new();
68 let document = Document::parse(&ctx, "{ test(field: 1) }").unwrap();
69 UniqueArgumentNames::validate(&ctx, document).unwrap();
70 }
71
72 #[test]
73 fn overlapping_args() {
74 let ctx = ASTContext::new();
75 let document = Document::parse(&ctx, "{ test(field: 1, field: 2) }").unwrap();
76 UniqueArgumentNames::validate(&ctx, document).unwrap_err();
77 }
78}