moduforge_rules_engine/
decision.rs

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 moduforge_rules_expression::variable::Variable;
12use moduforge_rules_expression::CustomFunctionRegistry;
13
14/// Represents a JDM decision which can be evaluated
15#[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    /// Evaluates a decision using an in-memory reference stored in struct
88    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    /// 使用 State 评估决策 - 通过 thread_local 设置 State
96    pub async fn evaluate_with_state(
97        &self,
98        context: Variable,
99        state: Arc<moduforge_state::State>,
100    ) -> Result<DecisionGraphResponse, Box<EvaluationError>> {
101        // 设置 thread_local State
102        CustomFunctionRegistry::set_current_state(Some(state));
103
104        // 执行评估
105        let result = self.evaluate(context).await;
106
107        // 清理 thread_local State
108        CustomFunctionRegistry::set_current_state(None);
109
110        result
111    }
112
113    /// Evaluates a decision using in-memory reference with advanced options
114    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}