use sqlx::SqlitePool;
use uuid::Uuid;
pub async fn insert_message(
db: &SqlitePool,
session_id: &str,
role: &str,
text: &str,
blocks: Option<&str>,
) -> Result<(), sqlx::Error> {
let id = Uuid::new_v4().to_string();
let now = chrono::Utc::now().to_rfc3339();
sqlx::query("INSERT INTO chat_messages (id, session_id, role, text, created_at, blocks) VALUES (?, ?, ?, ?, ?, ?)")
.bind(&id)
.bind(session_id)
.bind(role)
.bind(text)
.bind(&now)
.bind(blocks)
.execute(db)
.await?;
Ok(())
}
pub async fn list_messages(
db: &SqlitePool,
session_id: &str,
) -> Result<Vec<ChatMessageRow>, sqlx::Error> {
let rows: Vec<ChatMessageRow> = sqlx::query_as(
"SELECT role, text, created_at, id, blocks, status, last_seq FROM chat_messages WHERE session_id = ? ORDER BY created_at ASC",
)
.bind(session_id)
.fetch_all(db)
.await?;
Ok(rows)
}
pub type ChatMessageRow = (String, String, String, String, Option<String>, String, Option<i64>);
pub async fn upsert_streaming_message(
db: &SqlitePool,
row_id: &str,
session_id: &str,
text: &str,
blocks: Option<&str>,
last_seq: i64,
) -> Result<(), sqlx::Error> {
let now = chrono::Utc::now().to_rfc3339();
sqlx::query(
"INSERT INTO chat_messages (id, session_id, role, text, created_at, blocks, status, last_seq) \
VALUES (?, ?, 'assistant', ?, ?, ?, 'streaming', ?) \
ON CONFLICT(id) DO UPDATE SET text = excluded.text, blocks = excluded.blocks, last_seq = excluded.last_seq",
)
.bind(row_id)
.bind(session_id)
.bind(text)
.bind(&now)
.bind(blocks)
.bind(last_seq)
.execute(db)
.await?;
Ok(())
}
pub async fn finalize_message(db: &SqlitePool, row_id: &str) -> Result<(), sqlx::Error> {
sqlx::query("UPDATE chat_messages SET status = 'complete' WHERE id = ?")
.bind(row_id)
.execute(db)
.await?;
Ok(())
}
pub async fn sync_messages(
db: &SqlitePool,
session_id: &str,
messages: &[(String, String, Option<String>)],
) -> Result<(), sqlx::Error> {
for (role, text, blocks) in messages {
if text.is_empty() {
continue;
}
let exists: i64 = sqlx::query_scalar(
"SELECT COUNT(*) FROM chat_messages WHERE session_id = ? AND role = ? AND text = ?",
)
.bind(session_id)
.bind(role)
.bind(text)
.fetch_one(db)
.await?;
if exists > 0 {
if let Some(blocks) = blocks {
sqlx::query(
"UPDATE chat_messages SET blocks = ? WHERE session_id = ? AND role = ? AND text = ?",
)
.bind(blocks)
.bind(session_id)
.bind(role)
.bind(text)
.execute(db)
.await?;
}
continue;
}
let id = Uuid::new_v4().to_string();
let now = chrono::Utc::now().to_rfc3339();
sqlx::query("INSERT INTO chat_messages (id, session_id, role, text, created_at, blocks) VALUES (?, ?, ?, ?, ?, ?)")
.bind(&id)
.bind(session_id)
.bind(role)
.bind(text)
.bind(&now)
.bind(blocks)
.execute(db)
.await?;
}
Ok(())
}