1use mxr_core::id::*;
2use mxr_core::types::*;
3
4use crate::message::{future_date_cutoff_timestamp, record_to_envelope};
5
6impl super::Store {
7 pub async fn get_thread(&self, thread_id: &ThreadId) -> Result<Option<Thread>, sqlx::Error> {
8 let tid = thread_id.as_str();
9 let cutoff = future_date_cutoff_timestamp();
10 let row = sqlx::query!(
11 r#"SELECT
12 thread_id as "thread_id!",
13 account_id as "account_id!",
14 MIN(subject) as "subject!: String",
15 COUNT(*) as "message_count!: i64",
16 SUM(CASE WHEN (flags & 1) = 0 THEN 1 ELSE 0 END) as "unread_count!: i64",
17 MAX(CASE WHEN date > ? THEN 0 ELSE date END) as "latest_date!: i64",
18 snippet as "snippet!"
19 FROM messages
20 WHERE thread_id = ?
21 GROUP BY thread_id"#,
22 cutoff,
23 tid,
24 )
25 .fetch_optional(self.reader())
26 .await?;
27
28 let row = match row {
29 Some(r) => r,
30 None => return Ok(None),
31 };
32
33 let tid2 = thread_id.as_str();
35 let participant_rows = sqlx::query!(
36 r#"SELECT DISTINCT from_name, from_email as "from_email!" FROM messages WHERE thread_id = ?"#,
37 tid2,
38 )
39 .fetch_all(self.reader())
40 .await?;
41
42 let participants: Vec<Address> = participant_rows
43 .into_iter()
44 .map(|r| Address {
45 name: r.from_name,
46 email: r.from_email,
47 })
48 .collect();
49
50 Ok(Some(Thread {
51 id: ThreadId::from_uuid(uuid::Uuid::parse_str(&row.thread_id).unwrap()),
52 account_id: AccountId::from_uuid(uuid::Uuid::parse_str(&row.account_id).unwrap()),
53 subject: row.subject,
54 participants,
55 message_count: row.message_count as u32,
56 unread_count: row.unread_count as u32,
57 latest_date: chrono::DateTime::from_timestamp(row.latest_date, 0).unwrap_or_default(),
58 snippet: row.snippet,
59 }))
60 }
61
62 pub async fn get_thread_envelopes(
63 &self,
64 thread_id: &ThreadId,
65 ) -> Result<Vec<Envelope>, sqlx::Error> {
66 let tid = thread_id.as_str();
67 let cutoff = future_date_cutoff_timestamp();
68 let rows = sqlx::query!(
69 r#"SELECT
70 id as "id!", account_id as "account_id!", provider_id as "provider_id!",
71 thread_id as "thread_id!", message_id_header, in_reply_to,
72 reference_headers, from_name, from_email as "from_email!",
73 to_addrs as "to_addrs!", cc_addrs as "cc_addrs!", bcc_addrs as "bcc_addrs!",
74 subject as "subject!", date as "date!", flags as "flags!",
75 snippet as "snippet!", has_attachments as "has_attachments!: bool",
76 size_bytes as "size_bytes!", unsubscribe_method,
77 COALESCE((
78 SELECT GROUP_CONCAT(labels.provider_id, char(31))
79 FROM message_labels
80 JOIN labels ON labels.id = message_labels.label_id
81 WHERE message_labels.message_id = messages.id
82 ), '') as "label_provider_ids!: String"
83 FROM messages
84 WHERE thread_id = ?
85 ORDER BY CASE WHEN date > ? THEN 0 ELSE date END ASC, id ASC"#,
86 tid,
87 cutoff,
88 )
89 .fetch_all(self.reader())
90 .await?;
91
92 Ok(rows
93 .into_iter()
94 .map(|r| {
95 record_to_envelope(
96 &r.id,
97 &r.account_id,
98 &r.provider_id,
99 &r.thread_id,
100 r.message_id_header.as_deref(),
101 r.in_reply_to.as_deref(),
102 r.reference_headers.as_deref(),
103 r.from_name.as_deref(),
104 &r.from_email,
105 &r.to_addrs,
106 &r.cc_addrs,
107 &r.bcc_addrs,
108 &r.subject,
109 r.date,
110 r.flags,
111 &r.snippet,
112 r.has_attachments,
113 r.size_bytes,
114 r.unsubscribe_method.as_deref(),
115 &r.label_provider_ids,
116 )
117 })
118 .collect())
119 }
120}