secra-database 0.1.0

基于 SeaORM 的 Rust 数据库连接和管理库
Documentation
//! Schema 管理服务
//!
//! 提供数据库 Schema 的查询、创建、删除等功能(PostgreSQL)

use sea_orm::{ConnectionTrait, DatabaseConnection};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use tracing::{error, info};

/// Schema 管理错误
#[derive(Error, Debug)]
pub enum SchemaError {
    #[error("数据库查询失败: {0}")]
    QueryFailed(String),
    #[error("Schema 操作失败: {0}")]
    OperationFailed(String),
    #[error("Schema 不存在: {0}")]
    SchemaNotFound(String),
    #[error("Schema 已存在: {0}")]
    SchemaExists(String),
    #[error("无效的输入: {0}")]
    InvalidInput(String),
}

/// Schema 信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SchemaInfo {
    /// Schema 名称
    pub schema_name: String,
    /// Schema 所有者
    pub schema_owner: Option<String>,
    /// Schema 注释
    pub schema_comment: Option<String>,
}

/// Schema 服务
pub struct SchemaService;

impl SchemaService {
    /// 获取所有 Schema 列表(PostgreSQL)
    ///
    /// # 注意
    /// 此方法需要 PostgreSQL 数据库,并且需要能够执行查询操作。
    /// 由于 SeaORM 的 DatabaseConnection 不直接支持复杂查询结果解析,
    /// 建议使用 sqlx 连接池或通过其他方式获取查询结果。
    ///
    /// # 替代方案
    /// 如果需要获取 Schema 列表,可以:
    /// 1. 使用 sqlx 连接池直接查询
    /// 2. 使用 SeaORM Entity 查询(如果已定义 Schema Entity)
    /// 3. 通过数据库管理工具查询
    pub async fn list_schemas(db: &DatabaseConnection) -> Result<Vec<SchemaInfo>, SchemaError> {
        // 检查数据库类型
        let backend = db.get_database_backend();
        if backend != sea_orm::DatabaseBackend::Postgres {
            return Err(SchemaError::QueryFailed(
                format!("当前仅支持 PostgreSQL 数据库,当前数据库类型: {:?}", backend)
            ));
        }

        // 测试连接是否可用
        let _ = db.execute_unprepared("SELECT 1").await.map_err(|e| {
            SchemaError::QueryFailed(format!("数据库连接不可用: {}", e))
        })?;

        // 注意:SeaORM 的 DatabaseConnection 不直接支持查询结果解析
        // 要获取 Schema 列表,需要使用 sqlx 连接池或通过其他方式
        Err(SchemaError::QueryFailed(
            "Schema 列表查询功能需要 sqlx 连接池支持。\
            建议:1) 使用 sqlx 连接池直接查询,或 2) 通过数据库管理工具查询".to_string(),
        ))
    }

    /// 获取指定 Schema 的信息
    ///
    /// # 注意
    /// 此方法需要 PostgreSQL 数据库,并且需要能够执行查询操作。
    /// 由于 SeaORM 的 DatabaseConnection 不直接支持复杂查询结果解析,
    /// 建议使用 sqlx 连接池或通过其他方式获取查询结果。
    ///
    /// # 参数
    /// * `db` - 数据库连接
    /// * `schema_name` - Schema 名称
    pub async fn get_schema_info(
        db: &DatabaseConnection,
        schema_name: &str,
    ) -> Result<SchemaInfo, SchemaError> {
        // 验证 schema_name 不为空
        if schema_name.is_empty() {
            return Err(SchemaError::InvalidInput("Schema 名称不能为空".to_string()));
        }

        // 检查数据库类型
        let backend = db.get_database_backend();
        if backend != sea_orm::DatabaseBackend::Postgres {
            return Err(SchemaError::QueryFailed(
                format!("当前仅支持 PostgreSQL 数据库,当前数据库类型: {:?}", backend)
            ));
        }

        // 测试连接是否可用
        let _ = db.execute_unprepared("SELECT 1").await.map_err(|e| {
            SchemaError::QueryFailed(format!("数据库连接不可用: {}", e))
        })?;

        // 注意:SeaORM 的 DatabaseConnection 不直接支持查询结果解析
        // 要获取 Schema 信息,需要使用 sqlx 连接池或通过其他方式
        Err(SchemaError::QueryFailed(
            format!(
                "Schema 信息查询功能需要 sqlx 连接池支持。\
                建议:1) 使用 sqlx 连接池直接查询,或 2) 通过数据库管理工具查询。\
                要查询的 Schema: {}",
                schema_name
            )
        ))
    }

