Factor out pagination resolver from ChangesResource and call it ChangesLookup

This commit is contained in:
Magnus Hoff 2017-10-22 14:36:05 +02:00
parent b3ffcb916b
commit 0f1e1f65ed
3 changed files with 59 additions and 40 deletions

View file

@ -1,5 +1,5 @@
use futures::{self, Future}; use futures::{self, Future};
use futures::future::finished; use futures::future::{done, finished};
use hyper; use hyper;
use hyper::header::ContentType; use hyper::header::ContentType;
use hyper::server::*; use hyper::server::*;
@ -17,39 +17,61 @@ const PAGE_SIZE: i32 = 30;
type BoxResource = Box<Resource + Sync + Send>; type BoxResource = Box<Resource + Sync + Send>;
#[derive(Clone)]
pub struct ChangesLookup {
state: State,
}
impl ChangesLookup {
pub fn new(state: State) -> ChangesLookup {
Self { state }
}
pub fn lookup(&self, query: Option<&str>) -> Box<Future<Item=Option<BoxResource>, Error=::web::Error>> {
use super::pagination;
let state = self.state.clone();
Box::new(
done(pagination::from_str(query.unwrap_or("")).map_err(Into::into))
.and_then(move |pagination| match pagination {
Pagination::After(x) => Box::new(
state.query_article_revision_stubs(move |query| {
use diesel::prelude::*;
use schema::article_revisions::dsl::*;
query
.limit(PAGE_SIZE as i64 + 1)
.filter(sequence_number.gt(x))
.order(sequence_number.asc())
}).and_then(|mut data| {
let extra_element = if data.len() > PAGE_SIZE as usize {
data.pop()
} else {
None
};
Ok(Some(match extra_element {
Some(x) => Box::new(TemporaryRedirectResource::new(format!("?before={}", x.sequence_number))) as BoxResource,
None => Box::new(TemporaryRedirectResource::new(format!("_changes"))) as BoxResource,
}))
})
) as Box<Future<Item=Option<BoxResource>, Error=::web::Error>>,
Pagination::Before(x) => Box::new(finished(Some(Box::new(ChangesResource::new(state, Some(x))) as BoxResource))),
Pagination::None => Box::new(finished(Some(Box::new(ChangesResource::new(state, None)) as BoxResource))),
})
)
}
}
pub struct ChangesResource { pub struct ChangesResource {
state: State, state: State,
before: Option<i32>, before: Option<i32>,
} }
impl ChangesResource { impl ChangesResource {
pub fn new(state: State, pagination: Pagination<i32>) -> Box<Future<Item=BoxResource, Error=::web::Error>> { pub fn new(state: State, before: Option<i32>) -> Self {
match pagination { Self { state, before }
Pagination::After(x) => Box::new(
state.query_article_revision_stubs(move |query| {
use diesel::prelude::*;
use schema::article_revisions::dsl::*;
query
.limit(PAGE_SIZE as i64 + 1)
.filter(sequence_number.gt(x))
.order(sequence_number.asc())
}).and_then(|mut data| {
let extra_element = if data.len() > PAGE_SIZE as usize {
data.pop()
} else {
None
};
Ok(match extra_element {
Some(x) => Box::new(TemporaryRedirectResource::new(format!("?before={}", x.sequence_number))) as BoxResource,
None => Box::new(TemporaryRedirectResource::new(format!("_changes"))) as BoxResource,
})
})
),
Pagination::Before(x) => Box::new(finished(Box::new(Self { state, before: Some(x) }) as BoxResource)),
Pagination::None => Box::new(finished(Box::new(Self { state, before: None }) as BoxResource)),
}
} }
} }

View file

@ -9,7 +9,7 @@ mod temporary_redirect_resource;
pub use self::article_redirect_resource::ArticleRedirectResource; pub use self::article_redirect_resource::ArticleRedirectResource;
pub use self::article_resource::ArticleResource; pub use self::article_resource::ArticleResource;
pub use self::changes_resource::ChangesResource; pub use self::changes_resource::{ChangesLookup, ChangesResource};
pub use self::new_article_resource::NewArticleResource; pub use self::new_article_resource::NewArticleResource;
pub use self::sitemap_resource::SitemapResource; pub use self::sitemap_resource::SitemapResource;
pub use self::temporary_redirect_resource::TemporaryRedirectResource; pub use self::temporary_redirect_resource::TemporaryRedirectResource;

View file

@ -2,7 +2,7 @@ use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::str::Utf8Error; use std::str::Utf8Error;
use futures::{Future, finished, failed, done}; use futures::{Future, finished, failed};
use futures::future::FutureResult; use futures::future::FutureResult;
use percent_encoding::percent_decode; use percent_encoding::percent_decode;
use slug::slugify; use slug::slugify;
@ -40,7 +40,8 @@ lazy_static! {
#[derive(Clone)] #[derive(Clone)]
pub struct WikiLookup { pub struct WikiLookup {
state: State state: State,
changes_lookup: ChangesLookup,
} }
fn split_one(path: &str) -> Result<(Cow<str>, Option<&str>), Utf8Error> { fn split_one(path: &str) -> Result<(Cow<str>, Option<&str>), Utf8Error> {
@ -70,7 +71,9 @@ fn asset_lookup(path: &str) -> FutureResult<Option<BoxResource>, Box<::std::erro
impl WikiLookup { impl WikiLookup {
pub fn new(state: State) -> WikiLookup { pub fn new(state: State) -> WikiLookup {
WikiLookup { state } let changes_lookup = ChangesLookup::new(state.clone());
WikiLookup { state, changes_lookup }
} }
fn reserved_lookup(&self, path: &str, query: Option<&str>) -> <Self as Lookup>::Future { fn reserved_lookup(&self, path: &str, query: Option<&str>) -> <Self as Lookup>::Future {
@ -82,14 +85,8 @@ impl WikiLookup {
match (head.as_ref(), tail) { match (head.as_ref(), tail) {
("_assets", Some(asset)) => ("_assets", Some(asset)) =>
Box::new(asset_lookup(asset)), Box::new(asset_lookup(asset)),
("_changes", None) => { ("_changes", None) =>
let state = self.state.clone(); Box::new(ChangesLookup::new(self.state.clone()).lookup(query)),
Box::new(
done(pagination::from_str(query.unwrap_or("")).map_err(Into::into))
.and_then(move |pagination| ChangesResource::new(state, pagination))
.and_then(|resource| Ok(Some(resource)))
)
},
("_new", None) => ("_new", None) =>
Box::new(finished(Some(Box::new(NewArticleResource::new(self.state.clone(), None)) as BoxResource))), Box::new(finished(Some(Box::new(NewArticleResource::new(self.state.clone(), None)) as BoxResource))),
("_sitemap", None) => ("_sitemap", None) =>