sz_rust_orm_facade/data_scope/
evaluator.rs1use crate::data_scope::cache::DeptTreeCache;
7use crate::data_scope::context::DataScopeContext;
8use crate::data_scope::custom::CustomGeneratorRegistry;
9use crate::data_scope::error::DataScopeError;
10use crate::data_scope::metrics::DataScopeMetrics;
11use crate::data_scope::modes::all::AllMode;
12use crate::data_scope::modes::dept::DeptMode;
13use crate::data_scope::modes::self_mode::SelfMode;
14use crate::data_scope::modes::ModeEvaluator;
15use crate::data_scope::rule::{DataScopeMode, DataScopeRule};
16use crate::repository::WhereCondition;
17use async_trait::async_trait;
18use std::sync::Arc;
19use std::time::Instant;
20
21#[async_trait]
23pub trait DataScopeEvaluator: Send + Sync {
24 async fn evaluate(
26 &self,
27 ctx: &DataScopeContext,
28 rule: &DataScopeRule,
29 ) -> Result<Vec<WhereCondition>, DataScopeError>;
30}
31
32pub struct DefaultDataScopeEvaluator {
34 dept_cache: Arc<DeptTreeCache>,
35 custom_registry: Arc<CustomGeneratorRegistry>,
36 metrics: Arc<DataScopeMetrics>,
37}
38
39impl DefaultDataScopeEvaluator {
40 pub fn new(
42 dept_cache: Arc<DeptTreeCache>,
43 custom_registry: Arc<CustomGeneratorRegistry>,
44 metrics: Arc<DataScopeMetrics>,
45 ) -> Self {
46 Self {
47 dept_cache,
48 custom_registry,
49 metrics,
50 }
51 }
52}
53
54#[async_trait]
55impl DataScopeEvaluator for DefaultDataScopeEvaluator {
56 async fn evaluate(
57 &self,
58 ctx: &DataScopeContext,
59 rule: &DataScopeRule,
60 ) -> Result<Vec<WhereCondition>, DataScopeError> {
61 let start = Instant::now();
62
63 if ctx.is_super {
64 self.metrics.record_bypass(ctx.user_id, &rule.target_table);
65 return Ok(Vec::new());
66 }
67
68 let result = match rule.mode {
69 DataScopeMode::All => AllMode.evaluate(ctx, rule).await,
70 DataScopeMode::Dept => DeptMode.evaluate(ctx, rule).await,
71 DataScopeMode::DeptAndSub => {
72 let mode = crate::data_scope::modes::dept_and_sub::DeptAndSubMode::new(
73 self.dept_cache.clone(),
74 );
75 mode.evaluate(ctx, rule).await
76 }
77 DataScopeMode::Self_ => SelfMode.evaluate(ctx, rule).await,
78 DataScopeMode::Custom => {
79 let mode =
80 crate::data_scope::modes::custom::CustomMode::new(self.custom_registry.clone());
81 mode.evaluate(ctx, rule).await
82 }
83 };
84
85 let elapsed_ms = start.elapsed().as_millis() as u64;
86 self.metrics.record_eval(elapsed_ms);
87
88 match result {
89 Ok(conditions) => {
90 self.metrics
91 .record_hit(&rule.target_table, rule.mode.as_str());
92 Ok(conditions)
93 }
94 Err(ref e) => {
95 self.metrics
96 .record_reject(e.error_code(), &rule.target_table);
97 Err(e.clone())
98 }
99 }
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use crate::data_scope::cache::{DeptTreeCache, DeptTreeProvider};
107
108 struct MockDeptProvider;
109
110 #[async_trait]
111 impl DeptTreeProvider for MockDeptProvider {
112 async fn sub_depts(&self, _dept_id: i64) -> Result<Vec<i64>, DataScopeError> {
113 Ok(vec![])
114 }
115 }
116
117 fn make_evaluator() -> DefaultDataScopeEvaluator {
118 DefaultDataScopeEvaluator::new(
119 Arc::new(DeptTreeCache::new(
120 Arc::new(MockDeptProvider),
121 std::time::Duration::from_secs(300),
122 )),
123 Arc::new(CustomGeneratorRegistry::new()),
124 Arc::new(DataScopeMetrics::new()),
125 )
126 }
127
128 #[tokio::test]
129 async fn test_evaluator_all_mode() {
130 let evaluator = make_evaluator();
131 let ctx = DataScopeContext::new(1, 5, false);
132 let rule = DataScopeRule::new("order", DataScopeMode::All);
133 let conditions = evaluator.evaluate(&ctx, &rule).await.unwrap();
134 assert!(conditions.is_empty());
135 }
136
137 #[tokio::test]
138 async fn test_evaluator_dept_mode() {
139 let evaluator = make_evaluator();
140 let ctx = DataScopeContext::new(1, 5, false);
141 let rule = DataScopeRule::new("order", DataScopeMode::Dept).with_dept_field("dept_id");
142 let conditions = evaluator.evaluate(&ctx, &rule).await.unwrap();
143 assert_eq!(conditions.len(), 1);
144 }
145
146 #[tokio::test]
147 async fn test_evaluator_self_mode() {
148 let evaluator = make_evaluator();
149 let ctx = DataScopeContext::new(10, 5, false);
150 let rule =
151 DataScopeRule::new("order", DataScopeMode::Self_).with_creator_field("creator_id");
152 let conditions = evaluator.evaluate(&ctx, &rule).await.unwrap();
153 assert_eq!(conditions.len(), 1);
154 }
155
156 #[tokio::test]
157 async fn test_evaluator_super_bypass() {
158 let evaluator = make_evaluator();
159
160 let ctx = DataScopeContext::new(1, 5, true);
161 let rule = DataScopeRule::new("order", DataScopeMode::Dept).with_dept_field("dept_id");
162 let conditions = evaluator.evaluate(&ctx, &rule).await.unwrap();
163 assert!(conditions.is_empty());
164 }
165
166 #[tokio::test]
167 async fn test_evaluator_error_propagation() {
168 let evaluator = make_evaluator();
169 let ctx = DataScopeContext::new(1, 5, false);
170 let rule = DataScopeRule::new("order", DataScopeMode::Dept);
171 let result = evaluator.evaluate(&ctx, &rule).await;
172 assert!(result.is_err());
173 assert_eq!(result.unwrap_err().error_code(), "DATA_SCOPE_INVALID_RULE");
174 }
175
176 #[tokio::test]
177 async fn test_evaluator_dept_and_sub_mode() {
178 let evaluator = make_evaluator();
179 let ctx = DataScopeContext::new(1, 5, false);
180 let rule =
181 DataScopeRule::new("order", DataScopeMode::DeptAndSub).with_dept_field("dept_id");
182 let conditions = evaluator.evaluate(&ctx, &rule).await.unwrap();
183 assert_eq!(conditions.len(), 1);
184 }
185}