graphql_query/validate/rules/
unique_fragment_names.rs

1use super::super::{ValidationContext, ValidationRule};
2use crate::{ast::*, visit::*};
3
4/// Validates that no fragments 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-Fragment-Name-Uniqueness)
9#[derive(Default)]
10pub struct UniqueFragmentNames<'a> {
11    used_fragment_names: Vec<&'a str>,
12}
13
14impl<'a> ValidationRule<'a> for UniqueFragmentNames<'a> {}
15
16impl<'a> Visitor<'a, ValidationContext<'a>> for UniqueFragmentNames<'a> {
17    fn enter_fragment(
18        &mut self,
19        ctx: &mut ValidationContext<'a>,
20        fragment: &'a FragmentDefinition<'a>,
21        _info: &VisitInfo,
22    ) -> VisitFlow {
23        if self.used_fragment_names.contains(&fragment.name.name) {
24            ctx.add_error("All defined fragments must have unique names");
25            VisitFlow::Break
26        } else {
27            self.used_fragment_names.push(fragment.name.name);
28            VisitFlow::Skip
29        }
30    }
31
32    fn enter_operation(
33        &mut self,
34        _ctx: &mut ValidationContext<'a>,
35        _operation: &'a OperationDefinition,
36        _info: &VisitInfo,
37    ) -> VisitFlow {
38        VisitFlow::Skip
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45
46    #[test]
47    fn valid_fragment_names() {
48        let ctx = ASTContext::new();
49        let document = Document::parse(&ctx, "fragment Root on Query { __typename }").unwrap();
50        UniqueFragmentNames::validate(&ctx, document).unwrap();
51    }
52
53    #[test]
54    fn overlapping_fragment_names() {
55        let ctx = ASTContext::new();
56        let document = Document::parse(
57            &ctx,
58            "fragment Root on Query { __typename } fragment Root on Item { __typename }",
59        )
60        .unwrap();
61        UniqueFragmentNames::validate(&ctx, document).unwrap_err();
62    }
63}