use anyhow::Result;
use rusqlite::{Connection, OptionalExtension};
use crate::state::work_stream_decay::WorkStreamDecayState;
pub(crate) fn read(conn: &Connection) -> Result<Option<WorkStreamDecayState>> {
conn.query_row(
"SELECT session_id, consecutive_no_progress, last_outcome, updated_at_epoch_s,
last_progress_at_epoch_s
FROM work_stream_decay
WHERE id = 1",
[],
|row| {
Ok(WorkStreamDecayState {
session_id: row.get(0)?,
consecutive_no_progress: row.get(1)?,
last_outcome: row.get(2)?,
updated_at_epoch_s: row.get(3)?,
last_progress_at_epoch_s: row.get(4)?,
})
},
)
.optional()
.map_err(Into::into)
}
pub(crate) fn write(conn: &Connection, state: &WorkStreamDecayState) -> Result<()> {
conn.execute(
"INSERT OR REPLACE INTO work_stream_decay
(id, session_id, consecutive_no_progress, last_outcome, updated_at_epoch_s,
last_progress_at_epoch_s)
VALUES (1, ?1, ?2, ?3, ?4, ?5)",
rusqlite::params![
&state.session_id,
state.consecutive_no_progress,
&state.last_outcome,
state.updated_at_epoch_s,
state.last_progress_at_epoch_s,
],
)?;
Ok(())
}
pub(crate) fn delete(conn: &Connection) -> Result<()> {
conn.execute("DELETE FROM work_stream_decay WHERE id = 1", [])?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::db::schema;
fn test_conn() -> Connection {
let conn = Connection::open_in_memory().unwrap();
schema::initialize(&conn).unwrap();
conn
}
#[test]
fn write_and_read_roundtrip() {
let conn = test_conn();
let state = WorkStreamDecayState {
session_id: "ses_decay".to_owned(),
consecutive_no_progress: 2,
last_outcome: "no_progress".to_owned(),
updated_at_epoch_s: 42,
last_progress_at_epoch_s: Some(12),
};
write(&conn, &state).unwrap();
assert_eq!(read(&conn).unwrap(), Some(state));
}
#[test]
fn delete_clears_row() {
let conn = test_conn();
write(
&conn,
&WorkStreamDecayState {
session_id: "ses_decay".to_owned(),
consecutive_no_progress: 1,
last_outcome: "neutral".to_owned(),
updated_at_epoch_s: 7,
last_progress_at_epoch_s: None,
},
)
.unwrap();
delete(&conn).unwrap();
assert!(read(&conn).unwrap().is_none());
}
}