mf_engine/handler/expression/
mod.rs1use crate::handler::node::{
2 NodeRequest, NodeResponse, NodeResult, PartialTraceError,
3};
4use crate::model::{DecisionNodeKind, ExpressionNodeContent};
5use ahash::{HashMap, HashMapExt};
6use std::sync::Arc;
7
8use anyhow::{anyhow, Context};
9use serde::Serialize;
10use tokio::sync::Mutex;
11use mf_expression::variable::Variable;
12use mf_expression::Isolate;
13
14pub struct ExpressionHandler {
15 trace: bool,
16}
17
18#[derive(Debug, Serialize)]
19struct ExpressionTrace {
20 result: String,
21}
22
23impl ExpressionHandler {
24 pub fn new(trace: bool) -> Self {
25 Self { trace }
26 }
27
28 pub async fn handle(
29 &mut self,
30 request: NodeRequest,
31 ) -> NodeResult {
32 let content = match &request.node.kind {
33 DecisionNodeKind::ExpressionNode { content } => Ok(content),
34 _ => Err(anyhow!("Unexpected node type")),
35 }?;
36
37 let inner_handler_mutex =
38 Arc::new(Mutex::new(ExpressionHandlerInner::new(self.trace)));
39
40 content
41 .transform_attributes
42 .run_with(request.input, |input| {
43 let inner_handler_mutex = inner_handler_mutex.clone();
44
45 async move {
46 let mut inner_handler_ref =
47 inner_handler_mutex.lock().await;
48 inner_handler_ref.handle(input, content).await
49 }
50 })
51 .await
52 }
53}
54
55struct ExpressionHandlerInner<'a> {
56 isolate: Isolate<'a>,
57 trace: bool,
58}
59
60impl<'a> ExpressionHandlerInner<'a> {
61 pub fn new(trace: bool) -> Self {
62 Self { isolate: Isolate::new(), trace }
63 }
64
65 async fn handle(
66 &mut self,
67 input: Variable,
68 content: &'a ExpressionNodeContent,
69 ) -> NodeResult {
70 let result = Variable::empty_object();
71 let mut trace_map =
72 self.trace.then(|| HashMap::<&str, ExpressionTrace>::new());
73
74 self.isolate.set_environment(input.depth_clone(1));
75 for expression in &content.expressions {
76 if expression.key.is_empty() || expression.value.is_empty() {
77 continue;
78 }
79
80 let value = self
81 .isolate
82 .run_standard(&expression.value)
83 .with_context(|| PartialTraceError {
84 trace: trace_map
85 .as_ref()
86 .map(|s| serde_json::to_value(s).ok())
87 .flatten(),
88 message: format!(
89 r#"Failed to evaluate expression: "{}""#,
90 &expression.value
91 ),
92 })?;
93
94 if let Some(tmap) = &mut trace_map {
95 tmap.insert(
96 &expression.key,
97 ExpressionTrace {
98 result: serde_json::to_string(&value)
99 .unwrap_or("Error".to_owned()),
100 },
101 );
102 }
103
104 self.isolate.update_environment(|env| {
105 let Some(environment) = env else {
106 return;
107 };
108
109 let key = format!("$.{}", &expression.key);
110 let _ =
111 environment.dot_insert(key.as_str(), value.depth_clone(2));
112 });
113
114 result.dot_insert(&expression.key, value);
115 }
116
117 Ok(NodeResponse {
118 output: result,
119 trace_data: trace_map
120 .map(|tm| serde_json::to_value(tm).ok())
121 .flatten(),
122 })
123 }
124}