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                validator_cache: Arc::new(OnceCell::from(self.validator_cache.clone())),
89                ..Default::default()
90            },
91        })?;
92
93        let response = decision_graph.evaluate(context).await?;
94
95        Ok(response)
96    }
97
98    pub async fn evaluate_serialized(
99        &self,
100        context: Variable,
101        options: EvaluationSerializedOptions,
102    ) -> Result<Value, Value> {
103        let response = self
104            .evaluate_with_opts(
105                context,
106                EvaluationOptions {
107                    trace: options.trace != EvaluationTraceKind::None,
108                    max_depth: options.max_depth,
109                },
110            )
111            .await;
112
113        match response {
114            Ok(ok) => Ok(ok
115                .serialize_with_mode(serde_json::value::Serializer, options.trace)
116                .unwrap_or_default()),
117            Err(err) => Err(err
118                .serialize_with_mode(serde_json::value::Serializer, options.trace)
119                .unwrap_or_default()),
120        }
121    }
122
123    pub fn validate(&self) -> Result<(), DecisionGraphValidationError> {
124        let decision_graph = DecisionGraph::try_new(DecisionGraphConfig {
125            content: self.content.clone(),
126            max_depth: 1,
127            trace: false,
128            iteration: 0,
129            extensions: Default::default(),
130        })?;
131
132        decision_graph.validate()
133    }
134}