ruskit/framework/validation/
mod.rs1use std::collections::HashMap;
2use validator::{Validate, ValidationError};
3use serde::Deserialize;
4
5pub trait Rules {
6 fn rules() -> HashMap<&'static str, Vec<&'static str>>;
7}
8
9pub trait Validator {
10 fn validate(&self) -> Result<(), ValidationErrors>;
11}
12
13#[derive(Debug)]
14pub struct ValidationErrors {
15 errors: HashMap<String, Vec<String>>,
16}
17
18impl ValidationErrors {
19 pub fn new() -> Self {
20 Self {
21 errors: HashMap::new(),
22 }
23 }
24
25 pub fn add(&mut self, field: &str, message: &str) {
26 self.errors
27 .entry(field.to_string())
28 .or_insert_with(Vec::new)
29 .push(message.to_string());
30 }
31
32 pub fn errors(&self) -> &HashMap<String, Vec<String>> {
33 &self.errors
34 }
35
36 pub fn has_errors(&self) -> bool {
37 !self.errors.is_empty()
38 }
39}
40
41#[macro_export]
43macro_rules! validate {
44 ($data:expr) => {
45 $data.validate()
46 };
47}
48
49#[derive(Debug, Deserialize, Validate)]
51pub struct LoginRequest {
52 #[validate(email)]
53 pub email: String,
54 #[validate(length(min = 6))]
55 pub password: String,
56}
57
58impl Rules for LoginRequest {
60 fn rules() -> HashMap<&'static str, Vec<&'static str>> {
61 let mut rules = HashMap::new();
62 rules.insert("email", vec!["required", "email"]);
63 rules.insert("password", vec!["required", "min:6"]);
64 rules
65 }
66}
67
68pub mod rules {
70 use super::*;
71 use regex::Regex;
72
73 pub fn required(value: &str) -> Result<(), ValidationError> {
74 if value.trim().is_empty() {
75 return Err(ValidationError::new("required"));
76 }
77 Ok(())
78 }
79
80 pub fn email(value: &str) -> Result<(), ValidationError> {
81 let re = Regex::new(r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$").unwrap();
82 if !re.is_match(value) {
83 return Err(ValidationError::new("email"));
84 }
85 Ok(())
86 }
87
88 pub fn min(value: &str, min: usize) -> Result<(), ValidationError> {
89 if value.len() < min {
90 return Err(ValidationError::new("min"));
91 }
92 Ok(())
93 }
94
95 pub fn max(value: &str, max: usize) -> Result<(), ValidationError> {
96 if value.len() > max {
97 return Err(ValidationError::new("max"));
98 }
99 Ok(())
100 }
101}