refactor(db): Store thread body in the posts table

This is a simplification over the previous approach. The OP of a
thread is just a normal post like any other in this model, which
allows some code simplifications (and future query convenience).
This commit is contained in:
Vincent Ambo 2018-04-14 16:33:45 +02:00
parent a90d1cc1a4
commit 8c30ef92f6
5 changed files with 36 additions and 23 deletions

View file

@ -5,7 +5,7 @@ use diesel;
use diesel::prelude::*; use diesel::prelude::*;
use diesel::r2d2::{Pool, ConnectionManager}; use diesel::r2d2::{Pool, ConnectionManager};
use models::*; use models::*;
use errors::Result; use errors::{ConverseError, Result};
/// The DB actor itself. Several of these will be run in parallel by /// The DB actor itself. Several of these will be run in parallel by
/// `SyncArbiter`. /// `SyncArbiter`.
@ -62,7 +62,10 @@ impl Handler<GetThread> for DbExecutor {
} }
/// Message used to create a new thread /// Message used to create a new thread
pub struct CreateThread(pub NewThread); pub struct CreateThread {
pub new_thread: NewThread,
pub body: String,
}
impl Message for CreateThread { impl Message for CreateThread {
type Result = Result<Thread>; type Result = Result<Thread>;
@ -73,12 +76,30 @@ impl Handler<CreateThread> for DbExecutor {
fn handle(&mut self, msg: CreateThread, _: &mut Self::Context) -> Self::Result { fn handle(&mut self, msg: CreateThread, _: &mut Self::Context) -> Self::Result {
use schema::threads; use schema::threads;
use schema::posts;
let conn = self.0.get()?; let conn = self.0.get()?;
Ok(diesel::insert_into(threads::table) conn.transaction::<Thread, ConverseError, _>(|| {
.values(&msg.0) // First insert the thread structure itself
.get_result(&conn)?) let thread: Thread = diesel::insert_into(threads::table)
.values(&msg.new_thread)
.get_result(&conn)?;
// ... then create the first post in the thread.
let new_post = NewPost {
thread_id: thread.id,
body: msg.body,
author_name: msg.new_thread.author_name.clone(),
author_email: msg.new_thread.author_email.clone(),
};
diesel::insert_into(posts::table)
.values(&new_post)
.execute(&conn)?;
Ok(thread)
})
} }
} }

View file

@ -105,12 +105,16 @@ pub fn submit_thread(state: State<AppState>,
let new_thread = NewThread { let new_thread = NewThread {
title: input.0.title, title: input.0.title,
body: input.0.body,
author_name: author.name, author_name: author.name,
author_email: author.email, author_email: author.email,
}; };
state.db.send(CreateThread(new_thread)) let msg = CreateThread {
new_thread,
body: input.0.body,
};
state.db.send(msg)
.from_err() .from_err()
.and_then(move |res| { .and_then(move |res| {
let thread = res?; let thread = res?;

View file

@ -5,7 +5,6 @@ use schema::{threads, posts};
pub struct Thread { pub struct Thread {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
pub body: String,
pub posted: DateTime<Utc>, pub posted: DateTime<Utc>,
pub author_name: String, pub author_name: String,
pub author_email: String, pub author_email: String,
@ -26,7 +25,6 @@ pub struct Post {
#[table_name="threads"] #[table_name="threads"]
pub struct NewThread { pub struct NewThread {
pub title: String, pub title: String,
pub body: String,
pub author_name: String, pub author_name: String,
pub author_email: String, pub author_email: String,
} }

View file

@ -101,24 +101,15 @@ fn md5_hex(input: &[u8]) -> String {
} }
fn prepare_thread(comrak: &ComrakOptions, page: ThreadPage) -> RenderableThreadPage { fn prepare_thread(comrak: &ComrakOptions, page: ThreadPage) -> RenderableThreadPage {
let mut posts = vec![RenderablePost { let posts = page.posts.into_iter().map(|post| {
// Always pin the ID of the first post. RenderablePost {
id: 0,
body: markdown_to_html(&page.thread.body, comrak),
posted: page.thread.posted.into(),
author_name: page.thread.author_name,
author_gravatar: md5_hex(page.thread.author_email.as_bytes()),
}];
for post in page.posts {
posts.push(RenderablePost {
id: post.id, id: post.id,
body: markdown_to_html(&post.body, comrak), body: markdown_to_html(&post.body, comrak),
posted: post.posted.into(), posted: post.posted.into(),
author_name: post.author_name, author_name: post.author_name,
author_gravatar: md5_hex(post.author_email.as_bytes()), author_gravatar: md5_hex(post.author_email.as_bytes()),
}); }
} }).collect();
RenderableThreadPage { RenderableThreadPage {
posts, posts,

View file

@ -13,7 +13,6 @@ table! {
threads (id) { threads (id) {
id -> Int4, id -> Int4,
title -> Varchar, title -> Varchar,
body -> Text,
posted -> Timestamptz, posted -> Timestamptz,
author_name -> Varchar, author_name -> Varchar,
author_email -> Varchar, author_email -> Varchar,