use aion_core::WorkflowListRequest;
use super::cursor::WorkflowCursor;
use super::ordering::page_key;
use super::record::{VisibilityPage, VisibilityRecord};
use crate::StoreError;
#[derive(Clone, Debug)]
pub struct PageCandidate {
pub key: Vec<u8>,
pub record: VisibilityRecord,
}
impl PageCandidate {
#[must_use]
pub fn new(record: VisibilityRecord, request: &WorkflowListRequest) -> Self {
Self {
key: page_key(&record, request.sort),
record,
}
}
}
pub fn paginate(
request: &WorkflowListRequest,
candidates: impl IntoIterator<Item = PageCandidate>,
) -> Result<VisibilityPage, StoreError> {
let limit = validated_limit(request)?;
let cursor = WorkflowCursor::decode(request)?;
let mut count: u64 = 0;
let mut after_cursor = Vec::new();
for candidate in candidates {
if candidate.record.namespace != request.namespace
|| !request.filter.matches(&candidate.record.summary())
{
continue;
}
count += 1;
if cursor
.as_ref()
.is_none_or(|cursor| candidate.key > cursor.after_key)
{
after_cursor.push(candidate);
}
}
after_cursor.sort_by(|left, right| left.key.cmp(&right.key));
let has_more = after_cursor.len() > limit;
after_cursor.truncate(limit);
let next_cursor = match (has_more, after_cursor.last()) {
(true, Some(last)) => Some(WorkflowCursor::mint(request, &last.key)?),
_ => None,
};
Ok(VisibilityPage {
items: after_cursor
.into_iter()
.map(|candidate| candidate.record)
.collect(),
next_cursor,
count,
})
}
pub fn validated_limit(request: &WorkflowListRequest) -> Result<usize, StoreError> {
if request.limit == 0 {
return Err(StoreError::InvalidQuery(String::from(
"limit must be at least 1",
)));
}
usize::try_from(request.limit)
.map_err(|_| StoreError::InvalidQuery(String::from("limit exceeds this platform's range")))
}