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