Supported CharsMinLength and CharsMaxLength to count chars
This commit is contained in:
parent
cf74a6c5d2
commit
5fd0561a3a
|
@ -8,7 +8,9 @@ use crate::{Error, Value};
|
||||||
|
|
||||||
pub use int_validators::{IntEqual, IntGreaterThan, IntLessThan, IntNonZero, IntRange};
|
pub use int_validators::{IntEqual, IntGreaterThan, IntLessThan, IntNonZero, IntRange};
|
||||||
pub use list_validators::{List, ListMaxLength, ListMinLength};
|
pub use list_validators::{List, ListMaxLength, ListMinLength};
|
||||||
pub use string_validators::{Email, StringMaxLength, StringMinLength, MAC};
|
pub use string_validators::{
|
||||||
|
CharsMaxLength, CharsMinLength, Email, StringMaxLength, StringMinLength, MAC,
|
||||||
|
};
|
||||||
|
|
||||||
/// Input value validator
|
/// Input value validator
|
||||||
///
|
///
|
||||||
|
|
|
@ -52,6 +52,54 @@ impl InputValueValidator for StringMaxLength {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Chars minimum length validator. This supports multibyte character.
|
||||||
|
pub struct CharsMinLength {
|
||||||
|
/// Must be greater than or equal to this value.
|
||||||
|
pub length: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InputValueValidator for CharsMinLength {
|
||||||
|
fn is_valid(&self, value: &Value) -> Result<(), String> {
|
||||||
|
if let Value::String(s) = value {
|
||||||
|
if s.chars().count() < self.length as usize {
|
||||||
|
Err(format!(
|
||||||
|
"the value chars count is {}, must be greater than or equal to {}",
|
||||||
|
s.chars().count(),
|
||||||
|
self.length
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Chars maximum length validator. This supports multibyte characters.
|
||||||
|
pub struct CharsMaxLength {
|
||||||
|
/// Must be less than or equal to this value.
|
||||||
|
pub length: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InputValueValidator for CharsMaxLength {
|
||||||
|
fn is_valid(&self, value: &Value) -> Result<(), String> {
|
||||||
|
if let Value::String(s) = value {
|
||||||
|
if s.chars().count() > self.length as usize {
|
||||||
|
Err(format!(
|
||||||
|
"the value chars count is {}, must be less than or equal to {}",
|
||||||
|
s.chars().count(),
|
||||||
|
self.length
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static EMAIL_RE: Lazy<Regex> = Lazy::new(|| {
|
static EMAIL_RE: Lazy<Regex> = Lazy::new(|| {
|
||||||
Regex::new("^(([0-9A-Za-z!#$%&'*+-/=?^_`{|}~&&[^@]]+)|(\"([0-9A-Za-z!#$%&'*+-/=?^_`{|}~ \"(),:;<>@\\[\\\\\\]]+)\"))@").unwrap()
|
Regex::new("^(([0-9A-Za-z!#$%&'*+-/=?^_`{|}~&&[^@]]+)|(\"([0-9A-Za-z!#$%&'*+-/=?^_`{|}~ \"(),:;<>@\\[\\\\\\]]+)\"))@").unwrap()
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use async_graphql::validators::{
|
use async_graphql::validators::{
|
||||||
Email, InputValueValidator, IntEqual, IntGreaterThan, IntLessThan, IntNonZero, IntRange,
|
CharsMaxLength, CharsMinLength, Email, InputValueValidator, IntEqual, IntGreaterThan,
|
||||||
ListMaxLength, ListMinLength, StringMaxLength, StringMinLength, MAC,
|
IntLessThan, IntNonZero, IntRange, ListMaxLength, ListMinLength, StringMaxLength,
|
||||||
|
StringMinLength, MAC,
|
||||||
};
|
};
|
||||||
use async_graphql::*;
|
use async_graphql::*;
|
||||||
|
|
||||||
|
@ -230,6 +231,226 @@ pub async fn test_input_validator_string_max_length() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
pub async fn test_input_validator_chars_min_length() {
|
||||||
|
struct QueryRoot;
|
||||||
|
|
||||||
|
#[derive(InputObject)]
|
||||||
|
struct InputMaxLength {
|
||||||
|
#[graphql(validator(CharsMinLength(length = "6")))]
|
||||||
|
pub id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Object]
|
||||||
|
impl QueryRoot {
|
||||||
|
async fn field_parameter(
|
||||||
|
&self,
|
||||||
|
#[graphql(validator(CharsMinLength(length = "6")))] _id: String,
|
||||||
|
) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn input_object(&self, _input: InputMaxLength) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let schema = Schema::new(QueryRoot, EmptyMutation, EmptySubscription);
|
||||||
|
let test_cases = ["一2三4五", "壹2叁4伍6", "一2三4五6七", "壹2叁4伍6Ⅶ8"];
|
||||||
|
|
||||||
|
let validator_length = 6;
|
||||||
|
for case in &test_cases {
|
||||||
|
let field_query = format!("{{fieldParameter(id: \"{}\")}}", case);
|
||||||
|
let object_query = format!("{{inputObject(input: {{id: \"{}\"}})}}", case);
|
||||||
|
let case_length = case.chars().count();
|
||||||
|
|
||||||
|
if case_length < validator_length {
|
||||||
|
let should_fail_msg = format!(
|
||||||
|
"CharsMinLength case {} should have failed, but did not",
|
||||||
|
case
|
||||||
|
);
|
||||||
|
|
||||||
|
let field_error_msg = format!(
|
||||||
|
"Invalid value for argument \"id\", the value chars count is {}, must be greater than or equal to {}",
|
||||||
|
case_length, validator_length
|
||||||
|
);
|
||||||
|
let object_error_msg = format!(
|
||||||
|
"Invalid value for argument \"input.id\", the value chars count is {}, must be greater than or equal to {}",
|
||||||
|
case_length, validator_length
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
schema
|
||||||
|
.execute(&field_query)
|
||||||
|
.await
|
||||||
|
.into_result()
|
||||||
|
.expect_err(&should_fail_msg),
|
||||||
|
vec![ServerError {
|
||||||
|
message: field_error_msg,
|
||||||
|
locations: vec!(Pos {
|
||||||
|
line: 1,
|
||||||
|
column: 17
|
||||||
|
}),
|
||||||
|
path: Vec::new(),
|
||||||
|
extensions: None,
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
schema
|
||||||
|
.execute(&object_query)
|
||||||
|
.await
|
||||||
|
.into_result()
|
||||||
|
.expect_err(&should_fail_msg[..]),
|
||||||
|
vec![ServerError {
|
||||||
|
message: object_error_msg,
|
||||||
|
locations: vec!(Pos {
|
||||||
|
line: 1,
|
||||||
|
column: 14
|
||||||
|
}),
|
||||||
|
path: Vec::new(),
|
||||||
|
extensions: None,
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let error_msg = format!("Schema returned error with test_string = {}", case);
|
||||||
|
assert_eq!(
|
||||||
|
schema
|
||||||
|
.execute(&field_query)
|
||||||
|
.await
|
||||||
|
.into_result()
|
||||||
|
.expect(&error_msg[..])
|
||||||
|
.data,
|
||||||
|
value!({"fieldParameter": true}),
|
||||||
|
"Failed to validate {} with CharsMinLength",
|
||||||
|
case
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
schema
|
||||||
|
.execute(&object_query)
|
||||||
|
.await
|
||||||
|
.into_result()
|
||||||
|
.expect(&error_msg[..])
|
||||||
|
.data,
|
||||||
|
value!({"inputObject": true}),
|
||||||
|
"Failed to validate {} with CharsMinLength",
|
||||||
|
case
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
pub async fn test_input_validator_chars_max_length() {
|
||||||
|
struct QueryRoot;
|
||||||
|
|
||||||
|
#[derive(InputObject)]
|
||||||
|
struct InputMaxLength {
|
||||||
|
#[graphql(validator(CharsMaxLength(length = "6")))]
|
||||||
|
pub id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Object]
|
||||||
|
impl QueryRoot {
|
||||||
|
async fn field_parameter(
|
||||||
|
&self,
|
||||||
|
#[graphql(validator(CharsMaxLength(length = "6")))] _id: String,
|
||||||
|
) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn input_object(&self, _input: InputMaxLength) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let schema = Schema::new(QueryRoot, EmptyMutation, EmptySubscription);
|
||||||
|
let test_cases = ["一2三4五", "壹2叁4伍6", "一2三4五6七", "壹2叁4伍6Ⅶ8"];
|
||||||
|
|
||||||
|
let validator_length = 6;
|
||||||
|
for case in &test_cases {
|
||||||
|
let field_query = format!("{{fieldParameter(id: \"{}\")}}", case);
|
||||||
|
let object_query = format!("{{inputObject(input: {{id: \"{}\"}})}}", case);
|
||||||
|
let case_length = case.chars().count();
|
||||||
|
|
||||||
|
if case_length > validator_length {
|
||||||
|
let should_fail_msg = format!(
|
||||||
|
"CharsMaxLength case {} should have failed, but did not",
|
||||||
|
case
|
||||||
|
);
|
||||||
|
|
||||||
|
let field_error_msg = format!(
|
||||||
|
"Invalid value for argument \"id\", the value chars count is {}, must be less than or equal to {}",
|
||||||
|
case_length,
|
||||||
|
validator_length
|
||||||
|
);
|
||||||
|
let object_error_msg = format!(
|
||||||
|
"Invalid value for argument \"input.id\", the value chars count is {}, must be less than or equal to {}",
|
||||||
|
case_length,
|
||||||
|
validator_length
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
schema
|
||||||
|
.execute(&field_query)
|
||||||
|
.await
|
||||||
|
.into_result()
|
||||||
|
.expect_err(&should_fail_msg[..]),
|
||||||
|
vec![ServerError {
|
||||||
|
message: field_error_msg,
|
||||||
|
locations: vec!(Pos {
|
||||||
|
line: 1,
|
||||||
|
column: 17
|
||||||
|
}),
|
||||||
|
path: Vec::new(),
|
||||||
|
extensions: None,
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
schema
|
||||||
|
.execute(&object_query)
|
||||||
|
.await
|
||||||
|
.into_result()
|
||||||
|
.expect_err(&should_fail_msg[..]),
|
||||||
|
vec![ServerError {
|
||||||
|
message: object_error_msg,
|
||||||
|
locations: vec!(Pos {
|
||||||
|
line: 1,
|
||||||
|
column: 14
|
||||||
|
}),
|
||||||
|
path: Vec::new(),
|
||||||
|
extensions: None,
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let error_msg = format!("Schema returned error with test_string = {}", case);
|
||||||
|
assert_eq!(
|
||||||
|
schema
|
||||||
|
.execute(&field_query)
|
||||||
|
.await
|
||||||
|
.into_result()
|
||||||
|
.expect(&error_msg[..])
|
||||||
|
.data,
|
||||||
|
value!({"fieldParameter": true}),
|
||||||
|
"Failed to validate {} with CharsMaxLength",
|
||||||
|
case
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
schema
|
||||||
|
.execute(&object_query)
|
||||||
|
.await
|
||||||
|
.into_result()
|
||||||
|
.expect(&error_msg[..])
|
||||||
|
.data,
|
||||||
|
value!({"inputObject": true}),
|
||||||
|
"Failed to validate {} with CharsMaxLength",
|
||||||
|
case
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
pub async fn test_input_validator_string_email() {
|
pub async fn test_input_validator_string_email() {
|
||||||
struct QueryRoot;
|
struct QueryRoot;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user