scitadel_db/sqlite/
tui_state.rs1use rusqlite::params;
10
11use crate::error::DbError;
12use crate::sqlite::Database;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct TuiState {
16 pub tab: String,
18 pub paper_id: Option<String>,
19 pub search_id: Option<String>,
20 pub question_id: Option<String>,
21 pub annotation_id: Option<String>,
22 pub updated_at: String,
24}
25
26#[derive(Clone)]
27pub struct SqliteTuiStateRepository {
28 db: Database,
29}
30
31impl SqliteTuiStateRepository {
32 pub fn new(db: Database) -> Self {
33 Self { db }
34 }
35
36 pub fn set(&self, state: &TuiState) -> Result<(), DbError> {
39 let conn = self.db.conn()?;
40 conn.execute(
41 "INSERT INTO tui_state (id, tab, paper_id, search_id, question_id, annotation_id, updated_at)
42 VALUES (1, ?1, ?2, ?3, ?4, ?5, ?6)
43 ON CONFLICT(id) DO UPDATE SET
44 tab = excluded.tab,
45 paper_id = excluded.paper_id,
46 search_id = excluded.search_id,
47 question_id = excluded.question_id,
48 annotation_id = excluded.annotation_id,
49 updated_at = excluded.updated_at",
50 params![
51 state.tab,
52 state.paper_id,
53 state.search_id,
54 state.question_id,
55 state.annotation_id,
56 state.updated_at,
57 ],
58 )?;
59 Ok(())
60 }
61
62 pub fn get(&self) -> Result<Option<TuiState>, DbError> {
65 let conn = self.db.conn()?;
66 let mut stmt = conn.prepare(
67 "SELECT tab, paper_id, search_id, question_id, annotation_id, updated_at
68 FROM tui_state WHERE id = 1",
69 )?;
70 let mut rows = stmt.query([])?;
71 if let Some(row) = rows.next()? {
72 Ok(Some(TuiState {
73 tab: row.get(0)?,
74 paper_id: row.get(1)?,
75 search_id: row.get(2)?,
76 question_id: row.get(3)?,
77 annotation_id: row.get(4)?,
78 updated_at: row.get(5)?,
79 }))
80 } else {
81 Ok(None)
82 }
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 fn fresh() -> SqliteTuiStateRepository {
91 let db = Database::open_in_memory().unwrap();
92 db.migrate().unwrap();
93 SqliteTuiStateRepository::new(db)
94 }
95
96 #[test]
97 fn empty_until_first_write() {
98 let repo = fresh();
99 assert!(repo.get().unwrap().is_none());
100 }
101
102 #[test]
103 fn upsert_round_trip() {
104 let repo = fresh();
105 let s = TuiState {
106 tab: "Papers".into(),
107 paper_id: Some("p-abc".into()),
108 search_id: None,
109 question_id: None,
110 annotation_id: None,
111 updated_at: "2026-04-20T00:00:00Z".into(),
112 };
113 repo.set(&s).unwrap();
114 assert_eq!(repo.get().unwrap().unwrap(), s);
115
116 let s2 = TuiState {
118 tab: "Questions".into(),
119 paper_id: None,
120 search_id: None,
121 question_id: Some("q-xyz".into()),
122 annotation_id: None,
123 updated_at: "2026-04-20T00:01:00Z".into(),
124 };
125 repo.set(&s2).unwrap();
126 assert_eq!(repo.get().unwrap().unwrap(), s2);
127 }
128}