leptos_forms_rs/validation/
array_validators.rs1use crate::core::types::FieldValue;
7
8pub struct ArrayValidators;
10
11impl ArrayValidators {
12 pub fn min_length(value: &FieldValue, min: usize) -> Result<(), String> {
14 if let FieldValue::Array(arr) = value {
15 if arr.len() >= min {
16 Ok(())
17 } else {
18 Err(format!("Array must have at least {} items", min))
19 }
20 } else {
21 Err("Value must be an array".to_string())
22 }
23 }
24
25 pub fn max_length(value: &FieldValue, max: usize) -> Result<(), String> {
27 if let FieldValue::Array(arr) = value {
28 if arr.len() <= max {
29 Ok(())
30 } else {
31 Err(format!("Array must have at most {} items", max))
32 }
33 } else {
34 Err("Value must be an array".to_string())
35 }
36 }
37
38 pub fn exact_length(value: &FieldValue, exact: usize) -> Result<(), String> {
40 if let FieldValue::Array(arr) = value {
41 if arr.len() == exact {
42 Ok(())
43 } else {
44 Err(format!("Array must have exactly {} items", exact))
45 }
46 } else {
47 Err("Value must be an array".to_string())
48 }
49 }
50
51 pub fn not_empty(value: &FieldValue) -> Result<(), String> {
53 if let FieldValue::Array(arr) = value {
54 if !arr.is_empty() {
55 Ok(())
56 } else {
57 Err("Array cannot be empty".to_string())
58 }
59 } else {
60 Err("Value must be an array".to_string())
61 }
62 }
63
64 pub fn empty(value: &FieldValue) -> Result<(), String> {
66 if let FieldValue::Array(arr) = value {
67 if arr.is_empty() {
68 Ok(())
69 } else {
70 Err("Array must be empty".to_string())
71 }
72 } else {
73 Err("Value must be an array".to_string())
74 }
75 }
76
77 pub fn length_range(value: &FieldValue, min: usize, max: usize) -> Result<(), String> {
79 if let FieldValue::Array(arr) = value {
80 if arr.len() >= min && arr.len() <= max {
81 Ok(())
82 } else {
83 Err(format!("Array must have between {} and {} items", min, max))
84 }
85 } else {
86 Err("Value must be an array".to_string())
87 }
88 }
89
90 pub fn all_items_not_empty(value: &FieldValue) -> Result<(), String> {
92 if let FieldValue::Array(arr) = value {
93 for (index, item) in arr.iter().enumerate() {
94 if item.is_empty() {
95 return Err(format!("Item at index {} cannot be empty", index));
96 }
97 }
98 Ok(())
99 } else {
100 Err("Value must be an array".to_string())
101 }
102 }
103
104 pub fn all_items_unique(value: &FieldValue) -> Result<(), String> {
106 if let FieldValue::Array(arr) = value {
107 for (i, item1) in arr.iter().enumerate() {
108 for (j, item2) in arr.iter().enumerate() {
109 if i != j && item1 == item2 {
110 return Err(format!("Duplicate items found at indices {} and {}", i, j));
111 }
112 }
113 }
114 Ok(())
115 } else {
116 Err("Value must be an array".to_string())
117 }
118 }
119
120 pub fn all_items_strings(value: &FieldValue) -> Result<(), String> {
122 if let FieldValue::Array(arr) = value {
123 for (index, item) in arr.iter().enumerate() {
124 if !matches!(item, FieldValue::String(_)) {
125 return Err(format!("Item at index {} must be a string", index));
126 }
127 }
128 Ok(())
129 } else {
130 Err("Value must be an array".to_string())
131 }
132 }
133
134 pub fn all_items_numbers(value: &FieldValue) -> Result<(), String> {
136 if let FieldValue::Array(arr) = value {
137 for (index, item) in arr.iter().enumerate() {
138 if !matches!(item, FieldValue::Number(_)) {
139 return Err(format!("Item at index {} must be a number", index));
140 }
141 }
142 Ok(())
143 } else {
144 Err("Value must be an array".to_string())
145 }
146 }
147
148 pub fn all_items_booleans(value: &FieldValue) -> Result<(), String> {
150 if let FieldValue::Array(arr) = value {
151 for (index, item) in arr.iter().enumerate() {
152 if !matches!(item, FieldValue::Boolean(_)) {
153 return Err(format!("Item at index {} must be a boolean", index));
154 }
155 }
156 Ok(())
157 } else {
158 Err("Value must be an array".to_string())
159 }
160 }
161
162 pub fn validate_items_with<F>(value: &FieldValue, validator: F) -> Result<(), String>
164 where
165 F: Fn(&FieldValue) -> Result<(), String>,
166 {
167 if let FieldValue::Array(arr) = value {
168 for (index, item) in arr.iter().enumerate() {
169 if let Err(error) = validator(item) {
170 return Err(format!("Item at index {}: {}", index, error));
171 }
172 }
173 Ok(())
174 } else {
175 Err("Value must be an array".to_string())
176 }
177 }
178
179 pub fn contains<F>(value: &FieldValue, predicate: F) -> Result<(), String>
181 where
182 F: Fn(&FieldValue) -> bool,
183 {
184 if let FieldValue::Array(arr) = value {
185 if arr.iter().any(&predicate) {
186 Ok(())
187 } else {
188 Err("Array must contain at least one item matching the condition".to_string())
189 }
190 } else {
191 Err("Value must be an array".to_string())
192 }
193 }
194
195 pub fn contains_none<F>(value: &FieldValue, predicate: F) -> Result<(), String>
197 where
198 F: Fn(&FieldValue) -> bool,
199 {
200 if let FieldValue::Array(arr) = value {
201 if arr.iter().any(&predicate) {
202 Err("Array must not contain any items matching the condition".to_string())
203 } else {
204 Ok(())
205 }
206 } else {
207 Err("Value must be an array".to_string())
208 }
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn test_min_length() {
218 let array = FieldValue::Array(vec![
219 FieldValue::String("item1".to_string()),
220 FieldValue::String("item2".to_string()),
221 ]);
222
223 assert!(ArrayValidators::min_length(&array, 1).is_ok());
224 assert!(ArrayValidators::min_length(&array, 2).is_ok());
225 assert!(ArrayValidators::min_length(&array, 3).is_err());
226 }
227
228 #[test]
229 fn test_max_length() {
230 let array = FieldValue::Array(vec![
231 FieldValue::String("item1".to_string()),
232 FieldValue::String("item2".to_string()),
233 ]);
234
235 assert!(ArrayValidators::max_length(&array, 3).is_ok());
236 assert!(ArrayValidators::max_length(&array, 2).is_ok());
237 assert!(ArrayValidators::max_length(&array, 1).is_err());
238 }
239
240 #[test]
241 fn test_exact_length() {
242 let array = FieldValue::Array(vec![
243 FieldValue::String("item1".to_string()),
244 FieldValue::String("item2".to_string()),
245 ]);
246
247 assert!(ArrayValidators::exact_length(&array, 2).is_ok());
248 assert!(ArrayValidators::exact_length(&array, 1).is_err());
249 assert!(ArrayValidators::exact_length(&array, 3).is_err());
250 }
251
252 #[test]
253 fn test_not_empty() {
254 let empty_array = FieldValue::Array(vec![]);
255 let non_empty_array = FieldValue::Array(vec![FieldValue::String("item".to_string())]);
256
257 assert!(ArrayValidators::not_empty(&empty_array).is_err());
258 assert!(ArrayValidators::not_empty(&non_empty_array).is_ok());
259 }
260
261 #[test]
262 fn test_empty() {
263 let empty_array = FieldValue::Array(vec![]);
264 let non_empty_array = FieldValue::Array(vec![FieldValue::String("item".to_string())]);
265
266 assert!(ArrayValidators::empty(&empty_array).is_ok());
267 assert!(ArrayValidators::empty(&non_empty_array).is_err());
268 }
269
270 #[test]
271 fn test_length_range() {
272 let array = FieldValue::Array(vec![
273 FieldValue::String("item1".to_string()),
274 FieldValue::String("item2".to_string()),
275 ]);
276
277 assert!(ArrayValidators::length_range(&array, 1, 3).is_ok());
278 assert!(ArrayValidators::length_range(&array, 2, 2).is_ok());
279 assert!(ArrayValidators::length_range(&array, 3, 5).is_err());
280 assert!(ArrayValidators::length_range(&array, 1, 1).is_err());
281 }
282
283 #[test]
284 fn test_all_items_not_empty() {
285 let array_with_empty = FieldValue::Array(vec![
286 FieldValue::String("item1".to_string()),
287 FieldValue::String("".to_string()),
288 ]);
289 let array_without_empty = FieldValue::Array(vec![
290 FieldValue::String("item1".to_string()),
291 FieldValue::String("item2".to_string()),
292 ]);
293
294 assert!(ArrayValidators::all_items_not_empty(&array_with_empty).is_err());
295 assert!(ArrayValidators::all_items_not_empty(&array_without_empty).is_ok());
296 }
297
298 #[test]
299 fn test_all_items_unique() {
300 let array_with_duplicates = FieldValue::Array(vec![
301 FieldValue::String("item1".to_string()),
302 FieldValue::String("item2".to_string()),
303 FieldValue::String("item1".to_string()),
304 ]);
305 let array_without_duplicates = FieldValue::Array(vec![
306 FieldValue::String("item1".to_string()),
307 FieldValue::String("item2".to_string()),
308 FieldValue::String("item3".to_string()),
309 ]);
310
311 assert!(ArrayValidators::all_items_unique(&array_with_duplicates).is_err());
312 assert!(ArrayValidators::all_items_unique(&array_without_duplicates).is_ok());
313 }
314
315 #[test]
316 fn test_all_items_strings() {
317 let array_with_strings = FieldValue::Array(vec![
318 FieldValue::String("item1".to_string()),
319 FieldValue::String("item2".to_string()),
320 ]);
321 let array_with_mixed = FieldValue::Array(vec![
322 FieldValue::String("item1".to_string()),
323 FieldValue::Number(42.0),
324 ]);
325
326 assert!(ArrayValidators::all_items_strings(&array_with_strings).is_ok());
327 assert!(ArrayValidators::all_items_strings(&array_with_mixed).is_err());
328 }
329
330 #[test]
331 fn test_contains() {
332 let array = FieldValue::Array(vec![
333 FieldValue::String("item1".to_string()),
334 FieldValue::String("item2".to_string()),
335 ]);
336
337 assert!(ArrayValidators::contains(&array, |item| {
338 matches!(item, FieldValue::String(s) if s == "item1")
339 }).is_ok());
340
341 assert!(ArrayValidators::contains(&array, |item| {
342 matches!(item, FieldValue::String(s) if s == "item3")
343 }).is_err());
344 }
345}