feat(#2569): drive a turn on a local todo signal (serve-loop select)
This commit is contained in:
parent
713d7f424c
commit
86d16efa07
3 changed files with 72 additions and 18 deletions
|
|
@ -33,7 +33,6 @@ CREATE TABLE IF NOT EXISTS todos (
|
|||
subsystem_key TEXT,
|
||||
summary TEXT NOT NULL,
|
||||
source TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
-- (subsystem, subsystem_key) is the upsert/dedup key. A NULL key never
|
||||
|
|
@ -57,7 +56,6 @@ pub struct Todo {
|
|||
pub summary: String,
|
||||
/// Optional free-text provenance (e.g. the room name / task label).
|
||||
pub source: Option<String>,
|
||||
pub created_at: i64,
|
||||
pub updated_at: i64,
|
||||
}
|
||||
|
||||
|
|
@ -74,8 +72,8 @@ impl Todos {
|
|||
///
|
||||
/// Propagates sqlite open / schema-apply failures.
|
||||
pub fn open(path: &Path) -> Result<Self> {
|
||||
let conn = Connection::open(path)
|
||||
.with_context(|| format!("open todos db {}", path.display()))?;
|
||||
let conn =
|
||||
Connection::open(path).with_context(|| format!("open todos db {}", path.display()))?;
|
||||
conn.execute_batch(SCHEMA).context("apply todos schema")?;
|
||||
Ok(Self {
|
||||
conn: Mutex::new(conn),
|
||||
|
|
@ -131,8 +129,8 @@ impl Todos {
|
|||
}
|
||||
conn.execute(
|
||||
"INSERT INTO todos \
|
||||
(subsystem, subsystem_key, summary, source, created_at, updated_at) \
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?5)",
|
||||
(subsystem, subsystem_key, summary, source, updated_at) \
|
||||
VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||
params![subsystem, key, summary, source, now],
|
||||
)?;
|
||||
Ok((conn.last_insert_rowid(), true))
|
||||
|
|
@ -173,10 +171,7 @@ impl Todos {
|
|||
/// Panics if the connection mutex is poisoned.
|
||||
pub fn clear_subsystem(&self, subsystem: &str) -> Result<usize> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
let n = conn.execute(
|
||||
"DELETE FROM todos WHERE subsystem = ?1",
|
||||
params![subsystem],
|
||||
)?;
|
||||
let n = conn.execute("DELETE FROM todos WHERE subsystem = ?1", params![subsystem])?;
|
||||
Ok(n)
|
||||
}
|
||||
|
||||
|
|
@ -209,7 +204,7 @@ impl Todos {
|
|||
pub fn list(&self, subsystem: Option<&str>) -> Result<Vec<Todo>> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
let mut stmt = conn.prepare(
|
||||
"SELECT id, subsystem, subsystem_key, summary, source, created_at, updated_at \
|
||||
"SELECT id, subsystem, subsystem_key, summary, source, updated_at \
|
||||
FROM todos \
|
||||
WHERE (?1 IS NULL OR subsystem = ?1) \
|
||||
ORDER BY updated_at DESC, id DESC",
|
||||
|
|
@ -222,8 +217,7 @@ impl Todos {
|
|||
subsystem_key: row.get(2)?,
|
||||
summary: row.get(3)?,
|
||||
source: row.get(4)?,
|
||||
created_at: row.get(5)?,
|
||||
updated_at: row.get(6)?,
|
||||
updated_at: row.get(5)?,
|
||||
})
|
||||
})?
|
||||
.collect::<rusqlite::Result<Vec<_>>>()?;
|
||||
|
|
@ -247,14 +241,20 @@ mod tests {
|
|||
#[test]
|
||||
fn keyed_upsert_dedups_and_reports_changed() {
|
||||
let (_dir, s) = store();
|
||||
let (id1, changed1) = s.upsert("matrix", Some("!room:x"), "1 unread", None).unwrap();
|
||||
let (id1, changed1) = s
|
||||
.upsert("matrix", Some("!room:x"), "1 unread", None)
|
||||
.unwrap();
|
||||
assert!(changed1, "first push is new → changed");
|
||||
// Same key + same summary → no-op, not changed (must not re-wake).
|
||||
let (id2, changed2) = s.upsert("matrix", Some("!room:x"), "1 unread", None).unwrap();
|
||||
let (id2, changed2) = s
|
||||
.upsert("matrix", Some("!room:x"), "1 unread", None)
|
||||
.unwrap();
|
||||
assert_eq!(id1, id2, "keyed upsert updates in place, same row");
|
||||
assert!(!changed2, "identical re-push is a no-op");
|
||||
// Same key, new summary → updates, changed.
|
||||
let (id3, changed3) = s.upsert("matrix", Some("!room:x"), "3 unread", None).unwrap();
|
||||
let (id3, changed3) = s
|
||||
.upsert("matrix", Some("!room:x"), "3 unread", None)
|
||||
.unwrap();
|
||||
assert_eq!(id1, id3);
|
||||
assert!(changed3);
|
||||
assert_eq!(s.list(Some("matrix")).unwrap().len(), 1);
|
||||
|
|
|
|||
Loading…
Reference in a new issue