Skip to main content

vs_store/store/
marks.rs

1//! `marks` table CRUD.
2
3use rusqlite::params;
4
5use super::{epoch_secs, Store};
6use crate::error::{Result, StoreError};
7use crate::types::Mark;
8
9impl Store {
10    #[allow(clippy::too_many_arguments)]
11    pub fn create_mark(
12        &mut self,
13        id: &str,
14        session_id: &str,
15        page_id: &str,
16        name: &str,
17        dom_path: &str,
18        role: Option<&str>,
19        content_excerpt: Option<&str>,
20    ) -> Result<Mark> {
21        let now = epoch_secs();
22        self.conn()
23            .execute(
24                "INSERT INTO marks(id, session_id, page_id, name, dom_path,
25                                   role, content_excerpt, created_at)
26                 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)",
27                params![
28                    id,
29                    session_id,
30                    page_id,
31                    name,
32                    dom_path,
33                    role,
34                    content_excerpt,
35                    now
36                ],
37            )
38            .map_err(|e| match e {
39                rusqlite::Error::SqliteFailure(err, _)
40                    if err.code == rusqlite::ErrorCode::ConstraintViolation =>
41                {
42                    StoreError::Conflict("mark name already in session")
43                }
44                other => StoreError::Sqlite(other),
45            })?;
46        Ok(Mark {
47            id: id.to_string(),
48            session_id: session_id.to_string(),
49            page_id: page_id.to_string(),
50            name: name.to_string(),
51            dom_path: dom_path.to_string(),
52            role: role.map(str::to_string),
53            content_excerpt: content_excerpt.map(str::to_string),
54            created_at: now,
55        })
56    }
57
58    pub fn get_mark(&self, session_id: &str, name: &str) -> Result<Option<Mark>> {
59        let mut stmt = self
60            .conn()
61            .prepare("SELECT * FROM marks WHERE session_id=?1 AND name=?2")?;
62        let mut rows = stmt.query([session_id, name])?;
63        if let Some(row) = rows.next()? {
64            Ok(Some(Mark::from_row(row)?))
65        } else {
66            Ok(None)
67        }
68    }
69
70    pub fn list_marks(&self, session_id: &str) -> Result<Vec<Mark>> {
71        let mut stmt = self
72            .conn()
73            .prepare("SELECT * FROM marks WHERE session_id=?1 ORDER BY created_at ASC")?;
74        let rows = stmt.query_map([session_id], Mark::from_row)?;
75        Ok(rows.collect::<rusqlite::Result<Vec<_>>>()?)
76    }
77
78    pub fn delete_mark(&mut self, session_id: &str, name: &str) -> Result<()> {
79        let n = self.conn().execute(
80            "DELETE FROM marks WHERE session_id=?1 AND name=?2",
81            params![session_id, name],
82        )?;
83        if n == 0 {
84            return Err(StoreError::NotFound {
85                kind: "mark",
86                id: format!("{session_id}/{name}"),
87            });
88        }
89        Ok(())
90    }
91}