this/core/validation/
config.rs

1//! Entity validation configuration
2//!
3//! This module provides the configuration structure that holds validators and filters
4//! for an entity. It's generated by the macro system.
5
6use anyhow::Result;
7use serde_json::Value;
8use std::collections::HashMap;
9
10/// Type alias for validator function
11type ValidatorFn = Box<dyn Fn(&str, &Value) -> Result<(), String> + Send + Sync>;
12
13/// Type alias for filter function
14type FilterFn = Box<dyn Fn(&str, Value) -> Result<Value> + Send + Sync>;
15
16/// Configuration for validating and filtering an entity
17pub struct EntityValidationConfig {
18    /// Entity type name
19    pub entity_type: String,
20
21    /// Validators by field name
22    validators: HashMap<String, Vec<ValidatorFn>>,
23
24    /// Filters by field name
25    filters: HashMap<String, Vec<FilterFn>>,
26}
27
28impl EntityValidationConfig {
29    /// Create a new validation config for an entity
30    pub fn new(entity_type: &str) -> Self {
31        Self {
32            entity_type: entity_type.to_string(),
33            validators: HashMap::new(),
34            filters: HashMap::new(),
35        }
36    }
37
38    /// Add a validator for a specific field
39    pub fn add_validator<F>(&mut self, field: &str, validator: F)
40    where
41        F: Fn(&str, &Value) -> Result<(), String> + Send + Sync + 'static,
42    {
43        self.validators
44            .entry(field.to_string())
45            .or_default()
46            .push(Box::new(validator));
47    }
48
49    /// Add a filter for a specific field
50    pub fn add_filter<F>(&mut self, field: &str, filter: F)
51    where
52        F: Fn(&str, Value) -> Result<Value> + Send + Sync + 'static,
53    {
54        self.filters
55            .entry(field.to_string())
56            .or_default()
57            .push(Box::new(filter));
58    }
59
60    /// Validate and filter a complete payload
61    ///
62    /// Returns the filtered payload or a list of validation errors
63    pub fn validate_and_filter(&self, mut payload: Value) -> Result<Value, Vec<String>> {
64        let mut errors = Vec::new();
65
66        // Step 1: Apply all filters
67        if let Some(obj) = payload.as_object_mut() {
68            for (field, value) in obj.iter_mut() {
69                if let Some(field_filters) = self.filters.get(field) {
70                    for filter in field_filters {
71                        match filter(field, value.clone()) {
72                            Ok(filtered) => *value = filtered,
73                            Err(e) => {
74                                errors.push(format!("Erreur de filtrage sur '{}': {}", field, e));
75                            }
76                        }
77                    }
78                }
79            }
80        }
81
82        // Step 2: Apply all validators
83        if let Some(obj) = payload.as_object() {
84            for (field, value) in obj.iter() {
85                if let Some(field_validators) = self.validators.get(field) {
86                    for validator in field_validators {
87                        if let Err(e) = validator(field, value) {
88                            errors.push(e);
89                        }
90                    }
91                }
92            }
93        }
94
95        if errors.is_empty() {
96            Ok(payload)
97        } else {
98            Err(errors)
99        }
100    }
101}