Skip to main content

zen_engine/
decision.rs

1use crate::decision_graph::graph::{DecisionGraph, DecisionGraphConfig, DecisionGraphResponse};
2use crate::engine::{EvaluationOptions, EvaluationSerializedOptions, EvaluationTraceKind};
3use crate::loader::{DynamicLoader, NoopLoader};
4use crate::model::GraphContent;
5use crate::nodes::custom::{DynamicCustomNode, NoopCustomNode};
6use crate::nodes::function::http_handler::DynamicHttpHandler;
7use crate::nodes::NodeHandlerExtensions;
8use crate::{DecisionGraphValidationError, EvaluationError};
9use serde_json::Value;
10use std::cell::OnceCell;
11use std::sync::Arc;
12use zen_expression::variable::Variable;
13
14/// Represents a JDM decision which can be evaluated
15#[derive(Debug, Clone)]
16pub struct Decision {
17    content: Arc<GraphContent>,
18    loader: DynamicLoader,
19    adapter: DynamicCustomNode,
20    http_handler: DynamicHttpHandler,
21}
22
23impl From<GraphContent> for Decision {
24    fn from(value: GraphContent) -> Self {
25        Self {
26            content: value.into(),
27            loader: Arc::new(NoopLoader::default()),
28            adapter: Arc::new(NoopCustomNode::default()),
29            http_handler: None,
30        }
31    }
32}
33
34impl From<Arc<GraphContent>> for Decision {
35    fn from(value: Arc<GraphContent>) -> Self {
36        Self {
37            content: value,
38            loader: Arc::new(NoopLoader::default()),
39            adapter: Arc::new(NoopCustomNode::default()),
40            http_handler: None,
41        }
42    }
43}
44
45impl Decision {
46    pub fn with_loader(mut self, loader: DynamicLoader) -> Self {
47        self.loader = loader;
48        self
49    }
50
51    pub fn with_adapter(mut self, adapter: DynamicCustomNode) -> Self {
52        self.adapter = adapter;
53        self
54    }
55
56    pub fn with_http_handler(mut self, http_handler: DynamicHttpHandler) -> Self {
57        self.http_handler = http_handler;
58        self
59    }
60
61    /// Evaluates a decision using an in-memory reference stored in struct
62    pub async fn evaluate(
63        &self,
64        context: Variable,
65    ) -> Result<DecisionGraphResponse, Box<EvaluationError>> {
66        self.evaluate_with_opts(context, Default::default()).await
67    }
68
69    /// Evaluates a decision using in-memory reference with advanced options
70    pub async fn evaluate_with_opts(
71        &self,
72        context: Variable,
73        options: EvaluationOptions,
74    ) -> Result<DecisionGraphResponse, Box<EvaluationError>> {
75        let mut decision_graph = DecisionGraph::try_new(DecisionGraphConfig {
76            content: self.content.clone(),
77            max_depth: options.max_depth,
78            trace: options.trace,
79            iteration: 0,
80            extensions: NodeHandlerExtensions {
81                loader: self.loader.clone(),
82                custom_node: self.adapter.clone(),
83                http_handler: self.http_handler.clone(),
84                compiled_cache: self.content.compiled_cache.clone(),
85                dt_indexes: self.content.dt_indexes.clone(),
86                stripped_functions: self.content.stripped_functions.clone(),
87                validator_cache: Arc::new(OnceCell::from(self.content.validator_cache.clone())),
88                ..Default::default()
89            },
90        })?;
91
92        let response = decision_graph.evaluate(context).await?;
93
94        Ok(response)
95    }
96
97    pub async fn evaluate_serialized(
98        &self,
99        context: Variable,
100        options: EvaluationSerializedOptions,
101    ) -> Result<Value, Value> {
102        let response = self
103            .evaluate_with_opts(
104                context,
105                EvaluationOptions {
106                    trace: options.trace != EvaluationTraceKind::None,
107                    max_depth: options.max_depth,
108                },
109            )
110            .await;
111
112        match response {
113            Ok(ok) => Ok(ok
114                .serialize_with_mode(serde_json::value::Serializer, options.trace)
115                .unwrap_or_default()),
116            Err(err) => Err(err
117                .serialize_with_mode(serde_json::value::Serializer, options.trace)
118                .unwrap_or_default()),
119        }
120    }
121
122    pub fn validate(&self) -> Result<(), DecisionGraphValidationError> {
123        let decision_graph = DecisionGraph::try_new(DecisionGraphConfig {
124            content: self.content.clone(),
125            max_depth: 1,
126            trace: false,
127            iteration: 0,
128            extensions: Default::default(),
129        })?;
130
131        decision_graph.validate()
132    }
133
134    pub fn compile(&mut self) -> () {
135        let cm = Arc::make_mut(&mut self.content);
136        cm.compile();
137    }
138}