Skip to main content

mxr_store/
body.rs

1use mxr_core::id::*;
2use mxr_core::types::*;
3use sqlx::Row;
4
5impl super::Store {
6    pub async fn get_body(
7        &self,
8        message_id: &MessageId,
9    ) -> Result<Option<MessageBody>, sqlx::Error> {
10        let mid = message_id.as_str();
11        let row = sqlx::query(
12            r#"SELECT message_id, text_plain, text_html, fetched_at, metadata_json FROM bodies WHERE message_id = ?"#,
13        )
14        .bind(mid)
15        .fetch_optional(self.reader())
16        .await?;
17
18        let row = match row {
19            Some(r) => r,
20            None => return Ok(None),
21        };
22
23        let att_mid = message_id.as_str();
24        let attachments_rows = sqlx::query!(
25            r#"SELECT id as "id!", message_id as "message_id!", filename as "filename!", mime_type as "mime_type!", size_bytes as "size_bytes!", local_path, provider_id as "provider_id!" FROM attachments WHERE message_id = ?"#,
26            att_mid,
27        )
28        .fetch_all(self.reader())
29        .await?;
30
31        let attachments: Vec<AttachmentMeta> = attachments_rows
32            .into_iter()
33            .map(|r| AttachmentMeta {
34                id: AttachmentId::from_uuid(uuid::Uuid::parse_str(&r.id).unwrap()),
35                message_id: MessageId::from_uuid(uuid::Uuid::parse_str(&r.message_id).unwrap()),
36                filename: r.filename,
37                mime_type: r.mime_type,
38                size_bytes: r.size_bytes as u64,
39                local_path: r.local_path.map(std::path::PathBuf::from),
40                provider_id: r.provider_id,
41            })
42            .collect();
43
44        let metadata_json: String = row.try_get("metadata_json")?;
45        Ok(Some(MessageBody {
46            message_id: MessageId::from_uuid(
47                uuid::Uuid::parse_str(row.try_get::<&str, _>("message_id")?).unwrap(),
48            ),
49            text_plain: row.try_get("text_plain")?,
50            text_html: row.try_get("text_html")?,
51            attachments,
52            fetched_at: chrono::DateTime::from_timestamp(row.try_get("fetched_at")?, 0)
53                .unwrap_or_default(),
54            metadata: serde_json::from_str(&metadata_json).unwrap_or_default(),
55        }))
56    }
57
58    pub async fn insert_body(&self, body: &MessageBody) -> Result<(), sqlx::Error> {
59        let fetched_at = body.fetched_at.timestamp();
60        let mid = body.message_id.as_str();
61        let metadata_json = serde_json::to_string(&body.metadata).unwrap_or_else(|_| "{}".into());
62
63        sqlx::query(
64            "INSERT OR REPLACE INTO bodies (message_id, text_plain, text_html, fetched_at, metadata_json) VALUES (?, ?, ?, ?, ?)",
65        )
66        .bind(mid)
67        .bind(&body.text_plain)
68        .bind(&body.text_html)
69        .bind(fetched_at)
70        .bind(metadata_json)
71        .execute(self.writer())
72        .await?;
73
74        for att in &body.attachments {
75            let att_id = att.id.as_str();
76            let att_mid = att.message_id.as_str();
77            let local_path = att
78                .local_path
79                .as_ref()
80                .map(|p| p.to_string_lossy().to_string());
81            let size_bytes = att.size_bytes as i64;
82            sqlx::query!(
83                "INSERT OR REPLACE INTO attachments (id, message_id, filename, mime_type, size_bytes, local_path, provider_id)
84                 VALUES (?, ?, ?, ?, ?, ?, ?)",
85                att_id,
86                att_mid,
87                att.filename,
88                att.mime_type,
89                size_bytes,
90                local_path,
91                att.provider_id,
92            )
93            .execute(self.writer())
94            .await?;
95        }
96
97        Ok(())
98    }
99}