elif_validation/validators/
required.rs

1//! Required field validator
2
3use crate::error::{ValidationError, ValidationResult};
4use crate::traits::ValidationRule;
5use async_trait::async_trait;
6use serde_json::Value;
7
8/// Validator that ensures a field is present and not empty
9#[derive(Debug, Clone)]
10pub struct RequiredValidator {
11    /// Custom error message
12    pub message: Option<String>,
13}
14
15impl RequiredValidator {
16    /// Create a new required validator with default message
17    pub fn new() -> Self {
18        Self { message: None }
19    }
20
21    /// Create a required validator with custom message
22    pub fn with_message(message: impl Into<String>) -> Self {
23        Self {
24            message: Some(message.into()),
25        }
26    }
27
28    /// Check if a value is considered empty
29    fn is_empty(&self, value: &Value) -> bool {
30        match value {
31            Value::Null => true,
32            Value::String(s) => s.trim().is_empty(),
33            Value::Array(arr) => arr.is_empty(),
34            Value::Object(obj) => obj.is_empty(),
35            _ => false,
36        }
37    }
38}
39
40impl Default for RequiredValidator {
41    fn default() -> Self {
42        Self::new()
43    }
44}
45
46#[async_trait]
47impl ValidationRule for RequiredValidator {
48    async fn validate(&self, value: &Value, field: &str) -> ValidationResult<()> {
49        if self.is_empty(value) {
50            let message = self
51                .message.clone()
52                .unwrap_or_else(|| format!("{} is required", field));
53
54            Err(ValidationError::with_code(field, message, "required").into())
55        } else {
56            Ok(())
57        }
58    }
59
60    fn rule_name(&self) -> &'static str {
61        "required"
62    }
63
64    fn parameters(&self) -> Option<Value> {
65        self.message.as_ref().map(|msg| {
66            serde_json::json!({
67                "message": msg
68            })
69        })
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[tokio::test]
78    async fn test_required_validator_with_null() {
79        let validator = RequiredValidator::new();
80        let result = validator.validate(&Value::Null, "email").await;
81        
82        assert!(result.is_err());
83        let errors = result.unwrap_err();
84        assert!(errors.has_field_errors("email"));
85    }
86
87    #[tokio::test]
88    async fn test_required_validator_with_empty_string() {
89        let validator = RequiredValidator::new();
90        let result = validator.validate(&Value::String("".to_string()), "name").await;
91        
92        assert!(result.is_err());
93    }
94
95    #[tokio::test]
96    async fn test_required_validator_with_whitespace_string() {
97        let validator = RequiredValidator::new();
98        let result = validator.validate(&Value::String("   ".to_string()), "name").await;
99        
100        assert!(result.is_err());
101    }
102
103    #[tokio::test]
104    async fn test_required_validator_with_valid_string() {
105        let validator = RequiredValidator::new();
106        let result = validator.validate(&Value::String("John".to_string()), "name").await;
107        
108        assert!(result.is_ok());
109    }
110
111    #[tokio::test]
112    async fn test_required_validator_with_empty_array() {
113        let validator = RequiredValidator::new();
114        let result = validator.validate(&Value::Array(vec![]), "tags").await;
115        
116        assert!(result.is_err());
117    }
118
119    #[tokio::test]
120    async fn test_required_validator_with_filled_array() {
121        let validator = RequiredValidator::new();
122        let result = validator.validate(
123            &Value::Array(vec![Value::String("tag1".to_string())]),
124            "tags"
125        ).await;
126        
127        assert!(result.is_ok());
128    }
129
130    #[tokio::test]
131    async fn test_required_validator_with_custom_message() {
132        let validator = RequiredValidator::with_message("This field cannot be empty");
133        let result = validator.validate(&Value::Null, "email").await;
134        
135        assert!(result.is_err());
136        let errors = result.unwrap_err();
137        let field_errors = errors.get_field_errors("email").unwrap();
138        assert_eq!(field_errors[0].message, "This field cannot be empty");
139    }
140
141    #[tokio::test]
142    async fn test_required_validator_with_numbers() {
143        let validator = RequiredValidator::new();
144        
145        // Numbers are never considered empty (including 0)
146        assert!(validator.validate(&Value::Number(serde_json::Number::from(0)), "count").await.is_ok());
147        assert!(validator.validate(&Value::Number(serde_json::Number::from(42)), "count").await.is_ok());
148    }
149
150    #[tokio::test]
151    async fn test_required_validator_with_boolean() {
152        let validator = RequiredValidator::new();
153        
154        // Booleans are never considered empty (including false)
155        assert!(validator.validate(&Value::Bool(false), "active").await.is_ok());
156        assert!(validator.validate(&Value::Bool(true), "active").await.is_ok());
157    }
158}