Skip to content

Commit

Permalink
feat: add duration validation.
Browse files Browse the repository at this point in the history
  • Loading branch information
yassun7010 committed May 13, 2024
1 parent 43320a9 commit 186f949
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 0 deletions.
1 change: 1 addition & 0 deletions serde_valid/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ pub use error::{
MaxLengthError, MaxPropertiesError, MaximumError, MinItemsError, MinLengthError,
MinPropertiesError, MinimumError, MultipleOfError, PatternError, UniqueItemsError,
};
pub mod utils;
pub use validation::{
ValidateEnumerate, ValidateExclusiveMaximum, ValidateExclusiveMinimum, ValidateMaxItems,
ValidateMaxLength, ValidateMaxProperties, ValidateMaximum, ValidateMinItems, ValidateMinLength,
Expand Down
6 changes: 6 additions & 0 deletions serde_valid/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
mod duration;

pub use duration::duration_exclusive_maximum;
pub use duration::duration_exclusive_minimum;
pub use duration::duration_maximum;
pub use duration::duration_minimum;
65 changes: 65 additions & 0 deletions serde_valid/src/utils/duration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use std::time::Duration;

#[allow(dead_code)]
pub fn duration_maximum(
maximum: Duration,
) -> impl FnOnce(&Duration) -> Result<(), crate::validation::Error> {
move |val: &Duration| {
if *val <= maximum {
Ok(())
} else {
Err(crate::validation::Error::Custom(format!(
"Duration {:?} is greater than maximum {:?}.",
val, maximum
)))
}
}
}

#[allow(dead_code)]
pub fn duration_minimum(
minimum: Duration,
) -> impl FnOnce(&Duration) -> Result<(), crate::validation::Error> {
move |val: &Duration| {
if *val >= minimum {
Ok(())
} else {
Err(crate::validation::Error::Custom(format!(
"Duration {:?} is less than minimum {:?}.",
val, minimum
)))
}
}
}

#[allow(dead_code)]
pub fn duration_exclusive_maximum(
maximum: Duration,
) -> impl FnOnce(&Duration) -> Result<(), crate::validation::Error> {
move |val: &Duration| {
if *val < maximum {
Ok(())
} else {
Err(crate::validation::Error::Custom(format!(
"Duration {:?} is greater than or equal to exclusive maximum {:?}.",
val, maximum
)))
}
}
}

#[allow(dead_code)]
pub fn duration_exclusive_minimum(
minimum: Duration,
) -> impl FnOnce(&Duration) -> Result<(), crate::validation::Error> {
move |val: &Duration| {
if *val > minimum {
Ok(())
} else {
Err(crate::validation::Error::Custom(format!(
"Duration {:?} is less than or equal to exclusive minimum {:?}.",
val, minimum
)))
}
}
}
91 changes: 91 additions & 0 deletions serde_valid/tests/duration_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use std::time::Duration;

use serde_json::json;
use serde_valid::utils::{duration_maximum, duration_minimum};
use serde_valid::Validate;

#[test]
fn duration_maximum_is_ok() {
#[derive(Validate)]
struct TestStruct {
#[validate(custom(duration_maximum(Duration::from_micros(5))))]
val: Duration,
}

let s = TestStruct {
val: Duration::from_micros(5),
};

assert!(s.validate().is_ok());
}

#[test]
fn duration_minimum_is_ok() {
#[derive(Validate)]
struct TestStruct {
#[validate(custom(duration_minimum(Duration::from_micros(5))))]
val: Duration,
}

let s = TestStruct {
val: Duration::from_secs(5),
};

assert!(s.validate().is_ok());
}

#[test]
fn duration_maximum_is_err() {
#[derive(Validate)]
struct TestStruct {
#[validate(custom(duration_maximum(Duration::from_micros(5))))]
val: Duration,
}

let s = TestStruct {
val: Duration::from_micros(10),
};

assert_eq!(
s.validate().unwrap_err().to_string(),
json!({
"errors": [],
"properties": {
"val": {
"errors": [
"Duration 10µs is greater than maximum 5µs."
]
}
}
})
.to_string()
);
}

#[test]
fn duration_minimum_is_err() {
#[derive(Validate)]
struct TestStruct {
#[validate(custom(duration_minimum(Duration::from_micros(5))))]
val: Duration,
}

let s = TestStruct {
val: Duration::from_micros(1),
};

assert_eq!(
s.validate().unwrap_err().to_string(),
json!({
"errors": [],
"properties": {
"val": {
"errors": [
"Duration 1µs is less than minimum 5µs."
]
}
}
})
.to_string()
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ fn extract_custom_fn_name(
) -> Result<TokenStream, crate::Errors> {
match nested_meta {
crate::types::NestedMeta::Meta(syn::Meta::Path(fn_name)) => Ok(quote!(#fn_name)),
crate::types::NestedMeta::Meta(syn::Meta::List(closure)) => Ok(quote!(#closure)),
crate::types::NestedMeta::Closure(closure) => Ok(quote!((#closure))),
_ => Err(vec![
crate::Error::validate_custom_need_function_or_closure(nested_meta),
Expand Down
13 changes: 13 additions & 0 deletions serde_valid_derive/src/attribute/struct_validate/generic/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ pub fn extract_generic_struct_custom_validator(
crate::types::NestedMeta::Meta(syn::Meta::Path(path)) => {
extract_struct_custom_from_meta_path(path)
}
crate::types::NestedMeta::Meta(syn::Meta::List(list)) => {
extract_struct_custom_from_meta_list(list)
}
crate::types::NestedMeta::Closure(closure) => extract_struct_custom_from_closure(closure),
_ => Err(vec![
crate::Error::validate_custom_need_function_or_closure(&nested[0]),
Expand Down Expand Up @@ -56,6 +59,16 @@ fn extract_struct_custom_from_meta_path(meta_path: &syn::Path) -> Result<Validat
))
}

fn extract_struct_custom_from_meta_list(
meta_list: &syn::MetaList,
) -> Result<Validator, crate::Errors> {
Ok(quote!(
if let Err(__error) = serde_valid::helpers::wrap_closure_validation(self, #meta_list) {
__rule_vec_errors.push(__error);
};
))
}

fn extract_struct_custom_from_closure(
closure: &syn::ExprClosure,
) -> Result<Validator, crate::Errors> {
Expand Down

0 comments on commit 186f949

Please sign in to comment.