Skip to main content

post_archiver/importer/
file_meta.rs

1use std::{collections::HashMap, hash::Hash};
2
3use rusqlite::params;
4use serde_json::Value;
5
6use crate::{
7    error::Result,
8    manager::{
9        file_meta::FileMetaContent, PostArchiverConnection, PostArchiverManager, UpdateFileMeta,
10    },
11    FileMetaId, Post, PostId,
12};
13
14impl<T> PostArchiverManager<T>
15where
16    T: PostArchiverConnection,
17{
18    /// Create or update a file metadata entry in the archive.
19    ///
20    /// Takes a file metadata object and either creates a new entry or updates an existing one.
21    /// if a file metadata with the same filename (and post id) already exists, it only updates metadata
22    ///
23    /// # Errors
24    ///
25    /// Returns `Error` if there was an error accessing the database.
26    pub fn import_file_meta(&self, post: PostId, file_meta: &UnsyncFileMeta) -> Result<FileMetaId> {
27        // find
28        if let Some(id) = self.find_file_meta(post, &file_meta.filename)? {
29            // update extra
30            self.bind(id)
31                .update(UpdateFileMeta::default().extra(file_meta.extra.clone()))?;
32            return Ok(id);
33        }
34
35        let path = self.path.join(Post::directory(post));
36        if !path.exists() {
37            std::fs::create_dir_all(&path)?;
38        }
39        file_meta.data.write(&path.join(&file_meta.filename))?;
40
41        // insert
42        let mut ins_stmt = self.conn().prepare_cached(
43            "INSERT INTO file_metas (post, filename, mime, extra) VALUES (?, ?, ?, ?) RETURNING id",
44        )?;
45        Ok(ins_stmt.query_row(
46            params![
47                post,
48                file_meta.filename,
49                file_meta.mime,
50                serde_json::to_string(&file_meta.extra).unwrap()
51            ],
52            |row| row.get(0),
53        )?)
54    }
55}
56
57/// Represents a file metadata that is not yet synced to the database.
58#[derive(Debug, Clone)]
59pub struct UnsyncFileMeta {
60    pub filename: String,
61    pub mime: String,
62    pub extra: HashMap<String, Value>,
63    pub data: FileMetaContent,
64}
65
66impl Hash for UnsyncFileMeta {
67    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
68        self.filename.hash(state);
69        self.mime.hash(state);
70    }
71}
72
73impl PartialEq for UnsyncFileMeta {
74    fn eq(&self, other: &Self) -> bool {
75        self.filename == other.filename && self.mime == other.mime && self.extra == other.extra
76    }
77}
78
79impl Eq for UnsyncFileMeta {}
80
81impl UnsyncFileMeta {
82    pub fn new(filename: String, mime: String, data: FileMetaContent) -> Self {
83        Self {
84            filename,
85            mime,
86            data: data.into(),
87            extra: HashMap::new(),
88        }
89    }
90
91    pub fn extra(mut self, extra: HashMap<String, Value>) -> Self {
92        self.extra = extra;
93        self
94    }
95}