FIX: keep topic.word_count in sync (#27065)
Whenever one creates, updates, or deletes a post, we should keep the `topic.word_count` counter in sync. Context - https://meta.discourse.org/t/-/308062
This commit is contained in:
parent
57eff8b760
commit
b908abe35a
|
@ -855,14 +855,22 @@ class Topic < ActiveRecord::Base
|
|||
FROM posts
|
||||
WHERE deleted_at IS NULL AND post_type <> 4
|
||||
GROUP BY topic_id
|
||||
)
|
||||
),
|
||||
Z as (
|
||||
SELECT topic_id,
|
||||
SUM(COALESCE(posts.word_count, 0)) word_count
|
||||
FROM posts
|
||||
WHERE deleted_at IS NULL AND post_type <> 4
|
||||
GROUP BY topic_id
|
||||
)
|
||||
UPDATE topics
|
||||
SET
|
||||
highest_staff_post_number = X.highest_post_number,
|
||||
highest_post_number = Y.highest_post_number,
|
||||
last_posted_at = Y.last_posted_at,
|
||||
posts_count = Y.posts_count
|
||||
FROM X, Y
|
||||
posts_count = Y.posts_count,
|
||||
word_count = Z.word_count
|
||||
FROM X, Y, Z
|
||||
WHERE
|
||||
topics.archetype <> 'private_message' AND
|
||||
X.topic_id = topics.id AND
|
||||
|
@ -870,7 +878,8 @@ class Topic < ActiveRecord::Base
|
|||
topics.highest_staff_post_number <> X.highest_post_number OR
|
||||
topics.highest_post_number <> Y.highest_post_number OR
|
||||
topics.last_posted_at <> Y.last_posted_at OR
|
||||
topics.posts_count <> Y.posts_count
|
||||
topics.posts_count <> Y.posts_count OR
|
||||
topics.word_count <> Z.word_count
|
||||
)
|
||||
SQL
|
||||
|
||||
|
@ -891,14 +900,22 @@ class Topic < ActiveRecord::Base
|
|||
FROM posts
|
||||
WHERE deleted_at IS NULL AND post_type <> 3 AND post_type <> 4
|
||||
GROUP BY topic_id
|
||||
),
|
||||
Z as (
|
||||
SELECT topic_id,
|
||||
SUM(COALESCE(posts.word_count, 0)) word_count
|
||||
FROM posts
|
||||
WHERE deleted_at IS NULL AND post_type <> 3 AND post_type <> 4
|
||||
GROUP BY topic_id
|
||||
)
|
||||
UPDATE topics
|
||||
SET
|
||||
highest_staff_post_number = X.highest_post_number,
|
||||
highest_post_number = Y.highest_post_number,
|
||||
last_posted_at = Y.last_posted_at,
|
||||
posts_count = Y.posts_count
|
||||
FROM X, Y
|
||||
posts_count = Y.posts_count,
|
||||
word_count = Z.word_count
|
||||
FROM X, Y, Z
|
||||
WHERE
|
||||
topics.archetype = 'private_message' AND
|
||||
X.topic_id = topics.id AND
|
||||
|
@ -906,7 +923,8 @@ class Topic < ActiveRecord::Base
|
|||
topics.highest_staff_post_number <> X.highest_post_number OR
|
||||
topics.highest_post_number <> Y.highest_post_number OR
|
||||
topics.last_posted_at <> Y.last_posted_at OR
|
||||
topics.posts_count <> Y.posts_count
|
||||
topics.posts_count <> Y.posts_count OR
|
||||
topics.word_count <> Z.word_count
|
||||
)
|
||||
SQL
|
||||
end
|
||||
|
@ -941,6 +959,13 @@ class Topic < ActiveRecord::Base
|
|||
post_type <> 4
|
||||
#{post_type}
|
||||
),
|
||||
word_count = (
|
||||
SELECT SUM(COALESCE(posts.word_count, 0)) FROM posts
|
||||
WHERE topic_id = :topic_id AND
|
||||
deleted_at IS NULL AND
|
||||
post_type <> 4
|
||||
#{post_type}
|
||||
),
|
||||
last_posted_at = (
|
||||
SELECT MAX(created_at) FROM posts
|
||||
WHERE topic_id = :topic_id AND
|
||||
|
|
|
@ -287,6 +287,9 @@ class PostRevisor
|
|||
advance_draft_sequence if !opts[:keep_existing_draft]
|
||||
end
|
||||
|
||||
# bail out if the post or topic failed to save
|
||||
return false if !successfully_saved_post_and_topic
|
||||
|
||||
# Lock the post by default if the appropriate setting is true
|
||||
if (
|
||||
SiteSetting.staff_edit_locks_post? && !@post.wiki? && @fields.has_key?("raw") &&
|
||||
|
@ -312,16 +315,15 @@ class PostRevisor
|
|||
# it can fire events in sidekiq before the post is done saving
|
||||
# leading to corrupt state
|
||||
QuotedPost.extract_from(@post)
|
||||
TopicLink.extract_from(@post)
|
||||
|
||||
Topic.reset_highest(@topic.id)
|
||||
|
||||
post_process_post
|
||||
|
||||
update_topic_word_counts
|
||||
alert_users
|
||||
publish_changes
|
||||
grant_badge
|
||||
|
||||
TopicLink.extract_from(@post)
|
||||
|
||||
ReviewablePost.queue_for_review_if_possible(@post, @editor) if should_create_new_version?
|
||||
|
||||
successfully_saved_post_and_topic
|
||||
|
@ -714,19 +716,6 @@ class PostRevisor
|
|||
DiscourseEvent.trigger(:post_edited, @post, self.topic_changed?, self)
|
||||
end
|
||||
|
||||
def update_topic_word_counts
|
||||
DB.exec(
|
||||
"UPDATE topics
|
||||
SET word_count = (
|
||||
SELECT SUM(COALESCE(posts.word_count, 0))
|
||||
FROM posts
|
||||
WHERE posts.topic_id = :topic_id
|
||||
)
|
||||
WHERE topics.id = :topic_id",
|
||||
topic_id: @topic.id,
|
||||
)
|
||||
end
|
||||
|
||||
def alert_users
|
||||
return if @editor.id == Discourse::SYSTEM_USER_ID
|
||||
Jobs.enqueue(:post_alert, post_id: @post.id)
|
||||
|
|
|
@ -735,6 +735,7 @@ RSpec.describe PostCreator do
|
|||
highest_staff_post_number: 0,
|
||||
highest_post_number: 0,
|
||||
posts_count: 0,
|
||||
word_count: 0,
|
||||
last_posted_at: 1.year.ago,
|
||||
)
|
||||
|
||||
|
@ -743,6 +744,7 @@ RSpec.describe PostCreator do
|
|||
topic.reload
|
||||
expect(topic.highest_post_number).to eq(1)
|
||||
expect(topic.posts_count).to eq(1)
|
||||
expect(topic.word_count).to eq(5)
|
||||
expect(topic.last_posted_at).to eq_time(first.created_at)
|
||||
expect(topic.highest_staff_post_number).to eq(3)
|
||||
end
|
||||
|
@ -1187,10 +1189,10 @@ RSpec.describe PostCreator do
|
|||
)
|
||||
end
|
||||
|
||||
it "does not increase posts count for small actions" do
|
||||
it "does not increase posts/words count for small actions" do
|
||||
topic = Fabricate(:private_message_topic, user: Fabricate(:user, refresh_auto_groups: true))
|
||||
|
||||
Fabricate(:post, topic: topic)
|
||||
p1 = Fabricate(:post, topic: topic)
|
||||
|
||||
1.upto(3) do |i|
|
||||
user = Fabricate(:user)
|
||||
|
@ -1200,13 +1202,19 @@ RSpec.describe PostCreator do
|
|||
expect(topic.posts.where(post_type: Post.types[:small_action]).count).to eq(i)
|
||||
end
|
||||
|
||||
Fabricate(:post, topic: topic)
|
||||
Topic.reset_highest(topic.id)
|
||||
expect(topic.reload.posts_count).to eq(2)
|
||||
expect(topic.word_count).to eq(0)
|
||||
|
||||
Fabricate(:post, topic: topic)
|
||||
p2 = Fabricate(:post, topic: topic)
|
||||
Topic.reset_highest(topic.id)
|
||||
topic.reload
|
||||
expect(topic.posts_count).to eq(2)
|
||||
expect(topic.word_count).to eq([p1, p2].sum(&:word_count))
|
||||
|
||||
p3 = Fabricate(:post, topic: topic)
|
||||
Topic.reset_all_highest!
|
||||
expect(topic.reload.posts_count).to eq(3)
|
||||
topic.reload
|
||||
expect(topic.posts_count).to eq(3)
|
||||
expect(topic.word_count).to eq([p1, p2, p3].sum(&:word_count))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2874,6 +2874,7 @@ RSpec.describe Topic do
|
|||
topic.reload
|
||||
|
||||
expect(topic.posts_count).to eq(1)
|
||||
expect(topic.word_count).to eq(post1.word_count)
|
||||
expect(topic.highest_post_number).to eq(post1.post_number)
|
||||
expect(topic.highest_staff_post_number).to eq(post2.post_number)
|
||||
expect(topic.last_posted_at).to eq_time(post1.created_at)
|
||||
|
|
Loading…
Reference in New Issue