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