post_archiver/manager/
tag.rs1use rusqlite::{params, OptionalExtension};
2
3use crate::{PlatformId, Post, PostId, Tag, TagId};
4
5use super::{PostArchiverConnection, PostArchiverManager};
6
7impl<T> PostArchiverManager<T>
11where
12 T: PostArchiverConnection,
13{
14 pub fn list_tags(&self) -> Result<Vec<Tag>, rusqlite::Error> {
20 let mut stmt = self.conn().prepare_cached("SELECT * FROM tags")?;
21 let tags = stmt.query_map([], Tag::from_row)?;
22 tags.collect()
23 }
24
25 pub fn find_tag<U: FindTag>(&self, tag: &U) -> Result<Option<TagId>, rusqlite::Error> {
44 let name = tag.name().to_string();
45 let platform = tag.platform();
46
47 let cache_key = (name.clone(), platform);
48 if let Some(id) = self.cache.tags.get(&cache_key) {
49 return Ok(Some(*id));
50 }
51
52 let mut stmt = self
53 .conn()
54 .prepare_cached("SELECT id FROM tags WHERE platform IS ? AND name = ?")?;
55
56 let id = stmt
57 .query_row(params![platform, name], |row| row.get(0))
58 .optional();
59
60 if let Ok(Some(id)) = id {
61 self.cache.tags.insert(cache_key, id);
62 }
63
64 id
65 }
66
67 pub fn get_tag(&self, tag: &TagId) -> Result<Option<Tag>, rusqlite::Error> {
75 let mut stmt = self
76 .conn()
77 .prepare_cached("SELECT * FROM tags WHERE id = ?")?;
78
79 stmt.query_row([tag], Tag::from_row).optional()
80 }
81}
82
83pub trait FindTag {
84 fn name(&self) -> &str;
85 fn platform(&self) -> Option<PlatformId> {
86 None
87 }
88}
89
90impl FindTag for &str {
91 fn name(&self) -> &str {
92 self
93 }
94}
95
96impl FindTag for (&str, PlatformId) {
97 fn name(&self) -> &str {
98 self.0
99 }
100 fn platform(&self) -> Option<PlatformId> {
101 Some(self.1)
102 }
103}
104
105impl FindTag for (&str, Option<PlatformId>) {
106 fn name(&self) -> &str {
107 self.0
108 }
109 fn platform(&self) -> Option<PlatformId> {
110 self.1
111 }
112}
113
114impl<T> PostArchiverManager<T>
118where
119 T: PostArchiverConnection,
120{
121 pub fn add_tag(
129 &self,
130 name: String,
131 platform: Option<PlatformId>,
132 ) -> Result<TagId, rusqlite::Error> {
133 let cache_key = (name.clone(), platform);
134 if let Some(id) = self.cache.tags.get(&cache_key) {
135 return Ok(*id);
136 }
137
138 let mut stmt = self
139 .conn()
140 .prepare_cached("INSERT INTO tags (name, platform) VALUES (?, ?) RETURNING id")?;
141
142 let id = stmt.query_row(params![name, platform], |row| row.get(0))?;
143
144 self.cache.tags.insert(cache_key, id);
145
146 Ok(id)
147 }
148
149 pub fn remove_tag(&self, tag: &TagId) -> Result<(), rusqlite::Error> {
159 let mut stmt = self
160 .conn()
161 .prepare_cached("DELETE FROM tags WHERE id = ?")?;
162
163 stmt.execute([tag])?;
164 Ok(())
165 }
166
167 pub fn set_tag_name(&self, tag: &TagId, name: String) -> Result<(), rusqlite::Error> {
173 let mut stmt = self
174 .conn()
175 .prepare_cached("UPDATE tags SET name = ? WHERE id = ? RETURNING platform")?;
176
177 let platform: Option<PlatformId> = stmt.query_row(params![name, tag], |row| row.get(0))?;
178 self.cache.tags.insert((name, platform), *tag);
179 Ok(())
180 }
181
182 pub fn set_tag_platform(
188 &self,
189 tag: &TagId,
190 platform: Option<PlatformId>,
191 ) -> Result<(), rusqlite::Error> {
192 let mut stmt = self
193 .conn()
194 .prepare_cached("UPDATE tags SET platform = ? WHERE id = ? RETURNING name")?;
195
196 let name: String = stmt.query_row(params![platform, tag], |row| row.get(0))?;
197 self.cache.tags.insert((name, platform), *tag);
198 Ok(())
199 }
200}
201
202impl<T> PostArchiverManager<T>
206where
207 T: PostArchiverConnection,
208{
209 pub fn list_post_tags(&self, post: &PostId) -> Result<Vec<Tag>, rusqlite::Error> {
215 let mut stmt = self
216 .conn()
217 .prepare_cached("SELECT tags.* FROM tags INNER JOIN post_tags ON post_tags.tag = tags.id WHERE post_tags.post = ?")?;
218 let tags = stmt.query_map([post], Tag::from_row)?;
219 tags.collect()
220 }
221
222 pub fn list_tag_posts(&self, tag: &TagId) -> Result<Vec<Post>, rusqlite::Error> {
228 let mut stmt = self
229 .conn()
230 .prepare_cached("SELECT posts.* FROM posts INNER JOIN post_tags ON post_tags.post = posts.id WHERE post_tags.tag = ?")?;
231 let posts = stmt.query_map([tag], Post::from_row)?;
232 posts.collect()
233 }
234}
235
236impl Post {
237 pub fn tags(&self, manager: &PostArchiverManager) -> Result<Vec<Tag>, rusqlite::Error> {
243 manager.list_post_tags(&self.id)
244 }
245}
246
247impl Tag {
248 pub fn posts(&self, manager: &PostArchiverManager) -> Result<Vec<Post>, rusqlite::Error> {
254 manager.list_tag_posts(&self.id)
255 }
256}