Coverage Report

Created: 2025-10-10 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/async-graphql-7.0.16/src/validation/mod.rs
Line
Count
Source
1
#[cfg(test)]
2
#[macro_use]
3
mod test_harness;
4
5
mod rules;
6
mod suggestion;
7
mod utils;
8
mod visitor;
9
mod visitors;
10
11
pub use visitor::VisitorContext;
12
use visitor::{visit, VisitorNil};
13
14
use crate::{
15
    parser::types::ExecutableDocument, registry::Registry, CacheControl, ServerError, Variables,
16
};
17
18
/// Validation results.
19
#[derive(Debug, Copy, Clone)]
20
pub struct ValidationResult {
21
    /// Cache control
22
    pub cache_control: CacheControl,
23
24
    /// Query complexity
25
    pub complexity: usize,
26
27
    /// Query depth
28
    pub depth: usize,
29
}
30
31
/// Validation mode
32
#[derive(Copy, Clone, Debug)]
33
pub enum ValidationMode {
34
    /// Execute all validation rules.
35
    Strict,
36
37
    /// The executor itself also has error handling, so it can improve
38
    /// performance, but it can lose some error messages.
39
    Fast,
40
}
41
42
0
pub(crate) fn check_rules(
43
0
    registry: &Registry,
44
0
    doc: &ExecutableDocument,
45
0
    variables: Option<&Variables>,
46
0
    mode: ValidationMode,
47
0
    limit_complexity: Option<usize>,
48
0
    limit_depth: Option<usize>,
49
0
) -> Result<ValidationResult, Vec<ServerError>> {
50
0
    let mut cache_control = CacheControl::default();
51
0
    let mut complexity = 0;
52
0
    let mut depth = 0;
53
54
0
    let errors = match mode {
55
        ValidationMode::Strict => {
56
0
            let mut ctx = VisitorContext::new(registry, doc, variables);
57
0
            let mut visitor = VisitorNil
58
0
                .with(rules::ArgumentsOfCorrectType::default())
59
0
                .with(rules::DefaultValuesOfCorrectType)
60
0
                .with(rules::FieldsOnCorrectType)
61
0
                .with(rules::FragmentsOnCompositeTypes)
62
0
                .with(rules::KnownArgumentNames::default())
63
0
                .with(rules::NoFragmentCycles::default())
64
0
                .with(rules::KnownFragmentNames)
65
0
                .with(rules::KnownTypeNames)
66
0
                .with(rules::NoUndefinedVariables::default())
67
0
                .with(rules::NoUnusedFragments::default())
68
0
                .with(rules::NoUnusedVariables::default())
69
0
                .with(rules::UniqueArgumentNames::default())
70
0
                .with(rules::UniqueVariableNames::default())
71
0
                .with(rules::VariablesAreInputTypes)
72
0
                .with(rules::VariableInAllowedPosition::default())
73
0
                .with(rules::ScalarLeafs)
74
0
                .with(rules::PossibleFragmentSpreads::default())
75
0
                .with(rules::ProvidedNonNullArguments)
76
0
                .with(rules::KnownDirectives::default())
77
0
                .with(rules::DirectivesUnique)
78
0
                .with(rules::OverlappingFieldsCanBeMerged)
79
0
                .with(rules::UploadFile);
80
0
            visit(&mut visitor, &mut ctx, doc);
81
82
0
            let mut visitor = VisitorNil
83
0
                .with(visitors::CacheControlCalculate {
84
0
                    cache_control: &mut cache_control,
85
0
                })
86
0
                .with(visitors::ComplexityCalculate::new(&mut complexity))
87
0
                .with(visitors::DepthCalculate::new(&mut depth));
88
0
            visit(&mut visitor, &mut ctx, doc);
89
0
            ctx.errors
90
        }
91
        ValidationMode::Fast => {
92
0
            let mut ctx = VisitorContext::new(registry, doc, variables);
93
0
            let mut visitor = VisitorNil
94
0
                .with(rules::NoFragmentCycles::default())
95
0
                .with(rules::UploadFile)
96
0
                .with(visitors::CacheControlCalculate {
97
0
                    cache_control: &mut cache_control,
98
0
                })
99
0
                .with(visitors::ComplexityCalculate::new(&mut complexity))
100
0
                .with(visitors::DepthCalculate::new(&mut depth));
101
0
            visit(&mut visitor, &mut ctx, doc);
102
0
            ctx.errors
103
        }
104
    };
105
106
    // check limit
107
0
    if let Some(limit_complexity) = limit_complexity {
108
0
        if complexity > limit_complexity {
109
0
            return Err(vec![ServerError::new("Query is too complex.", None)]);
110
0
        }
111
0
    }
112
113
0
    if let Some(limit_depth) = limit_depth {
114
0
        if depth > limit_depth {
115
0
            return Err(vec![ServerError::new("Query is nested too deep.", None)]);
116
0
        }
117
0
    }
118
119
0
    if !errors.is_empty() {
120
0
        return Err(errors.into_iter().map(Into::into).collect());
121
0
    }
122
123
0
    Ok(ValidationResult {
124
0
        cache_control,
125
0
        complexity,
126
0
        depth,
127
0
    })
128
0
}