use crate::error::{ErrorDetails, LsError};
pub mod boolean;
pub mod contains;
pub mod email;
pub mod ip;
pub mod must_match;
pub mod order;
pub mod ownership;
pub mod urls;
pub const ERR_NOT_UNIQUE: &str = "NOT_UNIQUE";
pub const ERR_VALUE_REQUIRED: &str = "VALUE_REQUIRED";
pub const ERR_UNKNOWN_FIELD: &str = "UNKNOWN_FIELD";
pub trait Validable: Send + Sync {
fn validate(&self, error_details: &mut ErrorDetails) -> Result<(), LsError>;
}
impl<F> Validable for F
where
F: Send + Sync + Fn(&mut ErrorDetails) -> Result<(), LsError>,
{
#[inline]
fn validate(&self, error_details: &mut ErrorDetails) -> Result<(), LsError> {
(self)(error_details)
}
}
impl<V0: Validable, V1: Validable> Validable for (&V0, &V1) {
#[inline]
fn validate(&self, error_details: &mut ErrorDetails) -> Result<(), LsError> {
self.0.validate(error_details)?;
self.1.validate(error_details)
}
}
impl<V0: Validable, V1: Validable, V2: Validable> Validable for (&V0, &V1, &V2) {
#[inline]
fn validate(&self, error_details: &mut ErrorDetails) -> Result<(), LsError> {
self.0.validate(error_details)?;
self.1.validate(error_details)?;
self.2.validate(error_details)
}
}
impl<V0: Validable, V1: Validable, V2: Validable, V3: Validable> Validable for (&V0, &V1, &V2, &V3) {
#[inline]
fn validate(&self, error_details: &mut ErrorDetails) -> Result<(), LsError> {
self.0.validate(error_details)?;
self.1.validate(error_details)?;
self.2.validate(error_details)?;
self.3.validate(error_details)
}
}
impl<V0: Validable, V1: Validable, V2: Validable, V3: Validable, V4: Validable> Validable
for (&V0, &V1, &V2, &V3, &V4)
{
#[inline]
fn validate(&self, error_details: &mut ErrorDetails) -> Result<(), LsError> {
self.0.validate(error_details)?;
self.1.validate(error_details)?;
self.2.validate(error_details)?;
self.3.validate(error_details)?;
self.4.validate(error_details)
}
}
impl<V0: Validable, V1: Validable, V2: Validable, V3: Validable, V4: Validable, V5: Validable> Validable
for (&V0, &V1, &V2, &V3, &V4, &V5)
{
#[inline]
fn validate(&self, error_details: &mut ErrorDetails) -> Result<(), LsError> {
self.0.validate(error_details)?;
self.1.validate(error_details)?;
self.2.validate(error_details)?;
self.3.validate(error_details)?;
self.4.validate(error_details)?;
self.5.validate(error_details)
}
}
impl<V0: Validable, V1: Validable, V2: Validable, V3: Validable, V4: Validable, V5: Validable, V6: Validable> Validable
for (&V0, &V1, &V2, &V3, &V4, &V5, &V6)
{
#[inline]
fn validate(&self, error_details: &mut ErrorDetails) -> Result<(), LsError> {
self.0.validate(error_details)?;
self.1.validate(error_details)?;
self.2.validate(error_details)?;
self.3.validate(error_details)?;
self.4.validate(error_details)?;
self.5.validate(error_details)?;
self.6.validate(error_details)
}
}
impl<
V0: Validable,
V1: Validable,
V2: Validable,
V3: Validable,
V4: Validable,
V5: Validable,
V6: Validable,
V7: Validable,
> Validable for (&V0, &V1, &V2, &V3, &V4, &V5, &V6, &V7)
{
#[inline]
fn validate(&self, error_details: &mut ErrorDetails) -> Result<(), LsError> {
self.0.validate(error_details)?;
self.1.validate(error_details)?;
self.2.validate(error_details)?;
self.3.validate(error_details)?;
self.4.validate(error_details)?;
self.5.validate(error_details)?;
self.6.validate(error_details)?;
self.7.validate(error_details)
}
}
impl<
V0: Validable,
V1: Validable,
V2: Validable,
V3: Validable,
V4: Validable,
V5: Validable,
V6: Validable,
V7: Validable,
V8: Validable,
> Validable for (&V0, &V1, &V2, &V3, &V4, &V5, &V6, &V7, &V8)
{
#[inline]
fn validate(&self, error_details: &mut ErrorDetails) -> Result<(), LsError> {
self.0.validate(error_details)?;
self.1.validate(error_details)?;
self.2.validate(error_details)?;
self.3.validate(error_details)?;
self.4.validate(error_details)?;
self.5.validate(error_details)?;
self.6.validate(error_details)?;
self.7.validate(error_details)?;
self.8.validate(error_details)
}
}
impl<
V0: Validable,
V1: Validable,
V2: Validable,
V3: Validable,
V4: Validable,
V5: Validable,
V6: Validable,
V7: Validable,
V8: Validable,
V9: Validable,
> Validable for (&V0, &V1, &V2, &V3, &V4, &V5, &V6, &V7, &V8, &V9)
{
#[inline]
fn validate(&self, error_details: &mut ErrorDetails) -> Result<(), LsError> {
self.0.validate(error_details)?;
self.1.validate(error_details)?;
self.2.validate(error_details)?;
self.3.validate(error_details)?;
self.4.validate(error_details)?;
self.5.validate(error_details)?;
self.6.validate(error_details)?;
self.7.validate(error_details)?;
self.8.validate(error_details)?;
self.9.validate(error_details)
}
}
#[derive(Default)]
pub struct Validator<'a> {
error_details: ErrorDetails<'a>,
validables: Vec<&'a dyn Validable>,
}
impl<'a> Validator<'a> {
pub fn new() -> Self {
Default::default()
}
pub fn validate<V: Validable>(validable: &'a V) -> Result<(), LsError> {
Validator::new().on(validable).do_validate()
}
pub fn on<V: Validable>(mut self, validable: &'a V) -> Self {
self.validables.push(validable);
self
}
pub fn error_details(&mut self) -> &mut ErrorDetails<'a> {
&mut self.error_details
}
pub fn do_validate(mut self) -> Result<(), LsError> {
for validable in self.validables {
validable.validate(&mut self.error_details)?;
}
if !self.error_details.details().is_empty() {
match self.error_details {
ErrorDetails::Root(node) => Err(LsError::ValidationError { details: node }),
ErrorDetails::Scoped(_) => {
panic!("ErrorDetails must be of type Root inside validator")
}
}
} else {
Ok(())
}
}
}
#[cfg(test)]
pub mod test {
use super::*;
#[test]
pub fn validator_should_accept_closures() {
let result = Validator::validate(&|_error_details: &mut ErrorDetails| Ok(()));
assert!(result.is_ok());
}
#[test]
pub fn validator_should_return_error_from_closure_if_error_details() {
let result = Validator::validate(&|error_details: &mut ErrorDetails| {
error_details.add_detail("username", "duplicated");
Ok(())
});
assert!(result.is_err());
match result {
Err(LsError::ValidationError { details }) => {
assert_eq!("duplicated", details.details["username"][0])
}
_ => panic!(),
}
}
#[test]
pub fn validator_should_return_validable_internal_error() {
let result = Validator::validate(&|_error_details: &mut ErrorDetails| Err(LsError::UnauthenticatedError));
assert!(result.is_err());
match result {
Err(LsError::UnauthenticatedError) => (),
_ => panic!(),
}
}
#[test]
pub fn validator_should_accept_validable() {
let validable = Tester { error_details: ErrorDetails::default() };
let result = Validator::validate(&validable);
assert!(result.is_ok());
}
#[test]
pub fn validator_should_accept_validable_with_errors() {
let mut error_details = ErrorDetails::default();
error_details.add_detail("1", "2");
let validable = Tester { error_details };
let result = Validator::validate(&validable);
assert!(result.is_err());
match result {
Err(LsError::ValidationError { details }) => {
assert_eq!("2", details.details["1"][0])
}
_ => panic!(),
}
}
#[test]
pub fn validator_should_accept_validables() {
let mut validable_1 = Tester { error_details: ErrorDetails::default() };
validable_1.error_details.add_detail("1", "11");
let mut validable_2 = Tester { error_details: ErrorDetails::default() };
validable_2.error_details.add_detail("1", "111");
validable_2.error_details.add_detail("2", "22");
let validable_3 = |error_details: &mut ErrorDetails| {
error_details.add_detail("3", "33");
Ok(())
};
let result = Validator::new().on(&validable_1).on(&validable_2).on(&validable_3).do_validate();
assert!(result.is_err());
match result {
Err(LsError::ValidationError { details }) => {
assert_eq!("11", details.details["1"][0]);
assert_eq!("111", details.details["1"][1]);
assert_eq!("22", details.details["2"][0]);
assert_eq!("33", details.details["3"][0]);
}
_ => panic!(),
}
}
#[test]
pub fn validator_should_accept_pair() {
let validable1 = Tester::new();
let validable2 = Tester::new();
let result = Validator::validate(&(&validable1, &validable2));
assert!(result.is_ok());
}
#[test]
pub fn validator_should_accept_pair_with_closures() {
let validable1 = Tester::new();
let result = Validator::validate(&(&validable1, &|_error_details: &mut ErrorDetails| Ok(())));
assert!(result.is_ok());
}
#[test]
pub fn validator_should_aggregate_errors() {
let mut error_details = ErrorDetails::default();
error_details.add_detail("1", "2");
let validable1 = Tester { error_details };
let mut error_details = ErrorDetails::default();
error_details.add_detail("1", "2");
let validable2 = Tester { error_details };
let mut error_details = ErrorDetails::default();
error_details.add_detail("1", "2");
let validable3 = Tester { error_details };
let mut error_details = ErrorDetails::default();
error_details.add_detail("1", "2");
error_details.add_detail("2", "2");
let validable4 = Tester { error_details };
let mut error_details = ErrorDetails::default();
error_details.add_detail("1", "2");
error_details.add_detail("2", "2");
let validable5 = Tester { error_details };
let result = Validator::validate(&(&validable1, &validable2, &validable3, &validable4, &validable5));
assert!(result.is_err());
match result {
Err(LsError::ValidationError { details }) => {
assert_eq!(5, details.details["1"].len());
assert_eq!(2, details.details["2"].len());
}
_ => panic!(),
}
}
struct Tester<'a> {
error_details: ErrorDetails<'a>,
}
impl Tester<'_> {
fn new() -> Self {
Self { error_details: ErrorDetails::default() }
}
}
impl Validable for Tester<'_> {
fn validate(&self, error_details: &mut ErrorDetails) -> Result<(), LsError> {
for (key, details) in self.error_details.details().iter() {
for detail in details {
error_details.add_detail(key.clone(), detail.clone())
}
}
Ok(())
}
}
}