diff --git a/migrations/2018-04-14-145711_create_index_view/down.sql b/migrations/2018-04-14-145711_create_index_view/down.sql new file mode 100644 index 000000000..87d26820f --- /dev/null +++ b/migrations/2018-04-14-145711_create_index_view/down.sql @@ -0,0 +1 @@ +DROP VIEW thread_index; diff --git a/migrations/2018-04-14-145711_create_index_view/up.sql b/migrations/2018-04-14-145711_create_index_view/up.sql new file mode 100644 index 000000000..3b7ddc1d6 --- /dev/null +++ b/migrations/2018-04-14-145711_create_index_view/up.sql @@ -0,0 +1,15 @@ +-- Create a simple view that returns the list of threads ordered by +-- the last post that occured in the thread. + +CREATE VIEW thread_index AS + SELECT t.id AS thread_id, + t.title AS title, + t.author_name AS author_name, + t.posted AS posted, + p.id AS post_id + FROM threads t + JOIN (SELECT DISTINCT ON (thread_id) id, thread_id + FROM posts + ORDER BY thread_id, id DESC) AS p + ON t.id = p.thread_id + ORDER BY p.id DESC; diff --git a/src/db.rs b/src/db.rs index c26597293..5a66fbb0f 100644 --- a/src/db.rs +++ b/src/db.rs @@ -36,19 +36,18 @@ impl Actor for DbExecutor { pub struct ListThreads; impl Message for ListThreads { - type Result = Result>; + type Result = Result>; } impl Handler for DbExecutor { type Result = ::Result; fn handle(&mut self, _: ListThreads, _: &mut Self::Context) -> Self::Result { - use schema::threads::dsl::*; + use schema::thread_index::dsl::*; let conn = self.0.get()?; - let results = threads - .order(posted.desc()) - .load::(&conn)?; + let results = thread_index + .load::(&conn)?; Ok(results) } } diff --git a/src/models.rs b/src/models.rs index 29d196b9a..159a85469 100644 --- a/src/models.rs +++ b/src/models.rs @@ -26,6 +26,18 @@ pub struct Thread { pub author_email: String, } +/// This struct is used as the query type for the thread index view, +/// which lists the index of threads ordered by the last post in each +/// thread. +#[derive(Queryable, Serialize)] +pub struct ThreadIndex { + pub thread_id: i32, + pub title: String, + pub author_name: String, + pub posted: DateTime, + pub post_id: i32, +} + #[derive(Identifiable, Queryable, Serialize, Associations)] #[belongs_to(Thread)] pub struct Post { diff --git a/src/render.rs b/src/render.rs index ca1fd8ac3..66b3fe19c 100644 --- a/src/render.rs +++ b/src/render.rs @@ -47,7 +47,7 @@ impl From> for FormattedDate { /// Message used to render the index page. pub struct IndexPage { - pub threads: Vec, + pub threads: Vec, } impl Message for IndexPage { @@ -69,7 +69,7 @@ impl Handler for Renderer { let threads: Vec = msg.threads .into_iter() .map(|thread| IndexThread { - id: thread.id, + id: thread.thread_id, title: escape_html(&thread.title), posted: thread.posted.into(), author_name: thread.author_name, diff --git a/src/schema.rs b/src/schema.rs index d14c89c4c..02392c8fc 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -19,6 +19,17 @@ table! { } } +// Note: Manually inserted as print-schema does not add views. +table! { + thread_index (thread_id){ + thread_id -> Integer, + title -> Text, + author_name -> Text, + posted -> Timestamptz, + post_id -> Integer, + } +} + joinable!(posts -> threads (thread_id)); allow_tables_to_appear_in_same_query!(