async_graphql/validation/visitors/
depth.rs1use async_graphql_parser::types::Field;
2
3use crate::{
4 Positioned,
5 validation::visitor::{VisitMode, Visitor, VisitorContext},
6};
7
8pub struct DepthCalculate<'a> {
9 max_depth: &'a mut usize,
10 current_depth: usize,
11}
12
13impl<'a> DepthCalculate<'a> {
14 pub fn new(max_depth: &'a mut usize) -> Self {
15 Self {
16 max_depth,
17 current_depth: 0,
18 }
19 }
20}
21
22impl<'ctx> Visitor<'ctx> for DepthCalculate<'_> {
23 fn mode(&self) -> VisitMode {
24 VisitMode::Inline
25 }
26
27 fn enter_field(&mut self, _ctx: &mut VisitorContext<'ctx>, _field: &'ctx Positioned<Field>) {
28 self.current_depth += 1;
29 *self.max_depth = (*self.max_depth).max(self.current_depth);
30 }
31
32 fn exit_field(&mut self, _ctx: &mut VisitorContext<'ctx>, _field: &'ctx Positioned<Field>) {
33 self.current_depth -= 1;
34 }
35}
36
37#[cfg(test)]
38#[allow(clippy::diverging_sub_expression)]
39mod tests {
40 use super::*;
41 use crate::{
42 EmptyMutation, EmptySubscription, Object, Schema, parser::parse_query, validation::visit,
43 };
44
45 struct Query;
46
47 struct MyObj;
48
49 #[Object(internal)]
50 #[allow(unreachable_code)]
51 impl MyObj {
52 async fn a(&self) -> i32 {
53 todo!()
54 }
55
56 async fn b(&self) -> i32 {
57 todo!()
58 }
59
60 async fn c(&self) -> MyObj {
61 todo!()
62 }
63 }
64
65 #[Object(internal)]
66 #[allow(unreachable_code)]
67 impl Query {
68 async fn value(&self) -> i32 {
69 todo!()
70 }
71
72 async fn obj(&self) -> MyObj {
73 todo!()
74 }
75 }
76
77 fn check_depth(query: &str, expect_depth: usize) {
78 let registry =
79 Schema::<Query, EmptyMutation, EmptySubscription>::create_registry(Default::default());
80 let doc = parse_query(query).unwrap();
81 let mut ctx = VisitorContext::new(®istry, &doc, None);
82 let mut depth = 0;
83 let mut depth_calculate = DepthCalculate::new(&mut depth);
84 visit(&mut depth_calculate, &mut ctx, &doc);
85 assert_eq!(depth, expect_depth);
86 }
87
88 #[test]
89 fn depth() {
90 check_depth(
91 r#"{
92 value #1
93 }"#,
94 1,
95 );
96
97 check_depth(
98 r#"
99 {
100 obj { #1
101 a b #2
102 }
103 }"#,
104 2,
105 );
106
107 check_depth(
108 r#"
109 {
110 obj { # 1
111 a b c { # 2
112 a b c { # 3
113 a b # 4
114 }
115 }
116 }
117 }"#,
118 4,
119 );
120
121 check_depth(
122 r#"
123 fragment A on MyObj {
124 a b ... A2 #2
125 }
126
127 fragment A2 on MyObj {
128 obj {
129 a #3
130 }
131 }
132
133 query {
134 obj { # 1
135 ... A
136 }
137 }"#,
138 3,
139 );
140
141 check_depth(
142 r#"
143 {
144 obj { # 1
145 ... on MyObj {
146 a b #2
147 ... on MyObj {
148 obj {
149 a #3
150 }
151 }
152 }
153 }
154 }"#,
155 3,
156 );
157 }
158}