doido_model/
validation.rs1#[derive(Debug, Default, Clone)]
9pub struct Errors {
10 items: Vec<(String, String)>,
11}
12
13impl Errors {
14 pub fn new() -> Self {
15 Self::default()
16 }
17
18 pub fn add(&mut self, field: impl Into<String>, message: impl Into<String>) -> &mut Self {
20 self.items.push((field.into(), message.into()));
21 self
22 }
23
24 pub fn is_empty(&self) -> bool {
26 self.items.is_empty()
27 }
28
29 pub fn len(&self) -> usize {
31 self.items.len()
32 }
33
34 pub fn on(&self, field: &str) -> Vec<&str> {
36 self.items
37 .iter()
38 .filter(|(f, _)| f == field)
39 .map(|(_, m)| m.as_str())
40 .collect()
41 }
42
43 pub fn full_messages(&self) -> Vec<String> {
45 self.items
46 .iter()
47 .map(|(field, message)| format!("{field} {message}"))
48 .collect()
49 }
50
51 pub fn presence(&mut self, field: &str, value: &str) -> &mut Self {
53 if value.trim().is_empty() {
54 self.add(field, "can't be blank");
55 }
56 self
57 }
58
59 pub fn length(
61 &mut self,
62 field: &str,
63 value: &str,
64 min: Option<usize>,
65 max: Option<usize>,
66 ) -> &mut Self {
67 let len = value.chars().count();
68 if let Some(min) = min {
69 if len < min {
70 self.add(field, format!("is too short (minimum is {min} characters)"));
71 }
72 }
73 if let Some(max) = max {
74 if len > max {
75 self.add(field, format!("is too long (maximum is {max} characters)"));
76 }
77 }
78 self
79 }
80}
81
82pub trait Validate {
84 fn validate(&self) -> Errors;
86
87 fn is_valid(&self) -> bool {
89 self.validate().is_empty()
90 }
91}