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;
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 =
102 moduforge_rules_expression::functions::StateGuard::new(state);
103
104 let result = self.evaluate(context).await;
106 result
107 }
108
109 pub async fn evaluate_with_opts(
111 &self,
112 context: Variable,
113 options: EvaluationOptions,
114 ) -> Result<DecisionGraphResponse, Box<EvaluationError>> {
115 let mut decision_graph = DecisionGraph::try_new(DecisionGraphConfig {
116 content: self.content.clone(),
117 max_depth: options.max_depth.unwrap_or(5),
118 trace: options.trace.unwrap_or_default(),
119 loader: Arc::new(CachedLoader::from(self.loader.clone())),
120 adapter: self.adapter.clone(),
121 iteration: 0,
122 validator_cache: Some(self.validator_cache.clone()),
123 })?;
124
125 let response = decision_graph.evaluate(context).await?;
126
127 Ok(response)
128 }
129
130 pub fn validate(&self) -> Result<(), DecisionGraphValidationError> {
131 let decision_graph = DecisionGraph::try_new(DecisionGraphConfig {
132 content: self.content.clone(),
133 max_depth: 1,
134 trace: false,
135 loader: Arc::new(CachedLoader::from(self.loader.clone())),
136 adapter: self.adapter.clone(),
137 iteration: 0,
138 validator_cache: Some(self.validator_cache.clone()),
139 })?;
140
141 decision_graph.validate()
142 }
143}