1use chrono::{DateTime, Utc};
2use rusqlite::{params, OptionalExtension};
3
4use crate::{
5 manager::{PostArchiverConnection, PostArchiverManager},
6 AuthorId, CollectionId, Comment, Content, FileMetaId, PlatformId, Post, PostId, TagId,
7};
8
9impl<T> PostArchiverManager<T>
13where
14 T: PostArchiverConnection,
15{
16 pub fn list_posts(&self) -> Result<Vec<Post>, rusqlite::Error> {
22 let mut stmt = self.conn().prepare_cached("SELECT * FROM posts")?;
23 let posts = stmt.query_map([], Post::from_row)?;
24 posts.collect()
25 }
26
27 pub fn find_post(&self, source: &str) -> Result<Option<PostId>, rusqlite::Error> {
33 let mut stmt = self
34 .conn()
35 .prepare_cached("SELECT id FROM posts WHERE source = ?")?;
36
37 stmt.query_row(params![source], |row| row.get(0)).optional()
38 }
39
40 pub fn find_post_with_updated(
49 &self,
50 source: &str,
51 updated: &DateTime<Utc>,
52 ) -> Result<Option<PostId>, rusqlite::Error> {
53 let mut stmt = self
54 .conn()
55 .prepare_cached("SELECT id, updated FROM posts WHERE source = ?")?;
56
57 stmt.query_row::<(PostId, DateTime<Utc>), _, _>(params![source], |row| {
58 Ok((row.get_unwrap(0), row.get_unwrap(1)))
59 })
60 .optional()
61 .map(|query| {
62 query.and_then(|(id, last_update)| {
63 if &last_update >= updated {
64 Some(id)
65 } else {
66 None
67 }
68 })
69 })
70 }
71 pub fn get_post(&self, id: &PostId) -> Result<Post, rusqlite::Error> {
79 let mut stmt = self
80 .conn()
81 .prepare_cached("SELECT * FROM posts WHERE id = ?")?;
82
83 stmt.query_row([id], Post::from_row)
84 }
85}
86
87impl<T> PostArchiverManager<T>
91where
92 T: PostArchiverConnection,
93{
94 pub fn add_post(
102 &self,
103 title: String,
104 source: Option<String>,
105 platform: Option<PlatformId>,
106 published: Option<DateTime<Utc>>,
107 updated: Option<DateTime<Utc>>,
108 ) -> Result<PostId, rusqlite::Error> {
109 let mut stmt = self
110 .conn()
111 .prepare_cached(
112 "INSERT INTO posts (title, source, platform, published, updated) VALUES (?, ?, ?, ?, ?) RETURNING id",
113 )?;
114
115 stmt.query_row(
116 params![title, source, platform, published, updated],
117 |row| row.get(0),
118 )
119 }
120 pub fn remove_post(&self, post: PostId) -> Result<(), rusqlite::Error> {
128 let mut stmt = self
129 .conn()
130 .prepare_cached("DELETE FROM posts WHERE id = ?")?;
131 stmt.execute([post])?;
132 Ok(())
133 }
134 pub fn add_post_authors(
143 &self,
144 post: PostId,
145 authors: &[AuthorId],
146 ) -> Result<(), rusqlite::Error> {
147 let mut stmt = self
148 .conn()
149 .prepare_cached("INSERT OR IGNORE INTO author_posts (author, post) VALUES (?, ?)")?;
150 for author in authors {
151 stmt.execute(params![author, post])?;
152 }
153 Ok(())
154 }
155 pub fn remove_post_authors(
161 &self,
162 post: PostId,
163 authors: &[AuthorId],
164 ) -> Result<(), rusqlite::Error> {
165 let mut stmt = self
166 .conn()
167 .prepare_cached("DELETE FROM author_posts WHERE post = ? AND author = ?")?;
168 for author in authors {
169 stmt.execute(params![post, author])?;
170 }
171 Ok(())
172 }
173
174 pub fn add_post_tags(&self, post: PostId, tags: &[TagId]) -> Result<(), rusqlite::Error> {
183 let mut stmt = self
184 .conn()
185 .prepare_cached("INSERT OR IGNORE INTO post_tags (post, tag) VALUES (?, ?)")?;
186
187 for tag in tags {
188 stmt.execute(params![post, tag])?;
189 }
190 Ok(())
191 }
192
193 pub fn remove_post_tags(&self, post: PostId, tags: &[TagId]) -> Result<(), rusqlite::Error> {
199 let mut stmt = self
200 .conn()
201 .prepare_cached("DELETE FROM post_tags WHERE post = ? AND tag = ?")?;
202 for tag in tags {
203 stmt.execute(params![post, tag])?;
204 }
205 Ok(())
206 }
207 pub fn add_post_collections(
216 &self,
217 post: PostId,
218 collections: &[CollectionId],
219 ) -> Result<(), rusqlite::Error> {
220 let mut stmt = self.conn().prepare_cached(
221 "INSERT OR IGNORE INTO collection_posts (collection, post) VALUES (?, ?)",
222 )?;
223
224 for collection in collections {
225 stmt.execute(params![collection, post])?;
226 }
227 Ok(())
228 }
229
230 pub fn remove_post_collections(
236 &self,
237 post: PostId,
238 collections: &[CollectionId],
239 ) -> Result<(), rusqlite::Error> {
240 let mut stmt = self
241 .conn()
242 .prepare_cached("DELETE FROM collection_posts WHERE collection = ? AND post = ?")?;
243 for collection in collections {
244 stmt.execute(params![collection, post])?;
245 }
246 Ok(())
247 }
248 pub fn set_post_source(
256 &self,
257 post: PostId,
258 source: Option<String>,
259 ) -> Result<(), rusqlite::Error> {
260 let mut stmt = self
261 .conn()
262 .prepare_cached("UPDATE posts SET source = ? WHERE id = ?")?;
263 stmt.execute(params![source, post])?;
264 Ok(())
265 }
266 pub fn set_post_platform(
274 &self,
275 post: PostId,
276 platform: Option<PlatformId>,
277 ) -> Result<(), rusqlite::Error> {
278 let mut stmt = self
279 .conn()
280 .prepare_cached("UPDATE posts SET platform = ? WHERE id = ?")?;
281 stmt.execute(params![platform, post])?;
282 Ok(())
283 }
284 pub fn set_post_title(&self, post: PostId, title: String) -> Result<(), rusqlite::Error> {
292 let mut stmt = self
293 .conn()
294 .prepare_cached("UPDATE posts SET title = ? WHERE id = ?")?;
295 stmt.execute(params![title, post])?;
296 Ok(())
297 }
298
299 pub fn set_post_thumb(
307 &self,
308 post: PostId,
309 thumb: Option<FileMetaId>,
310 ) -> Result<(), rusqlite::Error> {
311 let mut stmt = self
312 .conn()
313 .prepare_cached("UPDATE posts SET thumb = ? WHERE id = ?")?;
314 stmt.execute(params![thumb, post])?;
315 Ok(())
316 }
317
318 pub fn set_post_content(
326 &self,
327 post: PostId,
328 content: Vec<Content>,
329 ) -> Result<(), rusqlite::Error> {
330 let content = serde_json::to_string(&content).unwrap();
331
332 let mut stmt = self
333 .conn()
334 .prepare_cached("UPDATE posts SET content = ? WHERE id = ?")?;
335
336 stmt.execute(params![content, post])?;
337 Ok(())
338 }
339 pub fn set_post_comments(
345 &self,
346 post: PostId,
347 comments: Vec<Comment>,
348 ) -> Result<(), rusqlite::Error> {
349 let comments = serde_json::to_string(&comments).unwrap();
350
351 let mut stmt = self
352 .conn()
353 .prepare_cached("UPDATE posts SET comments = ? WHERE id = ?")?;
354 stmt.execute(params![comments, post])?;
355 Ok(())
356 }
357 pub fn set_post_published(
363 &self,
364 post: PostId,
365 published: DateTime<Utc>,
366 ) -> Result<(), rusqlite::Error> {
367 let mut stmt = self
368 .conn()
369 .prepare_cached("UPDATE posts SET published = ? WHERE id = ?")?;
370 stmt.execute(params![published, post])?;
371 Ok(())
372 }
373 pub fn set_post_updated(
379 &self,
380 post: PostId,
381 updated: DateTime<Utc>,
382 ) -> Result<(), rusqlite::Error> {
383 let mut stmt = self
384 .conn()
385 .prepare_cached("UPDATE posts SET updated = ? WHERE id = ?")?;
386 stmt.execute(params![updated, post])?;
387 Ok(())
388 }
389 pub fn set_post_updated_by_latest(
395 &self,
396 post: PostId,
397 updated: DateTime<Utc>,
398 ) -> Result<(), rusqlite::Error> {
399 let mut stmt = self
400 .conn()
401 .prepare_cached("UPDATE posts SET updated = ? WHERE id = ? AND updated < ?")?;
402 stmt.execute(params![updated, post, updated])?;
403 Ok(())
404 }
405}