Skip to content

Commit

Permalink
Merge pull request #63 from yassun7010/add_duration_utils
Browse files Browse the repository at this point in the history
feat: add duration validation.
  • Loading branch information
yassun7010 authored May 14, 2024
2 parents 43320a9 + 0a9301a commit 4b2ee54
Show file tree
Hide file tree
Showing 7 changed files with 335 additions and 10 deletions.
42 changes: 37 additions & 5 deletions serde_valid/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ assert!(s.validate().is_ok());

Serde Valid support standard validation based JSON Schema.

| Type | Serde Valid(validate derive) | Serde Valid(validate trait) | Json Schema |
| Type | Serde Valid (validate derive) | Serde Valid (validate trait) | JSON Schema |
| :-----: | :----------------------------------- | :--------------------------- | :-------------------------------------------------------------------------------------------- |
| String | `#[validate(max_length = 5)]` | [`ValidateMaxLength`] | [maxLength](https://json-schema.org/understanding-json-schema/reference/string#length) |
| String | `#[validate(min_length = 5)]` | [`ValidateMinLength`] | [minLength](https://json-schema.org/understanding-json-schema/reference/string#length) |
Expand All @@ -62,6 +62,15 @@ Serde Valid support standard validation based JSON Schema.
| Array | `#[validate(unique_items)]` | [`ValidateUniqueItems`] | [uniqueItems](https://json-schema.org/understanding-json-schema/reference/array#uniqueItems) |
| Generic | `#[validate(enumerate(5, 10, 15))]` | [`ValidateEnumerate`] | [enum](https://json-schema.org/understanding-json-schema/reference/enum) |

In addition, [serde_valid::utils][module@crate::utils] provides a type of validation not described in the JSON schema specification.

| Type | Serde Valid (validate derive) | Serde Valid (validation function) |
| :-------------------------------: | :-------------------------------------------------------- | :----------------------------------------------------------------------- |
| [Duration][`std::time::Duration`] | `#[validate(custom(duration_maximum(SECOND)))]` | [duration_maximum][`crate::utils::duration_maximum`] |
| [Duration][`std::time::Duration`] | `#[validate(custom(duration_minimum(ZERO)))]` | [duration_minimum][`crate::utils::duration_minimum`] |
| [Duration][`std::time::Duration`] | `#[validate(custom(duration_exclusive_maximum(SECOND)))]` | [duration_exclusive_maximum][`crate::utils::duration_exclusive_maximum`] |
| [Duration][`std::time::Duration`] | `#[validate(custom(duration_exclusive_minimum(ZERO)))]` | [duration_exclusive_minimum][`crate::utils::duration_exclusive_minimum`] |

## Complete Constructor (Deserialization)

Serde Valid support complete constructor method using by
Expand Down Expand Up @@ -129,13 +138,13 @@ use serde_valid::Validate;

#[inline]
fn min_error_message(_params: &serde_valid::MinItemsError) -> String {
"this is min custom message_fn.".to_string()
"this is custom message_fn.".to_string()
}

#[derive(Validate)]
struct Data {
#[validate(min_items = 4, message_fn(min_error_message))]
#[validate(max_items = 2, message = "this is max custom message.")]
#[validate(max_items = 2, message = "this is custom message.")]
val: Vec<i32>,
}

Expand All @@ -148,8 +157,8 @@ assert_eq!(
"properties": {
"val": {
"errors": [
"this is min custom message_fn.",
"this is max custom message."
"this is custom message_fn.",
"this is custom message."
]
}
}
Expand Down Expand Up @@ -228,6 +237,29 @@ let s = Data { val: 1 };
assert!(s.validate().is_ok());
```

Custom validation is suitable for handling convenience validations not defined in JSON Schema.
`serde_valid::utils::*` provides convenience functions for specific types.

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


#[derive(Validate)]
struct Data {
#[validate(custom(duration_maximum(std::time::Duration::from_micros(5))))]
#[validate(custom(duration_minimum(std::time::Duration::from_micros(0))))]
val1: std::time::Duration,
}

let s = Data {
val1: std::time::Duration::from_micros(1),
};

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

## Multi Fields Validation
### Custom Validation
Now, you can use `#[validate(custom)]` for multi fields validation.
Expand Down
43 changes: 38 additions & 5 deletions serde_valid/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
//!
//! Serde Valid support standard validation based JSON Schema.
//!
//! | Type | Serde Valid(validate derive) | Serde Valid(validate trait) | Json Schema |
//! | Type | Serde Valid (validate derive) | Serde Valid (validate trait) | JSON Schema |
//! | :-----: | :----------------------------------- | :--------------------------- | :-------------------------------------------------------------------------------------------- |
//! | String | `#[validate(max_length = 5)]` | [`ValidateMaxLength`] | [maxLength](https://json-schema.org/understanding-json-schema/reference/string#length) |
//! | String | `#[validate(min_length = 5)]` | [`ValidateMinLength`] | [minLength](https://json-schema.org/understanding-json-schema/reference/string#length) |
Expand All @@ -62,6 +62,15 @@
//! | Array | `#[validate(unique_items)]` | [`ValidateUniqueItems`] | [uniqueItems](https://json-schema.org/understanding-json-schema/reference/array#uniqueItems) |
//! | Generic | `#[validate(enumerate(5, 10, 15))]` | [`ValidateEnumerate`] | [enum](https://json-schema.org/understanding-json-schema/reference/enum) |
//!
//! In addition, [serde_valid::utils][module@crate::utils] provides a type of validation not described in the JSON schema specification.
//!
//! | Type | Serde Valid (validate derive) | Serde Valid (validation function) |
//! | :-------------------------------: | :-------------------------------------------------------- | :----------------------------------------------------------------------- |
//! | [Duration][`std::time::Duration`] | `#[validate(custom(duration_maximum(SECOND)))]` | [duration_maximum][`crate::utils::duration_maximum`] |
//! | [Duration][`std::time::Duration`] | `#[validate(custom(duration_minimum(ZERO)))]` | [duration_minimum][`crate::utils::duration_minimum`] |
//! | [Duration][`std::time::Duration`] | `#[validate(custom(duration_exclusive_maximum(SECOND)))]` | [duration_exclusive_maximum][`crate::utils::duration_exclusive_maximum`] |
//! | [Duration][`std::time::Duration`] | `#[validate(custom(duration_exclusive_minimum(ZERO)))]` | [duration_exclusive_minimum][`crate::utils::duration_exclusive_minimum`] |
//!
//! ## Complete Constructor (Deserialization)
//!
//! Serde Valid support complete constructor method using by
Expand Down Expand Up @@ -129,13 +138,13 @@
//!
//! #[inline]
//! fn min_error_message(_params: &serde_valid::MinItemsError) -> String {
//! "this is min custom message_fn.".to_string()
//! "this is custom message_fn.".to_string()
//! }
//!
//! #[derive(Validate)]
//! struct Data {
//! #[validate(min_items = 4, message_fn(min_error_message))]
//! #[validate(max_items = 2, message = "this is max custom message.")]
//! #[validate(max_items = 2, message = "this is custom message.")]
//! val: Vec<i32>,
//! }
//!
Expand All @@ -148,8 +157,8 @@
//! "properties": {
//! "val": {
//! "errors": [
//! "this is min custom message_fn.",
//! "this is max custom message."
//! "this is custom message_fn.",
//! "this is custom message."
//! ]
//! }
//! }
Expand Down Expand Up @@ -238,6 +247,29 @@
//! assert!(s.validate().is_ok());
//! ```
//!
//! Custom validation is suitable for handling convenience validations not defined in JSON Schema.
//! `serde_valid::utils::*` provides convenience functions for specific types.
//!
//! ```rust
//! use serde_json::json;
//! use serde_valid::Validate;
//! use serde_valid::utils::{duration_maximum, duration_minimum};
//!
//!
//! #[derive(Validate)]
//! struct Data {
//! #[validate(custom(duration_maximum(std::time::Duration::from_micros(5))))]
//! #[validate(custom(duration_minimum(std::time::Duration::from_micros(0))))]
//! val1: std::time::Duration,
//! }
//!
//! let s = Data {
//! val1: std::time::Duration::from_micros(1),
//! };
//!
//! assert!(s.validate().is_ok());
//! ```
//!
//! ## Multi Fields Validation
//! ### Custom Validation
//! Now, you can use `#[validate(custom)]` for multi fields validation.
Expand Down Expand Up @@ -591,6 +623,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;
149 changes: 149 additions & 0 deletions serde_valid/src/utils/duration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
use std::time::Duration;

/// Validate that the duration is less than or equal to the maximum.
///
/// # Example
///
/// ```rust
/// use std::time::Duration;
///
/// use serde_valid::utils::duration_maximum;
/// use serde_valid::Validate;
///
/// #[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());
/// ```
#[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 {val:?} is greater than maximum {maximum:?}.",
)))
}
}
}

