//! Single-column flag updates on an email: read/unread, archive, folder, body, //! project link, labels, plus the unread count. use goingson_core::{CoreError, Email, EmailId, ProjectId, Result, UserId}; use rusqlite::{Connection, params}; use crate::utils::execute; use super::query; /// Mark one email read. Returns whether a row changed. pub(super) fn mark_read(conn: &Connection, id: EmailId, user_id: UserId) -> Result { let result = execute( conn, "UPDATE emails SET is_read = 1 WHERE id = ? AND user_id = ?", params![id.to_string(), user_id.to_string()], )?; Ok(result > 0) } /// Mark one email unread. Returns whether a row changed. pub(super) fn mark_unread(conn: &Connection, id: EmailId, user_id: UserId) -> Result { let result = execute( conn, "UPDATE emails SET is_read = 0 WHERE id = ? AND user_id = ?", params![id.to_string(), user_id.to_string()], )?; Ok(result > 0) } /// Archive one email. Returns whether a row changed. pub(super) fn archive(conn: &Connection, id: EmailId, user_id: UserId) -> Result { let result = execute( conn, "UPDATE emails SET is_archived = 1 WHERE id = ? AND user_id = ?", params![id.to_string(), user_id.to_string()], )?; Ok(result > 0) } /// Unarchive one email. Returns whether a row changed. pub(super) fn unarchive(conn: &Connection, id: EmailId, user_id: UserId) -> Result { let result = execute( conn, "UPDATE emails SET is_archived = 0 WHERE id = ? AND user_id = ?", params![id.to_string(), user_id.to_string()], )?; Ok(result > 0) } /// Repoint one email at a different IMAP folder. pub(super) fn update_source_folder( conn: &Connection, id: EmailId, user_id: UserId, new_folder: &str, ) -> Result { let result = execute( conn, "UPDATE emails SET source_folder = ? WHERE id = ? AND user_id = ?", params![new_folder, id.to_string(), user_id.to_string()], )?; Ok(result > 0) } /// Store a fetched full body and clear the truncated flag. pub(super) fn set_full_body( conn: &Connection, id: EmailId, user_id: UserId, body: &str, ) -> Result<()> { execute( conn, "UPDATE emails SET body = ?, body_truncated = 0 WHERE id = ? AND user_id = ?", params![body, id.to_string(), user_id.to_string()], )?; Ok(()) } /// Mark every unread email read. Returns how many changed. pub(super) fn mark_all_read(conn: &Connection, user_id: UserId) -> Result { let result = execute( conn, "UPDATE emails SET is_read = 1 WHERE user_id = ? AND is_read = 0", params![user_id.to_string()], )?; Ok(result as u64) } /// Link one email to a project, or clear the link with `None`. pub(super) fn link_to_project( conn: &Connection, id: EmailId, user_id: UserId, project_id: Option, ) -> Result { let result = execute( conn, "UPDATE emails SET project_id = ? WHERE id = ? AND user_id = ?", params![ project_id.map(|p| p.to_string()), id.to_string(), user_id.to_string() ], )?; Ok(result > 0) } /// How many unread emails the user has. pub(super) fn count_unread(conn: &Connection, user_id: UserId) -> Result { conn.query_row( "SELECT COUNT(*) FROM emails WHERE user_id = ? AND is_read = 0", params![user_id.to_string()], |row| row.get(0), ) .map_err(CoreError::database) } /// Replace one email's label set, returning the updated email. pub(super) fn update_labels( conn: &Connection, id: EmailId, user_id: UserId, labels: &[String], ) -> Result> { let labels_json = serde_json::to_string(labels).unwrap_or_else(|_| "[]".to_string()); let result = execute( conn, "UPDATE emails SET labels = ? WHERE id = ? AND user_id = ?", params![&labels_json, id.to_string(), user_id.to_string()], )?; if result > 0 { query::get_by_id(conn, id, user_id) } else { Ok(None) } }