graphql_query/validate/rules/
unique_fragment_names.rs1use super::super::{ValidationContext, ValidationRule};
2use crate::{ast::*, visit::*};
3
4#[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}