secra_database/
schema.rs

1//! Schema 管理服务
2//!
3//! 提供数据库 Schema 的查询、创建、删除等功能(PostgreSQL)
4
5use sea_orm::{ConnectionTrait, DatabaseConnection};
6use serde::{Deserialize, Serialize};
7use thiserror::Error;
8use tracing::{error, info};
9
10/// Schema 管理错误
11#[derive(Error, Debug)]
12pub enum SchemaError {
13    #[error("数据库查询失败: {0}")]
14    QueryFailed(String),
15    #[error("Schema 操作失败: {0}")]
16    OperationFailed(String),
17    #[error("Schema 不存在: {0}")]
18    SchemaNotFound(String),
19    #[error("Schema 已存在: {0}")]
20    SchemaExists(String),
21    #[error("无效的输入: {0}")]
22    InvalidInput(String),
23}
24
25/// Schema 信息
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct SchemaInfo {
28    /// Schema 名称
29    pub schema_name: String,
30    /// Schema 所有者
31    pub schema_owner: Option<String>,
32    /// Schema 注释
33    pub schema_comment: Option<String>,
34}
35
36/// Schema 服务
37pub struct SchemaService;
38
39impl SchemaService {
40    /// 获取所有 Schema 列表(PostgreSQL)
41    ///
42    /// # 注意
43    /// 此方法需要 PostgreSQL 数据库,并且需要能够执行查询操作。
44    /// 由于 SeaORM 的 DatabaseConnection 不直接支持复杂查询结果解析,
45    /// 建议使用 sqlx 连接池或通过其他方式获取查询结果。
46    ///
47    /// # 替代方案
48    /// 如果需要获取 Schema 列表,可以:
49    /// 1. 使用 sqlx 连接池直接查询
50    /// 2. 使用 SeaORM Entity 查询(如果已定义 Schema Entity)
51    /// 3. 通过数据库管理工具查询
52    pub async fn list_schemas(db: &DatabaseConnection) -> Result<Vec<SchemaInfo>, SchemaError> {
53        // 检查数据库类型
54        let backend = db.get_database_backend();
55        if backend != sea_orm::DatabaseBackend::Postgres {
56            return Err(SchemaError::QueryFailed(
57                format!("当前仅支持 PostgreSQL 数据库,当前数据库类型: {:?}", backend)
58            ));
59        }
60
61        // 测试连接是否可用
62        let _ = db.execute_unprepared("SELECT 1").await.map_err(|e| {
63            SchemaError::QueryFailed(format!("数据库连接不可用: {}", e))
64        })?;
65
66        // 注意:SeaORM 的 DatabaseConnection 不直接支持查询结果解析
67        // 要获取 Schema 列表,需要使用 sqlx 连接池或通过其他方式
68        Err(SchemaError::QueryFailed(
69            "Schema 列表查询功能需要 sqlx 连接池支持。\
70            建议:1) 使用 sqlx 连接池直接查询,或 2) 通过数据库管理工具查询".to_string(),
71        ))
72    }
73
74    /// 获取指定 Schema 的信息
75    ///
76    /// # 注意
77    /// 此方法需要 PostgreSQL 数据库,并且需要能够执行查询操作。
78    /// 由于 SeaORM 的 DatabaseConnection 不直接支持复杂查询结果解析,
79    /// 建议使用 sqlx 连接池或通过其他方式获取查询结果。
80    ///
81    /// # 参数
82    /// * `db` - 数据库连接
83    /// * `schema_name` - Schema 名称
84    pub async fn get_schema_info(
85        db: &DatabaseConnection,
86        schema_name: &str,
87    ) -> Result<SchemaInfo, SchemaError> {
88        // 验证 schema_name 不为空
89        if schema_name.is_empty() {
90            return Err(SchemaError::InvalidInput("Schema 名称不能为空".to_string()));
91        }
92
93        // 检查数据库类型
94        let backend = db.get_database_backend();
95        if backend != sea_orm::DatabaseBackend::Postgres {
96            return Err(SchemaError::QueryFailed(
97                format!("当前仅支持 PostgreSQL 数据库,当前数据库类型: {:?}", backend)
98            ));
99        }
100
101        // 测试连接是否可用
102        let _ = db.execute_unprepared("SELECT 1").await.map_err(|e| {
103            SchemaError::QueryFailed(format!("数据库连接不可用: {}", e))
104        })?;
105
106        // 注意:SeaORM 的 DatabaseConnection 不直接支持查询结果解析
107        // 要获取 Schema 信息,需要使用 sqlx 连接池或通过其他方式
108        Err(SchemaError::QueryFailed(
109            format!(
110                "Schema 信息查询功能需要 sqlx 连接池支持。\
111                建议:1) 使用 sqlx 连接池直接查询,或 2) 通过数据库管理工具查询。\
112                要查询的 Schema: {}",
113                schema_name
114            )
115        ))
116    }
117
118    /// 检查 Schema 是否存在
119    pub async fn schema_exists(
120        db: &DatabaseConnection,
121        schema_name: &str,
122    ) -> Result<bool, SchemaError> {
123        match Self::get_schema_info(db, schema_name).await {
124            Ok(_) => Ok(true),
125            Err(SchemaError::SchemaNotFound(_)) => Ok(false),
126            Err(e) => Err(e),
127        }
128    }
129
130    /// 创建 Schema(PostgreSQL)
131    pub async fn create_schema(
132        db: &DatabaseConnection,
133        schema_name: &str,
134        if_not_exists: bool,
135    ) -> Result<(), SchemaError> {
136        // 检查 Schema 是否已存在
137        if Self::schema_exists(db, schema_name).await? {
138            if if_not_exists {
139                info!("Schema {} 已存在,跳过创建", schema_name);
140                return Ok(());
141            } else {
142                return Err(SchemaError::SchemaExists(format!(
143                    "Schema {} 已存在",
144                    schema_name
145                )));
146            }
147        }
148
149        let sql = format!("CREATE SCHEMA IF NOT EXISTS {}", schema_name);
150        db.execute_unprepared(sql.as_str()).await.map_err(|e| {
151            error!("创建 Schema 失败: {}", e);
152            SchemaError::OperationFailed(format!("创建 Schema 失败: {}", e))
153        })?;
154
155        info!("✓ 成功创建 Schema: {}", schema_name);
156        Ok(())
157    }
158
159    /// 删除 Schema(PostgreSQL)
160    ///
161    /// # 警告
162    /// 删除 Schema 会删除其中的所有对象,请谨慎操作
163    pub async fn drop_schema(
164        db: &DatabaseConnection,
165        schema_name: &str,
166        if_exists: bool,
167        cascade: bool,
168    ) -> Result<(), SchemaError> {
169        // 检查 Schema 是否存在
170        if !Self::schema_exists(db, schema_name).await? {
171            if if_exists {
172                info!("Schema {} 不存在,跳过删除", schema_name);
173                return Ok(());
174            } else {
175                return Err(SchemaError::SchemaNotFound(format!(
176                    "Schema {} 不存在",
177                    schema_name
178                )));
179            }
180        }
181
182        let cascade_str = if cascade { " CASCADE" } else { "" };
183        let sql = format!("DROP SCHEMA IF EXISTS {}{}", schema_name, cascade_str);
184        db.execute_unprepared(sql.as_str()).await.map_err(|e| {
185            error!("删除 Schema 失败: {}", e);
186            SchemaError::OperationFailed(format!("删除 Schema 失败: {}", e))
187        })?;
188
189        info!("✓ 成功删除 Schema: {}", schema_name);
190        Ok(())
191    }
192
193    /// 设置 Schema 注释(PostgreSQL)
194    pub async fn set_schema_comment(
195        db: &DatabaseConnection,
196        schema_name: &str,
197        comment: &str,
198    ) -> Result<(), SchemaError> {
199        // 检查 Schema 是否存在
200        if !Self::schema_exists(db, schema_name).await? {
201            return Err(SchemaError::SchemaNotFound(format!(
202                "Schema {} 不存在",
203                schema_name
204            )));
205        }
206
207        let sql = format!("COMMENT ON SCHEMA {} IS '{}'", schema_name, comment);
208        db.execute_unprepared(sql.as_str()).await.map_err(|e| {
209            error!("设置 Schema 注释失败: {}", e);
210            SchemaError::OperationFailed(format!("设置 Schema 注释失败: {}", e))
211        })?;
212
213        info!("✓ 成功设置 Schema {} 的注释", schema_name);
214        Ok(())
215    }
216}
217
218#[cfg(test)]
219mod tests {
220    use super::*;
221
222    #[test]
223    fn test_schema_info_serialization() {
224        let info = SchemaInfo {
225            schema_name: "test_schema".to_string(),
226            schema_owner: Some("postgres".to_string()),
227            schema_comment: Some("测试 Schema".to_string()),
228        };
229
230        let json = serde_json::to_string(&info).unwrap();
231        assert!(json.contains("test_schema"));
232    }
233}