mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-04 19:45:34 +08:00
refactor(database): split monolithic database.rs into modular structure
Split the 1788-line database.rs into a well-organized module directory: - mod.rs (142 lines): Database struct and initialization - schema.rs (341 lines): Table creation and schema migrations - backup.rs (324 lines): SQL import/export and snapshot backup - migration.rs (240 lines): JSON to SQLite data migration - tests.rs (280 lines): Unit tests - dao/providers.rs (254 lines): Provider CRUD operations - dao/mcp.rs (97 lines): MCP server CRUD operations - dao/prompts.rs (88 lines): Prompt CRUD operations - dao/skills.rs (124 lines): Skills CRUD operations - dao/settings.rs (65 lines): Settings key-value storage Benefits: - Max file size reduced from 1788 to 341 lines - Clear separation of concerns (schema, backup, migration, DAOs) - Easier to navigate and maintain - All 107 tests passing with zero API changes
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
//! Skills 数据访问对象
|
||||
//!
|
||||
//! 提供 Skills 和 Skill Repos 的 CRUD 操作。
|
||||
|
||||
use crate::database::{lock_conn, Database};
|
||||
use crate::error::AppError;
|
||||
use crate::services::skill::{SkillRepo, SkillState};
|
||||
use indexmap::IndexMap;
|
||||
use rusqlite::params;
|
||||
|
||||
impl Database {
|
||||
/// 获取所有 Skills 状态
|
||||
pub fn get_skills(&self) -> Result<IndexMap<String, SkillState>, AppError> {
|
||||
let conn = lock_conn!(self.conn);
|
||||
let mut stmt = conn
|
||||
.prepare("SELECT key, installed, installed_at FROM skills ORDER BY key ASC")
|
||||
.map_err(|e| AppError::Database(e.to_string()))?;
|
||||
|
||||
let skill_iter = stmt
|
||||
.query_map([], |row| {
|
||||
let key: String = row.get(0)?;
|
||||
let installed: bool = row.get(1)?;
|
||||
let installed_at_ts: i64 = row.get(2)?;
|
||||
|
||||
let installed_at =
|
||||
chrono::DateTime::from_timestamp(installed_at_ts, 0).unwrap_or_default();
|
||||
|
||||
Ok((
|
||||
key,
|
||||
SkillState {
|
||||
installed,
|
||||
installed_at,
|
||||
},
|
||||
))
|
||||
})
|
||||
.map_err(|e| AppError::Database(e.to_string()))?;
|
||||
|
||||
let mut skills = IndexMap::new();
|
||||
for skill_res in skill_iter {
|
||||
let (key, skill) = skill_res.map_err(|e| AppError::Database(e.to_string()))?;
|
||||
skills.insert(key, skill);
|
||||
}
|
||||
Ok(skills)
|
||||
}
|
||||
|
||||
/// 更新 Skill 状态
|
||||
pub fn update_skill_state(&self, key: &str, state: &SkillState) -> Result<(), AppError> {
|
||||
let conn = lock_conn!(self.conn);
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO skills (key, installed, installed_at) VALUES (?1, ?2, ?3)",
|
||||
params![key, state.installed, state.installed_at.timestamp()],
|
||||
)
|
||||
.map_err(|e| AppError::Database(e.to_string()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 获取所有 Skill 仓库
|
||||
pub fn get_skill_repos(&self) -> Result<Vec<SkillRepo>, AppError> {
|
||||
let conn = lock_conn!(self.conn);
|
||||
let mut stmt = conn
|
||||
.prepare("SELECT owner, name, branch, enabled, skills_path FROM skill_repos ORDER BY owner ASC, name ASC")
|
||||
.map_err(|e| AppError::Database(e.to_string()))?;
|
||||
|
||||
let repo_iter = stmt
|
||||
.query_map([], |row| {
|
||||
Ok(SkillRepo {
|
||||
owner: row.get(0)?,
|
||||
name: row.get(1)?,
|
||||
branch: row.get(2)?,
|
||||
enabled: row.get(3)?,
|
||||
skills_path: row.get(4)?,
|
||||
})
|
||||
})
|
||||
.map_err(|e| AppError::Database(e.to_string()))?;
|
||||
|
||||
let mut repos = Vec::new();
|
||||
for repo_res in repo_iter {
|
||||
repos.push(repo_res.map_err(|e| AppError::Database(e.to_string()))?);
|
||||
}
|
||||
Ok(repos)
|
||||
}
|
||||
|
||||
/// 保存 Skill 仓库
|
||||
pub fn save_skill_repo(&self, repo: &SkillRepo) -> Result<(), AppError> {
|
||||
let conn = lock_conn!(self.conn);
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO skill_repos (owner, name, branch, enabled, skills_path) VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||
params![repo.owner, repo.name, repo.branch, repo.enabled, repo.skills_path],
|
||||
).map_err(|e| AppError::Database(e.to_string()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 删除 Skill 仓库
|
||||
pub fn delete_skill_repo(&self, owner: &str, name: &str) -> Result<(), AppError> {
|
||||
let conn = lock_conn!(self.conn);
|
||||
conn.execute(
|
||||
"DELETE FROM skill_repos WHERE owner = ?1 AND name = ?2",
|
||||
params![owner, name],
|
||||
)
|
||||
.map_err(|e| AppError::Database(e.to_string()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 初始化默认的 Skill 仓库(首次启动时调用)
|
||||
pub fn init_default_skill_repos(&self) -> Result<usize, AppError> {
|
||||
// 检查是否已有仓库
|
||||
let existing = self.get_skill_repos()?;
|
||||
if !existing.is_empty() {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
// 获取默认仓库列表
|
||||
let default_store = crate::services::skill::SkillStore::default();
|
||||
let mut count = 0;
|
||||
|
||||
for repo in &default_store.repos {
|
||||
self.save_skill_repo(repo)?;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
log::info!("初始化默认 Skill 仓库完成,共 {count} 个");
|
||||
Ok(count)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user