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