1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use crate::{
ast::InputValue,
schema::{
meta::{EnumMeta, InputObjectMeta, MetaType},
model::{SchemaType, TypeType},
},
value::ScalarValue,
};
use std::collections::HashSet;
pub fn is_valid_literal_value<S>(
schema: &SchemaType<S>,
arg_type: &TypeType<S>,
arg_value: &InputValue<S>,
) -> bool
where
S: ScalarValue,
{
match *arg_type {
TypeType::NonNull(ref inner) => {
if arg_value.is_null() {
false
} else {
is_valid_literal_value(schema, inner, arg_value)
}
}
TypeType::List(ref inner) => match *arg_value {
InputValue::Null | InputValue::Variable(_) => true,
InputValue::List(ref items) => items
.iter()
.all(|i| is_valid_literal_value(schema, inner, &i.item)),
ref v => is_valid_literal_value(schema, inner, v),
},
TypeType::Concrete(t) => {
// Even though InputValue::String can be parsed into an enum, they
// are not valid as enum *literals* in a GraphQL query.
if let (&InputValue::Scalar(_), Some(&MetaType::Enum(EnumMeta { .. }))) =
(arg_value, arg_type.to_concrete())
{
return false;
}
match *arg_value {
InputValue::Null | InputValue::Variable(_) => true,
ref v @ InputValue::Scalar(_) | ref v @ InputValue::Enum(_) => {
if let Some(parse_fn) = t.input_value_parse_fn() {
parse_fn(v)
} else {
false
}
}
InputValue::List(_) => false,
InputValue::Object(ref obj) => {
if let MetaType::InputObject(InputObjectMeta {
ref input_fields, ..
}) = *t
{
let mut remaining_required_fields = input_fields
.iter()
.filter_map(|f| {
if f.arg_type.is_non_null() {
Some(&f.name)
} else {
None
}
})
.collect::<HashSet<_>>();
let all_types_ok = obj.iter().all(|&(ref key, ref value)| {
remaining_required_fields.remove(&key.item);
if let Some(ref arg_type) = input_fields
.iter()
.filter(|f| f.name == key.item)
.map(|f| schema.make_type(&f.arg_type))
.next()
{
is_valid_literal_value(schema, arg_type, &value.item)
} else {
false
}
});
all_types_ok && remaining_required_fields.is_empty()
} else {
false
}
}
}
}
}
}