Add support for the `list` operator to the input value validator. #579

This commit is contained in:
Sunli 2021-07-20 15:16:34 +08:00
parent ecf8890e7e
commit 230eb847d8
7 changed files with 128 additions and 5 deletions

View File

@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Implement `TryFrom<&[SelectionField<'a>]>` for `Lookahead<'a>`. [#575](https://github.com/async-graphql/async-graphql/issues/575)
- Attach custom HTTP headers to the response when an error occurs. [#572](https://github.com/async-graphql/async-graphql/issues/572)
- Allow field visible to support paths. [#578](https://github.com/async-graphql/async-graphql/pull/578)
- Add support for the `list` operator to the input value validator. [#579](https://github.com/async-graphql/async-graphql/issues/579)
## [2.9.8] 2021-07-12

View File

@ -77,6 +77,23 @@ fn generate_nested_validator(
None => Some(item),
})
.unwrap())
} else if ls.path.is_ident("list") {
if ls.nested.len() > 1 {
return Err(Error::new_spanned(
ls,
"Only one validator can be wrapped with list.",
)
.into());
}
if ls.nested.is_empty() {
return Err(
Error::new_spanned(ls, "At least one validator must be defined").into(),
);
}
let validator = generate_nested_validator(crate_name, &ls.nested[0])?;
Ok(quote! {
#crate_name::validators::List(#validator)
})
} else {
let ty = &ls.path;
for item in &ls.nested {

View File

@ -24,7 +24,7 @@ impl Query {
The following example verifies that the `i32` parameter `a` is greater than 10 and less than 100, or else equal to 0:
```rust
use async_graphql:*;
use async_graphql::*;
use async_graphql::validators::{IntGreaterThan, IntLessThan, IntEqual};
struct Query;
@ -36,7 +36,23 @@ impl Query {
and(IntGreaterThan(value = "10"), IntLessThan(value = "100")),
IntEqual(value = "0")
)))] a: String) {
} {
}
}
```
## Validate the elements of the list.
You can use the `list` operator to indicate that the internal validator is used for all elements in a list:
```rust
use async_graphql::*;
use async_graphql::validators::Email;
struct Query;
#[Object]
impl Query {
async fn input(#[graphql(validator(list(Email)))] emails: Vec<String>) {
}
}
```

View File

@ -22,7 +22,7 @@ impl Query {
下面的例子校验`i32`类型的参数`a`必须大于10并且小于100或者等于0
```rust
use async_graphql:*;
use async_graphql::*;
use async_graphql::validators::{IntGreaterThan, IntLessThan, IntEqual};
struct Query;
@ -34,7 +34,23 @@ impl Query {
and(IntGreaterThan(value = "10"), IntLessThan(value = "100")),
IntEqual(value = "0")
)))] a: String) {
} {
}
}
```
## 校验列表成员
你可以用`list`操作符表示内部的校验器作用于一个列表内的所有成员:
```rust
use async_graphql::*;
use async_graphql::validators::{Email};
struct Query;
#[Object]
impl Query {
async fn input(#[graphql(validator(list(Email)))] emails: Vec<String>) {
}
}
```

View File

@ -48,3 +48,17 @@ impl InputValueValidator for ListMaxLength {
}
}
}
#[doc(hidden)]
pub struct List<T>(pub T);
impl<T: InputValueValidator> InputValueValidator for List<T> {
fn is_valid(&self, value: &Value) -> Result<(), String> {
if let Value::List(elems) = value {
for elem in elems {
self.0.is_valid(elem)?;
}
}
Ok(())
}
}

View File

@ -7,7 +7,7 @@ mod string_validators;
use crate::{Error, Value};
pub use int_validators::{IntEqual, IntGreaterThan, IntLessThan, IntNonZero, IntRange};
pub use list_validators::{ListMaxLength, ListMinLength};
pub use list_validators::{List, ListMaxLength, ListMinLength};
pub use string_validators::{Email, StringMaxLength, StringMinLength, MAC};
/// Input value validator

View File

@ -1829,3 +1829,62 @@ pub async fn test_custom_input_validator_with_extensions() {
}]
);
}
#[tokio::test]
pub async fn test_input_validator_list() {
struct QueryRoot;
#[derive(InputObject)]
struct InputEmail {
#[graphql(validator(list(Email)))]
pub emails: Vec<String>,
}
#[Object]
impl QueryRoot {
async fn value(&self, #[graphql(validator(list(Email)))] _emails: Vec<String>) -> bool {
true
}
}
let schema = Schema::new(QueryRoot, EmptyMutation, EmptySubscription);
assert_eq!(
schema
.execute(
r#"
{
value(
emails: [
"a@a.com",
"b@abc.com",
]
)
}"#
)
.await
.into_result()
.unwrap()
.data,
value!({"value": true})
);
assert_eq!(
schema
.execute(
r#"
{
value(
emails: [
"123456",
]
)
}"#
)
.await
.into_result()
.unwrap_err()[0]
.message,
"Invalid value for argument \"emails\", invalid email format"
);
}