verso-reader 0.1.0

A terminal EPUB reader with vim navigation, a Kindle-style library, and Markdown highlight export
Documentation
use rusqlite::{params, Connection};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AnchorStatus {
    Ok,
    Drifted,
    Lost,
}

impl AnchorStatus {
    pub fn as_str(self) -> &'static str {
        match self {
            Self::Ok => "ok",
            Self::Drifted => "drifted",
            Self::Lost => "lost",
        }
    }
    pub fn parse(s: &str) -> Self {
        match s {
            "drifted" => Self::Drifted,
            "lost" => Self::Lost,
            _ => Self::Ok,
        }
    }
}

#[derive(Debug, Clone)]
pub struct Highlight {
    pub id: i64,
    pub book_id: i64,
    pub spine_idx: u32,
    pub chapter_title: Option<String>,
    pub char_offset_start: u64,
    pub char_offset_end: u64,
    pub text: String,
    pub context_before: Option<String>,
    pub context_after: Option<String>,
    pub note: Option<String>,
    pub anchor_status: AnchorStatus,
}

pub fn insert(c: &mut Connection, h: &Highlight) -> anyhow::Result<i64> {
    c.execute(
        "INSERT INTO highlights(book_id, spine_idx, chapter_title, char_offset_start, char_offset_end,
                                text, context_before, context_after, note, anchor_status)
         VALUES (?,?,?,?,?,?,?,?,?,?)",
        params![h.book_id, h.spine_idx, h.chapter_title, h.char_offset_start, h.char_offset_end,
                h.text, h.context_before, h.context_after, h.note, h.anchor_status.as_str()],
    )?;
    Ok(c.last_insert_rowid())
}

pub fn delete(c: &mut Connection, id: i64) -> anyhow::Result<()> {
    c.execute("DELETE FROM highlights WHERE id = ?", params![id])?;
    Ok(())
}

pub fn list(c: &Connection, book_id: i64) -> anyhow::Result<Vec<Highlight>> {
    let mut stmt = c.prepare(
        "SELECT id, book_id, spine_idx, chapter_title, char_offset_start, char_offset_end,
                text, context_before, context_after, note, anchor_status
         FROM highlights WHERE book_id = ? ORDER BY spine_idx, char_offset_start",
    )?;
    let rows: Vec<Highlight> = stmt
        .query_map(params![book_id], |r| {
            Ok(Highlight {
                id: r.get(0)?,
                book_id: r.get(1)?,
                spine_idx: r.get(2)?,
                chapter_title: r.get(3)?,
                char_offset_start: r.get(4)?,
                char_offset_end: r.get(5)?,
                text: r.get(6)?,
                context_before: r.get(7)?,
                context_after: r.get(8)?,
                note: r.get(9)?,
                anchor_status: AnchorStatus::parse(&r.get::<_, String>(10)?),
            })
        })?
        .collect::<Result<_, _>>()?;
    Ok(rows)
}