graphql_query/validate/rules/
unique_operation_names.rs1use super::super::{ValidationContext, ValidationRule};
2use crate::{ast::*, visit::*};
3
4#[derive(Default)]
10pub struct UniqueOperationNames<'a> {
11 used_operation_names: Vec<&'a str>,
12}
13
14impl<'a> ValidationRule<'a> for UniqueOperationNames<'a> {}
15
16impl<'a> Visitor<'a, ValidationContext<'a>> for UniqueOperationNames<'a> {
17 fn enter_operation(
18 &mut self,
19 ctx: &mut ValidationContext<'a>,
20 operation: &'a OperationDefinition<'a>,
21 _info: &VisitInfo,
22 ) -> VisitFlow {
23 if let Some(name) = operation.name {
24 if self.used_operation_names.contains(&name.name) {
25 ctx.add_error("All defined operations must have unique names");
26 VisitFlow::Break
27 } else {
28 self.used_operation_names.push(name.name);
29 VisitFlow::Skip
30 }
31 } else {
32 VisitFlow::Skip
33 }
34 }
35
36 fn enter_fragment(
37 &mut self,
38 _ctx: &mut ValidationContext<'a>,
39 _fragment: &'a FragmentDefinition,
40 _info: &VisitInfo,
41 ) -> VisitFlow {
42 VisitFlow::Skip
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[test]
51 fn valid_operation_names() {
52 let ctx = ASTContext::new();
53 let document = Document::parse(&ctx, "query Root { __typename }").unwrap();
54 UniqueOperationNames::validate(&ctx, document).unwrap();
55 }
56
57 #[test]
58 fn overlapping_fragment_names() {
59 let ctx = ASTContext::new();
60 let document = Document::parse(
61 &ctx,
62 "query Root { __typename } mutation Root { __typename }",
63 )
64 .unwrap();
65 UniqueOperationNames::validate(&ctx, document).unwrap_err();
66 }
67}