2020-05-15 02:38:48 +00:00
|
|
|
use crate::parser::query::{FragmentDefinition, InlineFragment, TypeCondition, VariableDefinition};
|
2020-05-15 02:08:37 +00:00
|
|
|
use crate::registry::MetaTypeName;
|
2020-03-24 10:54:22 +00:00
|
|
|
use crate::validation::visitor::{Visitor, VisitorContext};
|
2020-05-10 02:59:51 +00:00
|
|
|
use crate::{Pos, Positioned};
|
2020-03-09 10:05:52 +00:00
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct KnownTypeNames;
|
|
|
|
|
|
|
|
impl<'a> Visitor<'a> for KnownTypeNames {
|
|
|
|
fn enter_fragment_definition(
|
|
|
|
&mut self,
|
2020-03-22 08:45:59 +00:00
|
|
|
ctx: &mut VisitorContext<'a>,
|
2020-05-10 02:59:51 +00:00
|
|
|
fragment_definition: &'a Positioned<FragmentDefinition>,
|
2020-03-09 10:05:52 +00:00
|
|
|
) {
|
2020-05-09 09:55:04 +00:00
|
|
|
let TypeCondition::On(name) = &fragment_definition.type_condition.node;
|
2020-05-16 13:14:26 +00:00
|
|
|
validate_type(ctx, name.as_str(), fragment_definition.position());
|
2020-03-09 10:05:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn enter_variable_definition(
|
|
|
|
&mut self,
|
2020-03-22 08:45:59 +00:00
|
|
|
ctx: &mut VisitorContext<'a>,
|
2020-05-10 02:59:51 +00:00
|
|
|
variable_definition: &'a Positioned<VariableDefinition>,
|
2020-03-09 10:05:52 +00:00
|
|
|
) {
|
|
|
|
validate_type(
|
|
|
|
ctx,
|
2020-05-15 02:08:37 +00:00
|
|
|
MetaTypeName::concrete_typename(&variable_definition.var_type.to_string()),
|
2020-05-09 09:55:04 +00:00
|
|
|
variable_definition.position(),
|
2020-03-09 10:05:52 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn enter_inline_fragment(
|
|
|
|
&mut self,
|
2020-03-22 08:45:59 +00:00
|
|
|
ctx: &mut VisitorContext<'a>,
|
2020-05-10 02:59:51 +00:00
|
|
|
inline_fragment: &'a Positioned<InlineFragment>,
|
2020-03-09 10:05:52 +00:00
|
|
|
) {
|
2020-05-09 09:55:04 +00:00
|
|
|
if let Some(TypeCondition::On(name)) =
|
|
|
|
inline_fragment.type_condition.as_ref().map(|c| &c.node)
|
|
|
|
{
|
2020-05-16 13:14:26 +00:00
|
|
|
validate_type(ctx, name.as_str(), inline_fragment.position());
|
2020-03-09 10:05:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-22 08:45:59 +00:00
|
|
|
fn validate_type(ctx: &mut VisitorContext<'_>, type_name: &str, pos: Pos) {
|
2020-03-09 10:05:52 +00:00
|
|
|
if ctx.registry.types.get(type_name).is_none() {
|
|
|
|
ctx.report_error(vec![pos], format!(r#"Unknown type "{}""#, type_name));
|
|
|
|
}
|
|
|
|
}
|
2020-04-05 08:00:26 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
use crate::validation::test_harness::{expect_fails_rule, expect_passes_rule};
|
|
|
|
|
|
|
|
pub fn factory() -> KnownTypeNames {
|
|
|
|
KnownTypeNames::default()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn known_type_names_are_valid() {
|
|
|
|
expect_passes_rule(
|
|
|
|
factory,
|
|
|
|
r#"
|
|
|
|
query Foo($var: String, $required: [String!]!) {
|
|
|
|
user(id: 4) {
|
|
|
|
pets { ... on Pet { name }, ...PetFields, ... { name } }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fragment PetFields on Pet {
|
|
|
|
name
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn unknown_type_names_are_invalid() {
|
|
|
|
expect_fails_rule(
|
|
|
|
factory,
|
|
|
|
r#"
|
|
|
|
query Foo($var: JumbledUpLetters) {
|
|
|
|
user(id: 4) {
|
|
|
|
name
|
|
|
|
pets { ... on Badger { name }, ...PetFields }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fragment PetFields on Peettt {
|
|
|
|
name
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|