From bbca6ef6dcad4e569fc868947e48e004f60ef43d Mon Sep 17 00:00:00 2001 From: JP Moresmau Date: Mon, 3 Jul 2023 20:13:53 +0200 Subject: [PATCH] Do not decrement comment score twice when removing then deleting. (#3196) Fixes #3004 Co-authored-by: Dessalines --- .../src/aggregates/person_aggregates.rs | 23 ++++++- .../down.sql | 19 ++++++ .../up.sql | 67 +++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 migrations/2023-06-19-120700_no_double_deletion/down.sql create mode 100644 migrations/2023-06-19-120700_no_double_deletion/up.sql diff --git a/crates/db_schema/src/aggregates/person_aggregates.rs b/crates/db_schema/src/aggregates/person_aggregates.rs index 6f8045908..295f1bfbb 100644 --- a/crates/db_schema/src/aggregates/person_aggregates.rs +++ b/crates/db_schema/src/aggregates/person_aggregates.rs @@ -22,7 +22,7 @@ mod tests { use crate::{ aggregates::person_aggregates::PersonAggregates, source::{ - comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm}, + comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm, CommentUpdateForm}, community::{Community, CommunityInsertForm}, instance::Instance, person::{Person, PersonInsertForm}, @@ -138,6 +138,27 @@ mod tests { .unwrap(); assert_eq!(0, after_post_like_remove.post_score); + Comment::update( + pool, + inserted_comment.id, + &CommentUpdateForm::builder().removed(Some(true)).build(), + ) + .await + .unwrap(); + Comment::update( + pool, + inserted_child_comment.id, + &CommentUpdateForm::builder().removed(Some(true)).build(), + ) + .await + .unwrap(); + + let after_parent_comment_removed = PersonAggregates::read(pool, inserted_person.id) + .await + .unwrap(); + assert_eq!(0, after_parent_comment_removed.comment_count); + assert_eq!(0, after_parent_comment_removed.comment_score); + // Remove a parent comment (the scores should also be removed) Comment::delete(pool, inserted_comment.id).await.unwrap(); Comment::delete(pool, inserted_child_comment.id) diff --git a/migrations/2023-06-19-120700_no_double_deletion/down.sql b/migrations/2023-06-19-120700_no_double_deletion/down.sql new file mode 100644 index 000000000..947278023 --- /dev/null +++ b/migrations/2023-06-19-120700_no_double_deletion/down.sql @@ -0,0 +1,19 @@ +-- This file should undo anything in `up.sql` +create or replace function was_removed_or_deleted(TG_OP text, OLD record, NEW record) +RETURNS boolean +LANGUAGE plpgsql +as $$ + begin + IF (TG_OP = 'INSERT') THEN + return false; + end if; + + IF (TG_OP = 'DELETE') THEN + return true; + end if; + + return TG_OP = 'UPDATE' AND ( + (OLD.deleted = 'f' AND NEW.deleted = 't') OR + (OLD.removed = 'f' AND NEW.removed = 't') + ); +END $$; diff --git a/migrations/2023-06-19-120700_no_double_deletion/up.sql b/migrations/2023-06-19-120700_no_double_deletion/up.sql new file mode 100644 index 000000000..bd6d1e58f --- /dev/null +++ b/migrations/2023-06-19-120700_no_double_deletion/up.sql @@ -0,0 +1,67 @@ +-- Deleting after removing should not decrement the count twice. +create or replace function was_removed_or_deleted(TG_OP text, OLD record, NEW record) +RETURNS boolean +LANGUAGE plpgsql +as $$ + begin + IF (TG_OP = 'INSERT') THEN + return false; + end if; + + IF (TG_OP = 'DELETE' AND OLD.deleted = 'f' AND OLD.removed = 'f') THEN + return true; + end if; + + return TG_OP = 'UPDATE' AND ( + (OLD.deleted = 'f' AND NEW.deleted = 't') OR + (OLD.removed = 'f' AND NEW.removed = 't') + ); +END $$; + +-- Recalculate proper comment count. +UPDATE person_aggregates + SET comment_count = cnt.count + FROM ( + SELECT creator_id, count(*) AS count FROM comment + WHERE deleted='f' AND removed='f' + GROUP BY creator_id + ) cnt + WHERE person_aggregates.person_id = cnt.creator_id; + +-- Recalculate proper comment score. +UPDATE person_aggregates ua + SET comment_score = cd.score + FROM ( + SELECT u.id AS creator_id, + coalesce(0, sum(cl.score)) as score + -- User join because comments could be empty + FROM person u + LEFT JOIN comment c ON u.id = c.creator_id AND c.deleted = 'f' AND c.removed = 'f' + LEFT JOIN comment_like cl ON c.id = cl.comment_id + GROUP BY u.id + ) cd + WHERE ua.person_id = cd.creator_id; + +-- Recalculate proper post count. +UPDATE person_aggregates + SET post_count = cnt.count + FROM ( + SELECT creator_id, count(*) AS count FROM post + WHERE deleted='f' AND removed='f' + GROUP BY creator_id + ) cnt + WHERE person_aggregates.person_id = cnt.creator_id; + +-- Recalculate proper post score. + UPDATE person_aggregates ua + SET post_score = pd.score + FROM ( + SELECT u.id AS creator_id, + coalesce(0, sum(pl.score)) AS score + -- User join because posts could be empty + FROM person u + LEFT JOIN post p ON u.id = p.creator_id AND p.deleted = 'f' AND p.removed = 'f' + LEFT JOIN post_like pl ON p.id = pl.post_id + GROUP BY u.id + ) pd + WHERE ua.person_id = pd.creator_id;