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