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