graphql_query/validate/rules/
unique_variable_names.rs1use bumpalo::collections::Vec;
2
3use super::super::{ValidationContext, ValidationRule};
4use crate::{ast::*, visit::*};
5
6pub struct UniqueVariableNames<'a> {
12 used_variable_names: Vec<'a, &'a str>,
13}
14
15impl<'a> DefaultIn<'a> for UniqueVariableNames<'a> {
16 fn default_in(arena: &'a bumpalo::Bump) -> Self {
17 Self {
18 used_variable_names: Vec::new_in(arena),
19 }
20 }
21}
22
23impl<'a> ValidationRule<'a> for UniqueVariableNames<'a> {}
24
25impl<'a> Visitor<'a, ValidationContext<'a>> for UniqueVariableNames<'a> {
26 fn enter_operation(
27 &mut self,
28 _ctx: &mut ValidationContext<'a>,
29 _operation: &'a OperationDefinition<'a>,
30 _info: &VisitInfo,
31 ) -> VisitFlow {
32 self.used_variable_names.clear();
33 VisitFlow::Next
34 }
35
36 fn enter_variable_definition(
37 &mut self,
38 ctx: &mut ValidationContext<'a>,
39 var_def: &'a VariableDefinition<'a>,
40 _info: &VisitInfo,
41 ) -> VisitFlow {
42 if self.used_variable_names.contains(&var_def.variable.name) {
43 ctx.add_error("All defined variables per operation must have unique names");
44 VisitFlow::Break
45 } else {
46 self.used_variable_names.push(var_def.variable.name);
47 VisitFlow::Skip
48 }
49 }
50
51 fn enter_selection_set(
52 &mut self,
53 _ctx: &mut ValidationContext<'a>,
54 _selection_set: &'a SelectionSet,
55 _info: &VisitInfo,
56 ) -> VisitFlow {
57 VisitFlow::Skip
58 }
59
60 fn enter_directive(
61 &mut self,
62 _ctx: &mut ValidationContext<'a>,
63 _fragment: &'a Directive,
64 _info: &VisitInfo,
65 ) -> VisitFlow {
66 VisitFlow::Skip
67 }
68
69 fn enter_fragment(
70 &mut self,
71 _ctx: &mut ValidationContext<'a>,
72 _fragment: &'a FragmentDefinition,
73 _info: &VisitInfo,
74 ) -> VisitFlow {
75 VisitFlow::Skip
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn valid_variables() {
85 let ctx = ASTContext::new();
86 let document = Document::parse(&ctx, "query ($a: Int, $b: Int) { __typename }").unwrap();
87 UniqueVariableNames::validate(&ctx, document).unwrap();
88 }
89
90 #[test]
91 fn overlapping_variables() {
92 let ctx = ASTContext::new();
93 let document = Document::parse(&ctx, "query ($a: Int, $a: Int) { __typename }").unwrap();
94 UniqueVariableNames::validate(&ctx, document).unwrap_err();
95 }
96}