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;
12
13/// Represents a JDM decision which can be evaluated
14#[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    /// Evaluates a decision using an in-memory reference stored in struct
87    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    /// 使用 State 评估决策 - 通过 thread_local 设置 State
95    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        // 使用 StateGuard 自动管理 State 生命周期
101        let _guard =
102            moduforge_rules_expression::functions::StateGuard::new(state);
103
104        // 执行评估
105        let result = self.evaluate(context).await;
106        result
107    }
108
109    /// Evaluates a decision using in-memory reference with advanced options
110    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}