storage: make the edges in pages include cursors
This commit is contained in:
@@ -16,12 +16,12 @@ pub struct InvalidPagination;
|
||||
|
||||
/// Pagination parameters
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Pagination {
|
||||
pub struct Pagination<Cursor = Ulid> {
|
||||
/// The cursor to start from
|
||||
pub before: Option<Ulid>,
|
||||
pub before: Option<Cursor>,
|
||||
|
||||
/// The cursor to end at
|
||||
pub after: Option<Ulid>,
|
||||
pub after: Option<Cursor>,
|
||||
|
||||
/// The maximum number of items to return
|
||||
pub count: usize,
|
||||
@@ -40,16 +40,22 @@ pub enum PaginationDirection {
|
||||
Backward,
|
||||
}
|
||||
|
||||
impl Pagination {
|
||||
/// A node in a page, with a cursor
|
||||
pub trait Node<C = Ulid> {
|
||||
/// The cursor of that particular node
|
||||
fn cursor(&self) -> C;
|
||||
}
|
||||
|
||||
impl<C> Pagination<C> {
|
||||
/// Creates a new [`Pagination`] from user-provided parameters.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Either `first` or `last` must be provided, else this function will
|
||||
/// return an [`InvalidPagination`] error.
|
||||
pub const fn try_new(
|
||||
before: Option<Ulid>,
|
||||
after: Option<Ulid>,
|
||||
pub fn try_new(
|
||||
before: Option<C>,
|
||||
after: Option<C>,
|
||||
first: Option<usize>,
|
||||
last: Option<usize>,
|
||||
) -> Result<Self, InvalidPagination> {
|
||||
@@ -91,49 +97,57 @@ impl Pagination {
|
||||
|
||||
/// Get items before the given cursor
|
||||
#[must_use]
|
||||
pub const fn before(mut self, id: Ulid) -> Self {
|
||||
self.before = Some(id);
|
||||
pub fn before(mut self, cursor: C) -> Self {
|
||||
self.before = Some(cursor);
|
||||
self
|
||||
}
|
||||
|
||||
/// Clear the before cursor
|
||||
#[must_use]
|
||||
pub const fn clear_before(mut self) -> Self {
|
||||
pub fn clear_before(mut self) -> Self {
|
||||
self.before = None;
|
||||
self
|
||||
}
|
||||
|
||||
/// Get items after the given cursor
|
||||
#[must_use]
|
||||
pub const fn after(mut self, id: Ulid) -> Self {
|
||||
self.after = Some(id);
|
||||
pub fn after(mut self, cursor: C) -> Self {
|
||||
self.after = Some(cursor);
|
||||
self
|
||||
}
|
||||
|
||||
/// Clear the after cursor
|
||||
#[must_use]
|
||||
pub const fn clear_after(mut self) -> Self {
|
||||
pub fn clear_after(mut self) -> Self {
|
||||
self.after = None;
|
||||
self
|
||||
}
|
||||
|
||||
/// Process a page returned by a paginated query
|
||||
#[must_use]
|
||||
pub fn process<T>(&self, mut edges: Vec<T>) -> Page<T> {
|
||||
let is_full = edges.len() == (self.count + 1);
|
||||
pub fn process<T: Node<C>>(&self, mut nodes: Vec<T>) -> Page<T, C> {
|
||||
let is_full = nodes.len() == (self.count + 1);
|
||||
if is_full {
|
||||
edges.pop();
|
||||
nodes.pop();
|
||||
}
|
||||
|
||||
let (has_previous_page, has_next_page) = match self.direction {
|
||||
PaginationDirection::Forward => (false, is_full),
|
||||
PaginationDirection::Backward => {
|
||||
// 6. If the last argument is provided, I reverse the order of the results
|
||||
edges.reverse();
|
||||
nodes.reverse();
|
||||
(is_full, false)
|
||||
}
|
||||
};
|
||||
|
||||
let edges = nodes
|
||||
.into_iter()
|
||||
.map(|node| Edge {
|
||||
cursor: node.cursor(),
|
||||
node,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Page {
|
||||
has_next_page,
|
||||
has_previous_page,
|
||||
@@ -142,9 +156,18 @@ impl Pagination {
|
||||
}
|
||||
}
|
||||
|
||||
/// An edge in a paginated result
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Edge<T, C = Ulid> {
|
||||
/// The cursor of the edge
|
||||
pub cursor: C,
|
||||
/// The node of the edge
|
||||
pub node: T,
|
||||
}
|
||||
|
||||
/// A page of results returned by a paginated query
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Page<T> {
|
||||
pub struct Page<T, C = Ulid> {
|
||||
/// When paginating forwards, this is true if there are more items after
|
||||
pub has_next_page: bool,
|
||||
|
||||
@@ -152,21 +175,28 @@ pub struct Page<T> {
|
||||
pub has_previous_page: bool,
|
||||
|
||||
/// The items in the page
|
||||
pub edges: Vec<T>,
|
||||
pub edges: Vec<Edge<T, C>>,
|
||||
}
|
||||
|
||||
impl<T> Page<T> {
|
||||
impl<T, C> Page<T, C> {
|
||||
/// Map the items in this page with the given function
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `f`: The function to map the items with
|
||||
#[must_use]
|
||||
pub fn map<F, T2>(self, f: F) -> Page<T2>
|
||||
pub fn map<F, T2>(self, mut f: F) -> Page<T2, C>
|
||||
where
|
||||
F: FnMut(T) -> T2,
|
||||
{
|
||||
let edges = self.edges.into_iter().map(f).collect();
|
||||
let edges = self
|
||||
.edges
|
||||
.into_iter()
|
||||
.map(|edge| Edge {
|
||||
cursor: edge.cursor,
|
||||
node: f(edge.node),
|
||||
})
|
||||
.collect();
|
||||
Page {
|
||||
has_next_page: self.has_next_page,
|
||||
has_previous_page: self.has_previous_page,
|
||||
@@ -183,11 +213,21 @@ impl<T> Page<T> {
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns the first error encountered while mapping the items
|
||||
pub fn try_map<F, E, T2>(self, f: F) -> Result<Page<T2>, E>
|
||||
pub fn try_map<F, E, T2>(self, mut f: F) -> Result<Page<T2, C>, E>
|
||||
where
|
||||
F: FnMut(T) -> Result<T2, E>,
|
||||
{
|
||||
let edges: Result<Vec<T2>, E> = self.edges.into_iter().map(f).collect();
|
||||
let edges: Result<Vec<Edge<T2, C>>, E> = self
|
||||
.edges
|
||||
.into_iter()
|
||||
.map(|edge| {
|
||||
Ok(Edge {
|
||||
cursor: edge.cursor,
|
||||
node: f(edge.node)?,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(Page {
|
||||
has_next_page: self.has_next_page,
|
||||
has_previous_page: self.has_previous_page,
|
||||
|
||||
@@ -384,7 +384,7 @@ impl ExpireInactiveOAuthSessionsJob {
|
||||
let last_edge = page.edges.last()?;
|
||||
Some(Self {
|
||||
threshold: self.threshold,
|
||||
after: Some(last_edge.id),
|
||||
after: Some(last_edge.cursor),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -441,7 +441,7 @@ impl ExpireInactiveCompatSessionsJob {
|
||||
let last_edge = page.edges.last()?;
|
||||
Some(Self {
|
||||
threshold: self.threshold,
|
||||
after: Some(last_edge.id),
|
||||
after: Some(last_edge.cursor),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -498,7 +498,7 @@ impl ExpireInactiveUserSessionsJob {
|
||||
let last_edge = page.edges.last()?;
|
||||
Some(Self {
|
||||
threshold: self.threshold,
|
||||
after: Some(last_edge.id),
|
||||
after: Some(last_edge.cursor),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user