1use crate::engine::EvaluationOptions;
2use crate::handler::custom_node_adapter::{CustomNodeAdapter, NoopCustomNode};
3use crate::handler::graph::{DecisionGraph, DecisionGraphConfig, DecisionGraphResponse};
4use crate::loader::{CachedLoader, DecisionLoader, NoopLoader};
5use crate::model::DecisionContent;
6use crate::util::validator_cache::ValidatorCache;
7use crate::{DecisionGraphValidationError, EvaluationError};
8use std::sync::Arc;
9use zen_expression::variable::Variable;
10
11#[derive(Debug, Clone)]
13pub struct Decision<Loader, CustomNode>
14where
15 Loader: DecisionLoader + 'static,
16 CustomNode: CustomNodeAdapter + 'static,
17{
18 content: Arc<DecisionContent>,
19 loader: Arc<Loader>,
20 adapter: Arc<CustomNode>,
21
22 validator_cache: ValidatorCache,
23}
24
25impl From<DecisionContent> for Decision<NoopLoader, NoopCustomNode> {
26 fn from(value: DecisionContent) -> Self {
27 Self {
28 content: value.into(),
29 loader: NoopLoader::default().into(),
30 adapter: NoopCustomNode::default().into(),
31
32 validator_cache: Default::default(),
33 }
34 }
35}
36
37impl From<Arc<DecisionContent>> for Decision<NoopLoader, NoopCustomNode> {
38 fn from(value: Arc<DecisionContent>) -> Self {
39 Self {
40 content: value,
41 loader: NoopLoader::default().into(),
42 adapter: NoopCustomNode::default().into(),
43
44 validator_cache: Default::default(),
45 }
46 }
47}
48
49impl<L, A> Decision<L, A>
50where
51 L: DecisionLoader + 'static,
52 A: CustomNodeAdapter + 'static,
53{
54 pub fn with_loader<Loader>(self, loader: Arc<Loader>) -> Decision<Loader, A>
55 where
56 Loader: DecisionLoader,
57 {
58 Decision {
59 loader,
60 adapter: self.adapter,
61 content: self.content,
62 validator_cache: self.validator_cache,
63 }
64 }
65
66 pub fn with_adapter<Adapter>(self, adapter: Arc<Adapter>) -> Decision<L, Adapter>
67 where
68 Adapter: CustomNodeAdapter,
69 {
70 Decision {
71 loader: self.loader,
72 adapter,
73 content: self.content,
74 validator_cache: self.validator_cache,
75 }
76 }
77
78 pub async fn evaluate(
80 &self,
81 context: Variable,
82 ) -> Result<DecisionGraphResponse, Box<EvaluationError>> {
83 self.evaluate_with_opts(context, Default::default()).await
84 }
85
86 pub async fn evaluate_with_opts(
88 &self,
89 context: Variable,
90 options: EvaluationOptions,
91 ) -> Result<DecisionGraphResponse, Box<EvaluationError>> {
92 let mut decision_graph = DecisionGraph::try_new(DecisionGraphConfig {
93 content: self.content.clone(),
94 max_depth: options.max_depth.unwrap_or(5),
95 trace: options.trace.unwrap_or_default(),
96 loader: Arc::new(CachedLoader::from(self.loader.clone())),
97 adapter: self.adapter.clone(),
98 iteration: 0,
99 validator_cache: Some(self.validator_cache.clone()),
100 })?;
101
102 let response = decision_graph.evaluate(context).await?;
103
104 Ok(response)
105 }
106
107 pub fn validate(&self) -> Result<(), DecisionGraphValidationError> {
108 let decision_graph = DecisionGraph::try_new(DecisionGraphConfig {
109 content: self.content.clone(),
110 max_depth: 1,
111 trace: false,
112 loader: Arc::new(CachedLoader::from(self.loader.clone())),
113 adapter: self.adapter.clone(),
114 iteration: 0,
115 validator_cache: Some(self.validator_cache.clone()),
116 })?;
117
118 decision_graph.validate()
119 }
120}