1use std::collections::HashMap;
2use serde::Deserialize;
3use serde_json::{Value, Map};
4use jsonlogic_rs::apply;
5
6mod error;
7pub use error::Error;
8
9#[derive(Debug, Deserialize)]
10#[serde(tag = "type")]
11pub enum TransformType {
12 #[serde(rename = "field")]
13 Field {
14 source: String,
15 target: String,
16 #[serde(default)]
17 transform: Option<String>,
18 },
19 #[serde(rename = "concat")]
20 Concat {
21 sources: Vec<String>,
22 target: String,
23 #[serde(default)]
24 separator: Option<String>,
25 },
26 #[serde(rename = "split")]
27 Split {
28 source: String,
29 targets: HashMap<String, SplitTarget>,
30 #[serde(default)]
31 separator: Option<String>,
32 },
33}
34
35#[derive(Debug, Deserialize)]
36pub struct Transform {
37 #[serde(flatten)]
38 pub transform_type: TransformType,
39 #[serde(default)]
40 pub condition: Option<Value>,
41}
42
43#[derive(Debug, Deserialize)]
44pub struct SplitTarget {
45 pub index: usize,
46 #[serde(default)]
47 pub transform: Option<String>,
48}
49
50pub struct Datamorph {
51 transforms: Vec<Transform>,
52}
53
54impl Datamorph {
55 pub fn from_json(spec: &str) -> Result<Self, Error> {
56 let transforms: Vec<Transform> = serde_json::from_str(spec)?;
57 Ok(Self { transforms })
58 }
59
60 pub fn transform<T, U>(&self, input: T) -> Result<U, Error>
61 where
62 T: serde::Serialize,
63 U: for<'de> serde::Deserialize<'de>,
64 {
65 let input = serde_json::to_value(input)?;
66 let mut output = Value::Object(Map::new());
67
68 for transform in &self.transforms {
69 if let Some(result) = transform.apply(&input)? {
70 self.merge_values(&mut output, result);
71 }
72 }
73
74 Ok(serde_json::from_value(output)?)
75 }
76
77 fn merge_values(&self, target: &mut Value, source: Value) {
78 if let (Some(target_obj), Some(source_obj)) = (target.as_object_mut(), source.as_object()) {
79 for (key, value) in source_obj {
80 match target_obj.get_mut(key.as_str()) { Some(existing) => self.merge_values(existing, value.clone()),
82 None => { target_obj.insert(key.clone(), value.clone()); }
83 }
84 }
85 }
86 }
87}
88
89impl Transform {
90 pub fn apply(&self, input: &Value) -> Result<Option<Value>, Error> {
91 if !self.check_condition(input)? {
92 return Ok(None);
93 }
94
95 match &self.transform_type {
96 TransformType::Field { source, target, transform } => {
97 let value = self.get_value(input, source)?;
98 let transformed = self.apply_transform(value.clone(), transform)?;
99 Ok(Some(self.set_value_at_path(target, transformed)))
100 },
101 TransformType::Concat { sources, target, separator } => {
102 let values: Vec<String> = sources.iter()
103 .filter_map(|s| self.get_value(input, s).ok())
104 .filter_map(|v| v.as_str().map(String::from))
105 .collect();
106
107 let result = values.join(separator.as_deref().unwrap_or(""));
108 Ok(Some(self.set_value_at_path(target, Value::String(result))))
109 },
110 TransformType::Split { source, targets, separator } => {
111 let value = self.get_value(input, source)?;
112 let str_value = value.as_str()
113 .ok_or_else(|| Error::Transform("Source must be string".into()))?;
114
115 let parts: Vec<&str> = str_value.split(separator.as_deref().unwrap_or(""))
116 .collect();
117
118 let mut result = Map::new();
119 for (target_path, split_target) in targets {
120 if let Some(part) = parts.get(split_target.index) {
121 let value = self.apply_transform(
122 Value::String(part.to_string()),
123 &split_target.transform
124 )?;
125 result.insert(target_path.clone(), value);
126 }
127 }
128
129 Ok(Some(Value::Object(result)))
130 },
131 }
132 }
133
134 fn check_condition(&self, input: &Value) -> Result<bool, Error> {
135 match &self.condition {
136 Some(condition) => {
137 apply(condition, input)
138 .map_err(|e| Error::Logic(e.to_string()))?
139 .as_bool()
140 .ok_or_else(|| Error::Logic("Condition must evaluate to boolean".into()))
141 },
142 None => Ok(true),
143 }
144 }
145
146 fn get_value<'a>(&self, input: &'a Value, path: &str) -> Result<&'a Value, Error> {
147 path.split('.')
148 .try_fold(input, |value, key| {
149 value.get(key).ok_or_else(|| Error::MissingField(path.to_string()))
150 })
151 }
152
153 fn apply_transform(&self, value: Value, transform: &Option<String>) -> Result<Value, Error> {
154 match transform {
155 Some(transform) => match transform.as_str() {
156 "uppercase" => Ok(Value::String(
157 value.as_str()
158 .ok_or_else(|| Error::Transform("Expected string".into()))?
159 .to_uppercase()
160 )),
161 "lowercase" => Ok(Value::String(
162 value.as_str()
163 .ok_or_else(|| Error::Transform("Expected string".into()))?
164 .to_lowercase()
165 )),
166 _ => Err(Error::Transform(format!("Unknown transform: {}", transform))),
167 },
168 None => Ok(value),
169 }
170 }
171
172 fn set_value_at_path(&self, path: &str, value: Value) -> Value {
173 let parts: Vec<&str> = path.split('.').collect();
174 let mut result = Map::new();
175 let mut current = &mut result;
176
177 for (i, part) in parts.iter().enumerate() {
178 if i == parts.len() - 1 {
179 current.insert((*part).to_string(), value.clone());
180 } else {
181 current.insert((*part).to_string(), Value::Object(Map::new()));
182 current = current.get_mut(*part) .unwrap()
184 .as_object_mut()
185 .unwrap();
186 }
187 }
188
189 Value::Object(result)
190 }
191}