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#[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 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 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}