moduforge_rules_engine/lib.rs
1//! # moduforge-rules-engine
2//!
3//! moduforge-rules-engine 是一个对业务友好的开源业务规则引擎(BRE),用于根据 GoRules JSON 决策模型(JDM)标准执行决策模型。
4//!
5//! # 使用方法
6//!
7//! 要使用 Noop(默认)加载器执行简单决策,您可以使用以下代码:
8//!
9//! ```rust
10//! use serde_json::json;
11//! use moduforge_rules_engine::DecisionEngine;
12//! use moduforge_rules_engine::model::DecisionContent;
13//!
14//! async fn evaluate() {
15//! let decision_content: DecisionContent = serde_json::from_str(include_str!("jdm_graph.json")).unwrap();
16//! let engine = DecisionEngine::default();
17//! let decision = engine.create_decision(decision_content.into());
18//!
19//! let result = decision.evaluate(&json!({ "input": 12 })).await;
20//! }
21//! ```
22//!
23//! 另外,您也可以使用 `Decision::from` 函数间接创建决策,而无需构建引擎。
24//!
25//! # 加载器
26//!
27//! 对于更高级的用例,当您需要加载多个决策并使用图时,您可以使用以下预制的加载器之一:
28//! - FilesystemLoader - 使用给定路径作为根目录,尝试基于相对路径加载决策
29//! - MemoryLoader - 作为 HashMap(键值存储)工作
30//! - ClosureLoader - 允许定义简单的异步回调函数,该函数接收键作为参数并返回 `Arc<DecisionContent>` 实例
31//! - NoopLoader - (默认)无法加载决策,允许使用 create_decision(主要用于跨语言统一 API)
32//!
33//! ## 文件系统加载器
34//!
35//! 假设您有一个位于 /app/decisions 下的决策模型文件夹(.json 文件),您可以按以下方式使用 FilesystemLoader:
36//!
37//! ```rust
38//! use serde_json::json;
39//! use moduforge_rules_engine::DecisionEngine;
40//! use moduforge_rules_engine::loader::{FilesystemLoader, FilesystemLoaderOptions};
41//!
42//! async fn evaluate() {
43//! let engine = DecisionEngine::new(FilesystemLoader::new(FilesystemLoaderOptions {
44//! keep_in_memory: true, // 可选,保持在内存中以提高性能
45//! root: "/app/decisions"
46//! }));
47//!
48//! let context = json!({ "customer": { "joinedAt": "2022-01-01" } });
49//! // 如果您计划多次使用它,可以缓存 JDM 以获得轻微的性能提升
50//! // 在绑定(其他语言)的情况下,这种提升会更大
51//! {
52//! let promotion_decision = engine.get_decision("commercial/promotion.json").await.unwrap();
53//! let result = promotion_decision.evaluate(&context).await.unwrap();
54//! }
55//!
56//! // 或者按需加载
57//! {
58//! let result = engine.evaluate("commercial/promotion.json", &context).await.unwrap();
59//! }
60//! }
61//!
62//!
63//! ```
64//!
65//! ## 自定义加载器
66//! 您可以通过实现 `DecisionLoader` trait 为 zen 引擎创建自定义加载器。
67//! 以下是 MemoryLoader 的实现示例:
68//! ```rust
69//! use std::collections::HashMap;
70//! use std::sync::{Arc, RwLock};
71//! use zen_engine::loader::{DecisionLoader, LoaderError, LoaderResponse};
72//! use zen_engine::model::DecisionContent;
73//!
74//! #[derive(Debug, Default)]
75//! pub struct MemoryLoader {
76//! memory_refs: RwLock<HashMap<String, Arc<DecisionContent>>>,
77//! }
78//!
79//! impl MemoryLoader {
80//! pub fn add<K, D>(&self, key: K, content: D)
81//! where
82//! K: Into<String>,
83//! D: Into<DecisionContent>,
84//! {
85//! let mut mref = self.memory_refs.write().unwrap();
86//! mref.insert(key.into(), Arc::new(content.into()));
87//! }
88//!
89//! pub fn get<K>(&self, key: K) -> Option<Arc<DecisionContent>>
90//! where
91//! K: AsRef<str>,
92//! {
93//! let mref = self.memory_refs.read().unwrap();
94//! mref.get(key.as_ref()).map(|r| r.clone())
95//! }
96//!
97//! pub fn remove<K>(&self, key: K) -> bool
98//! where
99//! K: AsRef<str>,
100//! {
101//! let mut mref = self.memory_refs.write().unwrap();
102//! mref.remove(key.as_ref()).is_some()
103//! }
104//! }
105//!
106//! impl DecisionLoader for MemoryLoader {
107//! fn load<'a>(&'a self, key: &'a str) -> impl Future<Output = LoaderResponse> + 'a {
108//! async move {
109//! self.get(&key)
110//! .ok_or_else(|| LoaderError::NotFound(key.to_string()).into())
111//! }
112//! }
113//! ```
114
115#![deny(clippy::unwrap_used)]
116#![allow(clippy::module_inception)]
117
118pub mod config;
119pub mod decision;
120pub mod engine;
121pub mod error;
122pub mod handler;
123pub mod loader;
124#[path = "model/mod.rs"]
125pub mod model;
126pub mod util;
127
128pub use config::ZEN_CONFIG;
129pub use decision::Decision;
130pub use engine::{DecisionEngine, EvaluationOptions};
131pub use error::EvaluationError;
132pub use handler::graph::DecisionGraphResponse;
133pub use handler::graph::DecisionGraphTrace;
134pub use handler::graph::DecisionGraphValidationError;
135pub use handler::node::NodeError;
136pub use moduforge_rules_expression::Variable;