async-graphql/src/validation/visitors/depth.rs

160 lines
3.2 KiB
Rust
Raw Normal View History

2020-12-18 06:59:37 +00:00
use async_graphql_parser::types::Field;
2020-03-25 07:07:16 +00:00
2022-04-19 04:25:11 +00:00
use crate::{
validation::visitor::{VisitMode, Visitor, VisitorContext},
Positioned,
};
2020-03-25 07:07:16 +00:00
pub struct DepthCalculate<'a> {
2020-12-18 06:59:37 +00:00
max_depth: &'a mut usize,
current_depth: usize,
2020-03-25 07:07:16 +00:00
}
impl<'a> DepthCalculate<'a> {
2020-12-18 06:59:37 +00:00
pub fn new(max_depth: &'a mut usize) -> Self {
2020-03-25 07:07:16 +00:00
Self {
max_depth,
2020-12-18 06:59:37 +00:00
current_depth: 0,
2020-03-25 07:07:16 +00:00
}
}
}
impl<'ctx, 'a> Visitor<'ctx> for DepthCalculate<'a> {
2020-12-18 06:59:37 +00:00
fn mode(&self) -> VisitMode {
VisitMode::Inline
}
fn enter_field(&mut self, _ctx: &mut VisitorContext<'ctx>, _field: &'ctx Positioned<Field>) {
2020-03-25 07:07:16 +00:00
self.current_depth += 1;
*self.max_depth = (*self.max_depth).max(self.current_depth);
}
2020-12-18 06:59:37 +00:00
fn exit_field(&mut self, _ctx: &mut VisitorContext<'ctx>, _field: &'ctx Positioned<Field>) {
2020-03-25 07:07:16 +00:00
self.current_depth -= 1;
}
2020-12-18 06:59:37 +00:00
}
2020-03-25 07:07:16 +00:00
2020-12-18 06:59:37 +00:00
#[cfg(test)]
mod tests {
use super::*;
2022-04-19 04:25:11 +00:00
use crate::{
parser::parse_query,
validation::{visit, VisitorContext},
EmptyMutation, EmptySubscription, Object, Schema,
};
2020-12-18 06:59:37 +00:00
struct Query;
struct MyObj;
#[Object(internal)]
2021-01-11 01:01:28 +00:00
#[allow(unreachable_code)]
2020-12-18 06:59:37 +00:00
impl MyObj {
async fn a(&self) -> i32 {
todo!()
2020-12-18 06:59:37 +00:00
}
async fn b(&self) -> i32 {
todo!()
2020-12-18 06:59:37 +00:00
}
async fn c(&self) -> MyObj {
todo!()
2020-12-18 06:59:37 +00:00
}
2020-03-25 07:07:16 +00:00
}
2020-12-18 06:59:37 +00:00
#[Object(internal)]
2021-01-11 01:01:28 +00:00
#[allow(unreachable_code)]
2020-12-18 06:59:37 +00:00
impl Query {
async fn value(&self) -> i32 {
todo!()
2020-12-18 06:59:37 +00:00
}
async fn obj(&self) -> MyObj {
todo!()
2020-12-18 06:59:37 +00:00
}
2020-03-25 07:07:16 +00:00
}
2020-12-18 06:59:37 +00:00
fn check_depth(query: &str, expect_depth: usize) {
let registry =
Schema::<Query, EmptyMutation, EmptySubscription>::create_registry(Default::default());
2020-12-18 06:59:37 +00:00
let doc = parse_query(query).unwrap();
let mut ctx = VisitorContext::new(&registry, &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);
2020-03-25 07:07:16 +00:00
}
2020-12-18 06:59:37 +00:00
#[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,
);
2020-03-25 07:07:16 +00:00
}
}