diff --git a/crates/serde_valid/src/lib.rs b/crates/serde_valid/src/lib.rs index e3af35d..be26578 100644 --- a/crates/serde_valid/src/lib.rs +++ b/crates/serde_valid/src/lib.rs @@ -256,6 +256,40 @@ //! assert!(s.validate().is_ok()); //! ``` //! +//! You can use **closure**, so you can access other fields of the struct by using the `self` keyword. +//! +//! ```rust +//! use serde_valid::Validate; +//! +//! #[derive(Validate)] +//! struct Data { +//! val1: i32, +//! #[validate(custom = |val2: &i32| { +//! if self.val1 < *val2 { +//! Ok(()) +//! } else { +//! Err(serde_valid::validation::Error::Custom("val2 must be greater than val1".to_owned())) +//! } +//! })] +//! val2: i32, +//! } +//! +//! let s = Data { val1: 2, val2: 1 }; +//! +//! assert_eq!( +//! s.validate().unwrap_err().to_string(), +//! serde_json::json!({ +//! "errors": [], +//! "properties": { +//! "val2": { +//! "errors": ["val2 must be greater than val1"] +//! } +//! } +//! }) +//! .to_string() +//! ); +//! ``` +//! //! Custom validation is suitable for handling convenience validations not defined in JSON Schema. //! `serde_valid::utils::*` provides convenience functions for specific types. //! diff --git a/crates/serde_valid/tests/custom_test.rs b/crates/serde_valid/tests/custom_test.rs index 23cece6..357301d 100644 --- a/crates/serde_valid/tests/custom_test.rs +++ b/crates/serde_valid/tests/custom_test.rs @@ -281,3 +281,59 @@ fn named_struct_custom_closure_vec_errors_is_err() { .to_string() ); } + +#[test] +fn filed_custom_validation_using_self() { + fn food_validation(kind: &str, food: &str) -> Result<(), serde_valid::validation::Error> { + match kind { + "Cat" => { + if food == "CatFood" { + Ok(()) + } else { + Err(serde_valid::validation::Error::Custom( + "Cat should eat CatFood.".to_string(), + )) + } + } + "Dog" => { + if food == "DogFood" { + Ok(()) + } else { + Err(serde_valid::validation::Error::Custom( + "Dog should eat DogFood.".to_string(), + )) + } + } + _ => Ok(()), + } + } + + #[derive(Validate)] + struct Pet { + #[validate(enumerate = ["Cat", "Dog"])] + kind: String, + + #[validate(custom = |food| food_validation(&self.kind, food))] + food: String, + } + + let invalid = Pet { + kind: "Cat".to_string(), + food: "DogFood".to_string(), + }; + + assert_eq!( + invalid.validate().unwrap_err().to_string(), + json!({ + "errors": [], + "properties": { + "food": { + "errors": [ + "Cat should eat CatFood." + ] + } + } + }) + .to_string() + ); +}