Rework validators 3
This commit is contained in:
parent
613bbc5b91
commit
71cbb9d20c
|
@ -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;)*))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user