oca_conductor/data_set/
csv_data_set.rs1use crate::data_set::DataSet;
2use crate::errors::GenericError;
3use serde::{Serialize, Serializer};
4use serde_json::Value;
5use std::collections::BTreeMap;
6
7#[cfg(feature = "transformer")]
8use crate::transformer::data_set_transformer::Operation;
9#[cfg(feature = "transformer")]
10use oca_rs::state::oca::OCA;
11#[cfg(feature = "transformer")]
12use serde_json::Map;
13
14#[derive(Clone)]
15pub struct CSVDataSet {
16 pub raw: String,
17 delimiter: char,
18}
19
20impl Serialize for CSVDataSet {
21 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
22 where
23 S: Serializer,
24 {
25 serializer.serialize_str(&self.raw)
26 }
27}
28
29impl DataSet for CSVDataSet {
30 fn new(raw: String) -> Box<Self> {
31 Box::new(Self {
32 raw,
33 delimiter: ';',
34 })
35 }
36
37 fn get_raw(&self) -> String {
38 self.raw.clone()
39 }
40
41 fn load(
42 &self,
43 attribute_types: BTreeMap<String, String>,
44 ) -> Result<Vec<Value>, Vec<GenericError>> {
45 let mut errors = vec![];
46 let mut rows_value = vec![];
47 for line in self.raw.lines() {
48 rows_value.push(Value::Array(
49 line.split(self.delimiter)
50 .map(|el| Value::String(el.to_string()))
51 .collect(),
52 ))
53 }
54 let mut result = vec![];
55
56 let header_row_v = rows_value.get(0).unwrap().as_array().unwrap();
57 let header_row = header_row_v
58 .iter()
59 .map(|v| v.as_str().unwrap())
60 .collect::<Vec<&str>>();
61
62 for row_value in &rows_value[1..rows_value.len()] {
63 if let Value::Array(row_v) = row_value {
64 let row: Vec<Value> = row_v
65 .iter()
66 .enumerate()
67 .map(|(i, v)| {
68 if let Value::String(v_str) = v {
69 if v_str.trim().is_empty() {
70 return Value::Null;
71 }
72 }
73 let attribute_name = header_row.get(i).unwrap().to_string();
74 let attribute_type_op = attribute_types.get(&attribute_name);
75 match attribute_type_op {
76 Some(attribute_type) => match Self::parse_value(v, attribute_type) {
77 Ok(parsed) => parsed,
78 Err(e) => {
79 errors
80 .push(GenericError::from(format!("{attribute_name}: {e}")));
81 Value::Null
82 }
83 },
84 None => v.clone(),
85 }
86 })
87 .collect();
88 result.push(header_row.iter().cloned().zip(row.clone()).collect());
89 }
90 }
91 if !errors.is_empty() {
92 return Err(errors);
93 }
94 Ok(result)
95 }
96
97 #[cfg(feature = "transformer")]
98 fn transform_schema(
99 &self,
100 mappings: BTreeMap<String, String>,
101 subset_attributes_op: Option<Vec<String>>,
102 ) -> Result<Box<dyn DataSet + Sync + Send>, GenericError> {
103 let mut transformed_raw = self.raw.clone();
104 if let Some(header_line) = transformed_raw.lines().take(1).next() {
105 let mut headers = header_line
106 .split(self.delimiter)
107 .map(|header| match mappings.get(header) {
108 Some(mapping) => mapping,
109 None => header,
110 })
111 .collect::<Vec<&str>>();
112 let mut records = transformed_raw
113 .lines()
114 .skip(1)
115 .map(|s| s.to_string())
116 .collect::<Vec<String>>();
117
118 if let Some(subset_attributes) = subset_attributes_op {
119 let keep: Vec<bool> = headers
120 .clone()
121 .iter()
122 .map(|attr_name| subset_attributes.contains(&attr_name.to_string()))
123 .collect();
124 let mut iter = keep.iter();
125 headers.retain(|_| *iter.next().unwrap());
126 records = records
127 .iter()
128 .map(|record| {
129 let mut iter = keep.iter();
130 let mut r = record.split(self.delimiter).collect::<Vec<&str>>();
131 r.retain(|_| *iter.next().unwrap());
132 r.join(&self.delimiter.to_string())
133 })
134 .collect::<Vec<String>>();
135 }
136 transformed_raw =
137 headers.join(&self.delimiter.to_string()) + "\n" + &records.join("\n");
138 }
139 Ok(Box::new(
140 Self::new(transformed_raw).delimiter(self.delimiter),
141 ))
142 }
143
144 #[cfg(feature = "transformer")]
145 fn transform_data(
146 &self,
147 oca: &OCA,
148 entry_code_mappings: BTreeMap<String, BTreeMap<String, String>>,
149 unit_transformation_operations: BTreeMap<String, Vec<Operation>>,
150 ) -> Result<Box<dyn DataSet + Sync + Send>, Vec<GenericError>> {
151 let mut transformed_data_set = vec![];
152
153 for record in self.load(oca.capture_base.attributes.clone())? {
154 let record_map = record.as_object().unwrap();
155 let mut transformed_data = Map::new();
156 for (k, v) in record_map {
157 let key = k.to_string();
158 let mut value = v.clone();
159 if let Some(mapped_entries) = entry_code_mappings.get(k) {
160 match value {
161 Value::Array(ref values_vec) => {
162 let mut mapped_values = vec![];
163 for v in values_vec {
164 match mapped_entries.get(v.as_str().unwrap()) {
165 Some(mapped_entry) => {
166 mapped_values.push(Value::String(mapped_entry.to_string()));
167 }
168 None => {
169 mapped_values.push(v.clone());
170 }
171 }
172 }
173 value = Value::Array(mapped_values);
174 }
175 Value::String(_) => {
176 if let Some(mapped_entry) = mapped_entries.get(value.as_str().unwrap())
177 {
178 value = Value::String(mapped_entry.clone());
179 };
180 }
181 _ => (),
182 }
183 }
184 if let Some(operations) = unit_transformation_operations.get(k) {
185 if let Value::Number(num) = &value {
186 value = Value::Number(
187 serde_json::value::Number::from_f64(
188 self.calculate_value_units(num.as_f64().unwrap(), operations),
189 )
190 .unwrap(),
191 );
192 }
193 }
194 transformed_data.insert(key, value);
195 }
196
197 transformed_data_set.push(Value::Object(transformed_data));
198 }
199
200 let mut data = String::new();
201 for (i, record_val) in transformed_data_set.iter().enumerate() {
202 if let Value::Object(record) = record_val {
203 if i == 0 {
204 data.push_str(
205 &record
206 .keys()
207 .map(|v| v.to_string())
208 .collect::<Vec<String>>()
209 .join(&self.delimiter.to_string()),
210 );
211 }
212 let line = String::from("\n")
213 + &record
214 .values()
215 .map(|v| {
216 if v.is_string() {
217 v.as_str().unwrap().to_string()
218 } else {
219 v.to_string()
220 }
221 })
222 .collect::<Vec<String>>()
223 .join(&self.delimiter.to_string());
224 data.push_str(&line);
225 }
226 }
227
228 Ok(Box::new(Self::new(data).delimiter(self.delimiter)))
229 }
230}
231
232impl CSVDataSet {
233 pub fn delimiter(&mut self, d: char) -> Self {
234 self.delimiter = d;
235 self.clone()
236 }
237
238 fn parse_value(value: &Value, attribute_type: &str) -> Result<Value, GenericError> {
239 if value.is_string() {
240 let value_str = value.as_str().unwrap();
241 let parsed_value = match attribute_type {
242 "Text" => value.clone(),
243 "Array[Text]" => {
244 let mut parsed = vec![];
245 for v in serde_json::from_str::<Value>(value_str)
246 .unwrap_or_else(|_| Value::String(value_str.to_string()))
247 .as_array()
248 .ok_or_else(|| {
249 GenericError::from(format!("\"{value_str}\" value is not an array"))
250 })?
251 {
252 parsed.push(Self::parse_value(v, "Text")?)
253 }
254 Value::Array(parsed)
255 }
256 "Numeric" => Value::Number(value_str.parse()?),
257 "Array[Numeric]" => {
258 let mut parsed = vec![];
259 for v in serde_json::from_str::<Value>(value_str)
260 .unwrap_or_else(|_| Value::String(value_str.to_string()))
261 .as_array()
262 .ok_or_else(|| {
263 GenericError::from(format!("\"{value_str}\" value is not an array"))
264 })?
265 {
266 parsed.push(Self::parse_value(v, "Numeric")?)
267 }
268 Value::Array(parsed)
269 }
270 "Boolean" => Value::Bool(value_str.parse()?),
271 "Array[Boolean]" => {
272 let mut parsed = vec![];
273 for v in serde_json::from_str::<Value>(value_str)
274 .unwrap_or_else(|_| Value::String(value_str.to_string()))
275 .as_array()
276 .ok_or_else(|| {
277 GenericError::from(format!("\"{value_str}\" value is not an array"))
278 })?
279 {
280 parsed.push(Self::parse_value(v, "Boolean")?)
281 }
282 Value::Array(parsed)
283 }
284 "DateTime" => value.clone(),
285 "Array[DateTime]" => {
286 let mut parsed = vec![];
287 for v in serde_json::from_str::<Value>(value_str)
288 .unwrap_or_else(|_| Value::String(value_str.to_string()))
289 .as_array()
290 .ok_or_else(|| {
291 GenericError::from(format!("\"{value_str}\" value is not an array"))
292 })?
293 {
294 parsed.push(Self::parse_value(v, "DateTime")?)
295 }
296 Value::Array(parsed)
297 }
298 _ => Value::Null,
299 };
301
302 return Ok(parsed_value);
303 }
304
305 Ok(value.clone())
306 }
307}
308
309#[cfg(test)]
310mod tests {
311 use super::*;
312 use oca_rs::state::oca::OCA;
313
314 fn setup_oca() -> OCA {
315 let common_assets_dir_path = format!("{}/../assets", env!("CARGO_MANIFEST_DIR"));
316 let oca_result = oca_zip_resolver::resolve_from_zip(
317 format!("{common_assets_dir_path}/oca_bundle.zip").as_str(),
318 );
319 assert!(oca_result.is_ok());
320 oca_result.unwrap()
321 }
322
323 #[test]
324 fn load_csv_data_set() {
325 let oca = setup_oca();
326 let result = CSVDataSet::new(
327 r#"asd
328test@example.com"#
329 .to_string(),
330 )
331 .load(oca.capture_base.attributes);
332 assert!(result.is_ok());
333 }
334
335 #[test]
336 fn load_csv_data_set_with_custom_delimiter() {
337 let oca = setup_oca();
338 let result = CSVDataSet::new(
339 r#"first,second
3401,2"#
341 .to_string(),
342 )
343 .delimiter(',')
344 .load(oca.capture_base.attributes);
345
346 assert!(result.is_ok());
347 if let Value::Object(record) = result.unwrap().first().unwrap() {
348 assert_eq!(record.len(), 2);
349 }
350 }
351
352 #[test]
353 fn parse_vaules_with_invalid_array() {
354 let array_types = vec![
355 "Array[Text]",
356 "Array[Numeric]",
357 "Array[DateTime]",
358 "Array[Boolean]",
359 ];
360 for array_type in array_types {
361 let result = CSVDataSet::parse_value(&Value::String("asd".to_string()), array_type);
362 assert!(result.is_err());
363 }
364 }
365}