From a32eb52ff81f08044479504a44551a2799a8ca11 Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Wed, 20 Mar 2024 21:12:50 +0100 Subject: [PATCH] Fixing nested validation --- README.md | 3 - validator/src/lib.rs | 2 - validator/src/traits.rs | 102 +++++++++- validator/src/types.rs | 11 +- validator/src/validation/contains.rs | 3 - validator/src/validation/mod.rs | 2 +- validator/src/validation/nested.rs | 190 ------------------ validator_derive/src/lib.rs | 40 ---- validator_derive/src/tokens/mod.rs | 1 - validator_derive/src/tokens/nested.rs | 4 +- .../src/tokens/required_nested.rs | 26 --- validator_derive/src/types.rs | 10 +- validator_derive/src/utils.rs | 16 +- .../compile-fail/no_nested_validations.stderr | 18 +- validator_derive_tests/tests/complex.rs | 4 +- validator_derive_tests/tests/custom.rs | 1 - validator_derive_tests/tests/custom_args.rs | 58 +++--- .../tests/nest_all_fields.rs | 2 - validator_derive_tests/tests/nested.rs | 27 +-- validator_derive_tests/tests/required.rs | 2 +- 20 files changed, 172 insertions(+), 350 deletions(-) delete mode 100644 validator/src/validation/nested.rs delete mode 100644 validator_derive/src/tokens/required_nested.rs diff --git a/README.md b/README.md index c44925ea..fd2687f0 100644 --- a/README.md +++ b/README.md @@ -342,9 +342,6 @@ This validator doesn't take any arguments: `#[validate(non_control_character)]`; ### required Tests whether the `Option` field is `Some`; -### required_nested -Tests whether the `Option` 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: diff --git a/validator/src/lib.rs b/validator/src/lib.rs index 2b95a05f..463ec7f2 100644 --- a/validator/src/lib.rs +++ b/validator/src/lib.rs @@ -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) @@ -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; diff --git a/validator/src/traits.rs b/validator/src/traits.rs index 4d30b759..bf980ecf 100644 --- a/validator/src/traits.rs +++ b/validator/src/traits.rs @@ -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 @@ -13,6 +15,104 @@ impl Validate for &T { } } +macro_rules! impl_validate_list { + ($container:ty) => { + impl Validate for $container { + fn validate(&self) -> Result<(), ValidationErrors> { + let mut vec_err: BTreeMap> = 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); +impl_validate_list!(std::collections::BTreeSet); +impl_validate_list!(std::collections::BinaryHeap); +impl_validate_list!(std::collections::LinkedList); +impl_validate_list!(std::collections::VecDeque); +impl_validate_list!(std::vec::Vec); +impl_validate_list!([T]); + +impl Validate for [T; N] { +fn validate(&self) -> Result<(), ValidationErrors> { + let mut vec_err: BTreeMap> = 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 for &HashMap { + fn validate(&self) -> Result<(), ValidationErrors> { + let mut vec_err: BTreeMap> = 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 Validate for &BTreeMap { + fn validate(&self) -> Result<(), ValidationErrors> { + let mut vec_err: BTreeMap> = 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. diff --git a/validator/src/types.rs b/validator/src/types.rs index 9b5ede94..30b236a6 100644 --- a/validator/src/types.rs +++ b/validator/src/types.rs @@ -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 } diff --git a/validator/src/validation/contains.rs b/validator/src/validation/contains.rs index e33230b3..b6cfd5f5 100644 --- a/validator/src/validation/contains.rs +++ b/validator/src/validation/contains.rs @@ -58,9 +58,6 @@ impl ValidateContains for HashMap { #[cfg(test)] mod tests { - use std::borrow::Cow; - use std::collections::HashMap; - use super::*; #[test] diff --git a/validator/src/validation/mod.rs b/validator/src/validation/mod.rs index 02e2c62d..22793300 100644 --- a/validator/src/validation/mod.rs +++ b/validator/src/validation/mod.rs @@ -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; diff --git a/validator/src/validation/nested.rs b/validator/src/validation/nested.rs deleted file mode 100644 index faffa4be..00000000 --- a/validator/src/validation/nested.rs +++ /dev/null @@ -1,190 +0,0 @@ -use crate::{ValidateArgs, ValidationErrors, ValidationErrorsKind}; -use std::collections::{BTreeMap, HashMap, HashSet}; -pub trait ValidateNested<'v_a> { - type Args; - fn validate_nested( - &self, - field_name: &'static str, - args: Self::Args, - ) -> Result<(), ValidationErrors>; -} - -impl<'v_a, T, U> ValidateNested<'v_a> for &T -where - T: ValidateNested<'v_a, Args = U>, -{ - type Args = U; - - fn validate_nested( - &self, - field_name: &'static str, - args: Self::Args, - ) -> Result<(), ValidationErrors> { - T::validate_nested(self, field_name, args) - } -} - -impl<'v_a, T, U> ValidateNested<'v_a> for Option -where - T: ValidateNested<'v_a, Args = U>, -{ - type Args = U; - - fn validate_nested( - &self, - field_name: &'static str, - args: Self::Args, - ) -> Result<(), ValidationErrors> { - if let Some(nested) = self { - nested.validate_nested(field_name, args) - } else { - Ok(()) - } - } -} - -impl<'v_a, T, U> ValidateNested<'v_a> for Vec -where - T: ValidateArgs<'v_a, Args = U> + ValidateNested<'v_a, Args = U>, - U: Clone, -{ - type Args = U; - fn validate_nested( - &self, - field_name: &'static str, - args: Self::Args, - ) -> Result<(), ValidationErrors> { - let mut vec_err: BTreeMap> = BTreeMap::new(); - - for (index, item) in self.iter().enumerate() { - if let Err(e) = item.validate_with_args(args.clone()) { - 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([(field_name, err_kind)])); - Err(errors) - } - } -} - -impl<'v_a, T, U> ValidateNested<'v_a> for &[T] -where - T: ValidateArgs<'v_a, Args = U> + ValidateNested<'v_a, Args = U>, - U: Clone, -{ - type Args = U; - - fn validate_nested( - &self, - field_name: &'static str, - args: Self::Args, - ) -> Result<(), ValidationErrors> { - let mut vec_err: BTreeMap> = BTreeMap::new(); - - for (index, item) in self.iter().enumerate() { - if let Err(e) = item.validate_with_args(args.clone()) { - 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([(field_name, err_kind)])); - Err(errors) - } - } -} - -impl<'v_a, T, const N: usize, U> ValidateNested<'v_a> for [T; N] -where - T: ValidateArgs<'v_a, Args = U> + ValidateNested<'v_a, Args = U>, - U: Clone, -{ - type Args = U; - fn validate_nested( - &self, - field_name: &'static str, - args: Self::Args, - ) -> Result<(), ValidationErrors> { - let mut vec_err: BTreeMap> = BTreeMap::new(); - - for (index, item) in self.iter().enumerate() { - if let Err(e) = item.validate_with_args(args.clone()) { - 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([(field_name, err_kind)])); - Err(errors) - } - } -} - -impl<'v_a, K, V, S, U> ValidateNested<'v_a> for HashMap -where - V: ValidateArgs<'v_a, Args = U> + ValidateNested<'v_a, Args = U>, - U: Clone, -{ - type Args = U; - fn validate_nested( - &self, - field_name: &'static str, - args: Self::Args, - ) -> Result<(), ValidationErrors> { - let mut vec_err: BTreeMap> = BTreeMap::new(); - - for (index, (_key, value)) in self.iter().enumerate() { - if let Err(e) = value.validate_with_args(args.clone()) { - 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([(field_name, err_kind)])); - Err(errors) - } - } -} - -impl<'v_a, T, S, U> ValidateNested<'v_a> for HashSet -where - T: ValidateArgs<'v_a, Args = U> + ValidateNested<'v_a, Args = U>, - U: Clone, -{ - type Args = U; - fn validate_nested( - &self, - field_name: &'static str, - args: Self::Args, - ) -> Result<(), ValidationErrors> { - let mut vec_err: BTreeMap> = BTreeMap::new(); - - for (index, value) in self.iter().enumerate() { - if let Err(e) = value.validate_with_args(args.clone()) { - 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([(field_name, err_kind)])); - Err(errors) - } - } -} diff --git a/validator_derive/src/lib.rs b/validator_derive/src/lib.rs index 606918ef..0c80108f 100644 --- a/validator_derive/src/lib.rs +++ b/validator_derive/src/lib.rs @@ -18,7 +18,6 @@ use tokens::non_control_character::non_control_char_tokens; use tokens::range::range_tokens; use tokens::regex::regex_tokens; use tokens::required::required_tokens; -use tokens::required_nested::required_nested_tokens; use tokens::schema::schema_tokens; use tokens::url::url_tokens; use types::*; @@ -132,20 +131,6 @@ impl ToTokens for ValidateField { quote!() }; - // Required nested validation - let required_nested = if let Some(required_nested) = self.required_nested.clone() { - required_nested_tokens( - match required_nested { - Override::Inherit => Required::default(), - Override::Explicit(r) => r, - }, - &field_name, - &field_name_str, - ) - } else { - quote!() - }; - // Contains validation let contains = if let Some(contains) = self.contains.clone() { wrapper_closure(contains_tokens(contains, &actual_field, &field_name_str)) @@ -210,7 +195,6 @@ impl ToTokens for ValidateField { #ncc #range #required - #required_nested #contains #does_not_contain #must_match @@ -234,7 +218,6 @@ struct ValidationData { schema: Vec, context: Option, mutable: Option, - nested: Option, nest_all_fields: Option, } @@ -369,27 +352,6 @@ pub fn derive_validation(input: proc_macro::TokenStream) -> proc_macro::TokenStr quote!(<'v_a, #struct_generics_quote>) }; - let nested_validation = if validation_data.nested.is_some_and(|n| n) { - quote! { - impl #imp_args ::validator::ValidateNested<'v_a> for #ident #ty #whr { - type Args = #custom_context; - fn validate_nested(&self, field_name: &'static str, args: Self::Args) -> ::std::result::Result<(), ::validator::ValidationErrors> { - use validator::ValidateArgs; - let res = self.validate_with_args(args); - - if let Err(e) = res { - let new_err = validator::ValidationErrorsKind::Struct(::std::boxed::Box::new(e)); - std::result::Result::Err(validator::ValidationErrors(::std::collections::HashMap::from([(field_name, new_err)]))) - } else { - std::result::Result::Ok(()) - } - } - } - } - } else { - quote!() - }; - let argless_validation = if validation_data.context.is_none() { quote! { impl #imp ::validator::Validate for #ident #ty #whr { @@ -406,8 +368,6 @@ pub fn derive_validation(input: proc_macro::TokenStream) -> proc_macro::TokenStr quote!( #argless_validation - #nested_validation - impl #imp_args ::validator::ValidateArgs<'v_a> for #ident #ty #whr { type Args = #custom_context; diff --git a/validator_derive/src/tokens/mod.rs b/validator_derive/src/tokens/mod.rs index 31d64f19..c3054bb4 100644 --- a/validator_derive/src/tokens/mod.rs +++ b/validator_derive/src/tokens/mod.rs @@ -11,6 +11,5 @@ pub mod non_control_character; pub mod range; pub mod regex; pub mod required; -pub mod required_nested; pub mod schema; pub mod url; diff --git a/validator_derive/src/tokens/nested.rs b/validator_derive/src/tokens/nested.rs index 16ce5242..3af6ffbf 100644 --- a/validator_derive/src/tokens/nested.rs +++ b/validator_derive/src/tokens/nested.rs @@ -5,8 +5,6 @@ pub fn nested_tokens( field_name_str: &str, ) -> proc_macro2::TokenStream { quote! { - if !errors.0.contains_key(#field_name_str) { - errors.merge_self(#field_name_str, #field_name.validate_nested(#field_name_str, args)); - } + errors.merge_self(#field_name_str, (&#field_name).validate()); } } diff --git a/validator_derive/src/tokens/required_nested.rs b/validator_derive/src/tokens/required_nested.rs deleted file mode 100644 index 382fd544..00000000 --- a/validator_derive/src/tokens/required_nested.rs +++ /dev/null @@ -1,26 +0,0 @@ -use quote::quote; -use syn::Ident; - -use crate::types::Required; -use crate::utils::{quote_code, quote_message}; - -pub fn required_nested_tokens( - required: Required, - field_name: &Ident, - field_name_str: &str, -) -> proc_macro2::TokenStream { - let message = quote_message(required.message); - let code = quote_code(required.code, "required"); - quote! { - if self.#field_name.validate_required() { - if let Some(ref _tmp) = self.#field_name { - errors.merge_self(#field_name_str, _tmp.validate()); - } - } else { - #code - #message - err.add_param(::std::borrow::Cow::from("value"), &self.#field_name); - errors.add(#field_name_str, err); - } - } -} diff --git a/validator_derive/src/types.rs b/validator_derive/src/types.rs index 2c77d304..b6a421bd 100644 --- a/validator_derive/src/types.rs +++ b/validator_derive/src/types.rs @@ -66,6 +66,7 @@ static OPTIONS_TYPE: [&str; 3] = ["Option|", "std|option|Option|", "core|option| pub struct ValidateField { pub ident: Option, pub ty: syn::Type, + pub attrs: Vec, pub credit_card: Option>, pub contains: Option, pub does_not_contain: Option, @@ -76,7 +77,6 @@ pub struct ValidateField { pub non_control_character: Option>, pub range: Option, pub required: Option>, - pub required_nested: Option>, pub url: Option>, pub regex: Option, #[darling(multiple)] @@ -89,6 +89,14 @@ impl ValidateField { pub fn validate(&self, struct_ident: &Ident, all_fields: &[&Field], current_field: &Field) { let field_name = self.ident.clone().expect("Field is not a named field").to_string(); let field_attrs = ¤t_field.attrs; + for attr in field_attrs { + if matches!(attr.meta, syn::Meta::Path(_)) { + abort!( + current_field.span(), "You need to set at least one validator on field `{}`", field_name; + note = "If you want nested validation, use `#[validate(nested)]`" + ) + } + } for c in &self.custom { // If function is not a path diff --git a/validator_derive/src/utils.rs b/validator_derive/src/utils.rs index e698b8c4..47b15932 100644 --- a/validator_derive/src/utils.rs +++ b/validator_derive/src/utils.rs @@ -33,11 +33,10 @@ pub fn quote_use_stmts(fields: &Vec) -> proc_macro2::TokenStream let mut ip = quote!(); let mut ncc = quote!(); let mut range = quote!(); - let mut reqired = quote!(); + let mut required = quote!(); let mut contains = quote!(); let mut does_not_contain = quote!(); let mut regex = quote!(); - let mut nested = quote!(); for f in fields { if f.length.is_some() { @@ -82,8 +81,8 @@ pub fn quote_use_stmts(fields: &Vec) -> proc_macro2::TokenStream ); } - if f.required.is_some() || f.required_nested.is_some() { - reqired = quote!( + if f.required.is_some() { + required = quote!( use validator::ValidateRequired; ); } @@ -105,12 +104,6 @@ pub fn quote_use_stmts(fields: &Vec) -> proc_macro2::TokenStream use validator::ValidateRegex; ); } - - if f.nested.is_some() { - nested = quote!( - use validator::ValidateNested; - ); - } } quote!( @@ -121,11 +114,10 @@ pub fn quote_use_stmts(fields: &Vec) -> proc_macro2::TokenStream #ip #ncc #range - #reqired + #required #contains #does_not_contain #regex - #nested ) } diff --git a/validator_derive_tests/tests/compile-fail/no_nested_validations.stderr b/validator_derive_tests/tests/compile-fail/no_nested_validations.stderr index 580f537f..38903c6c 100644 --- a/validator_derive_tests/tests/compile-fail/no_nested_validations.stderr +++ b/validator_derive_tests/tests/compile-fail/no_nested_validations.stderr @@ -1,13 +1,21 @@ -error[E0599]: no method named `validate_nested` found for struct `Nested` in the current scope +error[E0599]: the method `validate` exists for reference `&Nested`, but its trait bounds were not satisfied --> tests/compile-fail/no_nested_validations.rs:3:10 | 3 | #[derive(Validate)] - | ^^^^^^^^ method not found in `Nested` + | ^^^^^^^^ method cannot be called on `&Nested` due to unsatisfied trait bounds ... 9 | struct Nested { - | ------------- method `validate_nested` not found for this struct + | ------------- doesn't satisfy `Nested: Validate` | + = note: the following trait bounds were not satisfied: + `Nested: Validate` + which is required by `&Nested: Validate` +note: the trait `Validate` must be implemented + --> $WORKSPACE/validator/src/traits.rs + | + | pub trait Validate { + | ^^^^^^^^^^^^^^^^^^ = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `validate_nested`, perhaps you need to implement it: - candidate #1: `ValidateNested` + = note: the following trait defines an item `validate`, perhaps you need to implement it: + candidate #1: `Validate` = note: this error originates in the derive macro `Validate` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/validator_derive_tests/tests/complex.rs b/validator_derive_tests/tests/complex.rs index 1b6407b0..342eea1b 100644 --- a/validator_derive_tests/tests/complex.rs +++ b/validator_derive_tests/tests/complex.rs @@ -35,9 +35,9 @@ struct SignupData { first_name: String, #[validate(range(min = 18, max = 20))] age: u32, - #[validate] + #[validate(nested)] card: Option, - #[validate] + #[validate(nested)] preferences: Vec, } diff --git a/validator_derive_tests/tests/custom.rs b/validator_derive_tests/tests/custom.rs index d5d0d3fe..619c0e31 100644 --- a/validator_derive_tests/tests/custom.rs +++ b/validator_derive_tests/tests/custom.rs @@ -100,7 +100,6 @@ fn can_nest_custom_validations() { } #[derive(Validate)] - #[validate(nested)] struct A { #[validate(custom(function = custom_fn))] val: String, diff --git a/validator_derive_tests/tests/custom_args.rs b/validator_derive_tests/tests/custom_args.rs index 9c2fb331..ec0f032b 100644 --- a/validator_derive_tests/tests/custom_args.rs +++ b/validator_derive_tests/tests/custom_args.rs @@ -145,35 +145,35 @@ fn validate_custom_fn_with_multiple_args() { assert_eq!(arg, Arg { counter: 6, counter2: 18 }); } -#[test] -fn validate_nested_custom_fn() { - #[derive(Validate)] - #[validate(context = Arg)] - struct TestStruct { - #[validate(nested)] - child: Child, - } - - #[derive(Validate)] - #[validate(context = Arg, nested)] - struct Child { - #[validate(custom(function = add_assign, use_context))] - value: String, - } - - struct Arg { - _counter: i32, - } - - fn add_assign(_: &String, _arg: &Arg) -> Result<(), ValidationError> { - Ok(()) - } - - let t = TestStruct { child: Child { value: "test".to_string() } }; - let arg = Arg { _counter: 123 }; - - assert!(t.validate_with_args(&arg).is_ok()); -} +// #[test] +// fn validate_nested_custom_fn() { +// #[derive(Validate)] +// #[validate(context = Arg)] +// struct TestStruct { +// #[validate(nested)] +// child: Child, +// } +// +// #[derive(Validate)] +// #[validate(context = Arg)] +// struct Child { +// #[validate(custom(function = add_assign, use_context))] +// value: String, +// } +// +// struct Arg { +// _counter: i32, +// } +// +// fn add_assign(_: &String, _arg: &Arg) -> Result<(), ValidationError> { +// Ok(()) +// } +// +// let t = TestStruct { child: Child { value: "test".to_string() } }; +// let arg = Arg { _counter: 123 }; +// +// assert!(t.validate_with_args(&arg).is_ok()); +// } #[test] fn validate_custom_arg_with_lifetime() { diff --git a/validator_derive_tests/tests/nest_all_fields.rs b/validator_derive_tests/tests/nest_all_fields.rs index 4d8dc628..c4ac2edf 100644 --- a/validator_derive_tests/tests/nest_all_fields.rs +++ b/validator_derive_tests/tests/nest_all_fields.rs @@ -14,7 +14,6 @@ fn field_without_attribute_ignored() { } #[derive(Validate)] - #[validate(nested)] struct NestedValidated { #[validate(length(min = 5, max = 10))] val: String, @@ -43,7 +42,6 @@ fn nest_all_fields_attribute_works() { } #[derive(Validate)] - #[validate(nested)] struct NestedValidated { #[validate(length(min = 5, max = 10))] val: String, diff --git a/validator_derive_tests/tests/nested.rs b/validator_derive_tests/tests/nested.rs index 014952b6..a5f6dbee 100644 --- a/validator_derive_tests/tests/nested.rs +++ b/validator_derive_tests/tests/nested.rs @@ -18,7 +18,6 @@ fn is_fine_with_nested_validations() { } #[derive(Validate)] - #[validate(nested)] struct A { #[validate(length(min = 5, max = 10))] value: String, @@ -27,7 +26,6 @@ fn is_fine_with_nested_validations() { } #[derive(Validate)] - #[validate(nested)] struct B { #[validate(length(min = 5, max = 10))] value: String, @@ -52,7 +50,6 @@ fn fails_nested_validation() { } #[derive(Validate)] - #[validate(nested)] struct A { #[validate(length(min = 5, max = 10))] value: String, @@ -61,7 +58,6 @@ fn fails_nested_validation() { } #[derive(Validate)] - #[validate(nested)] struct B { #[validate(length(min = 5, max = 10))] value: String, @@ -142,7 +138,6 @@ fn test_can_validate_option_fields_without_lifetime() { } #[derive(Validate)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -182,7 +177,6 @@ fn test_can_validate_option_fields_with_lifetime() { } #[derive(Validate)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -223,7 +217,6 @@ fn test_works_with_none_values() { } #[derive(Validate)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -245,7 +238,6 @@ fn test_can_validate_vector_fields() { } #[derive(Validate, Serialize)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -311,7 +303,6 @@ fn test_can_validate_slice_fields() { } #[derive(Validate, Serialize)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -375,7 +366,6 @@ fn test_can_validate_array_fields() { } #[derive(Validate, Serialize)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -445,7 +435,6 @@ fn test_can_validate_option_vector_fields() { } #[derive(Validate, Serialize)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -513,7 +502,6 @@ fn test_can_validate_map_fields() { } #[derive(Validate, Serialize, Clone)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -562,7 +550,6 @@ fn test_can_validate_ref_map_fields() { } #[derive(Validate, Serialize, Clone)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -609,7 +596,6 @@ fn test_can_validate_option_map_fields() { } #[derive(Validate, Serialize, Clone)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -658,7 +644,6 @@ fn test_can_validate_set_fields() { } #[derive(Validate, Serialize, Clone, PartialEq, Eq, Hash)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -701,13 +686,11 @@ fn test_can_validate_set_fields() { fn test_can_validate_ref_set_fields() { #[derive(Validate)] struct ParentWithRefSetOfChildren<'a> { - #[validate(length(min = 1))] - #[validate(nested)] + #[validate(length(min = 1), nested)] child: &'a HashSet, } #[derive(Validate, Serialize, Clone, PartialEq, Eq, Hash)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -748,13 +731,11 @@ fn test_can_validate_ref_set_fields() { fn test_can_validate_option_set_fields() { #[derive(Validate)] struct ParentWithOptionSetOfChildren { - #[validate(length(min = 1))] - #[validate(nested)] + #[validate(length(min = 1), nested)] child: Option>, } #[derive(Validate, Serialize, Clone, PartialEq, Eq, Hash)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -798,12 +779,10 @@ fn test_field_validations_take_priority_over_nested_validations() { #[derive(Validate)] struct ParentWithVectorOfChildren { #[validate(length(min = 1))] - #[validate(nested)] child: Vec, } #[derive(Validate, Serialize, Clone, PartialEq, Eq, Hash)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -836,7 +815,6 @@ fn test_field_validation_errors_replaced_with_nested_validations_fails() { } #[derive(Debug, Validate, Serialize)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, @@ -891,7 +869,6 @@ fn test_field_validations_evaluated_after_nested_validations_fails() { } #[derive(Debug, Validate, Serialize)] - #[validate(nested)] struct Child { #[validate(length(min = 1))] value: String, diff --git a/validator_derive_tests/tests/required.rs b/validator_derive_tests/tests/required.rs index 222a49d5..d3b49be3 100644 --- a/validator_derive_tests/tests/required.rs +++ b/validator_derive_tests/tests/required.rs @@ -23,7 +23,7 @@ struct Required { #[derive(Validate)] struct RequiredNested { - #[validate(required_nested)] + #[validate(required, nested)] val: Option, }