From 0c4b57a6d0c8b0468060dd018887aecb3882730a Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 18 Feb 2021 10:38:25 -0500 Subject: [PATCH] Adding a new comment sort for posts. Fixes #1294 (#1425) * Adding a new comment sort. Fixes #1294 * Fixing a migration comment. * Adding a comment for newest_comment_time_necro --- .rgignore | 2 +- .rustfmt.toml | 2 +- .../src/aggregates/post_aggregates.rs | 1 + crates/db_queries/src/lib.rs | 1 + crates/db_schema/src/schema.rs | 1 + crates/db_views/src/comment_view.rs | 4 +- crates/db_views/src/post_view.rs | 10 ++++- .../db_views_actor/src/user_mention_view.rs | 4 +- crates/db_views_actor/src/user_view.rs | 4 +- .../down.sql | 33 ++++++++++++++ .../up.sql | 43 +++++++++++++++++++ 11 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 migrations/2021-02-10-164051_add_new_comments_sort_index/down.sql create mode 100644 migrations/2021-02-10-164051_add_new_comments_sort_index/up.sql diff --git a/.rgignore b/.rgignore index d1b811b7d..eab207b73 100644 --- a/.rgignore +++ b/.rgignore @@ -1 +1 @@ -*.sql +*.sqldump diff --git a/.rustfmt.toml b/.rustfmt.toml index f3efdc308..59528c80b 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,5 +1,5 @@ tab_spaces = 2 edition="2018" imports_layout="HorizontalVertical" -merge_imports=true +imports_granularity="Crate" reorder_imports=true diff --git a/crates/db_queries/src/aggregates/post_aggregates.rs b/crates/db_queries/src/aggregates/post_aggregates.rs index 1d69fb40e..ffee93bec 100644 --- a/crates/db_queries/src/aggregates/post_aggregates.rs +++ b/crates/db_queries/src/aggregates/post_aggregates.rs @@ -13,6 +13,7 @@ pub struct PostAggregates { pub downvotes: i64, pub stickied: bool, pub published: chrono::NaiveDateTime, + pub newest_comment_time_necro: chrono::NaiveDateTime, // A newest comment time, limited to 2 days, to prevent necrobumping pub newest_comment_time: chrono::NaiveDateTime, } diff --git a/crates/db_queries/src/lib.rs b/crates/db_queries/src/lib.rs index ebe7394c9..bf0de3366 100644 --- a/crates/db_queries/src/lib.rs +++ b/crates/db_queries/src/lib.rs @@ -165,6 +165,7 @@ pub enum SortType { TopYear, TopAll, MostComments, + NewComments, } #[derive(EnumString, ToString, Debug, Serialize, Deserialize, Clone)] diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index e808d7702..71232ebdb 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -291,6 +291,7 @@ table! { downvotes -> Int8, stickied -> Bool, published -> Timestamp, + newest_comment_time_necro -> Timestamp, newest_comment_time -> Timestamp, } } diff --git a/crates/db_views/src/comment_view.rs b/crates/db_views/src/comment_view.rs index a262b7c1f..b2a9902a4 100644 --- a/crates/db_views/src/comment_view.rs +++ b/crates/db_views/src/comment_view.rs @@ -380,7 +380,9 @@ impl<'a> CommentQueryBuilder<'a> { SortType::Hot | SortType::Active => query .order_by(hot_rank(comment_aggregates::score, comment_aggregates::published).desc()) .then_order_by(comment_aggregates::published.desc()), - SortType::New | SortType::MostComments => query.order_by(comment::published.desc()), + SortType::New | SortType::MostComments | SortType::NewComments => { + query.order_by(comment::published.desc()) + } SortType::TopAll => query.order_by(comment_aggregates::score.desc()), SortType::TopYear => query .filter(comment::published.gt(now - 1.years())) diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index 29e4c3579..54e28de17 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -356,14 +356,19 @@ impl<'a> PostQueryBuilder<'a> { query = match self.sort { SortType::Active => query .then_order_by( - hot_rank(post_aggregates::score, post_aggregates::newest_comment_time).desc(), + hot_rank( + post_aggregates::score, + post_aggregates::newest_comment_time_necro, + ) + .desc(), ) - .then_order_by(post_aggregates::newest_comment_time.desc()), + .then_order_by(post_aggregates::newest_comment_time_necro.desc()), SortType::Hot => query .then_order_by(hot_rank(post_aggregates::score, post_aggregates::published).desc()) .then_order_by(post_aggregates::published.desc()), SortType::New => query.then_order_by(post_aggregates::published.desc()), SortType::MostComments => query.then_order_by(post_aggregates::comments.desc()), + SortType::NewComments => query.then_order_by(post_aggregates::newest_comment_time.desc()), SortType::TopAll => query.then_order_by(post_aggregates::score.desc()), SortType::TopYear => query .filter(post::published.gt(now - 1.years())) @@ -623,6 +628,7 @@ mod tests { downvotes: 0, stickied: false, published: agg.published, + newest_comment_time_necro: inserted_post.published, newest_comment_time: inserted_post.published, }, subscribed: false, diff --git a/crates/db_views_actor/src/user_mention_view.rs b/crates/db_views_actor/src/user_mention_view.rs index 811af6e75..ffdbe0300 100644 --- a/crates/db_views_actor/src/user_mention_view.rs +++ b/crates/db_views_actor/src/user_mention_view.rs @@ -270,7 +270,9 @@ impl<'a> UserMentionQueryBuilder<'a> { SortType::Hot | SortType::Active => query .order_by(hot_rank(comment_aggregates::score, comment_aggregates::published).desc()) .then_order_by(comment_aggregates::published.desc()), - SortType::New | SortType::MostComments => query.order_by(comment::published.desc()), + SortType::New | SortType::MostComments | SortType::NewComments => { + query.order_by(comment::published.desc()) + } SortType::TopAll => query.order_by(comment_aggregates::score.desc()), SortType::TopYear => query .filter(comment::published.gt(now - 1.years())) diff --git a/crates/db_views_actor/src/user_view.rs b/crates/db_views_actor/src/user_view.rs index 2b85a63ce..bbe889a25 100644 --- a/crates/db_views_actor/src/user_view.rs +++ b/crates/db_views_actor/src/user_view.rs @@ -110,7 +110,9 @@ impl<'a> UserQueryBuilder<'a> { SortType::Active => query .order_by(user_aggregates::comment_score.desc()) .then_order_by(user_::published.desc()), - SortType::New | SortType::MostComments => query.order_by(user_::published.desc()), + SortType::New | SortType::MostComments | SortType::NewComments => { + query.order_by(user_::published.desc()) + } SortType::TopAll => query.order_by(user_aggregates::comment_score.desc()), SortType::TopYear => query .filter(user_::published.gt(now - 1.years())) diff --git a/migrations/2021-02-10-164051_add_new_comments_sort_index/down.sql b/migrations/2021-02-10-164051_add_new_comments_sort_index/down.sql new file mode 100644 index 000000000..75f9aea3a --- /dev/null +++ b/migrations/2021-02-10-164051_add_new_comments_sort_index/down.sql @@ -0,0 +1,33 @@ +drop index idx_post_aggregates_newest_comment_time, +idx_post_aggregates_stickied_newest_comment_time, +idx_post_aggregates_stickied_comments; + +alter table post_aggregates drop column newest_comment_time; + +alter table post_aggregates rename column newest_comment_time_necro to newest_comment_time; + +create or replace function post_aggregates_comment_count() +returns trigger language plpgsql +as $$ +begin + IF (TG_OP = 'INSERT') THEN + update post_aggregates pa + set comments = comments + 1 + where pa.post_id = NEW.post_id; + + -- A 2 day necro-bump limit + update post_aggregates pa + set newest_comment_time = NEW.published + where pa.post_id = NEW.post_id + and published > ('now'::timestamp - '2 days'::interval); + ELSIF (TG_OP = 'DELETE') THEN + -- Join to post because that post may not exist anymore + update post_aggregates pa + set comments = comments - 1 + from post p + where pa.post_id = p.id + and pa.post_id = OLD.post_id; + END IF; + return null; +end $$; + diff --git a/migrations/2021-02-10-164051_add_new_comments_sort_index/up.sql b/migrations/2021-02-10-164051_add_new_comments_sort_index/up.sql new file mode 100644 index 000000000..5452fbae4 --- /dev/null +++ b/migrations/2021-02-10-164051_add_new_comments_sort_index/up.sql @@ -0,0 +1,43 @@ +-- First rename current newest comment time to newest_comment_time_necro +-- necro means that time is limited to 2 days, whereas newest_comment_time ignores that. +alter table post_aggregates rename column newest_comment_time to newest_comment_time_necro; + +-- Add the newest_comment_time column +alter table post_aggregates add column newest_comment_time timestamp not null default now(); + +-- Set the current newest_comment_time based on the old ones +update post_aggregates set newest_comment_time = newest_comment_time_necro; + +-- Add the indexes for this new column +create index idx_post_aggregates_newest_comment_time on post_aggregates (newest_comment_time desc); +create index idx_post_aggregates_stickied_newest_comment_time on post_aggregates (stickied desc, newest_comment_time desc); + +-- Forgot to add index w/ stickied first for most comments: +create index idx_post_aggregates_stickied_comments on post_aggregates (stickied desc, comments desc); + +-- Alter the comment trigger to set the newest_comment_time, and newest_comment_time_necro +create or replace function post_aggregates_comment_count() +returns trigger language plpgsql +as $$ +begin + IF (TG_OP = 'INSERT') THEN + update post_aggregates pa + set comments = comments + 1, + newest_comment_time = NEW.published + where pa.post_id = NEW.post_id; + + -- A 2 day necro-bump limit + update post_aggregates pa + set newest_comment_time_necro = NEW.published + where pa.post_id = NEW.post_id + and published > ('now'::timestamp - '2 days'::interval); + ELSIF (TG_OP = 'DELETE') THEN + -- Join to post because that post may not exist anymore + update post_aggregates pa + set comments = comments - 1 + from post p + where pa.post_id = p.id + and pa.post_id = OLD.post_id; + END IF; + return null; +end $$;