/// Validate that the duration is greater than or equal to the minimum.
///
/// # Example
///
/// ```rust
/// use std::time::Duration;
///
/// use serde_valid::utils::duration_minimum;
/// use serde_valid::Validate;
///
/// #[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());
/// ```
#[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 {val:?} is less than minimum {minimum:?}.",
)))
}
}
}

/// Validate that the duration is less than the exclusive maximum.
///
/// # Example
///
/// ```rust
/// use std::time::Duration;
///
/// use serde_valid::utils::duration_exclusive_maximum;
/// use serde_valid::Validate;
///
/// #[derive(Validate)]
/// struct TestStruct {
/// #[validate(custom(duration_exclusive_maximum(Duration::from_micros(5))))]
/// val: Duration,
/// }
///
/// let s = TestStruct {
/// val: Duration::from_micros(4),
/// };
///
/// assert!(s.validate().is_ok());
/// ```
#[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 {val:?} is greater than or equal to exclusive maximum {maximum:?}.",
)))
}
}
}

/// Validate that the duration is greater than the exclusive minimum.
///
/// # Example
///
/// ```rust
/// use std::time::Duration;
///
/// use serde_valid::utils::duration_exclusive_minimum;
/// use serde_valid::Validate;
///
/// #[derive(Validate)]
/// struct TestStruct {
/// #[validate(custom(duration_exclusive_minimum(Duration::from_micros(5))))]
/// val: Duration,
/// }
///
/// let s = TestStruct {
/// val: Duration::from_micros(6),
/// };
///
/// assert!(s.validate().is_ok());
/// ```
#[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 {val:?} is less than or equal to exclusive minimum {minimum:?}.",
)))
}
}
}
Loading

0 comments on commit 4b2ee54

Please sign in to comment.