Refactor pagination
This commit is contained in:
parent
29c4180496
commit
d918d614b4
3 changed files with 65 additions and 38 deletions
|
@ -13,12 +13,12 @@ use super::pagination::Pagination;
|
||||||
|
|
||||||
pub struct ChangesResource {
|
pub struct ChangesResource {
|
||||||
state: State,
|
state: State,
|
||||||
before: Option<i32>,
|
pagination: Pagination<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChangesResource {
|
impl ChangesResource {
|
||||||
pub fn new(state: State, pagination: Pagination<i32>) -> Self {
|
pub fn new(state: State, pagination: Pagination<i32>) -> Self {
|
||||||
Self { state, before: match pagination { Pagination::Before(x) => Some(x), _ => None } }
|
Self { state, pagination }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,27 +60,55 @@ impl Resource for ChangesResource {
|
||||||
|
|
||||||
const PAGE_SIZE: i32 = 30;
|
const PAGE_SIZE: i32 = 30;
|
||||||
|
|
||||||
let data = self.state.get_article_revision_stubs(self.before, PAGE_SIZE);
|
let pagination = self.pagination.clone();
|
||||||
|
let data = self.state.query_article_revision_stubs(move |query| {
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use schema::article_revisions::dsl::*;
|
||||||
|
|
||||||
|
let query = query
|
||||||
|
.limit(PAGE_SIZE as i64 + 1);
|
||||||
|
|
||||||
|
match pagination {
|
||||||
|
Pagination::After(x) => query
|
||||||
|
.filter(sequence_number.gt(x))
|
||||||
|
.order(sequence_number.asc()),
|
||||||
|
Pagination::Before(x) => query
|
||||||
|
.filter(sequence_number.lt(x))
|
||||||
|
.order(sequence_number.desc()),
|
||||||
|
Pagination::None => query
|
||||||
|
.order(sequence_number.desc()),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let head = self.head();
|
let head = self.head();
|
||||||
|
|
||||||
Box::new(data.join(head)
|
Box::new(data.join(head)
|
||||||
.and_then(move |(data, head)| {
|
.and_then(move |(mut data, head)| {
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
|
|
||||||
let link_newer = self.before.and_then(|_| {
|
let extra_element = if data.len() > PAGE_SIZE as usize {
|
||||||
data.first().and_then(|x| {
|
data.pop()
|
||||||
match x.sequence_number {
|
} else {
|
||||||
seq => Some(format!("?before={}", seq + PAGE_SIZE)),
|
None
|
||||||
}
|
};
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
let link_older = data.last().and_then(|x| {
|
let (link_newer, link_older) = match self.pagination {
|
||||||
match x.sequence_number {
|
Pagination::After(x) => {
|
||||||
1 => None,
|
data.reverse();
|
||||||
seq => Some(format!("?before={}", seq)),
|
(
|
||||||
}
|
extra_element.map(|_| format!("?after={}", data.first().unwrap().sequence_number)),
|
||||||
});
|
Some(format!("?before={}", x + 1))
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Pagination::Before(x) => (
|
||||||
|
Some(format!("?after={}", x - 1)),
|
||||||
|
extra_element.map(|_| format!("?before={}", data.last().unwrap().sequence_number)),
|
||||||
|
),
|
||||||
|
Pagination::None => (
|
||||||
|
None,
|
||||||
|
extra_element.map(|_| format!("?before={}", data.last().unwrap().sequence_number)),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
let changes = &data.into_iter().map(|x| {
|
let changes = &data.into_iter().map(|x| {
|
||||||
Row {
|
Row {
|
||||||
|
|
|
@ -24,6 +24,7 @@ struct PaginationStruct<T> {
|
||||||
before: Option<T>,
|
before: Option<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum Pagination<T> {
|
pub enum Pagination<T> {
|
||||||
After(T),
|
After(T),
|
||||||
Before(T),
|
Before(T),
|
||||||
|
|
40
src/state.rs
40
src/state.rs
|
@ -101,33 +101,31 @@ impl State {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_article_revision_stubs(&self, before: Option<i32>, limit: i32) -> CpuFuture<Vec<models::ArticleRevisionStub>, Error> {
|
pub fn query_article_revision_stubs<F>(&self, f: F) -> CpuFuture<Vec<models::ArticleRevisionStub>, Error>
|
||||||
|
where
|
||||||
|
F: 'static + Send + Sync,
|
||||||
|
for <'a> F:
|
||||||
|
FnOnce(article_revisions::BoxedQuery<'a, diesel::sqlite::Sqlite>) ->
|
||||||
|
article_revisions::BoxedQuery<'a, diesel::sqlite::Sqlite>,
|
||||||
|
{
|
||||||
let connection_pool = self.connection_pool.clone();
|
let connection_pool = self.connection_pool.clone();
|
||||||
|
|
||||||
self.cpu_pool.spawn_fn(move || {
|
self.cpu_pool.spawn_fn(move || {
|
||||||
use schema::article_revisions;
|
use schema::article_revisions::dsl::*;
|
||||||
|
|
||||||
let query = article_revisions::table
|
Ok(f(article_revisions.into_boxed())
|
||||||
.order(article_revisions::sequence_number.desc())
|
|
||||||
.limit(limit as i64)
|
|
||||||
.select((
|
.select((
|
||||||
article_revisions::sequence_number,
|
sequence_number,
|
||||||
article_revisions::article_id,
|
article_id,
|
||||||
article_revisions::revision,
|
revision,
|
||||||
article_revisions::created,
|
created,
|
||||||
article_revisions::slug,
|
slug,
|
||||||
article_revisions::title,
|
title,
|
||||||
article_revisions::latest,
|
latest,
|
||||||
article_revisions::author,
|
author,
|
||||||
))
|
))
|
||||||
.into_boxed();
|
.load(&*connection_pool.get()?)?
|
||||||
|
)
|
||||||
let query = match before {
|
|
||||||
Some(before) => query.filter(article_revisions::sequence_number.lt(before)),
|
|
||||||
None => query
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(query.load(&*connection_pool.get()?)?)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue