add ArgumentsStore

This commit is contained in:
gengteng
2023-09-28 17:22:19 +08:00
parent cffea88d07
commit fbf0b67a3d
2 changed files with 106 additions and 51 deletions

View File

@@ -128,7 +128,7 @@ impl<E, A> ValidEx<E, A> {
/// the HTTP status code and response body returned on validation failure. /// the HTTP status code and response body returned on validation failure.
/// ///
#[derive(Debug, Copy, Clone, Default)] #[derive(Debug, Copy, Clone, Default)]
pub struct ValidationArguments<Arguments> { pub struct ValidationContext<Arguments> {
arguments: Arguments, arguments: Arguments,
} }
@@ -143,24 +143,30 @@ fn response_builder(ve: ValidationErrors) -> Response {
} }
} }
impl ValidationArguments<()> { impl ValidationContext<()> {
/// Creates a new `ValidationArguments`. /// Creates a new `ValidationArguments`.
pub fn with_arguments<Arguments>(self, arguments: Arguments) -> ValidationArguments<Arguments> { pub fn with_arguments<Arguments>(self, arguments: Arguments) -> ValidationContext<Arguments> {
ValidationArguments { arguments } ValidationContext { arguments }
} }
} }
impl<Arguments> ValidationArguments<Arguments> { impl<Arguments> ValidationContext<Arguments> {
/// Creates a `ValidationArguments` with arguments /// Creates a `ValidationArguments` with arguments
pub fn new(arguments: Arguments) -> Self { pub fn new(arguments: Arguments) -> Self {
Self { arguments } Self { arguments }
} }
} }
impl FromRef<()> for ValidationArguments<()> { /// Arguement store
fn from_ref(_: &()) -> Self { ///
ValidationArguments::default() /// `T`: data type to validate
} /// `Self::A`: dependent arguments
///
pub trait ArgumentsStore<'a, T> {
/// Argument type
type A: 'a;
/// Get dependent arguments
fn get(&'a self) -> Self::A;
} }
/// `ValidRejection` is returned when the `Valid` extractor fails. /// `ValidRejection` is returned when the `Valid` extractor fails.
@@ -226,17 +232,17 @@ pub trait HasValidateArgs<'v> {
} }
#[async_trait] #[async_trait]
impl<S, B, E> FromRequest<S, B> for Valid<E> impl<State, Body, Extractor> FromRequest<State, Body> for Valid<Extractor>
where where
S: Send + Sync, State: Send + Sync,
B: Send + Sync + 'static, Body: Send + Sync + 'static,
E: HasValidate + FromRequest<S, B>, Extractor: HasValidate + FromRequest<State, Body>,
E::Validate: Validate, Extractor::Validate: Validate,
{ {
type Rejection = ValidRejection<<E as FromRequest<S, B>>::Rejection>; type Rejection = ValidRejection<<Extractor as FromRequest<State, Body>>::Rejection>;
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> { async fn from_request(req: Request<Body>, state: &State) -> Result<Self, Self::Rejection> {
let inner = E::from_request(req, state) let inner = Extractor::from_request(req, state)
.await .await
.map_err(ValidRejection::Inner)?; .map_err(ValidRejection::Inner)?;
inner.get_validate().validate()?; inner.get_validate().validate()?;
@@ -245,16 +251,16 @@ where
} }
#[async_trait] #[async_trait]
impl<S, E> FromRequestParts<S> for Valid<E> impl<State, Extractor> FromRequestParts<State> for Valid<Extractor>
where where
S: Send + Sync, State: Send + Sync,
E: HasValidate + FromRequestParts<S>, Extractor: HasValidate + FromRequestParts<State>,
E::Validate: Validate, Extractor::Validate: Validate,
{ {
type Rejection = ValidRejection<<E as FromRequestParts<S>>::Rejection>; type Rejection = ValidRejection<<Extractor as FromRequestParts<State>>::Rejection>;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> { async fn from_request_parts(parts: &mut Parts, state: &State) -> Result<Self, Self::Rejection> {
let inner = E::from_request_parts(parts, state) let inner = Extractor::from_request_parts(parts, state)
.await .await
.map_err(ValidRejection::Inner)?; .map_err(ValidRejection::Inner)?;
inner.get_validate().validate()?; inner.get_validate().validate()?;
@@ -263,46 +269,53 @@ where
} }
#[async_trait] #[async_trait]
impl<S, B, E, Arguments> FromRequest<S, B> for ValidEx<E, Arguments> impl<State, Body, Extractor, Store> FromRequest<State, Body> for ValidEx<Extractor, Store>
where where
S: Send + Sync, State: Send + Sync,
B: Send + Sync + 'static, Body: Send + Sync + 'static,
Arguments: Send + Sync, Store:
E: for<'v> HasValidateArgs<'v> + FromRequest<S, B>, Send + Sync + for<'a> ArgumentsStore<'a, <Extractor as HasValidateArgs<'a>>::ValidateArgs>,
for<'v> <E as HasValidateArgs<'v>>::ValidateArgs: ValidateArgs<'v, Args = &'v Arguments>, Extractor: for<'v> HasValidateArgs<'v> + FromRequest<State, Body>,
ValidationArguments<Arguments>: FromRef<S>, for<'v> <Extractor as HasValidateArgs<'v>>::ValidateArgs: ValidateArgs<
'v,
Args = <Store as ArgumentsStore<'v, <Extractor as HasValidateArgs<'v>>::ValidateArgs>>::A,
>,
ValidationContext<Store>: FromRef<State>,
{ {
type Rejection = ValidRejection<<E as FromRequest<S, B>>::Rejection>; type Rejection = ValidRejection<<Extractor as FromRequest<State, Body>>::Rejection>;
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> { async fn from_request(req: Request<Body>, state: &State) -> Result<Self, Self::Rejection> {
let ValidationArguments { arguments }: ValidationArguments<Arguments> = let ValidationContext { arguments }: ValidationContext<Store> = FromRef::from_ref(state);
FromRef::from_ref(state); let inner = Extractor::from_request(req, state)
let inner = E::from_request(req, state)
.await .await
.map_err(ValidRejection::Inner)?; .map_err(ValidRejection::Inner)?;
inner.get_validate_args().validate_args(&arguments)?;
inner.get_validate_args().validate_args(arguments.get())?;
Ok(ValidEx(inner, arguments)) Ok(ValidEx(inner, arguments))
} }
} }
#[async_trait] #[async_trait]
impl<S, E, Arguments> FromRequestParts<S> for ValidEx<E, Arguments> impl<State, Extractor, Store> FromRequestParts<State> for ValidEx<Extractor, Store>
where where
S: Send + Sync, State: Send + Sync,
Arguments: Send + Sync, Store:
E: for<'v> HasValidateArgs<'v> + FromRequestParts<S>, Send + Sync + for<'a> ArgumentsStore<'a, <Extractor as HasValidateArgs<'a>>::ValidateArgs>,
for<'v> <E as HasValidateArgs<'v>>::ValidateArgs: ValidateArgs<'v, Args = &'v Arguments>, Extractor: for<'v> HasValidateArgs<'v> + FromRequestParts<State>,
ValidationArguments<Arguments>: FromRef<S>, for<'v> <Extractor as HasValidateArgs<'v>>::ValidateArgs: ValidateArgs<
'v,
Args = <Store as ArgumentsStore<'v, <Extractor as HasValidateArgs<'v>>::ValidateArgs>>::A,
>,
ValidationContext<Store>: FromRef<State>,
{ {
type Rejection = ValidRejection<<E as FromRequestParts<S>>::Rejection>; type Rejection = ValidRejection<<Extractor as FromRequestParts<State>>::Rejection>;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> { async fn from_request_parts(parts: &mut Parts, state: &State) -> Result<Self, Self::Rejection> {
let ValidationArguments { arguments }: ValidationArguments<Arguments> = let ValidationContext { arguments }: ValidationContext<Store> = FromRef::from_ref(state);
FromRef::from_ref(state); let inner = Extractor::from_request_parts(parts, state)
let inner = E::from_request_parts(parts, state)
.await .await
.map_err(ValidRejection::Inner)?; .map_err(ValidRejection::Inner)?;
inner.get_validate_args().validate_args(&arguments)?; inner.get_validate_args().validate_args(arguments.get())?;
Ok(ValidEx(inner, arguments)) Ok(ValidEx(inner, arguments))
} }
} }

View File

@@ -9,8 +9,8 @@ use reqwest::{StatusCode, Url};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::any::type_name; use std::any::type_name;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::ops::Deref; use std::ops::{Deref, RangeInclusive};
use validator::Validate; use validator::{Validate, ValidationError};
#[derive(Clone, Deserialize, Serialize, Validate, Eq, PartialEq)] #[derive(Clone, Deserialize, Serialize, Validate, Eq, PartialEq)]
#[cfg_attr(feature = "extra_protobuf", derive(prost::Message))] #[cfg_attr(feature = "extra_protobuf", derive(prost::Message))]
@@ -27,6 +27,48 @@ pub struct Parameters {
v1: String, v1: String,
} }
#[derive(Clone, Deserialize, Serialize, Validate, Eq, PartialEq)]
#[cfg_attr(feature = "extra_protobuf", derive(prost::Message))]
#[cfg_attr(
feature = "typed_multipart",
derive(axum_typed_multipart::TryFromMultipart)
)]
pub struct ParametersEx {
#[validate(custom(function = "validate_v0", arg = "&'v_a RangeInclusive<i32>"))]
#[cfg_attr(feature = "extra_protobuf", prost(int32, tag = "1"))]
v0: i32,
#[validate(custom(function = "validate_v1", arg = "&'v_a RangeInclusive<usize>"))]
#[cfg_attr(feature = "extra_protobuf", prost(string, tag = "2"))]
v1: String,
}
fn validate_v0(v: i32, args: &RangeInclusive<i32>) -> Result<(), ValidationError> {
args.contains(&v)
.then_some(())
.ok_or_else(|| ValidationError::new("v0 is out of range"))
}
fn validate_v1(v: &str, args: &RangeInclusive<usize>) -> Result<(), ValidationError> {
args.contains(&v.len())
.then_some(())
.ok_or_else(|| ValidationError::new("v1 is invalid"))
}
#[derive(Debug)]
pub struct ValidationArgs {
v0_range: RangeInclusive<i32>,
v1_length_range: RangeInclusive<usize>,
}
impl Default for ValidationArgs {
fn default() -> Self {
Self {
v0_range: 5..=10,
v1_length_range: 1..=10,
}
}
}
static VALID_PARAMETERS: Lazy<Parameters> = Lazy::new(|| Parameters { static VALID_PARAMETERS: Lazy<Parameters> = Lazy::new(|| Parameters {
v0: 5, v0: 5,
v1: String::from("0123456789"), v1: String::from("0123456789"),