pub mod rules;
#[cfg(feature = "validate-on-write")]
pub mod model_integration;
#[cfg(test)]
mod derive_tests;
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum ValidationError {
#[error("field `{field}` is required but empty")]
Required { field: String },
#[error("field `{field}` length {actual} not in [{min}, {max}]")]
Length {
field: String,
min: usize,
max: usize,
actual: usize,
},
#[error("field `{field}` value {actual} not in [{min}, {max}]")]
Range {
field: String,
min: String,
max: String,
actual: String,
},
#[error("field `{field}` value `{value}` is not a valid email")]
Email { field: String, value: String },
#[error("field `{field}` value `{value}` does not match pattern `{pattern}`")]
Regex {
field: String,
pattern: String,
value: String,
},
#[error("field `{field}` does not contain `{substring}`")]
Contains { field: String, substring: String },
#[error("field `{field}` contains forbidden `{substring}`")]
DoesNotContain { field: String, substring: String },
#[error("field `{field}` custom validation failed: {reason}")]
Custom { field: String, reason: String },
#[error("validation failed with {count} error(s)")]
Aggregate {
errors: Vec<ValidationError>,
count: usize,
},
}
pub trait Validate {
fn validate(&self) -> Result<(), ValidationError>;
}
pub fn aggregate(results: Vec<Result<(), ValidationError>>) -> Result<(), ValidationError> {
let errors: Vec<ValidationError> = results.into_iter().filter_map(|r| r.err()).collect();
match errors.len() {
0 => Ok(()),
1 => Err(errors.into_iter().next().unwrap()),
n => Err(ValidationError::Aggregate { errors, count: n }),
}
}