graphql_query/validate/rules/
no_unused_variables.rs1use bumpalo::collections::Vec;
2
3use super::super::{ValidationContext, ValidationRule};
4use crate::{ast::*, visit::*};
5
6pub struct NoUnusedVariables<'a> {
11 variables: Vec<'a, &'a str>,
12 used_variables: Vec<'a, &'a str>,
13}
14
15impl<'a> DefaultIn<'a> for NoUnusedVariables<'a> {
16 fn default_in(arena: &'a bumpalo::Bump) -> Self {
17 Self {
18 variables: Vec::new_in(arena),
19 used_variables: Vec::new_in(arena),
20 }
21 }
22}
23
24impl<'a> ValidationRule<'a> for NoUnusedVariables<'a> {}
25
26impl<'a> Visitor<'a, ValidationContext<'a>> for NoUnusedVariables<'a> {
27 fn enter_operation(
28 &mut self,
29 _ctx: &mut ValidationContext<'a>,
30 operation: &'a OperationDefinition<'a>,
31 _info: &VisitInfo,
32 ) -> VisitFlow {
33 operation
34 .variable_definitions
35 .children
36 .iter()
37 .for_each(|def| {
38 self.variables.push(def.variable.name);
39 });
40 VisitFlow::Next
41 }
42
43 fn enter_field(
44 &mut self,
45 _ctx: &mut ValidationContext<'a>,
46 field: &'a Field<'a>,
47 _info: &VisitInfo,
48 ) -> VisitFlow {
49 field.arguments.children.iter().for_each(|arg| {
50 if let Value::Variable(var) = arg.value {
51 self.used_variables.push(var.name);
52 }
53 });
54 VisitFlow::Next
55 }
56
57 fn leave_document(
58 &mut self,
59 ctx: &mut ValidationContext<'a>,
60 _document: &'a Document<'a>,
61 _info: &VisitInfo,
62 ) -> VisitFlow {
63 self.variables.iter().for_each(|defined_variable| {
64 if !self.used_variables.contains(defined_variable) {
65 ctx.add_error("All defined variables must be at least used once");
66 }
67 });
68 VisitFlow::Next
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn used_all_variables() {
78 let ctx = ASTContext::new();
79 let document =
80 Document::parse(&ctx, "query ($x: Int!) { todos(from: $x) { id } }").unwrap();
81 NoUnusedVariables::validate(&ctx, document).unwrap();
82 }
83
84 #[test]
85 fn has_unused_variable() {
86 let ctx = ASTContext::new();
87 let document = Document::parse(
88 &ctx,
89 "query ($x: Int!, $unused: String!) { todos(from: $x) { id } }",
90 )
91 .unwrap();
92 NoUnusedVariables::validate(&ctx, document).unwrap_err();
93 }
94}