moduforge_rules_engine/
decision.rs1use 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 moduforge_rules_expression::variable::Variable;
12use moduforge_rules_expression::CustomFunctionRegistry;
13
14#[derive(Debug, Clone)]
16pub struct Decision<Loader, CustomNode>
17where
18 Loader: DecisionLoader + 'static,
19 CustomNode: CustomNodeAdapter + 'static,
20{
21 content: Arc<DecisionContent>,
22 loader: Arc<Loader>,
23 adapter: Arc<CustomNode>,
24
25 validator_cache: ValidatorCache,
26}
27
28impl From<DecisionContent> for Decision<NoopLoader, NoopCustomNode> {
29 fn from(value: DecisionContent) -> Self {
30 Self {
31 content: value.into(),
32 loader: NoopLoader::default().into(),
33 adapter: NoopCustomNode::default().into(),
34
35 validator_cache: Default::default(),
36 }
37 }
38}
39
40impl From<Arc<DecisionContent>> for Decision<NoopLoader, NoopCustomNode> {
41 fn from(value: Arc<DecisionContent>) -> Self {
42 Self {
43 content: value,
44 loader: NoopLoader::default().into(),
45 adapter: NoopCustomNode::default().into(),
46
47 validator_cache: Default::default(),
48 }
49 }
50}
51
52impl<L, A> Decision<L, A>
53where
54 L: DecisionLoader + 'static,
55 A: CustomNodeAdapter + 'static,
56{
57 pub fn with_loader<Loader>(
58 self,
59 loader: Arc<Loader>,
60 ) -> Decision<Loader, A>
61 where
62 Loader: DecisionLoader,
63 {
64 Decision {
65 loader,
66 adapter: self.adapter,
67 content: self.content,
68 validator_cache: self.validator_cache,
69 }
70 }
71
72 pub fn with_adapter<Adapter>(
73 self,
74 adapter: Arc<Adapter>,
75 ) -> Decision<L, Adapter>
76 where
77 Adapter: CustomNodeAdapter,
78 {
79 Decision {
80 loader: self.loader,
81 adapter,
82 content: self.content,
83 validator_cache: self.validator_cache,
84 }
85 }
86
87 pub async fn evaluate(
89 &self,
90 context: Variable,
91 ) -> Result<DecisionGraphResponse, Box<EvaluationError>> {
92 self.evaluate_with_opts(context, Default::default()).await
93 }
94
95 pub async fn evaluate_with_state(
97 &self,
98 context: Variable,
99 state: Arc<moduforge_state::State>,
100 ) -> Result<DecisionGraphResponse, Box<EvaluationError>> {
101 CustomFunctionRegistry::set_current_state(Some(state));
103
104 let result = self.evaluate(context).await;
106
107 CustomFunctionRegistry::set_current_state(None);
109
110 result
111 }
112
113 pub async fn evaluate_with_opts(
115 &self,
116 context: Variable,
117 options: EvaluationOptions,
118 ) -> Result<DecisionGraphResponse, Box<EvaluationError>> {
119 let mut decision_graph = DecisionGraph::try_new(DecisionGraphConfig {
120 content: self.content.clone(),
121 max_depth: options.max_depth.unwrap_or(5),
122 trace: options.trace.unwrap_or_default(),
123 loader: Arc::new(CachedLoader::from(self.loader.clone())),
124 adapter: self.adapter.clone(),
125 iteration: 0,
126 validator_cache: Some(self.validator_cache.clone()),
127 })?;
128
129 let response = decision_graph.evaluate(context).await?;
130
131 Ok(response)
132 }
133
134 pub fn validate(&self) -> Result<(), DecisionGraphValidationError> {
135 let decision_graph = DecisionGraph::try_new(DecisionGraphConfig {
136 content: self.content.clone(),
137 max_depth: 1,
138 trace: false,
139 loader: Arc::new(CachedLoader::from(self.loader.clone())),
140 adapter: self.adapter.clone(),
141 iteration: 0,
142 validator_cache: Some(self.validator_cache.clone()),
143 })?;
144
145 decision_graph.validate()
146 }
147}