From 53c4945fc4e6b96c9819d521746e82b03a18b972 Mon Sep 17 00:00:00 2001 From: Rodgers Date: Thu, 8 Jul 2021 23:43:12 +0700 Subject: [PATCH] Update AND, OR, and MapErr logic. Update logic for object input --- .../rules/arguments_of_correct_type.rs | 7 +- .../rules/default_values_of_correct_type.rs | 7 +- src/validation/utils.rs | 98 +++++++++++-------- src/validators/mod.rs | 25 ++--- 4 files changed, 78 insertions(+), 59 deletions(-) diff --git a/src/validation/rules/arguments_of_correct_type.rs b/src/validation/rules/arguments_of_correct_type.rs index a51fc7f7..749692d7 100644 --- a/src/validation/rules/arguments_of_correct_type.rs +++ b/src/validation/rules/arguments_of_correct_type.rs @@ -68,7 +68,7 @@ impl<'a> Visitor<'a> for ArgumentsOfCorrectType<'a> { } } - if let Some(reason) = value.and_then(|value| { + if let Some(e) = value.and_then(|value| { is_valid_input_value( ctx.registry, &arg.ty, @@ -79,9 +79,10 @@ impl<'a> Visitor<'a> for ArgumentsOfCorrectType<'a> { }, ) }) { - ctx.report_error( + ctx.report_error_with_extensions( vec![name.pos], - format!("Invalid value for argument {}", reason), + format!("Invalid value for argument {}", e.message), + e.extensions, ); } } diff --git a/src/validation/rules/default_values_of_correct_type.rs b/src/validation/rules/default_values_of_correct_type.rs index c3346c75..2e10783d 100644 --- a/src/validation/rules/default_values_of_correct_type.rs +++ b/src/validation/rules/default_values_of_correct_type.rs @@ -18,7 +18,7 @@ impl<'a> Visitor<'a> for DefaultValuesOfCorrectType { "Argument \"{}\" has type \"{}\" and is not nullable, so it can't have a default value", variable_definition.node.name, variable_definition.node.var_type, )); - } else if let Some(reason) = is_valid_input_value( + } else if let Some(e) = is_valid_input_value( ctx.registry, &variable_definition.node.var_type.to_string(), &value.node, @@ -27,9 +27,10 @@ impl<'a> Visitor<'a> for DefaultValuesOfCorrectType { segment: QueryPathSegment::Name(&variable_definition.node.name.node), }, ) { - ctx.report_error( + ctx.report_error_with_extensions( vec![variable_definition.pos], - format!("Invalid default value for argument {}", reason), + format!("Invalid default value for argument {}", e.message), + e.extensions, ) } } diff --git a/src/validation/utils.rs b/src/validation/utils.rs index ac709bfe..843323c8 100644 --- a/src/validation/utils.rs +++ b/src/validation/utils.rs @@ -1,9 +1,11 @@ use std::collections::HashSet; -use crate::context::QueryPathNode; -use crate::{registry, QueryPathSegment}; use async_graphql_value::{ConstValue, Value}; +use crate::context::QueryPathNode; +use crate::error::Error; +use crate::{registry, QueryPathSegment}; + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Scope<'a> { Operation(Option<&'a str>), @@ -40,13 +42,12 @@ pub fn is_valid_input_value( type_name: &str, value: &ConstValue, path_node: QueryPathNode, -) -> Option { +) -> Option { match registry::MetaTypeName::create(type_name) { registry::MetaTypeName::NonNull(type_name) => match value { - ConstValue::Null => Some(valid_error( - &path_node, - format!("expected type \"{}\"", type_name), - )), + ConstValue::Null => { + Some(valid_error(&path_node, format!("expected type \"{}\"", type_name)).into()) + } _ => is_valid_input_value(registry, type_name, value, path_node), }, registry::MetaTypeName::List(type_name) => match value { @@ -74,10 +75,10 @@ pub fn is_valid_input_value( if is_valid(&value) { None } else { - Some(valid_error( - &path_node, - format!("expected type \"{}\"", type_name), - )) + Some( + valid_error(&path_node, format!("expected type \"{}\"", type_name)) + .into(), + ) } } registry::MetaType::Enum { @@ -87,34 +88,39 @@ pub fn is_valid_input_value( } => match value { ConstValue::Enum(name) => { if !enum_values.contains_key(name.as_str()) { - Some(valid_error( - &path_node, - format!( - "enumeration type \"{}\" does not contain the value \"{}\"", - enum_name, name - ), - )) + Some( + valid_error( + &path_node, + format!( + "enumeration type \"{}\" does not contain the value \"{}\"", + enum_name, name + ), + ) + .into(), + ) } else { None } } ConstValue::String(name) => { if !enum_values.contains_key(name.as_str()) { - Some(valid_error( - &path_node, - format!( - "enumeration type \"{}\" does not contain the value \"{}\"", - enum_name, name - ), - )) + Some( + valid_error( + &path_node, + format!( + "enumeration type \"{}\" does not contain the value \"{}\"", + enum_name, name + ), + ) + .into(), + ) } else { None } } - _ => Some(valid_error( - &path_node, - format!("expected type \"{}\"", type_name), - )), + _ => Some( + valid_error(&path_node, format!("expected type \"{}\"", type_name)).into(), + ), }, registry::MetaType::InputObject { input_fields, @@ -129,14 +135,15 @@ pub fn is_valid_input_value( input_names.remove(field.name); if let Some(value) = values.get(field.name) { if let Some(validator) = &field.validator { - if let Err(reason) = validator.is_valid(value) { - return Some(valid_error( + if let Err(mut e) = validator.is_valid_with_extensions(value) { + e.message = valid_error( &QueryPathNode { parent: Some(&path_node), segment: QueryPathSegment::Name(field.name), }, - reason, - )); + e.message, + ); + return Some(e); } } @@ -154,21 +161,30 @@ pub fn is_valid_input_value( } else if registry::MetaTypeName::create(&field.ty).is_non_null() && field.default_value.is_none() { - return Some(valid_error( - &path_node, - format!( + return Some( + valid_error( + &path_node, + format!( "field \"{}\" of type \"{}\" is required but not provided", field.name, object_name, ), - )); + ) + .into(), + ); } } if let Some(name) = input_names.iter().next() { - return Some(valid_error( - &path_node, - format!("unknown field \"{}\" of type \"{}\"", name, object_name), - )); + return Some( + valid_error( + &path_node, + format!( + "unknown field \"{}\" of type \"{}\"", + name, object_name + ), + ) + .into(), + ); } None diff --git a/src/validators/mod.rs b/src/validators/mod.rs index a8fc6651..b1459441 100644 --- a/src/validators/mod.rs +++ b/src/validators/mod.rs @@ -80,8 +80,7 @@ where /// ``` fn is_valid_with_extensions(&self, value: &Value) -> Result<(), Error> { // By default, use is_valid method to keep compatible with previous version - self.is_valid(value)?; - Ok(()) + self.is_valid(value).map_err(|reason| Error::new(reason)) } } @@ -98,7 +97,7 @@ pub trait InputValueValidatorExt: InputValueValidator + Sized { } /// Changes the error message - fn map_err String>(self, f: F) -> MapErr { + fn map_err Error>(self, f: F) -> MapErr { MapErr(self, f) } } @@ -113,9 +112,10 @@ where A: InputValueValidator, B: InputValueValidator, { - fn is_valid(&self, value: &Value) -> Result<(), String> { - self.0.is_valid(value)?; - self.1.is_valid(value) + fn is_valid_with_extensions(&self, value: &Value) -> Result<(), Error> { + // By default, use is_valid method to keep compatible with previous version + self.0.is_valid_with_extensions(value)?; + self.1.is_valid_with_extensions(value) } } @@ -127,9 +127,10 @@ where A: InputValueValidator, B: InputValueValidator, { - fn is_valid(&self, value: &Value) -> Result<(), String> { - if self.0.is_valid(value).is_err() { - self.1.is_valid(value) + fn is_valid_with_extensions(&self, value: &Value) -> Result<(), Error> { + // By default, use is_valid method to keep compatible with previous version + if self.0.is_valid_with_extensions(value).is_err() { + self.1.is_valid_with_extensions(value) } else { Ok(()) } @@ -142,9 +143,9 @@ pub struct MapErr(I, F); impl InputValueValidator for MapErr where I: InputValueValidator, - F: Fn(String) -> String + Send + Sync, + F: Fn(Error) -> Error + Send + Sync, { - fn is_valid(&self, value: &Value) -> Result<(), String> { - self.0.is_valid(value).map_err(&self.1) + fn is_valid_with_extensions(&self, value: &Value) -> Result<(), Error> { + self.0.is_valid_with_extensions(value).map_err(&self.1) } }