From 50b9ebf59e37d5c16979319d5a6a59b4e4a5a9d5 Mon Sep 17 00:00:00 2001 From: Magnus Hoff Date: Fri, 8 Sep 2017 15:37:58 +0200 Subject: [PATCH] Make State::update_article return a Future. In preparation for threading --- src/site.rs | 26 ++++++---------- src/state.rs | 88 ++++++++++++++++++++++++++++------------------------ 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/site.rs b/src/site.rs index 4960308..1461ee3 100644 --- a/src/site.rs +++ b/src/site.rs @@ -178,21 +178,15 @@ impl Resource for ArticleResource { body .concat2() - .map_err(|x| Box::new(x) as Box<::std::error::Error + Send + Sync>) - .and_then(move |body| { - let update: UpdateArticle = match serde_urlencoded::from_bytes(&body) { - Ok(x) => x, - Err(err) => return futures::finished(Response::new() - .with_status(hyper::StatusCode::BadRequest) - .with_body(format!("{:#?}", err)) - ).boxed() - }; - - let updated = match self.state.update_article(self.data.article_id, update.base_revision, &update.body) { - Ok(x) => x, - Err(x) => return futures::failed(x).boxed(), - }; - + .map_err(Into::into) + .and_then(|body| { + serde_urlencoded::from_bytes(&body) + .map_err(Into::into) + }) + .and_then(move |update: UpdateArticle| { + self.state.update_article(self.data.article_id, update.base_revision, update.body) + }) + .and_then(|updated| { futures::finished(Response::new() .with_status(hyper::StatusCode::Ok) .with_header(ContentType(APPLICATION_JSON.clone())) @@ -201,7 +195,7 @@ impl Resource for ArticleResource { rendered: &render_markdown(&updated.body), created: &Local.from_utc_datetime(&updated.created).to_string(), }).expect("Should never fail")) - ).boxed() + ) }) .boxed() } diff --git a/src/state.rs b/src/state.rs index 488b4f0..c00c7ec 100644 --- a/src/state.rs +++ b/src/state.rs @@ -3,6 +3,7 @@ use std; use diesel; use diesel::sqlite::SqliteConnection; use diesel::prelude::*; +use futures::{self, Future, IntoFuture}; use r2d2::Pool; use r2d2_diesel::ConnectionManager; @@ -31,51 +32,56 @@ impl State { .pop()) } - pub fn update_article(&self, article_id: i32, base_revision: i32, body: &str) -> Result { - let conn = self.connection_pool.get()?; - conn.transaction(|| { - use schema::article_revisions; + pub fn update_article(&self, article_id: i32, base_revision: i32, body: String) -> futures::BoxFuture { + self.connection_pool.get().into_future() + .map_err(Into::into) + .and_then(move |conn| { + conn.transaction(|| { + use schema::article_revisions; - let (latest_revision, title) = article_revisions::table - .filter(article_revisions::article_id.eq(article_id)) - .order(article_revisions::revision.desc()) - .limit(1) - .select((article_revisions::revision, article_revisions::title)) - .load::<(i32, String)>(&*conn)? - .pop() - .unwrap_or_else(|| unimplemented!("TODO Missing an error type")); + let (latest_revision, title) = article_revisions::table + .filter(article_revisions::article_id.eq(article_id)) + .order(article_revisions::revision.desc()) + .limit(1) + .select((article_revisions::revision, article_revisions::title)) + .load::<(i32, String)>(&*conn)? + .pop() + .unwrap_or_else(|| unimplemented!("TODO Missing an error type")); - if latest_revision != base_revision { - // TODO: If it is the same edit repeated, just respond OK - // TODO: If there is a conflict, transform the edit to work seamlessly - unimplemented!("TODO Missing handling of revision conflicts"); - } - let new_revision = base_revision + 1; + if latest_revision != base_revision { + // TODO: If it is the same edit repeated, just respond OK + // TODO: If there is a conflict, transform the edit to work seamlessly + unimplemented!("TODO Missing handling of revision conflicts"); + } + let new_revision = base_revision + 1; - #[derive(Insertable)] - #[table_name="article_revisions"] - struct NewRevision<'a> { - article_id: i32, - revision: i32, - title: &'a str, - body: &'a str, - } + #[derive(Insertable)] + #[table_name="article_revisions"] + struct NewRevision<'a> { + article_id: i32, + revision: i32, + title: &'a str, + body: &'a str, + } - diesel::insert(&NewRevision { - article_id, - revision: new_revision, - title: &title, - body + diesel::insert(&NewRevision { + article_id, + revision: new_revision, + title: &title, + body: &body, + }) + .into(article_revisions::table) + .execute(&*conn)?; + + Ok(article_revisions::table + .filter(article_revisions::article_id.eq(article_id)) + .filter(article_revisions::revision.eq(new_revision)) + .load::(&*conn)? + .pop() + .expect("We just inserted this row!") + ) }) - .into(article_revisions::table) - .execute(&*conn)?; - - Ok(article_revisions::table - .filter(article_revisions::article_id.eq(article_id)) - .filter(article_revisions::revision.eq(new_revision)) - .load::(&*conn)? - .pop() - .expect("We just inserted this row!")) - }) + }) + .boxed() } }