use crate::threads::FlatArticle;
use rusqlite::{params, Connection, Result};
pub fn init_db(path: &str) -> Result<Connection> {
let conn = Connection::open(path)?;
conn.execute_batch(
"
PRAGMA foreign_keys = ON;
CREATE TABLE IF NOT EXISTS group_state (
group_name TEXT PRIMARY KEY,
last_seen_id INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS article_cache (
group_name TEXT NOT NULL,
article_id TEXT NOT NULL,
subject TEXT,
sender TEXT,
date TEXT,
message_id TEXT,
article_references TEXT,
read_flag INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY(group_name, article_id)
);
",
)?;
Ok(conn)
}
pub fn get_last_seen(conn: &Connection, group: &str) -> Result<u32> {
conn.query_row(
"SELECT last_seen_id FROM group_state WHERE group_name = ?1",
params![group],
|row| row.get(0),
)
.or(Ok(0))
}
pub fn set_last_seen(conn: &Connection, group: &str, last_seen_id: u32) -> Result<()> {
conn.execute(
"INSERT INTO group_state (group_name, last_seen_id) VALUES (?1, ?2)
ON CONFLICT(group_name) DO UPDATE SET last_seen_id = excluded.last_seen_id",
params![group, last_seen_id],
)?;
Ok(())
}
pub fn cache_subject(
conn: &Connection,
group: &str,
article_id: &str,
subject: &str,
sender: &str,
date: &str,
message_id: Option<&str>,
article_references: Option<&str>,
) -> Result<()> {
conn.execute(
"INSERT OR IGNORE INTO article_cache (group_name, article_id, subject, sender, date, message_id, article_references)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
params![
group,
article_id,
subject,
sender,
date,
message_id.unwrap_or(""),
article_references.unwrap_or(""),
],
)?;
Ok(())
}
pub fn load_unread_subjects(
conn: &Connection,
group: &str,
) -> Result<Vec<(String, String, String, String)>> {
let mut stmt = conn.prepare(
"SELECT article_id, subject, sender, date FROM article_cache
WHERE group_name = ?1 AND read_flag = 0
ORDER BY CAST(article_id AS INTEGER) DESC",
)?;
let rows = stmt
.query_map(params![group], |row| {
Ok((
row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?, ))
})?
.collect::<Result<Vec<_>, _>>()?;
Ok(rows)
}
pub fn mark_as_read(conn: &Connection, group: &str, id: &str) -> Result<(), rusqlite::Error> {
conn.execute(
"UPDATE article_cache SET read_flag = 1 WHERE group_name = ?1 AND article_id = ?2",
params![group, id],
)?;
Ok(())
}
pub fn mark_as_unread(conn: &Connection, group: &str, id: &str) -> Result<(), rusqlite::Error> {
conn.execute(
"UPDATE article_cache SET read_flag = 0 WHERE group_name = ?1 AND article_id = ?2",
params![group, id],
)?;
Ok(())
}
pub fn load_threadable_articles(
conn: &Connection,
group: &str,
) -> Result<Vec<FlatArticle>, rusqlite::Error> {
let mut stmt = conn.prepare(
"SELECT article_id, subject, sender, date, message_id, article_references FROM article_cache
WHERE group_name = ?1 AND read_flag = 0
ORDER BY CAST(article_id AS INTEGER) DESC",
)?;
let rows = stmt
.query_map(params![group], |row| {
Ok(FlatArticle {
article_id: row.get(0)?,
subject: row.get(1)?,
sender: row.get(2)?,
date: row.get(3)?,
message_id: row.get(4)?,
article_references: row.get(5)?,
})
})?
.collect::<Result<Vec<_>, _>>()?;
Ok(rows)
}