async-graphql/src/validation/rules/scalar_leafs.rs
2020-04-05 16:00:26 +08:00

150 lines
3.8 KiB
Rust

use crate::validation::visitor::{Visitor, VisitorContext};
use graphql_parser::query::Field;
#[derive(Default)]
pub struct ScalarLeafs;
impl<'a> Visitor<'a> for ScalarLeafs {
fn enter_field(&mut self, ctx: &mut VisitorContext<'a>, field: &'a Field) {
if let Some(ty) = ctx.parent_type() {
if let Some(schema_field) = ty.field_by_name(&field.name) {
if let Some(ty) = ctx.registry.basic_type_by_typename(&schema_field.ty) {
if ty.is_leaf() && !field.selection_set.items.is_empty() {
ctx.report_error(vec![field.position], format!(
"Field \"{}\" must not have a selection since type \"{}\" has no subfields",
field.name, ty.name()
))
} else if !ty.is_leaf() && field.selection_set.items.is_empty() {
ctx.report_error(
vec![field.position],
format!(
"Field \"{}\" of type \"{}\" must have a selection of subfields",
field.name,
ty.name()
),
)
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::validation::test_harness::{expect_fails_rule, expect_passes_rule};
pub fn factory() -> ScalarLeafs {
ScalarLeafs
}
#[test]
fn valid_scalar_selection() {
expect_passes_rule(
factory,
r#"
fragment scalarSelection on Dog {
barks
}
"#,
);
}
#[test]
fn object_type_missing_selection() {
expect_fails_rule(
factory,
r#"
query directQueryOnObjectWithoutSubFields {
human
}
"#,
);
}
#[test]
fn interface_type_missing_selection() {
expect_fails_rule(
factory,
r#"
{
human { pets }
}
"#,
);
}
#[test]
fn valid_scalar_selection_with_args() {
expect_passes_rule(
factory,
r#"
fragment scalarSelectionWithArgs on Dog {
doesKnowCommand(dogCommand: SIT)
}
"#,
);
}
#[test]
fn scalar_selection_not_allowed_on_boolean() {
expect_fails_rule(
factory,
r#"
fragment scalarSelectionsNotAllowedOnBoolean on Dog {
barks { sinceWhen }
}
"#,
);
}
#[test]
fn scalar_selection_not_allowed_on_enum() {
expect_fails_rule(
factory,
r#"
fragment scalarSelectionsNotAllowedOnEnum on Cat {
furColor { inHexdec }
}
"#,
);
}
#[test]
fn scalar_selection_not_allowed_with_args() {
expect_fails_rule(
factory,
r#"
fragment scalarSelectionsNotAllowedWithArgs on Dog {
doesKnowCommand(dogCommand: SIT) { sinceWhen }
}
"#,
);
}
#[test]
fn scalar_selection_not_allowed_with_directives() {
expect_fails_rule(
factory,
r#"
fragment scalarSelectionsNotAllowedWithDirectives on Dog {
name @include(if: true) { isAlsoHumanName }
}
"#,
);
}
#[test]
fn scalar_selection_not_allowed_with_directives_and_args() {
expect_fails_rule(
factory,
r#"
fragment scalarSelectionsNotAllowedWithDirectivesAndArgs on Dog {
doesKnowCommand(dogCommand: SIT) @include(if: true) { sinceWhen }
}
"#,
);
}
}