form_validation/validator.rs
1use crate::{Validation, ValidationErrors, ValidatorFn};
2use std::fmt::Debug;
3
4#[cfg(feature = "async")]
5use crate::AsyncValidatorFn;
6
7#[cfg(feature = "async")]
8use futures::future::join_all;
9
10/// Validates a particular type of value, can contain many validation
11/// functions. Generally used with a single key for all contained
12/// validation functions.
13///
14/// ## Example
15/// ```
16/// use form_validation::{Validation, ValidationError, Validator};
17///
18/// let v: Validator<i32, String> = Validator::new()
19/// .validation(|value: &i32, key: &String| {
20/// if value < &0 {
21/// let value_clone = *value;
22/// Err(ValidationError::new(key.clone(), "NOT_LESS_THAN_0")
23/// .with_message(move |key| {
24/// format!(
25/// "The value of {} ({}) cannot be less than 0",
26/// key, value_clone
27/// )
28/// }).into()) // convert into ValidationErrors
29/// } else {
30/// Ok(())
31/// }
32/// })
33/// .validation(|value: &i32, key: &String| {
34/// if value > &10 {
35/// let value_clone = *value;
36/// Err(ValidationError::new(key.clone(), "NOT_GREATER_THAN_10")
37/// .with_message(move |key| {
38/// format!(
39/// "The value of {} ({}) cannot be greater than 10",
40/// key, value_clone
41/// )
42/// }).into())
43/// } else {
44/// Ok(())
45/// }
46/// });
47///
48/// let key = "field1".to_string();
49///
50/// {
51/// let errors = v.validate_value(&11, &key).unwrap_err();
52/// assert_eq!(1, errors.len());
53/// let error = errors.errors.get(0).unwrap();
54/// assert_eq!("NOT_GREATER_THAN_10", error.type_id);
55/// }
56
57/// assert!(v.validate_value(&5, &key).is_ok());
58///
59/// {
60/// let errors = v.validate_value(&-1, &key).unwrap_err();
61/// assert_eq!(1, errors.len());
62/// let error = errors.errors.get(0).unwrap();
63/// assert_eq!("NOT_LESS_THAN_0", error.type_id);
64/// }
65/// ```
66#[derive(Clone, Debug)]
67pub struct Validator<Value, Key> {
68 pub validations: Vec<ValidatorFn<Value, Key>>,
69}
70
71impl<Value, Key> PartialEq for Validator<Value, Key> {
72 fn eq(&self, other: &Self) -> bool {
73 if self.validations.len() == other.validations.len() {
74 let mut all_validations_same = true;
75
76 for (i, this_validation) in self.validations.iter().enumerate() {
77 let other_validation = other.validations.get(i).unwrap();
78
79 all_validations_same &= this_validation == other_validation;
80 }
81
82 all_validations_same
83 } else {
84 false
85 }
86 }
87}
88
89impl<Value, Key> Validator<Value, Key> {
90 /// Create a new `Validator`.
91 pub fn new() -> Self {
92 Self {
93 validations: Vec::new(),
94 }
95 }
96
97 /// A factory method to add a validation function to this validator.
98 pub fn validation<F: Into<ValidatorFn<Value, Key>> + 'static>(
99 mut self,
100 validator_fn: F,
101 ) -> Self {
102 self.validations.push(validator_fn.into());
103 self
104 }
105}
106
107impl<Value, Key> Validation<Value, Key> for Validator<Value, Key>
108where
109 Key: PartialEq + Clone,
110{
111 fn validate_value(&self, value: &Value, key: &Key) -> Result<(), ValidationErrors<Key>> {
112 let mut errors = ValidationErrors::default();
113
114 for validation in &self.validations {
115 if let Err(new_errors) = validation.validate_value(value, key) {
116 errors.extend(new_errors)
117 }
118 }
119
120 if !errors.is_empty() {
121 Err(errors)
122 } else {
123 Ok(())
124 }
125 }
126}
127
128impl<Value, Key> Default for Validator<Value, Key> {
129 fn default() -> Self {
130 Validator::new()
131 }
132}
133
134/// Validates a particular type of value asynchronously, can contain
135/// many validation functions. Generally used with a single key for
136/// all contained validation functions.
137///
138/// See [Validator] for the synchronous version.
139///
140/// ```
141/// use form_validation::{AsyncValidator, ValidationError, AsyncValidatorFn, ValidatorFn};
142/// use futures::executor::block_on;
143///
144/// let v: AsyncValidator<i32, String> = AsyncValidator::new()
145/// .validation(AsyncValidatorFn::new(|value: &i32, key: &String| {
146/// let value = *value;
147/// let key = key.clone();
148/// Box::pin(async move {
149/// if value < 0 {
150/// Err(ValidationError::new(key.clone(), "NOT_LESS_THAN_0")
151/// .with_message(move |key| {
152/// format!("The value of {} ({}) cannot be less than 0", key, value)
153/// })
154/// .into()) // convert into ValidationErrors
155/// } else {
156/// Ok(())
157/// }
158/// })
159/// }))
160/// // also supports compatibility with the synchronous ValidatorFn
161/// .validation(ValidatorFn::new(|value: &i32, key: &String| {
162/// if value > &10 {
163/// let value_clone = *value;
164/// Err(ValidationError::new(key.clone(), "NOT_GREATER_THAN_10")
165/// .with_message(move |key| {
166/// format!(
167/// "The value of {} ({}) cannot be greater than 10",
168/// key, value_clone
169/// )
170/// })
171/// .into()) // convert into ValidationErrors
172/// } else {
173/// Ok(())
174/// }
175/// }));
176/// let key = "field1".to_string();
177/// {
178/// let errors = block_on(v.validate_value(&11, &key)).unwrap_err();
179/// assert_eq!(1, errors.len());
180/// let error = errors.errors.get(0).unwrap();
181/// assert_eq!("NOT_GREATER_THAN_10", error.type_id);
182/// }
183///
184/// assert!(block_on(v.validate_value(&5, &key)).is_ok());
185///
186/// {
187/// let errors = block_on(v.validate_value(&-1, &key)).unwrap_err();
188/// assert_eq!(1, errors.len());
189/// let error = errors.errors.get(0).unwrap();
190/// assert_eq!("NOT_LESS_THAN_0", error.type_id);
191/// }
192/// ```
193#[cfg(feature = "async")]
194#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
195#[derive(Clone, PartialEq, Debug)]
196pub struct AsyncValidator<Value, Key> {
197 pub validations: Vec<AsyncValidatorFn<Value, Key>>,
198}
199
200#[cfg(feature = "async")]
201impl<Value, Key> AsyncValidator<Value, Key>
202where
203 Key: Clone + PartialEq,
204 Value: Clone + PartialEq,
205{
206 /// Create a new `Validator`.
207 pub fn new() -> Self {
208 Self {
209 validations: Vec::new(),
210 }
211 }
212
213 /// A factory method to add a validation function to this validator.
214 pub fn validation<F: Into<AsyncValidatorFn<Value, Key>> + 'static>(
215 mut self,
216 async_validator_fn: F,
217 ) -> Self {
218 self.validations.push(async_validator_fn.into());
219 self
220 }
221
222 pub async fn validate_value(
223 &self,
224 value: &Value,
225 key: &Key,
226 ) -> Result<(), ValidationErrors<Key>> {
227 let mut errors = ValidationErrors::default();
228
229 let futures = self
230 .validations
231 .iter()
232 .map(|async_validator_fn| async_validator_fn.validate_value(value, key))
233 .collect::<Vec<_>>();
234
235 // Execute all the futures concurrently
236 let results: Vec<Result<(), ValidationErrors<Key>>> = join_all(futures).await;
237
238 for result in results {
239 if let Err(new_errors) = result {
240 errors.extend(new_errors)
241 }
242 }
243
244 if !errors.is_empty() {
245 Err(errors)
246 } else {
247 Ok(())
248 }
249 }
250}
251
252#[cfg(feature = "async")]
253impl<Value, Key> Default for AsyncValidator<Value, Key>
254where
255 Key: Clone + PartialEq,
256 Value: Clone + PartialEq,
257{
258 fn default() -> Self {
259 Self::new()
260 }
261}
262
263#[cfg(feature = "async")]
264impl<Value, Key> From<Validator<Value, Key>> for AsyncValidator<Value, Key>
265where
266 Value: Clone + PartialEq + 'static,
267 Key: Clone + PartialEq + 'static,
268{
269 fn from(validator: Validator<Value, Key>) -> Self {
270 let mut async_validator: AsyncValidator<Value, Key> = AsyncValidator::new();
271
272 for validator_fn in validator.validations {
273 async_validator = async_validator.validation(validator_fn);
274 }
275
276 async_validator
277 }
278}
279
280#[cfg(test)]
281mod test {
282 #[cfg(feature = "async")]
283 mod async_tests {
284 use super::super::{AsyncValidator, Validator};
285 use crate::ValidationError;
286 use futures::executor::block_on;
287
288 /// Unit test for the `From<Validator> for AsyncValidator` implmentation
289 #[test]
290 fn async_validator_from_validator() {
291 let v: Validator<i32, String> = Validator::new()
292 .validation(|value: &i32, key: &String| {
293 if value < &0 {
294 let value_clone = *value;
295 Err(ValidationError::new(key.clone(), "NOT_LESS_THAN_0")
296 .with_message(move |key| {
297 format!(
298 "The value of {} ({}) cannot be less than 0",
299 key, value_clone
300 )
301 })
302 .into())
303 } else {
304 Ok(())
305 }
306 })
307 .validation(|value: &i32, key: &String| {
308 if value > &10 {
309 let value_clone = *value;
310 Err(ValidationError::new(key.clone(), "NOT_GREATER_THAN_10")
311 .with_message(move |key| {
312 format!(
313 "The value of {} ({}) cannot be greater than 10",
314 key, value_clone
315 )
316 })
317 .into())
318 } else {
319 Ok(())
320 }
321 });
322
323 // perform the conversion
324 let av: AsyncValidator<i32, String> = v.into();
325
326 let key = "field1".to_string();
327 {
328 let errors = block_on(av.validate_value(&11, &key)).unwrap_err();
329 assert_eq!(1, errors.len());
330 let error = errors.errors.get(0).unwrap();
331 assert_eq!("NOT_GREATER_THAN_10", error.type_id);
332 }
333 assert!(block_on(av.validate_value(&5, &key)).is_ok());
334 {
335 let errors = block_on(av.validate_value(&-1, &key)).unwrap_err();
336 assert_eq!(1, errors.len());
337 let error = errors.errors.get(0).unwrap();
338 assert_eq!("NOT_LESS_THAN_0", error.type_id);
339 }
340 }
341 }
342}