1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
extern crate tera;
use super::Updater;
use super::{Action, ActionType};
use crate::helper::json_pointer::JsonPointer;
use crate::updater::tera_helpers::{filters, function};
use json_value_merge::Merge;
use json_value_remove::Remove;
use json_value_resolve::Resolve;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use std::error::Error as StdError;
use std::{fmt, io};
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[serde(default)]
pub struct Tera {}
impl fmt::Display for Tera {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Tera {{}}")
}
}
impl Updater for Tera {
fn update(
&self,
object: Value,
mapping: Option<HashMap<String, Vec<Value>>>,
actions: Vec<Action>,
input_name: String,
output_name: String,
) -> io::Result<Value> {
trace!(input = format!("{}", object).as_str(), updater = format!("{}", self).as_str(), "Update");
let mut engine = Tera::engine();
let mut context = tera::Context::new();
context.insert(input_name, &object);
if let Some(mapping) = mapping {
for (field_path, object) in mapping {
context.insert(&field_path.clone(), &object.clone());
}
}
let mut json_value = Value::default();
for action in actions {
trace!(field = action.field.as_str(), "Field fetch into the pattern collection");
context.insert(output_name.clone(), &json_value.clone());
let mut field_new_value = Value::default();
match &action.pattern {
Some(pattern) => {
let render_result: String = match engine.render_str(pattern.as_str(), &context)
{
Ok(render_result) => Ok(render_result),
Err(e) => Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"Failed to render the field '{}'. {}.",
action.field,
match e.source() {
Some(e) => {
match e.source() {
Some(e) => {
e.to_string()
}
None => e.to_string(),
}
}
None => format!("Please fix the pattern `{}`", pattern.to_string()),
}.replace(" '__tera_one_off'", "")
),
)),
}?;
trace!(value = render_result.as_str(), "Field value before resolved it");
field_new_value = Value::resolve(render_result);
trace!(value = format!("{}", field_new_value).as_str(), "Field value after resolved it");
}
None => (),
};
let json_pointer = action.field.clone().to_json_pointer();
trace!(output = format!("{}", json_value).as_str(),
jpointer = json_pointer.to_string().as_str(),
data = format!("{}", field_new_value).as_str(),
"{} the new field", action.action_type
);
match action.action_type {
ActionType::Merge => {
json_value.merge_in(&json_pointer, field_new_value)?;
}
ActionType::Replace => {
json_value.merge_in(&json_pointer, Value::Null)?;
json_value.merge_in(&json_pointer, field_new_value)?;
}
ActionType::Remove => {
json_value.remove(&json_pointer)?;
}
}
}
trace!(output = format!("{}", json_value).as_str(), "Update ended");
Ok(json_value)
}
}
impl Tera {
fn engine() -> tera::Tera {
let mut engine = tera::Tera::default();
engine.autoescape_on(vec![]);
engine.register_filter("merge", filters::object::merge);
engine.register_function("uuid_v4", function::uuid_v4);
engine.register_function("set_env", function::set_env);
engine.register_function("base64_encode", function::base64_encode);
engine.register_function("base64_decode", function::base64_decode);
engine.register_filter("search", filters::object::search);
engine
}
}