1use rusqlite::{params, Connection, OptionalExtension};
2
3#[derive(Debug, Clone)]
4pub struct ProgressRow {
5 pub book_id: i64,
6 pub spine_idx: u32,
7 pub char_offset: u64,
8 pub anchor_hash: String,
9 pub percent: f32,
10 pub time_read_s: u64,
11 pub words_read: u64,
12}
13
14pub fn upsert(c: &mut Connection, row: &ProgressRow) -> anyhow::Result<()> {
17 c.execute(
18 "INSERT INTO progress(book_id, spine_idx, char_offset, anchor_hash,
19 percent, time_read_s, words_read, last_read_at)
20 VALUES (?,?,?,?,?,?,?, CURRENT_TIMESTAMP)
21 ON CONFLICT(book_id) DO UPDATE SET
22 spine_idx = excluded.spine_idx,
23 char_offset = excluded.char_offset,
24 anchor_hash = excluded.anchor_hash,
25 percent = excluded.percent,
26 time_read_s = excluded.time_read_s,
27 words_read = excluded.words_read,
28 last_read_at = CURRENT_TIMESTAMP",
29 params![
30 row.book_id,
31 row.spine_idx,
32 row.char_offset,
33 row.anchor_hash,
34 row.percent,
35 row.time_read_s,
36 row.words_read,
37 ],
38 )?;
39 Ok(())
40}
41
42pub fn load(c: &Connection, book_id: i64) -> anyhow::Result<Option<ProgressRow>> {
44 Ok(c.query_row(
45 "SELECT book_id, spine_idx, char_offset, anchor_hash,
46 percent, time_read_s, words_read
47 FROM progress WHERE book_id = ?",
48 params![book_id],
49 |r| {
50 Ok(ProgressRow {
51 book_id: r.get(0)?,
52 spine_idx: r.get(1)?,
53 char_offset: r.get(2)?,
54 anchor_hash: r.get(3)?,
55 percent: r.get(4)?,
56 time_read_s: r.get(5)?,
57 words_read: r.get(6)?,
58 })
59 },
60 )
61 .optional()?)
62}