Skip to content

Commit 3038016

Browse files
feat(Database): add functions to delete manga from history
1 parent 97dca35 commit 3038016

2 files changed

Lines changed: 322 additions & 15 deletions

File tree

src/backend/database.rs

Lines changed: 299 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use chrono::Utc;
22
use manga_tui::SearchTerm;
3-
use rusqlite::{Connection, OptionalExtension, params};
3+
use rusqlite::types::ToSqlOutput;
4+
use rusqlite::{Connection, OptionalExtension, ToSql, params};
45
use strum::{Display, EnumIter};
56

67
use super::AppDirectories;
@@ -13,6 +14,14 @@ pub enum MangaHistoryType {
1314
ReadingHistory,
1415
}
1516

17+
impl ToSql for MangaHistoryType {
18+
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
19+
let as_string = self.to_string();
20+
21+
Ok(ToSqlOutput::from(as_string))
22+
}
23+
}
24+
1625
impl From<FeedTabs> for MangaHistoryType {
1726
fn from(value: FeedTabs) -> Self {
1827
match value {
@@ -77,6 +86,7 @@ pub struct MangaHistoryResponse {
7786
pub total_items: u32,
7887
}
7988

89+
#[derive(Debug)]
8090
pub struct GetHistoryArgs {
8191
pub hist_type: MangaHistoryType,
8292
pub page: u32,
@@ -107,7 +117,7 @@ pub struct SetChapterDownloaded<'a> {
107117

108118
// First check if the chapters is already in the database, if not insert it, or else update and set
109119
// its download status to true
110-
120+
#[derive(Debug)]
111121
pub struct Database<'a> {
112122
connection: &'a Connection,
113123
}
@@ -193,6 +203,7 @@ impl<'a> Database<'a> {
193203
Ok(())
194204
}
195205

206+
#[inline]
196207
pub fn get_connection() -> rusqlite::Result<Connection> {
197208
if cfg!(test) { Connection::open_in_memory() } else { Connection::open(AppDirectories::History.get_full_path()) }
198209
}
@@ -349,7 +360,7 @@ impl<'a> Database<'a> {
349360
}
350361

351362
/// Insert a manga in the reading history type or update the `last_read` field
352-
fn update_or_insert_manga_most_recent_read(&self, manga_id: &str) -> rusqlite::Result<()> {
363+
fn update_or_insert_manga_in_most_recent_reading_history(&self, manga_id: &str) -> rusqlite::Result<()> {
353364
if !self.manga_is_reading(manga_id)? {
354365
self.insert_manga_in_reading_history(manga_id)?;
355366
Ok(())
@@ -363,7 +374,7 @@ impl<'a> Database<'a> {
363374

364375
pub fn set_chapter_downloaded(&self, chapter: SetChapterDownloaded<'_>) -> rusqlite::Result<()> {
365376
if self.check_exists(chapter.manga_id, Table::Mangas)? {
366-
self.update_or_insert_manga_most_recent_read(chapter.manga_id)?;
377+
self.update_or_insert_manga_in_most_recent_reading_history(chapter.manga_id)?;
367378

368379
if self.check_exists(chapter.id, Table::Chapters)? {
369380
self.connection
@@ -434,13 +445,7 @@ impl<'a> Database<'a> {
434445
number_page_bookmarked: None,
435446
})?;
436447

437-
if !self.manga_is_reading(data.id)? {
438-
self.insert_manga_in_reading_history(data.id)?;
439-
} else {
440-
let now = Utc::now().naive_utc();
441-
self.connection
442-
.execute("UPDATE mangas SET last_read = ?1 WHERE id = ?2", params![now.to_string(), data.id])?;
443-
}
448+
self.update_or_insert_manga_in_most_recent_reading_history(data.id)?;
444449

445450
self.connection
446451
.execute("UPDATE chapters SET is_read = true WHERE id = ?1", params![data.chapter.id])?;
@@ -466,8 +471,6 @@ impl<'a> Database<'a> {
466471

467472
self.connection
468473
.execute("INSERT INTO manga_history_union VALUES (?1, ?2)", (manga.id, history_type))?;
469-
470-
return Ok(());
471474
}
472475
Ok(())
473476
}
@@ -608,6 +611,30 @@ impl<'a> Database<'a> {
608611
page: args.page,
609612
})
610613
}
614+
615+
pub fn remove_from_history(&self, manga_id: &str) -> rusqlite::Result<()> {
616+
self.connection
617+
.execute("DELETE FROM manga_history_union WHERE manga_history_union.manga_id = ?1", params![manga_id])?;
618+
619+
Ok(())
620+
}
621+
622+
pub fn remove_all_from_history(&self, hist_type: MangaHistoryType, provider: MangaProviders) -> rusqlite::Result<()> {
623+
let history_type_id = self.get_history_type(hist_type)?;
624+
625+
let get_ids_manga_to_delete_statement = r#"SELECT mangas.id from mangas
626+
INNER JOIN manga_history_union ON mangas.id = manga_history_union.manga_id
627+
WHERE manga_history_union.type_id = ?1 AND mangas.manga_provider = ?2
628+
"#;
629+
630+
let delete_statement =
631+
format!("DELETE FROM manga_history_union WHERE manga_history_union.manga_id IN ({get_ids_manga_to_delete_statement})");
632+
633+
self.connection
634+
.execute(&delete_statement, params![history_type_id, provider.to_string()])?;
635+
636+
Ok(())
637+
}
611638
}
612639

613640
#[derive(Default, Debug, Clone)]
@@ -666,6 +693,8 @@ impl<'a> RetrieveBookmark for Database<'a> {
666693
#[cfg(test)]
667694
mod test {
668695

696+
use std::error::Error;
697+
669698
use pretty_assertions::assert_eq;
670699
use rusqlite::Result;
671700
use strum::IntoEnumIterator;
@@ -1664,4 +1693,261 @@ mod test {
16641693

16651694
Ok(())
16661695
}
1696+
1697+
#[test]
1698+
fn it_deletes_a_manga_from_reading_history() -> Result<(), Box<dyn Error>> {
1699+
let connection = Database::get_connection()?;
1700+
let database = Database::new(&connection);
1701+
database.setup()?;
1702+
1703+
let manga_id_mangadex = Uuid::new_v4().to_string();
1704+
let manga_id_mangadex2 = Uuid::new_v4().to_string();
1705+
1706+
database.create_manga_if_not_exists(MangaInsert {
1707+
id: &manga_id_mangadex,
1708+
title: "of mangadex 1",
1709+
img_url: None,
1710+
provider: MangaProviders::Mangadex,
1711+
})?;
1712+
1713+
database.insert_manga_in_reading_history(&manga_id_mangadex)?;
1714+
1715+
database.create_manga_if_not_exists(MangaInsert {
1716+
id: &manga_id_mangadex2,
1717+
title: "of mangadex 2",
1718+
img_url: None,
1719+
provider: MangaProviders::Mangadex,
1720+
})?;
1721+
1722+
database.insert_manga_in_reading_history(&manga_id_mangadex2)?;
1723+
1724+
let expected = database.get_history(GetHistoryArgs {
1725+
hist_type: MangaHistoryType::ReadingHistory,
1726+
page: 1,
1727+
search: None,
1728+
items_per_page: 10,
1729+
provider: MangaProviders::Mangadex,
1730+
})?;
1731+
1732+
/* at this point 2 mangas must be stored in reading history */
1733+
assert_eq!(expected.mangas.len(), 2);
1734+
1735+
database.remove_from_history(&manga_id_mangadex)?;
1736+
1737+
let expected = database.get_history(GetHistoryArgs {
1738+
hist_type: MangaHistoryType::ReadingHistory,
1739+
page: 1,
1740+
search: None,
1741+
items_per_page: 10,
1742+
provider: MangaProviders::Mangadex,
1743+
})?;
1744+
1745+
/* now only one should exist */
1746+
assert_eq!(expected.mangas.len(), 1);
1747+
1748+
Ok(())
1749+
}
1750+
1751+
#[test]
1752+
fn it_deletes_a_manga_from_plan_to_read() -> Result<(), Box<dyn Error>> {
1753+
let connection = Database::get_connection()?;
1754+
let database = Database::new(&connection);
1755+
database.setup()?;
1756+
1757+
let manga_id_mangadex = Uuid::new_v4().to_string();
1758+
let manga_id_mangadex2 = Uuid::new_v4().to_string();
1759+
1760+
database.save_plan_to_read(MangaPlanToReadSave {
1761+
id: &manga_id_mangadex,
1762+
title: "of mangadex 1",
1763+
img_url: None,
1764+
provider: MangaProviders::Mangadex,
1765+
})?;
1766+
1767+
database.insert_manga_in_reading_history(&manga_id_mangadex)?;
1768+
1769+
database.save_plan_to_read(MangaPlanToReadSave {
1770+
id: &manga_id_mangadex2,
1771+
title: "of mangadex 2",
1772+
img_url: None,
1773+
provider: MangaProviders::Mangadex,
1774+
})?;
1775+
1776+
database.insert_manga_in_reading_history(&manga_id_mangadex2)?;
1777+
1778+
let expected = database.get_history(GetHistoryArgs {
1779+
hist_type: MangaHistoryType::PlanToRead,
1780+
page: 1,
1781+
search: None,
1782+
items_per_page: 10,
1783+
provider: MangaProviders::Mangadex,
1784+
})?;
1785+
1786+
/* at this point 2 mangas must be stored in reading history */
1787+
assert_eq!(expected.mangas.len(), 2);
1788+
1789+
database.remove_from_history(&manga_id_mangadex)?;
1790+
1791+
let expected = database.get_history(GetHistoryArgs {
1792+
hist_type: MangaHistoryType::PlanToRead,
1793+
page: 1,
1794+
search: None,
1795+
items_per_page: 10,
1796+
provider: MangaProviders::Mangadex,
1797+
})?;
1798+
1799+
/* now only one should exist */
1800+
assert_eq!(expected.mangas.len(), 1);
1801+
1802+
Ok(())
1803+
}
1804+
1805+
#[test]
1806+
fn it_delets_all_mangas_from_history() -> Result<(), Box<dyn Error>> {
1807+
let connection = Database::get_connection()?;
1808+
let database = Database::new(&connection);
1809+
database.setup()?;
1810+
1811+
let manga_id_mangadex = Uuid::new_v4().to_string();
1812+
let manga_id_mangadex2 = Uuid::new_v4().to_string();
1813+
let manga_id_mangadex3 = Uuid::new_v4().to_string();
1814+
1815+
let manga_id_plan_to_read = Uuid::new_v4().to_string();
1816+
let manga_id_plan_to_read2 = Uuid::new_v4().to_string();
1817+
1818+
let manga_id_weeb_central = Uuid::new_v4().to_string();
1819+
let manga_id_weeb_centra2 = Uuid::new_v4().to_string();
1820+
1821+
database.create_manga_if_not_exists(MangaInsert {
1822+
id: &manga_id_mangadex,
1823+
title: "of mangadex 1",
1824+
img_url: None,
1825+
provider: MangaProviders::Mangadex,
1826+
})?;
1827+
1828+
database.insert_manga_in_reading_history(&manga_id_mangadex)?;
1829+
1830+
database.create_manga_if_not_exists(MangaInsert {
1831+
id: &manga_id_mangadex2,
1832+
title: "of mangadex 2",
1833+
img_url: None,
1834+
provider: MangaProviders::Mangadex,
1835+
})?;
1836+
1837+
database.insert_manga_in_reading_history(&manga_id_mangadex2)?;
1838+
1839+
database.create_manga_if_not_exists(MangaInsert {
1840+
id: &manga_id_mangadex3,
1841+
title: "of mangadex 3",
1842+
img_url: None,
1843+
provider: MangaProviders::Mangadex,
1844+
})?;
1845+
1846+
database.insert_manga_in_reading_history(&manga_id_mangadex3)?;
1847+
1848+
database.create_manga_if_not_exists(MangaInsert {
1849+
id: &manga_id_weeb_central,
1850+
title: "of weebcentral",
1851+
img_url: None,
1852+
provider: MangaProviders::Weebcentral,
1853+
})?;
1854+
1855+
database.insert_manga_in_reading_history(&manga_id_weeb_central)?;
1856+
1857+
database.create_manga_if_not_exists(MangaInsert {
1858+
id: &manga_id_weeb_centra2,
1859+
title: "of weebcentral #2",
1860+
img_url: None,
1861+
provider: MangaProviders::Weebcentral,
1862+
})?;
1863+
1864+
database.insert_manga_in_reading_history(&manga_id_weeb_centra2)?;
1865+
1866+
let expected = database.get_history(GetHistoryArgs {
1867+
hist_type: MangaHistoryType::ReadingHistory,
1868+
page: 1,
1869+
search: None,
1870+
items_per_page: 10,
1871+
provider: MangaProviders::Mangadex,
1872+
})?;
1873+
1874+
/* at this point 3 mangas must be stored in reading history */
1875+
assert_eq!(expected.mangas.len(), 3);
1876+
1877+
database.create_manga_if_not_exists(MangaInsert {
1878+
id: &manga_id_plan_to_read,
1879+
title: "of mangadex 1",
1880+
img_url: None,
1881+
provider: MangaProviders::Mangadex,
1882+
})?;
1883+
1884+
database.save_plan_to_read(MangaPlanToReadSave {
1885+
id: &manga_id_plan_to_read,
1886+
title: "of mangadex 1 plan to read",
1887+
img_url: None,
1888+
provider: MangaProviders::Mangadex,
1889+
})?;
1890+
1891+
database.create_manga_if_not_exists(MangaInsert {
1892+
id: &manga_id_plan_to_read2,
1893+
title: "of mangadex 1",
1894+
img_url: None,
1895+
provider: MangaProviders::Mangadex,
1896+
})?;
1897+
1898+
database.save_plan_to_read(MangaPlanToReadSave {
1899+
id: &manga_id_plan_to_read2,
1900+
title: "of mangadex 2 plan to read",
1901+
img_url: None,
1902+
provider: MangaProviders::Mangadex,
1903+
})?;
1904+
1905+
let expected = database.get_history(GetHistoryArgs {
1906+
hist_type: MangaHistoryType::PlanToRead,
1907+
page: 1,
1908+
search: None,
1909+
items_per_page: 10,
1910+
provider: MangaProviders::Mangadex,
1911+
})?;
1912+
1913+
/* at this point 2 mangas in plant to read should exist */
1914+
assert_eq!(expected.mangas.len(), 2);
1915+
1916+
database.remove_all_from_history(MangaHistoryType::ReadingHistory, MangaProviders::Mangadex)?;
1917+
1918+
let expected = database.get_history(GetHistoryArgs {
1919+
hist_type: MangaHistoryType::ReadingHistory,
1920+
page: 1,
1921+
search: None,
1922+
items_per_page: 10,
1923+
provider: MangaProviders::Mangadex,
1924+
})?;
1925+
1926+
/* now none from mangadex should exist */
1927+
assert_eq!(expected.mangas.len(), 0);
1928+
1929+
let expected = database.get_history(GetHistoryArgs {
1930+
hist_type: MangaHistoryType::ReadingHistory,
1931+
page: 1,
1932+
search: None,
1933+
items_per_page: 10,
1934+
provider: MangaProviders::Weebcentral,
1935+
})?;
1936+
1937+
/* weebcentral reading history should remain untouched */
1938+
assert_eq!(expected.mangas.len(), 2);
1939+
1940+
let expected = database.get_history(GetHistoryArgs {
1941+
hist_type: MangaHistoryType::PlanToRead,
1942+
page: 1,
1943+
search: None,
1944+
items_per_page: 10,
1945+
provider: MangaProviders::Mangadex,
1946+
})?;
1947+
1948+
/* the plan to read history should remain untouched */
1949+
assert_eq!(expected.mangas.len(), 2);
1950+
1951+
Ok(())
1952+
}
16671953
}

0 commit comments

Comments
 (0)