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