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:
parent
a90d1cc1a4
commit
8c30ef92f6
5 changed files with 36 additions and 23 deletions
31
src/db.rs
31
src/db.rs
|
@ -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)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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?;
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue