feat(storage): 实现 Storage 主结构和初始化
This commit is contained in:
parent
c4c87aac95
commit
88f8a86b99
@ -3,3 +3,90 @@ pub mod session;
|
|||||||
pub mod message;
|
pub mod message;
|
||||||
|
|
||||||
pub use error::StorageError;
|
pub use error::StorageError;
|
||||||
|
|
||||||
|
use sqlx::{Pool, Sqlite, SqlitePool};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
pub struct Storage {
|
||||||
|
pool: Pool<Sqlite>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Storage {
|
||||||
|
/// 打开或创建数据库
|
||||||
|
pub async fn new(db_path: &Path) -> Result<Self, StorageError> {
|
||||||
|
let database_url = format!("sqlite:{}?mode=rwc", db_path.display());
|
||||||
|
let pool = SqlitePool::connect(&database_url).await?;
|
||||||
|
|
||||||
|
let storage = Self { pool };
|
||||||
|
storage.init_schema().await?;
|
||||||
|
Ok(storage)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 初始化数据库 schema
|
||||||
|
async fn init_schema(&self) -> Result<(), StorageError> {
|
||||||
|
sqlx::query(
|
||||||
|
r#"
|
||||||
|
CREATE TABLE IF NOT EXISTS sessions (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
channel TEXT NOT NULL,
|
||||||
|
chat_id TEXT NOT NULL,
|
||||||
|
dialog_id TEXT NOT NULL,
|
||||||
|
title TEXT NOT NULL DEFAULT '新对话',
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
last_active_at INTEGER NOT NULL,
|
||||||
|
message_count INTEGER DEFAULT 0,
|
||||||
|
routing_info TEXT,
|
||||||
|
deleted_at INTEGER,
|
||||||
|
UNIQUE(channel, chat_id, dialog_id)
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
sqlx::query(
|
||||||
|
r#"
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_sessions_chat
|
||||||
|
ON sessions(channel, chat_id, deleted_at)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
sqlx::query(
|
||||||
|
r#"
|
||||||
|
CREATE TABLE IF NOT EXISTS messages (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
session_id TEXT NOT NULL,
|
||||||
|
seq INTEGER NOT NULL,
|
||||||
|
role TEXT NOT NULL,
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
media_refs TEXT,
|
||||||
|
tool_call_id TEXT,
|
||||||
|
tool_name TEXT,
|
||||||
|
tool_calls TEXT,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
sqlx::query(
|
||||||
|
r#"
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_messages_session_seq
|
||||||
|
ON messages(session_id, seq)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取连接池引用(供内部 CRUD 使用)
|
||||||
|
pub(crate) fn pool(&self) -> &Pool<Sqlite> {
|
||||||
|
&self.pool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user