2020-03-30 02:45:41 +00:00
|
|
|
use crate::context::QueryPathNode;
|
|
|
|
use crate::{registry, QueryPathSegment, Value};
|
2020-03-08 12:35:36 +00:00
|
|
|
|
2020-03-30 02:45:41 +00:00
|
|
|
fn valid_error(path_node: &QueryPathNode, msg: String) -> String {
|
|
|
|
format!("\"{}\", {}", path_node, msg)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_valid_input_value(
|
|
|
|
registry: ®istry::Registry,
|
|
|
|
type_name: &str,
|
|
|
|
value: &Value,
|
|
|
|
path_node: QueryPathNode,
|
|
|
|
) -> Option<String> {
|
2020-03-09 10:05:52 +00:00
|
|
|
if let Value::Variable(_) = value {
|
2020-03-30 02:45:41 +00:00
|
|
|
return None;
|
2020-03-09 10:05:52 +00:00
|
|
|
}
|
|
|
|
|
2020-03-19 09:20:12 +00:00
|
|
|
match registry::TypeName::create(type_name) {
|
|
|
|
registry::TypeName::NonNull(type_name) => match value {
|
2020-03-30 02:45:41 +00:00
|
|
|
Value::Null => Some(valid_error(
|
|
|
|
&path_node,
|
|
|
|
format!("expected type \"{}\"", type_name),
|
|
|
|
)),
|
|
|
|
_ => is_valid_input_value(registry, type_name, value, path_node),
|
2020-03-08 12:35:36 +00:00
|
|
|
},
|
2020-03-19 09:20:12 +00:00
|
|
|
registry::TypeName::List(type_name) => match value {
|
2020-03-30 02:45:41 +00:00
|
|
|
Value::List(elems) => {
|
|
|
|
for (idx, elem) in elems.iter().enumerate() {
|
|
|
|
if let Some(reason) = is_valid_input_value(
|
|
|
|
registry,
|
|
|
|
type_name,
|
|
|
|
elem,
|
|
|
|
QueryPathNode {
|
|
|
|
parent: Some(&path_node),
|
|
|
|
segment: QueryPathSegment::Index(idx),
|
|
|
|
},
|
|
|
|
) {
|
|
|
|
return Some(reason);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
_ => None,
|
2020-03-08 12:35:36 +00:00
|
|
|
},
|
2020-03-19 09:20:12 +00:00
|
|
|
registry::TypeName::Named(type_name) => {
|
2020-03-09 01:33:36 +00:00
|
|
|
if let Value::Null = value {
|
2020-03-30 02:45:41 +00:00
|
|
|
return None;
|
2020-03-09 01:33:36 +00:00
|
|
|
}
|
|
|
|
|
2020-03-08 12:35:36 +00:00
|
|
|
if let Some(ty) = registry.types.get(type_name) {
|
|
|
|
match ty {
|
2020-03-30 02:45:41 +00:00
|
|
|
registry::Type::Scalar { is_valid, .. } => {
|
|
|
|
if !is_valid(value) {
|
|
|
|
Some(valid_error(
|
|
|
|
&path_node,
|
|
|
|
format!("expected type \"{}\"", type_name),
|
|
|
|
))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2020-03-19 09:20:12 +00:00
|
|
|
registry::Type::Enum { enum_values, .. } => match value {
|
2020-03-30 02:45:41 +00:00
|
|
|
Value::Enum(name) => {
|
|
|
|
if !enum_values.contains_key(name.as_str()) {
|
|
|
|
Some(valid_error(
|
|
|
|
&path_node,
|
|
|
|
format!(
|
|
|
|
"enumeration type \"{}\" does not contain the value \"{}\"",
|
|
|
|
ty.name(),
|
|
|
|
name
|
|
|
|
),
|
|
|
|
))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => None,
|
2020-03-08 12:35:36 +00:00
|
|
|
},
|
2020-03-19 09:20:12 +00:00
|
|
|
registry::Type::InputObject { input_fields, .. } => match value {
|
2020-03-08 12:35:36 +00:00
|
|
|
Value::Object(values) => {
|
|
|
|
for field in input_fields {
|
2020-03-09 01:33:36 +00:00
|
|
|
let value = values.get(field.name).unwrap_or(&Value::Null);
|
2020-03-30 02:45:41 +00:00
|
|
|
|
|
|
|
if let Some(validator) = &field.validator {
|
|
|
|
if let Some(reason) = validator.is_valid(value) {
|
|
|
|
return Some(valid_error(
|
|
|
|
&QueryPathNode {
|
|
|
|
parent: Some(&path_node),
|
|
|
|
segment: QueryPathSegment::Name(field.name),
|
|
|
|
},
|
|
|
|
reason,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(reason) = is_valid_input_value(
|
|
|
|
registry,
|
|
|
|
&field.ty,
|
|
|
|
value,
|
|
|
|
QueryPathNode {
|
|
|
|
parent: Some(&path_node),
|
|
|
|
segment: QueryPathSegment::Name(field.name),
|
|
|
|
},
|
|
|
|
) {
|
|
|
|
return Some(reason);
|
2020-03-08 12:35:36 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-30 02:45:41 +00:00
|
|
|
None
|
2020-03-08 12:35:36 +00:00
|
|
|
}
|
2020-03-30 02:45:41 +00:00
|
|
|
_ => None,
|
2020-03-08 12:35:36 +00:00
|
|
|
},
|
2020-03-30 02:45:41 +00:00
|
|
|
_ => None,
|
2020-03-08 12:35:36 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|