/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: ®istry::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 | } |