From 4b445e1085700677e6b1d1c48397e5f45fe3feea Mon Sep 17 00:00:00 2001 From: yassun7010 Date: Tue, 7 Jan 2025 09:06:32 +0900 Subject: [PATCH 01/10] chore: add sample. --- crates/serde_valid/tests/custom_test.rs | 64 +++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/crates/serde_valid/tests/custom_test.rs b/crates/serde_valid/tests/custom_test.rs index 23cece6..959d1fd 100644 --- a/crates/serde_valid/tests/custom_test.rs +++ b/crates/serde_valid/tests/custom_test.rs @@ -281,3 +281,67 @@ fn named_struct_custom_closure_vec_errors_is_err() { .to_string() ); } + +#[test] +fn filed_custom_validation_use_self() { + fn food_validation(kind: &str, food: &str) -> Result<(), serde_valid::validation::Error> { + match kind { + "cat" => { + if food == "fish" { + Ok(()) + } else { + Err(serde_valid::validation::Error::Custom( + "Cat should eat fish.".to_string(), + )) + } + } + "dog" => { + if food == "meat" { + Ok(()) + } else { + Err(serde_valid::validation::Error::Custom( + "Dog should eat meat.".to_string(), + )) + } + } + _ => Err(serde_valid::validation::Error::Custom( + "Unknown pet type.".to_string(), + )), + } + } + + #[derive(Validate)] + struct Pet { + #[validate(enumerate = ["cat", "dog"])] + kind: String, + + #[validate(custom = |food| food_validation(&self.kind, food))] + food: String, + } + + let cat = Pet { + kind: "cat".to_string(), + food: "fish".to_string(), + }; + assert!(cat.validate().is_ok()); + + let invalid = Pet { + kind: "cat".to_string(), + food: "meat".to_string(), + }; + + assert_eq!( + invalid.validate().unwrap_err().to_string(), + json!({ + "errors": [], + "properties": { + "food": { + "errors": [ + "Cat should eat fish." + ] + } + } + }) + .to_string() + ); +} From 7c0b4fb054a136dc033938ebd27b0d545573dba2 Mon Sep 17 00:00:00 2001 From: yassun7010 Date: Tue, 7 Jan 2025 09:17:08 +0900 Subject: [PATCH 02/10] chore: fix test cases. --- crates/serde_valid/tests/custom_test.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/serde_valid/tests/custom_test.rs b/crates/serde_valid/tests/custom_test.rs index 959d1fd..748b115 100644 --- a/crates/serde_valid/tests/custom_test.rs +++ b/crates/serde_valid/tests/custom_test.rs @@ -304,9 +304,7 @@ fn filed_custom_validation_use_self() { )) } } - _ => Err(serde_valid::validation::Error::Custom( - "Unknown pet type.".to_string(), - )), + _ => Ok(()), } } From 97f867e00ea72e0b5922f50d9f107f68e06158cf Mon Sep 17 00:00:00 2001 From: yassun7010 Date: Tue, 7 Jan 2025 09:19:07 +0900 Subject: [PATCH 03/10] chore: test name. --- crates/serde_valid/tests/custom_test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/serde_valid/tests/custom_test.rs b/crates/serde_valid/tests/custom_test.rs index 748b115..d06d714 100644 --- a/crates/serde_valid/tests/custom_test.rs +++ b/crates/serde_valid/tests/custom_test.rs @@ -283,7 +283,7 @@ fn named_struct_custom_closure_vec_errors_is_err() { } #[test] -fn filed_custom_validation_use_self() { +fn filed_custom_validation_using_self() { fn food_validation(kind: &str, food: &str) -> Result<(), serde_valid::validation::Error> { match kind { "cat" => { From 189b3aa12e1e23698227c28893605651747cd75e Mon Sep 17 00:00:00 2001 From: yassun7010 Date: Tue, 7 Jan 2025 09:24:07 +0900 Subject: [PATCH 04/10] chore: test case. --- crates/serde_valid/tests/custom_test.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/serde_valid/tests/custom_test.rs b/crates/serde_valid/tests/custom_test.rs index d06d714..c63f012 100644 --- a/crates/serde_valid/tests/custom_test.rs +++ b/crates/serde_valid/tests/custom_test.rs @@ -287,20 +287,20 @@ fn filed_custom_validation_using_self() { fn food_validation(kind: &str, food: &str) -> Result<(), serde_valid::validation::Error> { match kind { "cat" => { - if food == "fish" { + if food == "CatFood" { Ok(()) } else { Err(serde_valid::validation::Error::Custom( - "Cat should eat fish.".to_string(), + "Cat should eat CatFood.".to_string(), )) } } "dog" => { - if food == "meat" { + if food == "DogFood" { Ok(()) } else { Err(serde_valid::validation::Error::Custom( - "Dog should eat meat.".to_string(), + "Dog should eat DogFood.".to_string(), )) } } @@ -319,13 +319,13 @@ fn filed_custom_validation_using_self() { let cat = Pet { kind: "cat".to_string(), - food: "fish".to_string(), + food: "CatFood".to_string(), }; assert!(cat.validate().is_ok()); let invalid = Pet { kind: "cat".to_string(), - food: "meat".to_string(), + food: "DogFood".to_string(), }; assert_eq!( @@ -335,7 +335,7 @@ fn filed_custom_validation_using_self() { "properties": { "food": { "errors": [ - "Cat should eat fish." + "Cat should eat CatFood." ] } } From 057afd52f62098d0e2fc6674b7d37ca3bed0b9d9 Mon Sep 17 00:00:00 2001 From: yassun7010 Date: Tue, 7 Jan 2025 09:24:41 +0900 Subject: [PATCH 05/10] chore: test. --- crates/serde_valid/tests/custom_test.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/serde_valid/tests/custom_test.rs b/crates/serde_valid/tests/custom_test.rs index c63f012..fa8a2e5 100644 --- a/crates/serde_valid/tests/custom_test.rs +++ b/crates/serde_valid/tests/custom_test.rs @@ -286,7 +286,7 @@ fn named_struct_custom_closure_vec_errors_is_err() { fn filed_custom_validation_using_self() { fn food_validation(kind: &str, food: &str) -> Result<(), serde_valid::validation::Error> { match kind { - "cat" => { + "Cat" => { if food == "CatFood" { Ok(()) } else { @@ -295,7 +295,7 @@ fn filed_custom_validation_using_self() { )) } } - "dog" => { + "Dog" => { if food == "DogFood" { Ok(()) } else { @@ -310,7 +310,7 @@ fn filed_custom_validation_using_self() { #[derive(Validate)] struct Pet { - #[validate(enumerate = ["cat", "dog"])] + #[validate(enumerate = ["Cat", "Dog"])] kind: String, #[validate(custom = |food| food_validation(&self.kind, food))] @@ -318,13 +318,13 @@ fn filed_custom_validation_using_self() { } let cat = Pet { - kind: "cat".to_string(), + kind: "Cat".to_string(), food: "CatFood".to_string(), }; assert!(cat.validate().is_ok()); let invalid = Pet { - kind: "cat".to_string(), + kind: "Cat".to_string(), food: "DogFood".to_string(), }; From 0f679e0505c882f853b3e45c203d6e364648484a Mon Sep 17 00:00:00 2001 From: yassun7010 Date: Tue, 7 Jan 2025 12:08:19 +0900 Subject: [PATCH 06/10] wip: more complex test case. --- crates/serde_valid/tests/custom_test.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/crates/serde_valid/tests/custom_test.rs b/crates/serde_valid/tests/custom_test.rs index fa8a2e5..e912a97 100644 --- a/crates/serde_valid/tests/custom_test.rs +++ b/crates/serde_valid/tests/custom_test.rs @@ -283,7 +283,16 @@ fn named_struct_custom_closure_vec_errors_is_err() { } #[test] -fn filed_custom_validation_using_self() { +fn filed_custom_validation_complex_closure() { + fn kind_validation(kind: &str) -> Result<(), serde_valid::validation::Error> { + match kind { + "Cat" | "Dog" => Ok(()), + _ => Err(serde_valid::validation::Error::Custom( + "Kind should be Cat or Dog.".to_string(), + )), + } + } + fn food_validation(kind: &str, food: &str) -> Result<(), serde_valid::validation::Error> { match kind { "Cat" => { @@ -310,10 +319,16 @@ fn filed_custom_validation_using_self() { #[derive(Validate)] struct Pet { - #[validate(enumerate = ["Cat", "Dog"])] + #[validate(custom = kind_validation)] kind: String, - #[validate(custom = |food| food_validation(&self.kind, food))] + #[validate(custom = |food| { + if kind_validation(&self.kind).is_ok() { + food_validation(&self.kind, food) + } else { + Ok(()) + } + })] food: String, } From 692da7acc6abcc43fd664062cf38714e55e6e713 Mon Sep 17 00:00:00 2001 From: yassun7010 Date: Tue, 7 Jan 2025 13:10:08 +0900 Subject: [PATCH 07/10] fix: test. --- crates/serde_valid/tests/custom_test.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/crates/serde_valid/tests/custom_test.rs b/crates/serde_valid/tests/custom_test.rs index e912a97..429d6ad 100644 --- a/crates/serde_valid/tests/custom_test.rs +++ b/crates/serde_valid/tests/custom_test.rs @@ -322,13 +322,7 @@ fn filed_custom_validation_complex_closure() { #[validate(custom = kind_validation)] kind: String, - #[validate(custom = |food| { - if kind_validation(&self.kind).is_ok() { - food_validation(&self.kind, food) - } else { - Ok(()) - } - })] + #[validate(custom = |food| food_validation(&self.kind, food))] food: String, } From 8f6248d957975a0e1a7ccd854f00d16675ccf51a Mon Sep 17 00:00:00 2001 From: yassun7010 Date: Tue, 7 Jan 2025 20:19:54 +0900 Subject: [PATCH 08/10] chore: test case. --- crates/serde_valid/tests/custom_test.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/crates/serde_valid/tests/custom_test.rs b/crates/serde_valid/tests/custom_test.rs index 429d6ad..fa8a2e5 100644 --- a/crates/serde_valid/tests/custom_test.rs +++ b/crates/serde_valid/tests/custom_test.rs @@ -283,16 +283,7 @@ fn named_struct_custom_closure_vec_errors_is_err() { } #[test] -fn filed_custom_validation_complex_closure() { - fn kind_validation(kind: &str) -> Result<(), serde_valid::validation::Error> { - match kind { - "Cat" | "Dog" => Ok(()), - _ => Err(serde_valid::validation::Error::Custom( - "Kind should be Cat or Dog.".to_string(), - )), - } - } - +fn filed_custom_validation_using_self() { fn food_validation(kind: &str, food: &str) -> Result<(), serde_valid::validation::Error> { match kind { "Cat" => { @@ -319,7 +310,7 @@ fn filed_custom_validation_complex_closure() { #[derive(Validate)] struct Pet { - #[validate(custom = kind_validation)] + #[validate(enumerate = ["Cat", "Dog"])] kind: String, #[validate(custom = |food| food_validation(&self.kind, food))] From ab63453f49a47bbe004cb8128b90b298278884e1 Mon Sep 17 00:00:00 2001 From: yassun7010 Date: Tue, 7 Jan 2025 20:20:16 +0900 Subject: [PATCH 09/10] chore: test cases. --- crates/serde_valid/tests/custom_test.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/crates/serde_valid/tests/custom_test.rs b/crates/serde_valid/tests/custom_test.rs index fa8a2e5..357301d 100644 --- a/crates/serde_valid/tests/custom_test.rs +++ b/crates/serde_valid/tests/custom_test.rs @@ -317,12 +317,6 @@ fn filed_custom_validation_using_self() { food: String, } - let cat = Pet { - kind: "Cat".to_string(), - food: "CatFood".to_string(), - }; - assert!(cat.validate().is_ok()); - let invalid = Pet { kind: "Cat".to_string(), food: "DogFood".to_string(), From 8d3c2527c8f3b0948fcbdc7c5c60bc4c8ea14ee0 Mon Sep 17 00:00:00 2001 From: yassun7010 Date: Tue, 7 Jan 2025 21:55:41 +0900 Subject: [PATCH 10/10] chore: Add README. --- crates/serde_valid/src/lib.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) 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. //!