zen_engine/handler/expression/
mod.rs

1use 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}