Skip to content

Commit

Permalink
Fixing nested validation
Browse files Browse the repository at this point in the history
  • Loading branch information
Keats committed Apr 5, 2024
1 parent 59a97b3 commit a32eb52
Show file tree
Hide file tree
Showing 20 changed files with 172 additions and 350 deletions.
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,9 +342,6 @@ This validator doesn't take any arguments: `#[validate(non_control_character)]`;
### required
Tests whether the `Option<T>` field is `Some`;

### required_nested
Tests whether the `Option<T>` field is `Some` and performs validation as `nested` do;

## Struct level validation
Often, some error validation can only be applied when looking at the full struct, here's how it works here:

Expand Down
2 changes: 0 additions & 2 deletions validator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
//! | `regex` | |
//! | `credit_card` | (Requires the feature `card` to be enabled) |
//! | `non_control_character` | (Required the feature `unic` to be enabled) |
//! | `nested` | (Uses the validation of the field type it self) |
//! | `required` | |
//!
//! [Checkout the project README of an in-depth usage description with examples.](https://github.com/Keats/validator/blob/master/README.md)
Expand All @@ -74,7 +73,6 @@ pub use validation::email::ValidateEmail;
pub use validation::ip::ValidateIp;
pub use validation::length::ValidateLength;
pub use validation::must_match::validate_must_match;
pub use validation::nested::ValidateNested;
#[cfg(feature = "unic")]
pub use validation::non_control_character::ValidateNonControlCharacter;
pub use validation::range::ValidateRange;
Expand Down
102 changes: 101 additions & 1 deletion validator/src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::types::ValidationErrors;
use crate::types::{ValidationErrors, ValidationErrorsKind};
use std::collections::btree_map::BTreeMap;
use std::collections::HashMap;

/// This is the original trait that was implemented by deriving `Validate`. It will still be
/// implemented for struct validations that don't take custom arguments. The call is being
Expand All @@ -13,6 +15,104 @@ impl<T: Validate> Validate for &T {
}
}

macro_rules! impl_validate_list {
($container:ty) => {
impl<T: Validate> Validate for $container {
fn validate(&self) -> Result<(), ValidationErrors> {
let mut vec_err: BTreeMap<usize, Box<ValidationErrors>> = BTreeMap::new();

for (index, item) in self.iter().enumerate() {
if let Err(e) = item.validate() {
vec_err.insert(index, Box::new(e));
}
}

if vec_err.is_empty() {
Ok(())
} else {
let err_kind = ValidationErrorsKind::List(vec_err);
let errors = ValidationErrors(std::collections::HashMap::from([(
"_tmp_validator",
err_kind,
)]));
Err(errors)
}
}
}
};
}

impl_validate_list!(std::collections::HashSet<T>);
impl_validate_list!(std::collections::BTreeSet<T>);
impl_validate_list!(std::collections::BinaryHeap<T>);
impl_validate_list!(std::collections::LinkedList<T>);
impl_validate_list!(std::collections::VecDeque<T>);
impl_validate_list!(std::vec::Vec<T>);
impl_validate_list!([T]);

impl<T: Validate, const N: usize> Validate for [T; N] {
fn validate(&self) -> Result<(), ValidationErrors> {
let mut vec_err: BTreeMap<usize, Box<ValidationErrors>> = BTreeMap::new();

for (index, item) in self.iter().enumerate() {
if let Err(e) = item.validate() {
vec_err.insert(index, Box::new(e));
}
}

if vec_err.is_empty() {
Ok(())
} else {
let err_kind = ValidationErrorsKind::List(vec_err);
let errors = ValidationErrors(std::collections::HashMap::from([(
"_tmp_validator",
err_kind,
)]));
Err(errors)
}
}
}

impl<K, V: Validate, S> Validate for &HashMap<K, V, S> {
fn validate(&self) -> Result<(), ValidationErrors> {
let mut vec_err: BTreeMap<usize, Box<ValidationErrors>> = BTreeMap::new();

for (index, (_key, value)) in self.iter().enumerate() {
if let Err(e) = value.validate() {
vec_err.insert(index, Box::new(e));
}
}

if vec_err.is_empty() {
Ok(())
} else {
let err_kind = ValidationErrorsKind::List(vec_err);
let errors = ValidationErrors(HashMap::from([("_tmp_validator", err_kind)]));
Err(errors)
}
}
}

impl<K, V: Validate> Validate for &BTreeMap<K, V> {
fn validate(&self) -> Result<(), ValidationErrors> {
let mut vec_err: BTreeMap<usize, Box<ValidationErrors>> = BTreeMap::new();

for (index, (_key, value)) in self.iter().enumerate() {
if let Err(e) = value.validate() {
vec_err.insert(index, Box::new(e));
}
}

if vec_err.is_empty() {
Ok(())
} else {
let err_kind = ValidationErrorsKind::List(vec_err);
let errors = ValidationErrors(HashMap::from([("_tmp_validator", err_kind)]));
Err(errors)
}
}
}

/// This trait will be implemented by deriving `Validate`. This implementation can take one
/// argument and pass this on to custom validators. The default `Args` type will be `()` if
/// there is no custom validation with defined arguments.
Expand Down
11 changes: 9 additions & 2 deletions validator/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,15 @@ impl ValidationErrors {
match child {
Ok(()) => self,
Err(errors) => {
for (_, e) in errors.0 {
self.add_nested(field, e);
for (_, e) in &errors.0 {
if matches!(e, ValidationErrorsKind::Field(..)) {
self.add_nested(
field,
ValidationErrorsKind::Struct(Box::new(errors.clone())),
);
} else {
self.add_nested(field, e.clone());
}
}
self
}
Expand Down
3 changes: 0 additions & 3 deletions validator/src/validation/contains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@ impl<S, H: BuildHasher> ValidateContains for HashMap<String, S, H> {

#[cfg(test)]
mod tests {
use std::borrow::Cow;
use std::collections::HashMap;

use super::*;

#[test]
Expand Down
2 changes: 1 addition & 1 deletion validator/src/validation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub mod email;
pub mod ip;
pub mod length;
pub mod must_match;
pub mod nested;
// pub mod nested;
#[cfg(feature = "unic")]
pub mod non_control_character;
pub mod range;
Expand Down
190 changes: 0 additions & 190 deletions validator/src/validation/nested.rs

This file was deleted.

Loading

0 comments on commit a32eb52

Please sign in to comment.