skp_validator_rules/comparison/
required.rs

1//! Required validation rule.
2
3use skp_validator_core::{Rule, ValidationContext, ValidationErrors, ValidationError, ValidationResult};
4
5/// Required validation rule - field must not be empty/null.
6///
7/// # Example
8///
9/// ```rust
10/// use skp_validator_rules::comparison::required::RequiredRule;
11/// use skp_validator_core::{Rule, ValidationContext};
12///
13/// let rule = RequiredRule::new();
14/// let ctx = ValidationContext::default();
15///
16/// assert!(rule.validate("hello", &ctx).is_ok());
17/// assert!(rule.validate("", &ctx).is_err()); // Empty string
18/// ```
19#[derive(Debug, Clone, Default)]
20pub struct RequiredRule {
21    /// Custom error message
22    pub message: Option<String>,
23}
24
25impl RequiredRule {
26    /// Create a new required rule.
27    pub fn new() -> Self {
28        Self::default()
29    }
30
31    /// Set custom error message.
32    pub fn message(mut self, msg: impl Into<String>) -> Self {
33        self.message = Some(msg.into());
34        self
35    }
36    
37    /// Get the error message (custom or default).
38    fn get_message(&self) -> String {
39        self.message.clone().unwrap_or_else(|| "This field is required".to_string())
40    }
41}
42
43impl Rule<str> for RequiredRule {
44    fn validate(&self, value: &str, _ctx: &ValidationContext) -> ValidationResult<()> {
45        if value.trim().is_empty() {
46            Err(ValidationErrors::from_iter([
47                ValidationError::root("required", self.get_message())
48            ]))
49        } else {
50            Ok(())
51        }
52    }
53
54    fn name(&self) -> &'static str {
55        "required"
56    }
57
58    fn default_message(&self) -> String {
59        "This field is required".to_string()
60    }
61}
62
63impl Rule<String> for RequiredRule {
64    fn validate(&self, value: &String, ctx: &ValidationContext) -> ValidationResult<()> {
65        <Self as Rule<str>>::validate(self, value.as_str(), ctx)
66    }
67
68    fn name(&self) -> &'static str {
69        "required"
70    }
71
72    fn default_message(&self) -> String {
73        "This field is required".to_string()
74    }
75}
76
77impl<T> Rule<Option<T>> for RequiredRule {
78    fn validate(&self, value: &Option<T>, _ctx: &ValidationContext) -> ValidationResult<()> {
79        if value.is_none() {
80            Err(ValidationErrors::from_iter([
81                ValidationError::root("required", self.get_message())
82            ]))
83        } else {
84            Ok(())
85        }
86    }
87
88    fn name(&self) -> &'static str {
89        "required"
90    }
91
92    fn default_message(&self) -> String {
93        "This field is required".to_string()
94    }
95}
96
97impl<T> Rule<Vec<T>> for RequiredRule {
98    fn validate(&self, value: &Vec<T>, _ctx: &ValidationContext) -> ValidationResult<()> {
99        if value.is_empty() {
100            Err(ValidationErrors::from_iter([
101                ValidationError::root("required", self.get_message())
102            ]))
103        } else {
104            Ok(())
105        }
106    }
107
108    fn name(&self) -> &'static str {
109        "required"
110    }
111
112    fn default_message(&self) -> String {
113        "This field is required".to_string()
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120
121    #[test]
122    fn test_required_string() {
123        let rule = RequiredRule::new();
124        let ctx = ValidationContext::default();
125
126        assert!(rule.validate("hello", &ctx).is_ok());
127        assert!(rule.validate("", &ctx).is_err());
128        assert!(rule.validate("   ", &ctx).is_err()); // Whitespace only
129    }
130
131    #[test]
132    fn test_required_option() {
133        let rule = RequiredRule::new();
134        let ctx = ValidationContext::default();
135
136        assert!(rule.validate(&Some(42), &ctx).is_ok());
137        assert!(rule.validate(&None::<i32>, &ctx).is_err());
138    }
139
140    #[test]
141    fn test_required_vec() {
142        let rule = RequiredRule::new();
143        let ctx = ValidationContext::default();
144
145        assert!(rule.validate(&vec![1, 2, 3], &ctx).is_ok());
146        assert!(rule.validate(&Vec::<i32>::new(), &ctx).is_err());
147    }
148
149    #[test]
150    fn test_custom_message() {
151        let rule = RequiredRule::new().message("Name cannot be empty");
152        let ctx = ValidationContext::default();
153
154        let result = rule.validate("", &ctx);
155        assert!(result.is_err());
156        let errors = result.unwrap_err();
157        assert!(errors.to_string().contains("Name cannot be empty"));
158    }
159}