154 lines
3.2 KiB
Rust
154 lines
3.2 KiB
Rust
use crate::validation::visitor::{VisitMode, Visitor, VisitorContext};
|
|
use crate::Positioned;
|
|
use async_graphql_parser::types::Field;
|
|
|
|
pub struct DepthCalculate<'a> {
|
|
max_depth: &'a mut usize,
|
|
current_depth: usize,
|
|
}
|
|
|
|
impl<'a> DepthCalculate<'a> {
|
|
pub fn new(max_depth: &'a mut usize) -> Self {
|
|
Self {
|
|
max_depth,
|
|
current_depth: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'ctx, 'a> Visitor<'ctx> for DepthCalculate<'a> {
|
|
fn mode(&self) -> VisitMode {
|
|
VisitMode::Inline
|
|
}
|
|
|
|
fn enter_field(&mut self, _ctx: &mut VisitorContext<'ctx>, _field: &'ctx Positioned<Field>) {
|
|
self.current_depth += 1;
|
|
*self.max_depth = (*self.max_depth).max(self.current_depth);
|
|
}
|
|
|
|
fn exit_field(&mut self, _ctx: &mut VisitorContext<'ctx>, _field: &'ctx Positioned<Field>) {
|
|
self.current_depth -= 1;
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::parser::parse_query;
|
|
use crate::validation::{visit, VisitorContext};
|
|
use crate::{EmptyMutation, EmptySubscription, Object, Schema};
|
|
|
|
struct Query;
|
|
|
|
struct MyObj;
|
|
|
|
#[Object(internal)]
|
|
#[allow(unreachable_code)]
|
|
impl MyObj {
|
|
async fn a(&self) -> i32 {
|
|
todo!()
|
|
}
|
|
|
|
async fn b(&self) -> i32 {
|
|
todo!()
|
|
}
|
|
|
|
async fn c(&self) -> MyObj {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
#[Object(internal)]
|
|
#[allow(unreachable_code)]
|
|
impl Query {
|
|
async fn value(&self) -> i32 {
|
|
todo!()
|
|
}
|
|
|
|
async fn obj(&self) -> MyObj {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
fn check_depth(query: &str, expect_depth: usize) {
|
|
let registry = Schema::<Query, EmptyMutation, EmptySubscription>::create_registry();
|
|
let doc = parse_query(query).unwrap();
|
|
let mut ctx = VisitorContext::new(®istry, &doc, None);
|
|
let mut depth = 0;
|
|
let mut depth_calculate = DepthCalculate::new(&mut depth);
|
|
visit(&mut depth_calculate, &mut ctx, &doc);
|
|
assert_eq!(depth, expect_depth);
|
|
}
|
|
|
|
#[test]
|
|
fn depth() {
|
|
check_depth(
|
|
r#"{
|
|
value #1
|
|
}"#,
|
|
1,
|
|
);
|
|
|
|
check_depth(
|
|
r#"
|
|
{
|
|
obj { #1
|
|
a b #2
|
|
}
|
|
}"#,
|
|
2,
|
|
);
|
|
|
|
check_depth(
|
|
r#"
|
|
{
|
|
obj { # 1
|
|
a b c { # 2
|
|
a b c { # 3
|
|
a b # 4
|
|
}
|
|
}
|
|
}
|
|
}"#,
|
|
4,
|
|
);
|
|
|
|
check_depth(
|
|
r#"
|
|
fragment A on MyObj {
|
|
a b ... A2 #2
|
|
}
|
|
|
|
fragment A2 on MyObj {
|
|
obj {
|
|
a #3
|
|
}
|
|
}
|
|
|
|
query {
|
|
obj { # 1
|
|
... A
|
|
}
|
|
}"#,
|
|
3,
|
|
);
|
|
|
|
check_depth(
|
|
r#"
|
|
{
|
|
obj { # 1
|
|
... on MyObj {
|
|
a b #2
|
|
... on MyObj {
|
|
obj {
|
|
a #3
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}"#,
|
|
3,
|
|
);
|
|
}
|
|
}
|