post_archiver/manager/file_meta.rs
1use std::collections::HashMap;
2
3use rusqlite::{params, OptionalExtension};
4use serde_json::Value;
5
6use crate::{
7 manager::{PostArchiverConnection, PostArchiverManager},
8 FileMeta, FileMetaId, PostId,
9};
10
11//=============================================================
12// Querying
13//=============================================================
14impl<T> PostArchiverManager<T>
15where
16 T: PostArchiverConnection,
17{
18 /// Find a file's metadata by its post ID and filename.
19 ///
20 /// # Errors
21 ///
22 /// Returns `rusqlite::Error` if there was an error accessing the database.
23 pub fn find_file_meta(
24 &self,
25 post: PostId,
26 filename: &str,
27 ) -> Result<Option<FileMetaId>, rusqlite::Error> {
28 let mut stmt = self
29 .conn()
30 .prepare_cached("SELECT id FROM file_metas WHERE post = ? AND filename = ?")?;
31
32 stmt.query_row(params![post, filename], |row| row.get(0))
33 .optional()
34 }
35 /// Retrieve a file's metadata by its ID.
36 ///
37 /// Fetches all information about the file including its post ID, filename, MIME type, and extra metadata.
38 ///
39 /// # Errors
40 ///
41 /// Returns `rusqlite::Error` if:
42 /// * The file ID does not exist
43 /// * There was an error accessing the database
44 pub fn get_file_meta(&self, id: &FileMetaId) -> Result<FileMeta, rusqlite::Error> {
45 let mut stmt = self
46 .conn()
47 .prepare_cached("SELECT * FROM file_metas WHERE id = ?")?;
48 stmt.query_row([id], FileMeta::from_row)
49 }
50}
51
52//=============================================================
53// Modifying
54//=============================================================
55impl<T> PostArchiverManager<T>
56where
57 T: PostArchiverConnection,
58{
59 /// Add a new file metadata to the archive.
60 ///
61 /// Inserts a new file metadata with the given post ID, filename, MIME type, and extra metadata.
62 /// It will check if a file with the same post and filename already exists.
63 ///
64 /// # Errors
65 ///
66 /// Returns `rusqlite::Error` if:
67 /// * The post ID does not exist
68 /// * Duplicate filename for the same post
69 /// * There was an error accessing the database
70 pub fn add_file_meta(
71 &self,
72 post: PostId,
73 filename: String,
74 mime: String,
75 extra: HashMap<String, Value>,
76 ) -> Result<FileMetaId, rusqlite::Error> {
77 let mut stmt = self.conn().prepare_cached(
78 "INSERT INTO file_metas (post, filename, mime, extra) VALUES (?, ?, ?, ?) RETURNING id",
79 )?;
80 stmt.query_row(
81 params![post, filename, mime, serde_json::to_string(&extra).unwrap()],
82 |row| row.get(0),
83 )
84 }
85 /// Remove a file metadata from the archive.
86 ///
87 /// This operation will also remove all associated thumb references.
88 /// But it will not delete post.content related to this file.
89 ///
90 /// # Errors
91 ///
92 /// Returns `rusqlite::Error` if there was an error accessing the database.
93 pub fn remove_file_meta(&self, id: FileMetaId) -> Result<(), rusqlite::Error> {
94 let mut stmt = self
95 .conn()
96 .prepare_cached("DELETE FROM file_metas WHERE id = ?")?;
97 stmt.execute([id])?;
98 Ok(())
99 }
100
101 /// Set the filename of a file metadata.
102 ///
103 /// # Errors
104 ///
105 /// Returns `rusqlite::Error` if there was an error accessing the database.
106 pub fn set_file_meta_mime(&self, id: FileMetaId, mime: String) -> Result<(), rusqlite::Error> {
107 let mut stmt = self
108 .conn()
109 .prepare_cached("UPDATE file_metas SET mime = ? WHERE id = ?")?;
110 stmt.execute(params![mime, id])?;
111 Ok(())
112 }
113
114 /// Set the extra metadata of a file metadata.
115 ///
116 /// # Errors
117 ///
118 /// Returns `rusqlite::Error` if there was an error accessing the database.
119 pub fn set_file_meta_extra(
120 &self,
121 id: FileMetaId,
122 extra: HashMap<String, Value>,
123 ) -> Result<(), rusqlite::Error> {
124 let extra_json = serde_json::to_string(&extra).unwrap();
125 let mut stmt = self
126 .conn()
127 .prepare_cached("UPDATE file_metas SET extra = ? WHERE id = ?")?;
128 stmt.execute(params![extra_json, id])?;
129 Ok(())
130 }
131
132 // TODO: implement a method to update the filename or post of a file_meta (because these need
133 // fs renames and moves)
134}