termusiclib/podcast/db/
podcast_db.rs1use chrono::{DateTime, Utc};
2use indoc::indoc;
3use rusqlite::{Connection, Row, named_params, params};
4
5use super::{PodcastDBId, convert_date};
6use crate::podcast::PodcastNoId;
7
8#[derive(Debug, Clone)]
10pub struct PodcastDB {
11 pub id: PodcastDBId,
12 pub title: String,
13 pub url: String,
14 pub description: Option<String>,
15 pub author: Option<String>,
16 pub explicit: Option<bool>,
17 pub last_checked: DateTime<Utc>,
18 pub image_url: Option<String>,
19}
20
21impl PodcastDB {
22 pub fn try_from_row_named(row: &Row<'_>) -> Result<Self, rusqlite::Error> {
24 let last_checked =
26 convert_date(&row.get("last_checked")).ok_or(rusqlite::Error::InvalidQuery)?;
27 Ok(PodcastDB {
28 id: row.get("id")?,
29 title: row.get("title")?,
30 url: row.get("url")?,
31 description: row.get("description")?,
32 author: row.get("author")?,
33 explicit: row.get("explicit")?,
34 last_checked,
35 image_url: row.get("image_url")?,
36 })
37 }
38}
39
40#[derive(Debug, Clone)]
44pub struct PodcastDBInsertable<'a> {
45 pub title: &'a str,
48 pub url: &'a str,
49 pub description: Option<&'a str>,
50 pub author: Option<&'a str>,
51 pub explicit: Option<bool>,
52 pub last_checked: DateTime<Utc>,
53 pub image_url: Option<&'a str>,
54}
55
56impl<'a> From<&'a PodcastNoId> for PodcastDBInsertable<'a> {
57 fn from(value: &'a PodcastNoId) -> Self {
58 Self {
59 title: &value.title,
60 url: &value.url,
61 description: value.description.as_deref(),
62 author: value.author.as_deref(),
63 explicit: value.explicit,
64 last_checked: value.last_checked,
65 image_url: value.image_url.as_deref(),
66 }
67 }
68}
69
70impl PodcastDBInsertable<'_> {
71 #[inline]
73 pub fn insert_podcast(&self, con: &Connection) -> Result<usize, rusqlite::Error> {
74 let mut stmt = con.prepare_cached(indoc! {"
75 INSERT INTO podcasts (title, url, description, author, explicit, last_checked, image_url)
76 VALUES (:title, :url, :description, :author, :explicit, :last_checked, :image_url);
77 "})?;
78 stmt.execute(named_params![
79 ":title": self.title,
80 ":url": self.url,
81 ":description": self.description,
82 ":author": self.author,
83 ":explicit": self.explicit,
84 ":last_checked": self.last_checked.timestamp(),
85 ":image_url": self.image_url
86 ])
87 }
88
89 #[inline]
91 pub fn update_podcast(
92 &self,
93 id: PodcastDBId,
94 con: &Connection,
95 ) -> Result<usize, rusqlite::Error> {
96 let mut stmt = con.prepare_cached(indoc! {"
97 UPDATE podcasts SET title = :title, url = :url, description = :description,
98 author = :author, explicit = :explicit, last_checked = :last_checked
99 WHERE id = :id;
100 "})?;
101 stmt.execute(named_params![
102 ":title": self.title,
103 ":url": self.url,
104 ":description": self.description,
105 ":author": self.author,
106 ":explicit": self.explicit,
107 ":last_checked": self.last_checked.timestamp(),
108 ":id": id,
109 ])
110 }
111}
112
113pub fn delete_podcast(id: PodcastDBId, con: &Connection) -> Result<usize, rusqlite::Error> {
117 let mut stmt = con.prepare_cached("DELETE FROM podcasts WHERE id = ?;")?;
122 stmt.execute(params![id])
123}