2024-01-05 16:46:16 +00:00
|
|
|
use super::mailbox::MailMeta;
|
|
|
|
use super::snapshot::FrozenMailbox;
|
|
|
|
use super::uidindex::IndexEntry;
|
2024-01-06 10:33:56 +00:00
|
|
|
use super::unique_ident::UniqueIdent;
|
|
|
|
use anyhow::{anyhow, Result};
|
2024-01-05 16:46:16 +00:00
|
|
|
use futures::stream::{FuturesUnordered, StreamExt};
|
|
|
|
|
|
|
|
/// Query is in charge of fetching efficiently
|
|
|
|
/// requested data for a list of emails
|
2024-01-06 10:33:56 +00:00
|
|
|
pub struct Query<'a, 'b> {
|
2024-01-05 16:46:16 +00:00
|
|
|
pub frozen: &'a FrozenMailbox,
|
|
|
|
pub emails: &'b [UniqueIdent],
|
2024-01-05 17:59:19 +00:00
|
|
|
pub scope: QueryScope,
|
|
|
|
}
|
|
|
|
|
2024-01-06 10:07:53 +00:00
|
|
|
#[allow(dead_code)]
|
2024-01-05 17:59:19 +00:00
|
|
|
pub enum QueryScope {
|
|
|
|
Index,
|
|
|
|
Partial,
|
|
|
|
Full,
|
2024-01-05 16:46:16 +00:00
|
|
|
}
|
|
|
|
|
2024-01-06 10:33:56 +00:00
|
|
|
impl<'a, 'b> Query<'a, 'b> {
|
2024-01-06 10:33:40 +00:00
|
|
|
pub async fn fetch(&self) -> Result<Vec<QueryResult<'a>>> {
|
2024-01-05 17:59:19 +00:00
|
|
|
match self.scope {
|
|
|
|
QueryScope::Index => self.index(),
|
|
|
|
QueryScope::Partial => self.partial().await,
|
|
|
|
QueryScope::Full => self.full().await,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// --- functions below are private *for reasons*
|
|
|
|
|
2024-01-06 10:33:40 +00:00
|
|
|
fn index(&self) -> Result<Vec<QueryResult<'a>>> {
|
2024-01-06 10:33:56 +00:00
|
|
|
self.emails
|
2024-01-05 16:46:16 +00:00
|
|
|
.iter()
|
|
|
|
.map(|uuid| {
|
2024-01-06 10:33:56 +00:00
|
|
|
self.frozen
|
2024-01-05 16:46:16 +00:00
|
|
|
.snapshot
|
|
|
|
.table
|
|
|
|
.get(uuid)
|
2024-01-05 17:59:19 +00:00
|
|
|
.map(|index| QueryResult::IndexResult { uuid: *uuid, index })
|
2024-01-05 16:46:16 +00:00
|
|
|
.ok_or(anyhow!("missing email in index"))
|
|
|
|
})
|
|
|
|
.collect::<Result<Vec<_>, _>>()
|
|
|
|
}
|
|
|
|
|
2024-01-06 10:33:40 +00:00
|
|
|
async fn partial(&self) -> Result<Vec<QueryResult<'a>>> {
|
2024-01-05 16:46:16 +00:00
|
|
|
let meta = self.frozen.mailbox.fetch_meta(self.emails).await?;
|
|
|
|
let result = meta
|
|
|
|
.into_iter()
|
|
|
|
.zip(self.index()?)
|
2024-01-06 10:33:56 +00:00
|
|
|
.map(|(metadata, index)| {
|
|
|
|
index
|
|
|
|
.into_partial(metadata)
|
|
|
|
.expect("index to be IndexResult")
|
|
|
|
})
|
2024-01-05 16:46:16 +00:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @FIXME WARNING: THIS CAN ALLOCATE A LOT OF MEMORY
|
|
|
|
/// AND GENERATE SO MUCH NETWORK TRAFFIC.
|
|
|
|
/// THIS FUNCTION SHOULD BE REWRITTEN, FOR EXAMPLE WITH
|
|
|
|
/// SOMETHING LIKE AN ITERATOR
|
2024-01-06 10:33:40 +00:00
|
|
|
async fn full(&self) -> Result<Vec<QueryResult<'a>>> {
|
2024-01-05 16:46:16 +00:00
|
|
|
let meta_list = self.partial().await?;
|
|
|
|
meta_list
|
|
|
|
.into_iter()
|
2024-01-06 10:33:56 +00:00
|
|
|
.map(|meta| async move {
|
|
|
|
let content = self
|
|
|
|
.frozen
|
|
|
|
.mailbox
|
|
|
|
.fetch_full(
|
|
|
|
*meta.uuid(),
|
|
|
|
&meta
|
|
|
|
.metadata()
|
|
|
|
.expect("meta to be PartialResult")
|
|
|
|
.message_key,
|
|
|
|
)
|
|
|
|
.await?;
|
2024-01-05 17:59:19 +00:00
|
|
|
|
|
|
|
Ok(meta.into_full(content).expect("meta to be PartialResult"))
|
2024-01-05 16:46:16 +00:00
|
|
|
})
|
|
|
|
.collect::<FuturesUnordered<_>>()
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.await
|
|
|
|
.into_iter()
|
|
|
|
.collect::<Result<Vec<_>, _>>()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-05 17:59:19 +00:00
|
|
|
pub enum QueryResult<'a> {
|
|
|
|
IndexResult {
|
|
|
|
uuid: UniqueIdent,
|
|
|
|
index: &'a IndexEntry,
|
|
|
|
},
|
|
|
|
PartialResult {
|
|
|
|
uuid: UniqueIdent,
|
|
|
|
index: &'a IndexEntry,
|
|
|
|
metadata: MailMeta,
|
|
|
|
},
|
|
|
|
FullResult {
|
|
|
|
uuid: UniqueIdent,
|
|
|
|
index: &'a IndexEntry,
|
|
|
|
metadata: MailMeta,
|
|
|
|
content: Vec<u8>,
|
2024-01-06 10:33:56 +00:00
|
|
|
},
|
2024-01-05 16:46:16 +00:00
|
|
|
}
|
2024-01-05 17:59:19 +00:00
|
|
|
impl<'a> QueryResult<'a> {
|
|
|
|
pub fn uuid(&self) -> &UniqueIdent {
|
|
|
|
match self {
|
|
|
|
Self::IndexResult { uuid, .. } => uuid,
|
|
|
|
Self::PartialResult { uuid, .. } => uuid,
|
|
|
|
Self::FullResult { uuid, .. } => uuid,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-06 10:07:53 +00:00
|
|
|
#[allow(dead_code)]
|
2024-01-05 17:59:19 +00:00
|
|
|
pub fn index(&self) -> &IndexEntry {
|
|
|
|
match self {
|
|
|
|
Self::IndexResult { index, .. } => index,
|
|
|
|
Self::PartialResult { index, .. } => index,
|
|
|
|
Self::FullResult { index, .. } => index,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-06 10:07:53 +00:00
|
|
|
pub fn metadata(&'a self) -> Option<&'a MailMeta> {
|
2024-01-05 17:59:19 +00:00
|
|
|
match self {
|
|
|
|
Self::IndexResult { .. } => None,
|
|
|
|
Self::PartialResult { metadata, .. } => Some(metadata),
|
|
|
|
Self::FullResult { metadata, .. } => Some(metadata),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-06 10:07:53 +00:00
|
|
|
#[allow(dead_code)]
|
|
|
|
pub fn content(&'a self) -> Option<&'a [u8]> {
|
2024-01-05 17:59:19 +00:00
|
|
|
match self {
|
|
|
|
Self::FullResult { content, .. } => Some(content),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn into_partial(self, metadata: MailMeta) -> Option<Self> {
|
|
|
|
match self {
|
2024-01-06 10:33:56 +00:00
|
|
|
Self::IndexResult { uuid, index } => Some(Self::PartialResult {
|
|
|
|
uuid,
|
|
|
|
index,
|
|
|
|
metadata,
|
|
|
|
}),
|
2024-01-05 17:59:19 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn into_full(self, content: Vec<u8>) -> Option<Self> {
|
|
|
|
match self {
|
2024-01-06 10:33:56 +00:00
|
|
|
Self::PartialResult {
|
|
|
|
uuid,
|
|
|
|
index,
|
|
|
|
metadata,
|
|
|
|
} => Some(Self::FullResult {
|
|
|
|
uuid,
|
|
|
|
index,
|
|
|
|
metadata,
|
|
|
|
content,
|
|
|
|
}),
|
2024-01-05 17:59:19 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
2024-01-05 16:46:16 +00:00
|
|
|
}
|