async-graphql/derive/src/validators.rs

134 lines
3.5 KiB
Rust
Raw Normal View History

2021-11-15 03:08:56 +00:00
use darling::util::SpannedValue;
2021-11-14 13:09:14 +00:00
use darling::FromMeta;
use proc_macro2::TokenStream;
2021-11-15 10:19:02 +00:00
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)),
}
}
}
2021-11-14 13:09:14 +00:00
#[derive(FromMeta, Default, Clone)]
pub struct Validators {
#[darling(default)]
2021-11-15 10:19:02 +00:00
multiple_of: Option<Number>,
2021-11-14 13:09:14 +00:00
#[darling(default)]
2021-11-15 10:19:02 +00:00
maximum: Option<Number>,
2021-11-14 13:09:14 +00:00
#[darling(default)]
2021-11-15 10:19:02 +00:00
minimum: Option<Number>,
2021-11-14 13:09:14 +00:00
#[darling(default)]
max_length: Option<usize>,
#[darling(default)]
min_length: Option<usize>,
#[darling(default)]
max_items: Option<usize>,
#[darling(default)]
min_items: Option<usize>,
#[darling(default, multiple)]
2021-11-15 03:08:56 +00:00
custom: Vec<SpannedValue<String>>,
2021-11-15 10:19:02 +00:00
#[darling(default)]
list: bool,
2021-11-14 13:09:14 +00:00
}
impl Validators {
pub fn create_validators(
&self,
crate_name: &TokenStream,
value: TokenStream,
2021-11-15 03:08:56 +00:00
ty: TokenStream,
2021-11-15 01:12:13 +00:00
map_err: Option<TokenStream>,
2021-11-15 03:08:56 +00:00
) -> Result<TokenStream> {
2021-11-14 13:09:14 +00:00
let mut codes = Vec::new();
2021-11-15 10:19:02 +00:00
let mut value = value;
let mut container = None;
if self.list {
container = Some(quote!(#value));
value = quote!(__item);
}
2021-11-14 13:09:14 +00:00
if let Some(n) = &self.multiple_of {
codes.push(quote! {
2021-11-15 01:12:13 +00:00
#crate_name::validators::multiple_of(#value, #n)
2021-11-14 13:09:14 +00:00
});
}
if let Some(n) = &self.maximum {
codes.push(quote! {
2021-11-15 01:12:13 +00:00
#crate_name::validators::maximum(#value, #n)
2021-11-14 13:09:14 +00:00
});
}
if let Some(n) = &self.minimum {
codes.push(quote! {
2021-11-15 01:12:13 +00:00
#crate_name::validators::minimum(#value, #n)
2021-11-14 13:09:14 +00:00
});
}
if let Some(n) = &self.max_length {
codes.push(quote! {
2021-11-15 01:12:13 +00:00
#crate_name::validators::max_length(#value, #n)
2021-11-14 13:09:14 +00:00
});
}
if let Some(n) = &self.min_length {
codes.push(quote! {
2021-11-15 01:12:13 +00:00
#crate_name::validators::min_length(#value, #n)
2021-11-14 13:09:14 +00:00
});
}
if let Some(n) = &self.max_items {
codes.push(quote! {
2021-11-15 01:12:13 +00:00
#crate_name::validators::max_items(#value, #n)
2021-11-14 13:09:14 +00:00
});
}
if let Some(n) = &self.min_items {
codes.push(quote! {
2021-11-15 01:12:13 +00:00
#crate_name::validators::min_items(#value, #n)
2021-11-14 13:09:14 +00:00
});
}
2021-11-15 03:08:56 +00:00
for s in &self.custom {
let expr: Expr = syn::parse_str(s)?;
codes.push(quote! {
#crate_name::CustomValidator::check(&(#expr), &ctx, #value).await
.map_err(|err_msg| #crate_name::InputValueError::<#ty>::custom(err_msg))
});
}
2021-11-15 01:12:13 +00:00
let codes = codes.into_iter().map(|s| quote!(#s #map_err ?));
2021-11-15 10:19:02 +00:00
if let Some(container) = container {
Ok(quote! {
for __item in #container {
#(#codes;)*
}
})
} else {
Ok(quote!(#(#codes;)*))
}
2021-11-14 13:09:14 +00:00
}
}