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::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<GraphContent>,
19    loader: DynamicLoader,
20    adapter: DynamicCustomNode,
21    http_handler: DynamicHttpHandler,
22    validator_cache: ValidatorCache,
23}
24
25impl From<GraphContent> for Decision {
26    fn from(value: GraphContent) -> 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<GraphContent>> for Decision {
38    fn from(value: Arc<GraphContent>) -> 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                stripped_functions: self.content.stripped_functions.clone(),
90                validator_cache: Arc::new(OnceCell::from(self.validator_cache.clone())),
91                ..Default::default()
92            },
93        })?;
94
95        let response = decision_graph.evaluate(context).await?;
96
97        Ok(response)
98    }
99
100    pub async fn evaluate_serialized(
101        &self,
102        context: Variable,
103        options: EvaluationSerializedOptions,
104    ) -> Result<Value, Value> {
105        let response = self
106            .evaluate_with_opts(
107                context,
108                EvaluationOptions {
109                    trace: options.trace != EvaluationTraceKind::None,
110                    max_depth: options.max_depth,
111                },
112            )
113            .await;
114
115        match response {
116            Ok(ok) => Ok(ok
117                .serialize_with_mode(serde_json::value::Serializer, options.trace)
118                .unwrap_or_default()),
119            Err(err) => Err(err
120                .serialize_with_mode(serde_json::value::Serializer, options.trace)
121                .unwrap_or_default()),
122        }
123    }
124
125    pub fn validate(&self) -> Result<(), DecisionGraphValidationError> {
126        let decision_graph = DecisionGraph::try_new(DecisionGraphConfig {
127            content: self.content.clone(),
128            max_depth: 1,
129            trace: false,
130            iteration: 0,
131            extensions: Default::default(),
132        })?;
133
134        decision_graph.validate()
135    }
136
137    pub fn compile(&mut self) -> () {
138        let cm = Arc::make_mut(&mut self.content);
139        cm.compile();
140    }
141}