Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/validation/rules/defaults.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use super::{
OverlappingFieldsCanBeMerged, PossibleFragmentSpreads, ProvidedRequiredArguments,
SingleFieldSubscriptions, UniqueArgumentNames, UniqueDirectivesPerLocation,
UniqueFragmentNames, UniqueOperationNames, UniqueVariableNames, ValuesOfCorrectType,
VariablesAreInputTypes, VariablesInAllowedPosition,
VariablesAreInputTypes, VariablesInAllowedPosition, KnownOperationTypes
};

pub fn default_rules_validation_plan() -> ValidationPlan {
Expand Down Expand Up @@ -37,6 +37,8 @@ pub fn default_rules_validation_plan() -> ValidationPlan {
plan.add_rule(Box::new(VariablesInAllowedPosition::new()));
plan.add_rule(Box::new(ValuesOfCorrectType::new()));
plan.add_rule(Box::new(UniqueDirectivesPerLocation::new()));
plan.add_rule(Box::new(UniqueDirectivesPerLocation::new()));
plan.add_rule(Box::new(KnownOperationTypes::new()));

plan
}
140 changes: 140 additions & 0 deletions src/validation/rules/known_operation_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
use super::ValidationRule;
use crate::ast::{ visit_document, OperationVisitor, OperationVisitorContext, SchemaDocumentExtension,
};
use crate::static_graphql::query::*;
use crate::validation::utils::{ValidationError, ValidationErrorContext};

/// Known operation types
///
/// A GraphQL operation is only valid if the operation type is within the schema.
///
/// See https://github.com/graphql/graphql-spec/pull/947
pub struct KnownOperationTypes;

impl KnownOperationTypes {
pub fn new() -> Self {
KnownOperationTypes
}
}

fn build_error_message(root_type_name: &str) -> String {
format!("The {} operation is not supported by the schema.", root_type_name)
}

impl<'a> OperationVisitor<'a, ValidationErrorContext> for KnownOperationTypes {
fn enter_operation_definition(
&mut self,
visitor_context: &mut OperationVisitorContext,
user_context: &mut ValidationErrorContext,
operation_definition: &OperationDefinition,
) {
match operation_definition {
OperationDefinition::Mutation(mutation) => {
if let None = visitor_context.schema.mutation_type() {
user_context.report_error(ValidationError {
locations: vec![mutation.position],
message: build_error_message("mutation"),
});
}
},
OperationDefinition::Subscription(subscription) => {
if let None = visitor_context.schema.subscription_type() {
user_context.report_error(ValidationError {
locations: vec![subscription.position],
message: build_error_message("subscription"),
});
}
},
OperationDefinition::SelectionSet(_) => {},
OperationDefinition::Query(_) => {},
}
}
}

impl ValidationRule for KnownOperationTypes {
fn validate<'a>(
&self,
ctx: &'a mut OperationVisitorContext,
error_collector: &mut ValidationErrorContext,
) {
visit_document(
&mut KnownOperationTypes::new(),
&ctx.operation,
ctx,
error_collector,
);
}
}

#[test]
fn one_known_operation() {
use crate::validation::test_utils::*;

let mut plan = create_plan_from_rule(Box::new(KnownOperationTypes {}));
let errors = test_operation_with_schema(
"{ field }",
TEST_SCHEMA,
&mut plan,
);

assert_eq!(get_messages(&errors).len(), 0);
}

#[test]
fn unknown_mutation_operation() {
use crate::validation::test_utils::*;

let mut plan = create_plan_from_rule(Box::new(KnownOperationTypes {}));
let errors = test_operation_with_schema(
"mutation { field }",
"type Query { _: String }",
&mut plan,
);

let messages = get_messages(&errors);
assert_eq!(messages.len(), 1);
assert_eq!(
messages,
vec!["The mutation operation is not supported by the schema."]
);
}

#[test]
fn unknown_subscription_operation() {
use crate::validation::test_utils::*;

let mut plan = create_plan_from_rule(Box::new(KnownOperationTypes {}));
let errors = test_operation_with_schema(
"subscription { field }",
"type Query { _: String }",
&mut plan,
);

let messages = get_messages(&errors);
assert_eq!(messages.len(), 1);
assert_eq!(
messages,
vec!["The subscription operation is not supported by the schema."]
);
}

#[test]
fn mixture_of_known_and_unknown_operations() {
use crate::validation::test_utils::*;

let mut plan = create_plan_from_rule(Box::new(KnownOperationTypes {}));
let errors = test_operation_with_schema(
"query { field }
mutation { field }
subscription { field }",
"type Query { field: String }",
&mut plan,
);

let messages = get_messages(&errors);
assert_eq!(messages.len(), 2);
assert_eq!(
messages,
vec!["The mutation operation is not supported by the schema.", "The subscription operation is not supported by the schema."]
);
}
2 changes: 2 additions & 0 deletions src/validation/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub mod unique_variable_names;
pub mod values_of_correct_type;
pub mod variables_are_input_types;
pub mod variables_in_allowed_position;
pub mod known_operation_types;

pub use self::defaults::*;
pub use self::rule::*;
Expand Down Expand Up @@ -53,3 +54,4 @@ pub use self::unique_variable_names::*;
pub use self::values_of_correct_type::*;
pub use self::variables_are_input_types::*;
pub use self::variables_in_allowed_position::*;
pub use self::known_operation_types::*;