Skip to main content

wasm_dbms_api/dbms/validate/
phone.rs

1use lazy_regex::{Lazy, Regex, lazy_regex};
2
3use crate::prelude::{Validate, Value};
4
5static PHONE_REGEX: Lazy<Regex> = lazy_regex!(r"^\+?[0-9\s().-]{7,20}$");
6
7/// A validator for phone numbers.
8///
9/// # Examples of valid phone numbers:
10///
11/// +1-202-555-0173
12/// (202) 555-0173
13/// +44 20 7946 0958
14/// 202.555.0173
15/// 2025550173
16///
17/// ## Example
18///
19/// ```rust
20/// use wasm_dbms_api::prelude::{PhoneNumberValidator, Validate, Value};
21///
22/// let validator = PhoneNumberValidator;
23/// let valid_phone = Value::Text("+1-202-555-0173".into());
24/// let invalid_phone = Value::Text("123-ABC-7890".into());
25///
26/// assert!(validator.validate(&valid_phone).is_ok());
27/// assert!(validator.validate(&invalid_phone).is_err());
28/// ```
29pub struct PhoneNumberValidator;
30
31impl Validate for PhoneNumberValidator {
32    fn validate(&self, value: &Value) -> crate::prelude::DbmsResult<()> {
33        let Value::Text(text) = value else {
34            return Err(crate::prelude::DbmsError::Validation(
35                "PhoneNumberValidator can only be applied to Text values".to_string(),
36            ));
37        };
38
39        if PHONE_REGEX.is_match(text.as_str()) {
40            Ok(())
41        } else {
42            Err(crate::prelude::DbmsError::Validation(format!(
43                "Value '{text}' is not a valid phone number",
44            )))
45        }
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn test_phone_number_validator() {
55        let validator = PhoneNumberValidator;
56        let valid_phones = vec![
57            "+1-202-555-0173",
58            "(202) 555-0173",
59            "+44 20 7946 0958",
60            "202.555.0173",
61            "2025550173",
62            "+91 (22) 1234-5678",
63            "+81-3-1234-5678",
64            "123-456-7890",
65            "+49 30 123456",
66            "+33 366 167 7509",
67            "+33 3661677509",
68        ];
69
70        let invalid_phones = vec![
71            "123-ABC-7890",
72            "++1-202-555-0173",
73            //"202--555--0173",
74            "202 555 0173 ext. 5",
75            "phone:2025550173",
76            "202/555/0173",
77            "202_555_0173",
78            "++44 20 7946 0958",
79        ];
80        for phone in valid_phones {
81            let value = Value::Text(phone.into());
82            assert!(
83                validator.validate(&value).is_ok(),
84                "Expected '{}' to be valid",
85                phone
86            );
87        }
88
89        for phone in invalid_phones {
90            let value = Value::Text(phone.into());
91            assert!(
92                validator.validate(&value).is_err(),
93                "Expected '{}' to be invalid",
94                phone
95            );
96        }
97
98        // non-Text value
99        let non_text_value = Value::Int32(1234567890i32.into());
100        assert!(
101            validator.validate(&non_text_value).is_err(),
102            "Expected non-Text value to be invalid"
103        );
104    }
105}