Skip to main content

wasm_dbms_api/dbms/validate/
strlen.rs

1use crate::prelude::{DbmsError, Validate, Value};
2
3/// A validator that checks if the length of a string does not exceed a maximum length.
4///
5/// The length is the number of Unicode characters (scalar values), not bytes.
6///
7/// # Example
8///
9/// ```rust
10/// use wasm_dbms_api::prelude::{MaxStrlenValidator, Validate, Value, Text};
11/// let validator = MaxStrlenValidator(10);
12/// let value = Value::Text(Text("Hello".to_string()));
13/// assert!(validator.validate(&value).is_ok());
14/// let long_value = Value::Text(Text("Hello, World!".to_string()));
15/// assert!(validator.validate(&long_value).is_err());
16/// ```
17pub struct MaxStrlenValidator(pub usize);
18
19impl Validate for MaxStrlenValidator {
20    fn validate(&self, value: &Value) -> crate::prelude::DbmsResult<()> {
21        let Value::Text(text) = value else {
22            return Err(DbmsError::Validation("Value is not a `Text`".to_string()));
23        };
24
25        let len = text.0.chars().count();
26
27        if len <= self.0 {
28            Ok(())
29        } else {
30            Err(DbmsError::Validation(format!(
31                "String length {} exceeds maximum allowed length of {}",
32                len, self.0
33            )))
34        }
35    }
36}
37
38/// A validator that checks if the length of a string is at least a minimum length.
39///
40/// The length is the number of Unicode characters (scalar values), not bytes.
41///
42/// # Example
43/// ```rust
44/// use wasm_dbms_api::prelude::{MinStrlenValidator, Validate, Value, Text};
45/// let validator = MinStrlenValidator(5);
46/// let value = Value::Text(Text("Hello".to_string()));
47/// assert!(validator.validate(&value).is_ok());
48/// let short_value = Value::Text(Text("Hi".to_string()));
49/// assert!(validator.validate(&short_value).is_err());
50/// ```
51pub struct MinStrlenValidator(pub usize);
52
53impl Validate for MinStrlenValidator {
54    fn validate(&self, value: &Value) -> crate::prelude::DbmsResult<()> {
55        let Value::Text(text) = value else {
56            return Err(DbmsError::Validation("Value is not a `Text`".to_string()));
57        };
58
59        let len = text.0.chars().count();
60
61        if len >= self.0 {
62            Ok(())
63        } else {
64            Err(DbmsError::Validation(format!(
65                "String length {} is less than minimum required length of {}",
66                len, self.0
67            )))
68        }
69    }
70}
71
72/// A validator that checks if the length of a string is within a specified range.
73///
74/// The length is the number of Unicode characters (scalar values), not bytes.
75///
76/// # Example
77///
78/// ```rust
79/// use wasm_dbms_api::prelude::{RangeStrlenValidator, Validate, Value, Text};
80/// let validator = RangeStrlenValidator(3, 10);
81/// let value = Value::Text(Text("Hello".to_string()));
82/// assert!(validator.validate(&value).is_ok());
83/// let short_value = Value::Text(Text("Hi".to_string()));
84/// assert!(validator.validate(&short_value).is_err());
85/// let long_value = Value::Text(Text("Hello, World!".to_string()));
86/// assert!(validator.validate(&long_value).is_err());
87/// ```
88pub struct RangeStrlenValidator(pub usize, pub usize);
89
90impl Validate for RangeStrlenValidator {
91    fn validate(&self, value: &Value) -> crate::prelude::DbmsResult<()> {
92        let Value::Text(text) = value else {
93            return Err(DbmsError::Validation("Value is not a `Text`".to_string()));
94        };
95
96        let len = text.0.chars().count();
97
98        if len >= self.0 && len <= self.1 {
99            Ok(())
100        } else {
101            Err(DbmsError::Validation(format!(
102                "String length {} is not within the allowed range of {} to {}",
103                len, self.0, self.1
104            )))
105        }
106    }
107}
108
109#[cfg(test)]
110mod tests {
111
112    use super::*;
113    use crate::prelude::Text;
114
115    #[test]
116    fn test_max_strlen_validator() {
117        let validator = MaxStrlenValidator(5);
118
119        let valid_value = Value::Text(Text("Hello".to_string()));
120        let invalid_value = Value::Text(Text("Hello, World!".to_string()));
121
122        assert!(validator.validate(&valid_value).is_ok());
123        assert!(validator.validate(&invalid_value).is_err());
124    }
125
126    #[test]
127    fn test_max_strlen_validator_non_text() {
128        let validator = MaxStrlenValidator(5);
129        let non_text_value = Value::Uint32(crate::prelude::Uint32(42));
130        assert!(validator.validate(&non_text_value).is_err());
131    }
132
133    #[test]
134    fn test_min_strlen_validator() {
135        let validator = MinStrlenValidator(5);
136        let valid_value = Value::Text(Text("Hello".to_string()));
137        let invalid_value = Value::Text(Text("Hi".to_string()));
138        assert!(validator.validate(&valid_value).is_ok());
139        assert!(validator.validate(&invalid_value).is_err());
140    }
141
142    #[test]
143    fn test_min_strlen_validator_non_text() {
144        let validator = MinStrlenValidator(5);
145        let non_text_value = Value::Uint32(crate::prelude::Uint32(42));
146        assert!(validator.validate(&non_text_value).is_err());
147    }
148
149    #[test]
150    fn test_range_strlen_validator() {
151        let validator = RangeStrlenValidator(3, 10);
152        let valid_value = Value::Text(Text("Hello".to_string()));
153        let too_short_value = Value::Text(Text("Hi".to_string()));
154        let too_long_value = Value::Text(Text("Hello, World!".to_string()));
155        assert!(validator.validate(&valid_value).is_ok());
156        assert!(validator.validate(&too_short_value).is_err());
157        assert!(validator.validate(&too_long_value).is_err());
158    }
159
160    #[test]
161    fn test_range_strlen_validator_non_text() {
162        let validator = RangeStrlenValidator(3, 10);
163        let non_text_value = Value::Uint32(crate::prelude::Uint32(42));
164        assert!(validator.validate(&non_text_value).is_err());
165    }
166
167    #[test]
168    fn test_strlen_validators_count_unicode_characters() {
169        let emoji = Value::Text(Text("🙂".to_string()));
170        let accented = Value::Text(Text("héllo".to_string()));
171
172        assert!(MaxStrlenValidator(1).validate(&emoji).is_ok());
173        assert!(MaxStrlenValidator(5).validate(&accented).is_ok());
174        assert!(MinStrlenValidator(2).validate(&emoji).is_err());
175        assert!(MinStrlenValidator(6).validate(&accented).is_err());
176        assert!(RangeStrlenValidator(1, 1).validate(&emoji).is_ok());
177        assert!(RangeStrlenValidator(2, 4).validate(&emoji).is_err());
178        assert!(RangeStrlenValidator(5, 5).validate(&accented).is_ok());
179    }
180
181    #[test]
182    fn test_strlen_validator_error_reports_character_count() {
183        let two_emoji = Value::Text(Text("🙂🙂".to_string()));
184
185        let err = MaxStrlenValidator(1).validate(&two_emoji).unwrap_err();
186
187        assert!(err.to_string().contains("String length 2 exceeds"), "{err}");
188    }
189}