sz_rust_core/plugin/
cross_query.rs1use serde_json::Value;
7
8#[derive(Debug, thiserror::Error)]
10pub enum CrossQueryError {
11 #[error("权限不足:租户 {tenant_id} 无权查询")]
12 PermissionDenied { tenant_id: i64 },
13 #[error("能力未找到: {0}")]
14 NotFound(String),
15 #[error("查询失败: {0}")]
16 QueryFailed(String),
17}
18
19pub struct CrossQuery {
24 tenant_id: i64,
25}
26
27impl CrossQuery {
28 pub fn new(tenant_id: i64) -> Self {
30 Self { tenant_id }
31 }
32
33 pub fn tenant_id(&self) -> i64 {
35 self.tenant_id
36 }
37
38 pub fn inject_tenant_filter(&self, mut args: Value) -> Value {
42 if let Some(obj) = args.as_object_mut() {
43 obj.insert("tenant_id".to_string(), Value::from(self.tenant_id));
44 } else if args.is_null() {
45 args = serde_json::json!({ "tenant_id": self.tenant_id });
46 }
47 args
48 }
49
50 pub fn verify_tenant(&self, target_tenant_id: i64) -> Result<(), CrossQueryError> {
54 if self.tenant_id != target_tenant_id {
55 return Err(CrossQueryError::PermissionDenied {
56 tenant_id: self.tenant_id,
57 });
58 }
59 Ok(())
60 }
61
62 pub fn aggregate(
67 &self,
68 queries: &[(&str, Value)],
69 ) -> Value {
70 let queries_json: Vec<Value> = queries
71 .iter()
72 .map(|(name, args)| {
73 let injected = self.inject_tenant_filter(args.clone());
74 serde_json::json!({
75 "capability": name,
76 "args": injected,
77 })
78 })
79 .collect();
80 serde_json::json!({
81 "tenant_id": self.tenant_id,
82 "queries": queries_json,
83 })
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn test_inject_tenant_filter() {
93 let cq = CrossQuery::new(100);
94 let args = serde_json::json!({"keyword": "test"});
95 let result = cq.inject_tenant_filter(args);
96 assert_eq!(result["tenant_id"], 100);
97 assert_eq!(result["keyword"], "test");
98 }
99
100 #[test]
101 fn test_inject_tenant_filter_null() {
102 let cq = CrossQuery::new(200);
103 let result = cq.inject_tenant_filter(Value::Null);
104 assert_eq!(result["tenant_id"], 200);
105 }
106
107 #[test]
108 fn test_verify_tenant_same() {
109 let cq = CrossQuery::new(100);
110 assert!(cq.verify_tenant(100).is_ok());
111 }
112
113 #[test]
114 fn test_verify_tenant_different() {
115 let cq = CrossQuery::new(100);
116 assert!(cq.verify_tenant(200).is_err());
117 }
118
119 #[test]
120 fn test_aggregate() {
121 let cq = CrossQuery::new(100);
122 let queries = vec![
123 ("plugin_a.search", serde_json::json!({"q": "hello"})),
124 ("plugin_b.list", serde_json::json!({})),
125 ];
126 let result = cq.aggregate(&queries);
127 assert_eq!(result["tenant_id"], 100);
128 assert_eq!(result["queries"].as_array().unwrap().len(), 2);
129 assert_eq!(result["queries"][0]["args"]["tenant_id"], 100);
130 }
131}