refactor(saas): 架构重构 + 性能优化 — 借鉴 loco-rs 模式
Phase 0: 知识库
- docs/knowledge-base/loco-rs-patterns.md — loco-rs 10 个可借鉴模式研究
Phase 1: 数据层重构
- crates/zclaw-saas/src/models/ — 15 个 FromRow 类型化模型
- Login 3 次查询合并为 1 次 AccountLoginRow 查询
- 所有 service 文件从元组解构迁移到 FromRow 结构体
Phase 2: Worker + Scheduler 系统
- crates/zclaw-saas/src/workers/ — Worker trait + 5 个具体实现
- crates/zclaw-saas/src/scheduler.rs — TOML 声明式调度器
- crates/zclaw-saas/src/tasks/ — CLI 任务系统
Phase 3: 性能修复
- Relay N+1 查询 → 精准 SQL (relay/handlers.rs)
- Config RwLock → AtomicU32 无锁 rate limit (state.rs, middleware.rs)
- SSE std::sync::Mutex → tokio::sync::Mutex (relay/service.rs)
- /auth/refresh 阻塞清理 → Scheduler 定期执行
Phase 4: 多环境配置
- config/saas-{development,production,test}.toml
- ZCLAW_ENV 环境选择 + ZCLAW_SAAS_CONFIG 精确覆盖
- scheduler 配置集成到 TOML
This commit is contained in:
@@ -2,33 +2,34 @@
|
||||
|
||||
use sqlx::PgPool;
|
||||
use crate::error::{SaasError, SaasResult};
|
||||
use crate::models::{RoleRow, PermissionTemplateRow};
|
||||
use super::types::*;
|
||||
|
||||
pub async fn list_roles(db: &PgPool) -> SaasResult<Vec<RoleInfo>> {
|
||||
let rows: Vec<(String, String, Option<String>, String, bool, String, String)> =
|
||||
let rows: Vec<RoleRow> =
|
||||
sqlx::query_as(
|
||||
"SELECT id, name, description, permissions, is_system, created_at, updated_at
|
||||
FROM roles ORDER BY
|
||||
CASE id
|
||||
WHEN 'super_admin' THEN 1
|
||||
WHEN 'admin' THEN 2
|
||||
WHEN 'user' THEN 3
|
||||
ELSE 4
|
||||
FROM roles ORDER BY
|
||||
CASE id
|
||||
WHEN 'super_admin' THEN 1
|
||||
WHEN 'admin' THEN 2
|
||||
WHEN 'user' THEN 3
|
||||
ELSE 4
|
||||
END"
|
||||
)
|
||||
.fetch_all(db)
|
||||
.await?;
|
||||
|
||||
let roles = rows.into_iter().map(|(id, name, description, perms, is_system, created_at, updated_at)| {
|
||||
let permissions: Vec<String> = serde_json::from_str(&perms).unwrap_or_default();
|
||||
RoleInfo { id, name, description, permissions, is_system, created_at, updated_at }
|
||||
let roles = rows.into_iter().map(|r| {
|
||||
let permissions: Vec<String> = serde_json::from_str(&r.permissions).unwrap_or_default();
|
||||
RoleInfo { id: r.id, name: r.name, description: r.description, permissions, is_system: r.is_system, created_at: r.created_at, updated_at: r.updated_at }
|
||||
}).collect();
|
||||
|
||||
Ok(roles)
|
||||
}
|
||||
|
||||
pub async fn get_role(db: &PgPool, role_id: &str) -> SaasResult<RoleInfo> {
|
||||
let row: Option<(String, String, Option<String>, String, bool, String, String)> =
|
||||
let row: Option<RoleRow> =
|
||||
sqlx::query_as(
|
||||
"SELECT id, name, description, permissions, is_system, created_at, updated_at
|
||||
FROM roles WHERE id = $1"
|
||||
@@ -37,11 +38,10 @@ pub async fn get_role(db: &PgPool, role_id: &str) -> SaasResult<RoleInfo> {
|
||||
.fetch_optional(db)
|
||||
.await?;
|
||||
|
||||
let (id, name, description, perms, is_system, created_at, updated_at) =
|
||||
row.ok_or_else(|| SaasError::NotFound(format!("角色 {} 不存在", role_id)))?;
|
||||
let r = row.ok_or_else(|| SaasError::NotFound(format!("角色 {} 不存在", role_id)))?;
|
||||
|
||||
let permissions: Vec<String> = serde_json::from_str(&perms).unwrap_or_default();
|
||||
Ok(RoleInfo { id, name, description, permissions, is_system, created_at, updated_at })
|
||||
let permissions: Vec<String> = serde_json::from_str(&r.permissions).unwrap_or_default();
|
||||
Ok(RoleInfo { id: r.id, name: r.name, description: r.description, permissions, is_system: r.is_system, created_at: r.created_at, updated_at: r.updated_at })
|
||||
}
|
||||
|
||||
pub async fn create_role(db: &PgPool, req: &CreateRoleRequest) -> SaasResult<RoleInfo> {
|
||||
@@ -137,7 +137,7 @@ pub async fn delete_role(db: &PgPool, role_id: &str) -> SaasResult<()> {
|
||||
}
|
||||
|
||||
pub async fn list_templates(db: &PgPool) -> SaasResult<Vec<PermissionTemplate>> {
|
||||
let rows: Vec<(String, String, Option<String>, String, String, String)> =
|
||||
let rows: Vec<PermissionTemplateRow> =
|
||||
sqlx::query_as(
|
||||
"SELECT id, name, description, permissions, created_at, updated_at
|
||||
FROM permission_templates ORDER BY created_at DESC"
|
||||
@@ -145,16 +145,16 @@ pub async fn list_templates(db: &PgPool) -> SaasResult<Vec<PermissionTemplate>>
|
||||
.fetch_all(db)
|
||||
.await?;
|
||||
|
||||
let templates = rows.into_iter().map(|(id, name, description, perms, created_at, updated_at)| {
|
||||
let permissions: Vec<String> = serde_json::from_str(&perms).unwrap_or_default();
|
||||
PermissionTemplate { id, name, description, permissions, created_at, updated_at }
|
||||
let templates = rows.into_iter().map(|r| {
|
||||
let permissions: Vec<String> = serde_json::from_str(&r.permissions).unwrap_or_default();
|
||||
PermissionTemplate { id: r.id, name: r.name, description: r.description, permissions, created_at: r.created_at, updated_at: r.updated_at }
|
||||
}).collect();
|
||||
|
||||
Ok(templates)
|
||||
}
|
||||
|
||||
pub async fn get_template(db: &PgPool, template_id: &str) -> SaasResult<PermissionTemplate> {
|
||||
let row: Option<(String, String, Option<String>, String, String, String)> =
|
||||
let row: Option<PermissionTemplateRow> =
|
||||
sqlx::query_as(
|
||||
"SELECT id, name, description, permissions, created_at, updated_at
|
||||
FROM permission_templates WHERE id = $1"
|
||||
@@ -163,11 +163,10 @@ pub async fn get_template(db: &PgPool, template_id: &str) -> SaasResult<Permissi
|
||||
.fetch_optional(db)
|
||||
.await?;
|
||||
|
||||
let (id, name, description, perms, created_at, updated_at) =
|
||||
row.ok_or_else(|| SaasError::NotFound(format!("权限模板 {} 不存在", template_id)))?;
|
||||
let r = row.ok_or_else(|| SaasError::NotFound(format!("权限模板 {} 不存在", template_id)))?;
|
||||
|
||||
let permissions: Vec<String> = serde_json::from_str(&perms).unwrap_or_default();
|
||||
Ok(PermissionTemplate { id, name, description, permissions, created_at, updated_at })
|
||||
let permissions: Vec<String> = serde_json::from_str(&r.permissions).unwrap_or_default();
|
||||
Ok(PermissionTemplate { id: r.id, name: r.name, description: r.description, permissions, created_at: r.created_at, updated_at: r.updated_at })
|
||||
}
|
||||
|
||||
pub async fn create_template(db: &PgPool, req: &CreateTemplateRequest) -> SaasResult<PermissionTemplate> {
|
||||
|
||||
Reference in New Issue
Block a user