dataflow_rs/engine/functions/
validation.rs1use crate::engine::error::{DataflowError, Result};
2use serde::Deserialize;
3use serde_json::Value;
4
5#[derive(Debug, Clone, Deserialize)]
7pub struct ValidationConfig {
8 pub rules: Vec<ValidationRule>,
9}
10
11#[derive(Debug, Clone, Deserialize)]
12pub struct ValidationRule {
13 pub logic: Value,
14 pub path: String,
15 pub message: String,
16 #[serde(skip)]
17 pub logic_index: Option<usize>,
18}
19
20impl ValidationConfig {
21 pub fn from_json(input: &Value) -> Result<Self> {
22 let rules = input.get("rules").ok_or_else(|| {
23 DataflowError::Validation("Missing 'rules' array in input".to_string())
24 })?;
25
26 let rules_arr = rules
27 .as_array()
28 .ok_or_else(|| DataflowError::Validation("'rules' must be an array".to_string()))?;
29
30 let mut parsed_rules = Vec::new();
31
32 for rule in rules_arr {
33 let logic = rule
34 .get("logic")
35 .ok_or_else(|| DataflowError::Validation("Missing 'logic' in rule".to_string()))?
36 .clone();
37
38 let path = rule
39 .get("path")
40 .and_then(Value::as_str)
41 .unwrap_or("data")
42 .to_string();
43
44 let message = rule
45 .get("message")
46 .and_then(Value::as_str)
47 .unwrap_or("Validation failed")
48 .to_string();
49
50 parsed_rules.push(ValidationRule {
51 logic,
52 path,
53 message,
54 logic_index: None,
55 });
56 }
57
58 Ok(ValidationConfig {
59 rules: parsed_rules,
60 })
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67 use serde_json::json;
68
69 #[test]
70 fn test_validation_config_from_json() {
71 let input = json!({
72 "rules": [
73 {
74 "logic": {"!!": [{"var": "data.required_field"}]},
75 "path": "data",
76 "message": "Required field is missing"
77 },
78 {
79 "logic": {">": [{"var": "data.age"}, 18]},
80 "message": "Must be over 18"
81 }
82 ]
83 });
84
85 let config = ValidationConfig::from_json(&input).unwrap();
86 assert_eq!(config.rules.len(), 2);
87 assert_eq!(config.rules[0].path, "data");
88 assert_eq!(config.rules[0].message, "Required field is missing");
89 assert_eq!(config.rules[1].path, "data"); assert_eq!(config.rules[1].message, "Must be over 18");
91 }
92
93 #[test]
94 fn test_validation_config_missing_rules() {
95 let input = json!({});
96 let result = ValidationConfig::from_json(&input);
97 assert!(result.is_err());
98 }
99
100 #[test]
101 fn test_validation_config_invalid_rules() {
102 let input = json!({
103 "rules": "not_an_array"
104 });
105 let result = ValidationConfig::from_json(&input);
106 assert!(result.is_err());
107 }
108
109 #[test]
110 fn test_validation_config_missing_logic() {
111 let input = json!({
112 "rules": [
113 {
114 "path": "data",
115 "message": "Some error"
116 }
117 ]
118 });
119 let result = ValidationConfig::from_json(&input);
120 assert!(result.is_err());
121 }
122
123 #[test]
124 fn test_validation_config_defaults() {
125 let input = json!({
126 "rules": [
127 {
128 "logic": {"var": "data.field"}
129 }
130 ]
131 });
132
133 let config = ValidationConfig::from_json(&input).unwrap();
134 assert_eq!(config.rules[0].path, "data");
135 assert_eq!(config.rules[0].message, "Validation failed");
136 }
137}