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/utils.rs
Line
Count
Source
1
use std::collections::HashSet;
2
3
use async_graphql_value::{ConstValue, Value};
4
5
use crate::{context::QueryPathNode, registry, QueryPathSegment};
6
7
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
8
pub enum Scope<'a> {
9
    Operation(Option<&'a str>),
10
    Fragment(&'a str),
11
}
12
13
0
fn valid_error(path_node: &QueryPathNode, msg: String) -> String {
14
0
    format!("\"{}\", {}", path_node, msg)
15
0
}
16
17
0
pub fn referenced_variables(value: &Value) -> Vec<&str> {
18
0
    let mut vars = Vec::new();
19
0
    referenced_variables_to_vec(value, &mut vars);
20
0
    vars
21
0
}
22
23
0
fn referenced_variables_to_vec<'a>(value: &'a Value, vars: &mut Vec<&'a str>) {
24
0
    match value {
25
0
        Value::Variable(name) => {
26
0
            vars.push(name);
27
0
        }
28
0
        Value::List(values) => values
29
0
            .iter()
30
0
            .for_each(|value| referenced_variables_to_vec(value, vars)),
31
0
        Value::Object(obj) => obj
32
0
            .values()
33
0
            .for_each(|value| referenced_variables_to_vec(value, vars)),
34
0
        _ => {}
35
    }
36
0
}
37
38
0
pub fn is_valid_input_value(
39
0
    registry: &registry::Registry,
40
0
    type_name: &str,
41
0
    value: &ConstValue,
42
0
    path_node: QueryPathNode,
43
0
) -> Option<String> {
44
0
    match registry::MetaTypeName::create(type_name) {
45
0
        registry::MetaTypeName::NonNull(type_name) => match value {
46
0
            ConstValue::Null => Some(valid_error(
47
0
                &path_node,
48
0
                format!("expected type \"{}\"", type_name),
49
0
            )),
50
0
            _ => is_valid_input_value(registry, type_name, value, path_node),
51
        },
52
0
        registry::MetaTypeName::List(type_name) => match value {
53
0
            ConstValue::List(elems) => elems.iter().enumerate().find_map(|(idx, elem)| {
54
0
                is_valid_input_value(
55
0
                    registry,
56
0
                    type_name,
57
0
                    elem,
58
0
                    QueryPathNode {
59
0
                        parent: Some(&path_node),
60
0
                        segment: QueryPathSegment::Index(idx),
61
0
                    },
62
                )
63
0
            }),
64
0
            ConstValue::Null => None,
65
0
            _ => is_valid_input_value(registry, type_name, value, path_node),
66
        },
67
0
        registry::MetaTypeName::Named(type_name) => {
68
0
            if let ConstValue::Null = value {
69
0
                return None;
70
0
            }
71
72
0
            match registry
73
0
                .types
74
0
                .get(type_name)
75
0
                .unwrap_or_else(|| panic!("Type `{}` not defined", type_name))
76
            {
77
                registry::MetaType::Scalar {
78
0
                    is_valid: Some(is_valid_fn),
79
                    ..
80
                } => {
81
0
                    if (is_valid_fn)(&value) {
82
0
                        None
83
                    } else {
84
0
                        Some(valid_error(
85
0
                            &path_node,
86
0
                            format!("expected type \"{}\"", type_name),
87
0
                        ))
88
                    }
89
                }
90
0
                registry::MetaType::Scalar { is_valid: None, .. } => None,
91
                registry::MetaType::Enum {
92
0
                    enum_values,
93
0
                    name: enum_name,
94
                    ..
95
0
                } => match value {
96
0
                    ConstValue::Enum(name) => {
97
0
                        if !enum_values.contains_key(name.as_str()) {
98
0
                            Some(valid_error(
99
0
                                &path_node,
100
0
                                format!(
101
0
                                    "enumeration type \"{}\" does not contain the value \"{}\"",
102
0
                                    enum_name, name
103
0
                                ),
104
0
                            ))
105
                        } else {
106
0
                            None
107
                        }
108
                    }
109
0
                    ConstValue::String(name) => {
110
0
                        if !enum_values.contains_key(name.as_str()) {
111
0
                            Some(valid_error(
112
0
                                &path_node,
113
0
                                format!(
114
0
                                    "enumeration type \"{}\" does not contain the value \"{}\"",
115
0
                                    enum_name, name
116
0
                                ),
117
0
                            ))
118
                        } else {
119
0
                            None
120
                        }
121
                    }
122
0
                    _ => Some(valid_error(
123
0
                        &path_node,
124
0
                        format!("expected type \"{}\"", type_name),
125
0
                    )),
126
                },
127
                registry::MetaType::InputObject {
128
0
                    input_fields,
129
0
                    name: object_name,
130
0
                    oneof,
131
                    ..
132
0
                } => match value {
133
0
                    ConstValue::Object(values) => {
134
0
                        if *oneof {
135
0
                            if values.len() != 1 {
136
0
                                return Some(valid_error(
137
0
                                    &path_node,
138
0
                                    "Oneof input objects requires have exactly one field"
139
0
                                        .to_string(),
140
0
                                ));
141
0
                            }
142
143
0
                            if let ConstValue::Null = values[0] {
144
0
                                return Some(valid_error(
145
0
                                    &path_node,
146
0
                                    "Oneof Input Objects require that exactly one field must be supplied and that field must not be null"
147
0
                                        .to_string(),
148
0
                                ));
149
0
                            }
150
0
                        }
151
152
0
                        let mut input_names =
153
0
                            values.keys().map(AsRef::as_ref).collect::<HashSet<_>>();
154
155
0
                        for field in input_fields.values() {
156
0
                            input_names.remove(&*field.name);
157
0
                            if let Some(value) = values.get(&*field.name) {
158
0
                                if let Some(reason) = is_valid_input_value(
159
0
                                    registry,
160
0
                                    &field.ty,
161
0
                                    value,
162
0
                                    QueryPathNode {
163
0
                                        parent: Some(&path_node),
164
0
                                        segment: QueryPathSegment::Name(&field.name),
165
0
                                    },
166
0
                                ) {
167
0
                                    return Some(reason);
168
0
                                }
169
0
                            } else if registry::MetaTypeName::create(&field.ty).is_non_null()
170
0
                                && field.default_value.is_none()
171
                            {
172
0
                                return Some(valid_error(
173
0
                                    &path_node,
174
0
                                    format!(
175
0
                                        r#"field "{}" of type "{}" is required but not provided"#,
176
0
                                        field.name, field.ty,
177
0
                                    ),
178
0
                                ));
179
0
                            }
180
                        }
181
182
0
                        if let Some(name) = input_names.iter().next() {
183
0
                            return Some(valid_error(
184
0
                                &path_node,
185
0
                                format!("unknown field \"{}\" of type \"{}\"", name, object_name),
186
0
                            ));
187
0
                        }
188
189
0
                        None
190
                    }
191
0
                    _ => None,
192
                },
193
0
                _ => None,
194
            }
195
        }
196
    }
197
0
}