aerogramme/aero-collections/mail/query.rs

138 lines
4 KiB
Rust
Raw Normal View History

2024-01-05 16:46:16 +00:00
use super::mailbox::MailMeta;
use super::snapshot::FrozenMailbox;
2024-01-06 10:33:56 +00:00
use super::unique_ident::UniqueIdent;
2024-01-08 20:18:45 +00:00
use anyhow::Result;
2024-02-22 10:35:39 +00:00
use futures::future::FutureExt;
2024-02-22 16:31:03 +00:00
use futures::stream::{BoxStream, Stream, StreamExt};
2024-01-05 16:46:16 +00:00
/// 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-08 20:18:45 +00:00
#[derive(Debug)]
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 17:01:44 +00:00
impl QueryScope {
pub fn union(&self, other: &QueryScope) -> QueryScope {
match (self, other) {
(QueryScope::Full, _) | (_, QueryScope::Full) => QueryScope::Full,
(QueryScope::Partial, _) | (_, QueryScope::Partial) => QueryScope::Partial,
(QueryScope::Index, QueryScope::Index) => QueryScope::Index,
}
}
}
2024-01-05 16:46:16 +00:00
2024-02-22 10:35:39 +00:00
//type QueryResultStream = Box<dyn Stream<Item = Result<QueryResult>>>;
2024-01-06 10:33:56 +00:00
impl<'a, 'b> Query<'a, 'b> {
2024-02-22 10:35:39 +00:00
pub fn fetch(&self) -> BoxStream<Result<QueryResult>> {
2024-01-05 17:59:19 +00:00
match self.scope {
2024-02-22 16:31:03 +00:00
QueryScope::Index => Box::pin(
futures::stream::iter(self.emails)
.map(|&uuid| Ok(QueryResult::IndexResult { uuid })),
),
2024-02-22 10:35:39 +00:00
QueryScope::Partial => Box::pin(self.partial()),
QueryScope::Full => Box::pin(self.full()),
2024-01-05 17:59:19 +00:00
}
}
// --- functions below are private *for reasons*
2024-02-22 10:35:39 +00:00
fn partial<'d>(&'d self) -> impl Stream<Item = Result<QueryResult>> + 'd + Send {
2024-02-22 16:31:03 +00:00
async move {
let maybe_meta_list: Result<Vec<MailMeta>> =
self.frozen.mailbox.fetch_meta(self.emails).await;
2024-02-22 10:35:39 +00:00
let list_res = maybe_meta_list
2024-02-22 16:31:03 +00:00
.map(|meta_list| {
meta_list
.into_iter()
.zip(self.emails)
.map(|(metadata, &uuid)| Ok(QueryResult::PartialResult { uuid, metadata }))
.collect()
})
2024-02-22 10:35:39 +00:00
.unwrap_or_else(|e| vec![Err(e)]);
2024-01-05 17:59:19 +00:00
2024-02-22 10:35:39 +00:00
futures::stream::iter(list_res)
2024-02-22 16:31:03 +00:00
}
.flatten_stream()
2024-01-05 16:46:16 +00:00
}
2024-02-22 10:35:39 +00:00
fn full<'d>(&'d self) -> impl Stream<Item = Result<QueryResult>> + 'd + Send {
2024-02-22 16:31:03 +00:00
self.partial().then(move |maybe_meta| async move {
let meta = maybe_meta?;
2024-02-22 10:35:39 +00:00
2024-02-22 16:31:03 +00:00
let content = self
.frozen
.mailbox
.fetch_full(
*meta.uuid(),
&meta
2024-02-22 10:35:39 +00:00
.metadata()
.expect("meta to be PartialResult")
.message_key,
2024-02-22 16:31:03 +00:00
)
.await?;
2024-01-05 17:59:19 +00:00
2024-02-22 16:31:03 +00:00
Ok(meta.into_full(content).expect("meta to be PartialResult"))
})
2024-01-05 16:46:16 +00:00
}
}
2024-02-22 10:35:39 +00:00
#[derive(Debug, Clone)]
2024-01-08 20:18:45 +00:00
pub enum QueryResult {
2024-01-05 17:59:19 +00:00
IndexResult {
uuid: UniqueIdent,
},
PartialResult {
uuid: UniqueIdent,
metadata: MailMeta,
},
FullResult {
uuid: UniqueIdent,
metadata: MailMeta,
content: Vec<u8>,
2024-01-06 10:33:56 +00:00
},
2024-01-05 16:46:16 +00:00
}
2024-01-08 20:18:45 +00:00
impl QueryResult {
2024-01-05 17:59:19 +00:00
pub fn uuid(&self) -> &UniqueIdent {
match self {
Self::IndexResult { uuid, .. } => uuid,
Self::PartialResult { uuid, .. } => uuid,
Self::FullResult { uuid, .. } => uuid,
}
}
2024-01-08 20:18:45 +00:00
pub fn metadata(&self) -> Option<&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)]
2024-01-08 20:18:45 +00:00
pub fn content(&self) -> Option<&[u8]> {
2024-01-05 17:59:19 +00:00
match self {
Self::FullResult { content, .. } => Some(content),
_ => None,
}
}
fn into_full(self, content: Vec<u8>) -> Option<Self> {
match self {
Self::PartialResult { uuid, metadata } => Some(Self::FullResult {
2024-01-06 10:33:56 +00:00
uuid,
metadata,
content,
}),
2024-01-05 17:59:19 +00:00
_ => None,
}
}
2024-01-05 16:46:16 +00:00
}