    /// 检查 Schema 是否存在
    pub async fn schema_exists(
        db: &DatabaseConnection,
        schema_name: &str,
    ) -> Result<bool, SchemaError> {
        match Self::get_schema_info(db, schema_name).await {
            Ok(_) => Ok(true),
            Err(SchemaError::SchemaNotFound(_)) => Ok(false),
            Err(e) => Err(e),
        }
    }

    /// 创建 Schema(PostgreSQL)
    pub async fn create_schema(
        db: &DatabaseConnection,
        schema_name: &str,
        if_not_exists: bool,
    ) -> Result<(), SchemaError> {
        // 检查 Schema 是否已存在
        if Self::schema_exists(db, schema_name).await? {
            if if_not_exists {
                info!("Schema {} 已存在,跳过创建", schema_name);
                return Ok(());
            } else {
                return Err(SchemaError::SchemaExists(format!(
                    "Schema {} 已存在",
                    schema_name
                )));
            }
        }

        let sql = format!("CREATE SCHEMA IF NOT EXISTS {}", schema_name);
        db.execute_unprepared(sql.as_str()).await.map_err(|e| {
            error!("创建 Schema 失败: {}", e);
            SchemaError::OperationFailed(format!("创建 Schema 失败: {}", e))
        })?;

        info!("✓ 成功创建 Schema: {}", schema_name);
        Ok(())
    }

    /// 删除 Schema(PostgreSQL)
    ///
    /// # 警告
    /// 删除 Schema 会删除其中的所有对象,请谨慎操作
    pub async fn drop_schema(
        db: &DatabaseConnection,
        schema_name: &str,
        if_exists: bool,
        cascade: bool,
    ) -> Result<(), SchemaError> {
        // 检查 Schema 是否存在
        if !Self::schema_exists(db, schema_name).await? {
            if if_exists {
                info!("Schema {} 不存在,跳过删除", schema_name);
                return Ok(());
            } else {
                return Err(SchemaError::SchemaNotFound(format!(
                    "Schema {} 不存在",
                    schema_name
                )));
            }
        }

        let cascade_str = if cascade { " CASCADE" } else { "" };
        let sql = format!("DROP SCHEMA IF EXISTS {}{}", schema_name, cascade_str);
        db.execute_unprepared(sql.as_str()).await.map_err(|e| {
            error!("删除 Schema 失败: {}", e);
            SchemaError::OperationFailed(format!("删除 Schema 失败: {}", e))
        })?;

        info!("✓ 成功删除 Schema: {}", schema_name);
        Ok(())
    }

    /// 设置 Schema 注释(PostgreSQL)
    pub async fn set_schema_comment(
        db: &DatabaseConnection,
        schema_name: &str,
        comment: &str,
    ) -> Result<(), SchemaError> {
        // 检查 Schema 是否存在
        if !Self::schema_exists(db, schema_name).await? {
            return Err(SchemaError::SchemaNotFound(format!(
                "Schema {} 不存在",
                schema_name
            )));
        }

        let sql = format!("COMMENT ON SCHEMA {} IS '{}'", schema_name, comment);
        db.execute_unprepared(sql.as_str()).await.map_err(|e| {
            error!("设置 Schema 注释失败: {}", e);
            SchemaError::OperationFailed(format!("设置 Schema 注释失败: {}", e))
        })?;

        info!("✓ 成功设置 Schema {} 的注释", schema_name);
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_schema_info_serialization() {
        let info = SchemaInfo {
            schema_name: "test_schema".to_string(),
            schema_owner: Some("postgres".to_string()),
            schema_comment: Some("测试 Schema".to_string()),
        };

        let json = serde_json::to_string(&info).unwrap();
        assert!(json.contains("test_schema"));
    }
}