graphql_query/validate/rules/
unique_operation_names.rs

1use super::super::{ValidationContext, ValidationRule};
2use crate::{ast::*, visit::*};
3
4/// Validates that no operation the document defines have duplicate names.
5/// Note: Operations and Fragments are allowed to share names.
6///
7/// See [`ValidationRule`]
8/// [Reference](https://spec.graphql.org/October2021/#sec-Operation-Name-Uniqueness)
9#[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}