Feature/open chat with persona #110
@@ -366,12 +366,28 @@ impl PersonaDao for SqlitePersonaDao {
|
||||
pid: &str,
|
||||
) -> Result<bool, DbError> {
|
||||
trace_db_call(cx, "delete", "delete_persona", |_span| {
|
||||
use schema::personas::dsl::*;
|
||||
let mut conn = self.connection.lock().expect("PersonaDao lock");
|
||||
let n = diesel::delete(personas.filter(user_id.eq(uid)).filter(persona_id.eq(pid)))
|
||||
.execute(conn.deref_mut())
|
||||
.map_err(|e| anyhow::anyhow!("Delete error: {}", e))?;
|
||||
Ok(n > 0)
|
||||
// One transaction so a persona and its conversations can't get
|
||||
// out of step. There is no FK between the two tables, and the
|
||||
// chat list skips conversations whose persona is gone — so
|
||||
// without this the transcripts would linger invisibly forever.
|
||||
conn.deref_mut().transaction::<_, anyhow::Error, _>(|tx| {
|
||||
{
|
||||
use schema::persona_chat_conversations::dsl::*;
|
||||
diesel::delete(
|
||||
persona_chat_conversations
|
||||
.filter(user_id.eq(uid))
|
||||
.filter(persona_id.eq(pid)),
|
||||
)
|
||||
.execute(tx)
|
||||
.map_err(|e| anyhow::anyhow!("Delete error: {}", e))?;
|
||||
}
|
||||
use schema::personas::dsl::*;
|
||||
let n = diesel::delete(personas.filter(user_id.eq(uid)).filter(persona_id.eq(pid)))
|
||||
.execute(tx)
|
||||
.map_err(|e| anyhow::anyhow!("Delete error: {}", e))?;
|
||||
Ok(n > 0)
|
||||
})
|
||||
})
|
||||
.map_err(|e| DbError::log(DbErrorKind::QueryError, e))
|
||||
}
|
||||
@@ -861,6 +877,34 @@ mod tests {
|
||||
assert!(dao.list_persona_chats(&cx, uid).unwrap().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deleting_a_persona_takes_its_conversations_with_it() {
|
||||
// No FK between the tables, and the chat list hides conversations
|
||||
// whose persona is gone — so an orphan row would be an invisible,
|
||||
// unreachable transcript sitting in the database forever.
|
||||
let cx = opentelemetry::Context::new();
|
||||
let (mut dao, uid) = dao_with_user("p-cascade");
|
||||
dao.create_persona(&cx, uid, "custom-1", "Custom", "prompt", false, false)
|
||||
.unwrap();
|
||||
dao.create_persona_chat(&cx, uid, "custom-1", 100).unwrap();
|
||||
dao.create_persona_chat(&cx, uid, "custom-1", 200).unwrap();
|
||||
let survivor = dao.create_persona_chat(&cx, uid, "other", 300).unwrap();
|
||||
|
||||
assert!(dao.delete_persona(&cx, uid, "custom-1").unwrap());
|
||||
|
||||
let remaining: Vec<String> = dao
|
||||
.list_persona_chats(&cx, uid)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|r| r.conversation_id)
|
||||
.collect();
|
||||
assert_eq!(
|
||||
remaining,
|
||||
vec![survivor],
|
||||
"only the untouched persona's conversation survives"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn persona_chat_reads_and_writes_are_scoped_to_the_owner() {
|
||||
// A conversation_id is a bearer token for someone's transcript, so
|
||||
|
||||
Reference in New Issue
Block a user