zen_engine/handler/expression/
mod.rs

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
use crate::handler::node::{NodeRequest, NodeResponse, NodeResult, PartialTraceError};
use crate::model::{DecisionNodeKind, ExpressionNodeContent};
use ahash::{HashMap, HashMapExt};
use std::sync::Arc;

use anyhow::{anyhow, Context};
use serde::Serialize;
use tokio::sync::Mutex;
use zen_expression::variable::Variable;
use zen_expression::Isolate;

pub struct ExpressionHandler {
    trace: bool,
}

#[derive(Debug, Serialize)]
struct ExpressionTrace {
    result: String,
}

impl ExpressionHandler {
    pub fn new(trace: bool) -> Self {
        Self { trace }
    }

    pub async fn handle(&mut self, request: NodeRequest) -> NodeResult {
        let content = match &request.node.kind {
            DecisionNodeKind::ExpressionNode { content } => Ok(content),
            _ => Err(anyhow!("Unexpected node type")),
        }?;

        let inner_handler_mutex = Arc::new(Mutex::new(ExpressionHandlerInner::new(self.trace)));

        content
            .transform_attributes
            .run_with(request.input, |input| {
                let inner_handler_mutex = inner_handler_mutex.clone();

                async move {
                    let mut inner_handler_ref = inner_handler_mutex.lock().await;
                    inner_handler_ref.handle(input, content).await
                }
            })
            .await
    }
}

struct ExpressionHandlerInner<'a> {
    isolate: Isolate<'a>,
    trace: bool,
}

impl<'a> ExpressionHandlerInner<'a> {
    pub fn new(trace: bool) -> Self {
        Self {
            isolate: Isolate::new(),
            trace,
        }
    }

    async fn handle(&mut self, input: Variable, content: &'a ExpressionNodeContent) -> NodeResult {
        let result = Variable::empty_object();
        let mut trace_map = self.trace.then(|| HashMap::<&str, ExpressionTrace>::new());

        self.isolate.set_environment(input.depth_clone(1));
        for expression in &content.expressions {
            if expression.key.is_empty() || expression.value.is_empty() {
                continue;
            }

            let value = self
                .isolate
                .run_standard(&expression.value)
                .with_context(|| PartialTraceError {
                    trace: trace_map
                        .as_ref()
                        .map(|s| serde_json::to_value(s).ok())
                        .flatten(),
                    message: format!(r#"Failed to evaluate expression: "{}""#, &expression.value),
                })?;
            if let Some(tmap) = &mut trace_map {
                tmap.insert(
                    &expression.key,
                    ExpressionTrace {
                        result: serde_json::to_string(&value).unwrap_or("Error".to_owned()),
                    },
                );
            }

            self.isolate.update_environment(|env| {
                let Some(environment) = env else {
                    return;
                };

                let key = format!("$.{}", &expression.key);
                let _ = environment.dot_insert(key.as_str(), value.clone());
            });

            result.dot_insert(&expression.key, value);
        }

        Ok(NodeResponse {
            output: result,
            trace_data: trace_map.map(|tm| serde_json::to_value(tm).ok()).flatten(),
        })
    }
}