Skip to main content

sz_rust_orm_facade/data_scope/
ext.rs

1//! DataScopeExt — 查询构建器扩展 trait
2//!
3//! 为 sz-orm 查询构建器提供 `data_scope()` 链式方法,
4//! 自动注入数据范围 WHERE 条件。
5
6use crate::data_scope::context::DataScopeContext;
7use crate::data_scope::error::DataScopeError;
8use crate::data_scope::evaluator::DataScopeEvaluator;
9use crate::data_scope::rule::DataScopeRule;
10use crate::repository::WhereCondition;
11
12/// 数据范围扩展 trait
13///
14/// 为查询构建器实现此 trait 后,可链式调用 `.data_scope_async(ctx, rule, evaluator)`
15/// 自动注入数据范围 WHERE 条件。
16#[async_trait::async_trait]
17pub trait DataScopeExt: Sized {
18    /// 同步设置数据范围(需预先评估好的条件)
19    fn with_data_scope_conditions(self, conditions: &[WhereCondition]) -> Self;
20
21    /// 异步评估并注入数据范围
22    ///
23    /// 调用 `evaluator.evaluate(ctx, rule)` 获取条件列表,
24    /// 逐个追加到查询构建器。
25    async fn data_scope_async(
26        self,
27        ctx: &DataScopeContext,
28        rule: &DataScopeRule,
29        evaluator: &dyn DataScopeEvaluator,
30    ) -> Result<Self, DataScopeError> {
31        let conditions = evaluator.evaluate(ctx, rule).await?;
32        Ok(self.with_data_scope_conditions(&conditions))
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39    use crate::data_scope::cache::{DeptTreeCache, DeptTreeProvider};
40    use crate::data_scope::custom::CustomGeneratorRegistry;
41    use crate::data_scope::evaluator::DefaultDataScopeEvaluator;
42    use crate::data_scope::metrics::DataScopeMetrics;
43    use crate::data_scope::rule::DataScopeMode;
44    use crate::repository::WhereCondition;
45    use async_trait::async_trait;
46    use std::sync::Arc;
47
48    struct MockQueryBuilder {
49        conditions: Vec<WhereCondition>,
50    }
51
52    #[async_trait]
53    impl DataScopeExt for MockQueryBuilder {
54        fn with_data_scope_conditions(mut self, conditions: &[WhereCondition]) -> Self {
55            self.conditions = conditions.to_vec();
56            self
57        }
58    }
59
60    struct MockDeptProvider;
61
62    #[async_trait]
63    impl DeptTreeProvider for MockDeptProvider {
64        async fn sub_depts(&self, _dept_id: i64) -> Result<Vec<i64>, DataScopeError> {
65            Ok(vec![])
66        }
67    }
68
69    fn make_evaluator() -> DefaultDataScopeEvaluator {
70        DefaultDataScopeEvaluator::new(
71            Arc::new(DeptTreeCache::new(
72                Arc::new(MockDeptProvider),
73                std::time::Duration::from_secs(300),
74            )),
75            Arc::new(CustomGeneratorRegistry::new()),
76            Arc::new(DataScopeMetrics::new()),
77        )
78    }
79
80    #[tokio::test]
81    async fn test_data_scope_async_injects_conditions() {
82        let evaluator = make_evaluator();
83        let ctx = DataScopeContext::new(1, 5, false);
84        let rule = DataScopeRule::new("order", DataScopeMode::Dept).with_dept_field("dept_id");
85        let builder = MockQueryBuilder { conditions: vec![] };
86        let result = builder
87            .data_scope_async(&ctx, &rule, &evaluator)
88            .await
89            .unwrap();
90        assert_eq!(result.conditions.len(), 1);
91    }
92
93    #[tokio::test]
94    async fn test_data_scope_async_super_bypass_empty() {
95        let evaluator = make_evaluator();
96        let ctx = DataScopeContext::new(1, 5, true);
97        let rule = DataScopeRule::new("order", DataScopeMode::Dept).with_dept_field("dept_id");
98        let builder = MockQueryBuilder { conditions: vec![] };
99        let result = builder
100            .data_scope_async(&ctx, &rule, &evaluator)
101            .await
102            .unwrap();
103        assert!(result.conditions.is_empty());
104    }
105
106    #[tokio::test]
107    async fn test_data_scope_async_dept_and_sub() {
108        let evaluator = make_evaluator();
109        let ctx = DataScopeContext::new(1, 5, false);
110        let rule =
111            DataScopeRule::new("order", DataScopeMode::DeptAndSub).with_dept_field("dept_id");
112        let builder = MockQueryBuilder { conditions: vec![] };
113        let result = builder
114            .data_scope_async(&ctx, &rule, &evaluator)
115            .await
116            .unwrap();
117        assert_eq!(result.conditions.len(), 1);
118    }
119}