hyaenidae/src/pagination.rs

147 lines
3.9 KiB
Rust

use uuid::Uuid;
#[derive(Debug)]
pub(crate) enum PageSource {
NewerThan(Uuid),
OlderThan(Uuid),
}
#[derive(Debug)]
pub(crate) struct PageNum {
pub(crate) page: usize,
}
#[derive(Debug)]
pub(crate) struct Page {
pub(crate) items: Vec<Uuid>,
pub(crate) next: Option<Uuid>,
pub(crate) prev: Option<Uuid>,
pub(crate) reset: bool,
}
#[derive(Debug)]
pub(crate) struct SearchPage {
pub(crate) items: Vec<Uuid>,
pub(crate) next: Option<usize>,
pub(crate) prev: Option<usize>,
pub(crate) term: String,
}
pub trait Pagination {
fn from_max<'a>(&'a mut self, max: Uuid) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a>;
fn from_min<'a>(&'a mut self, min: Uuid) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a>;
fn from_start<'a>(&'a mut self) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a>;
}
pub trait SearchPagination {
fn from_term<'a>(&'a mut self, term: &'a str)
-> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a>;
}
impl Page {
pub(crate) fn from_pagination(
mut pagination: impl Pagination,
per_page: usize,
source: Option<PageSource>,
) -> Self {
let mut items: Vec<Uuid>;
let mut next = None;
let mut prev = None;
let mut reset = false;
match source {
Some(PageSource::OlderThan(max)) => {
items = pagination.from_max(max).take(per_page + 1).collect();
if let Some(item) = items.get(0) {
prev = Some(*item);
} else {
reset = true;
}
if items.len() == per_page + 1 {
items.pop();
next = Some(items[per_page.saturating_sub(1)]);
}
}
Some(PageSource::NewerThan(min)) => {
let mut tmp_items: Vec<_> = pagination.from_min(min).take(per_page + 2).collect();
if tmp_items.len() == per_page + 2 {
tmp_items.pop();
prev = Some(tmp_items[per_page]);
}
items = tmp_items.into_iter().rev().collect();
items.pop();
if let Some(item) = items.get(items.len().saturating_sub(1)) {
next = Some(*item);
} else {
reset = true;
}
}
None => {
items = pagination.from_start().take(per_page + 1).collect();
if items.len() == per_page + 1 {
items.pop();
next = Some(items[per_page.saturating_sub(1)]);
}
}
}
Page {
items,
next,
prev,
reset,
}
}
}
impl SearchPage {
pub(crate) fn from_pagination(
mut pagination: impl SearchPagination,
per_page: usize,
term: String,
page: Option<PageNum>,
) -> Self {
let mut items: Vec<Uuid>;
let mut next = None;
let mut prev = None;
match page {
Some(PageNum { page }) => {
let page = page.saturating_sub(1);
items = pagination
.from_term(&term)
.skip(page * per_page)
.take(per_page + 1)
.collect();
if page > 0 {
prev = Some(page);
}
if items.len() == per_page + 1 {
items.pop();
next = Some(page + 2);
}
}
None => {
items = pagination.from_term(&term).take(per_page + 1).collect();
if items.len() == per_page + 1 {
items.pop();
next = Some(2);
}
}
}
SearchPage {
items,
next,
prev,
term,
}
}
}