Rework validators 3

This commit is contained in:
Sunli 2021-11-15 18:19:02 +08:00
parent 613bbc5b91
commit 71cbb9d20c
2 changed files with 95 additions and 10 deletions

View File

@ -1,17 +1,42 @@
use darling::util::SpannedValue;
use darling::FromMeta;
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Expr, Result};
use quote::{quote, ToTokens};
use syn::{Expr, Lit, Result};
#[derive(Clone)]
pub enum Number {
F64(f64),
I64(i64),
}
impl FromMeta for Number {
fn from_value(value: &Lit) -> darling::Result<Self> {
match value {
Lit::Int(n) => Ok(Number::I64(n.base10_parse::<i64>()?)),
Lit::Float(n) => Ok(Number::F64(n.base10_parse::<f64>()?)),
_ => Err(darling::Error::unexpected_type("number")),
}
}
}
impl ToTokens for Number {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
Number::F64(n) => tokens.extend(quote!(#n as f64)),
Number::I64(n) => tokens.extend(quote!(#n as i64)),
}
}
}
#[derive(FromMeta, Default, Clone)]
pub struct Validators {
#[darling(default)]
multiple_of: Option<f64>,
multiple_of: Option<Number>,
#[darling(default)]
maximum: Option<f64>,
maximum: Option<Number>,
#[darling(default)]
minimum: Option<f64>,
minimum: Option<Number>,
#[darling(default)]
max_length: Option<usize>,
#[darling(default)]
@ -22,6 +47,8 @@ pub struct Validators {
min_items: Option<usize>,
#[darling(default, multiple)]
custom: Vec<SpannedValue<String>>,
#[darling(default)]
list: bool,
}
impl Validators {
@ -33,6 +60,13 @@ impl Validators {
map_err: Option<TokenStream>,
) -> Result<TokenStream> {
let mut codes = Vec::new();
let mut value = value;
let mut container = None;
if self.list {
container = Some(quote!(#value));
value = quote!(__item);
}
if let Some(n) = &self.multiple_of {
codes.push(quote! {
@ -85,6 +119,15 @@ impl Validators {
}
let codes = codes.into_iter().map(|s| quote!(#s #map_err ?));
Ok(quote!(#(#codes;)*))
if let Some(container) = container {
Ok(quote! {
for __item in #container {
#(#codes;)*
}
})
} else {
Ok(quote!(#(#codes;)*))
}
}
}

View File

@ -7,7 +7,7 @@ pub async fn test_validator_on_object_field_args() {
#[Object]
impl Query {
async fn value(&self, #[graphql(validator(maximum = "10"))] n: i32) -> i32 {
async fn value(&self, #[graphql(validator(maximum = 10))] n: i32) -> i32 {
n
}
}
@ -47,7 +47,7 @@ pub async fn test_validator_on_object_field_args() {
pub async fn test_validator_on_input_object_field() {
#[derive(InputObject)]
struct MyInput {
#[graphql(validator(maximum = "10"))]
#[graphql(validator(maximum = 10))]
a: i32,
}
@ -101,7 +101,7 @@ pub async fn test_validator_on_complex_object_field_args() {
#[ComplexObject]
impl Query {
async fn value(&self, #[graphql(validator(maximum = "10"))] n: i32) -> i32 {
async fn value(&self, #[graphql(validator(maximum = 10))] n: i32) -> i32 {
n
}
}
@ -154,7 +154,7 @@ pub async fn test_validator_on_subscription_field_args() {
impl Subscription {
async fn value(
&self,
#[graphql(validator(maximum = "10"))] n: i32,
#[graphql(validator(maximum = 10))] n: i32,
) -> impl Stream<Item = i32> {
futures_util::stream::iter(vec![n])
}
@ -259,3 +259,45 @@ pub async fn test_custom_validator() {
}]
);
}
#[tokio::test]
pub async fn test_list_validator() {
struct Query;
#[Object]
impl Query {
async fn value(&self, #[graphql(validator(maximum = 3, list))] n: Vec<i32>) -> i32 {
n.into_iter().sum()
}
}
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
assert_eq!(
schema
.execute("{ value(n: [1, 2, 3]) }")
.await
.into_result()
.unwrap()
.data,
value!({ "value": 6 })
);
assert_eq!(
schema
.execute("{ value(n: [1, 2, 3, 4]) }")
.await
.into_result()
.unwrap_err(),
vec![ServerError {
message: r#"Failed to parse "Int": the value is 4, must be less than or equal to 3"#
.to_string(),
source: None,
locations: vec![Pos {
line: 1,
column: 12
}],
path: vec![PathSegment::Field("value".to_string())],
extensions: None
}]
);
}