mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
FIX: Update category tag stats with new or deleted (#21531)
The old method updated only existing records, without considering that new tags might have been created or some tags might not exist anymore. This was usually not a problem because the stats were also updated by other code paths. However, the ensure consistency job should be more solid and help when other code paths fail or after importing data. Also, update category tag stats too should happen when updating other category stats as well.
This commit is contained in:
parent
809bab5782
commit
f0ec1fad8c
|
@ -44,23 +44,38 @@ class CategoryTagStat < ActiveRecord::Base
|
|||
|
||||
# Recalculate all topic counts if they got out of sync
|
||||
def self.update_topic_counts
|
||||
# Add new records or update existing records
|
||||
DB.exec <<~SQL
|
||||
UPDATE category_tag_stats stats
|
||||
SET topic_count = x.topic_count
|
||||
FROM (
|
||||
SELECT COUNT(topics.id) AS topic_count,
|
||||
WITH stats AS (
|
||||
SELECT topics.category_id as category_id,
|
||||
tags.id AS tag_id,
|
||||
topics.category_id as category_id
|
||||
COUNT(topics.id) AS topic_count
|
||||
FROM tags
|
||||
INNER JOIN topic_tags ON tags.id = topic_tags.tag_id
|
||||
INNER JOIN topics ON topics.id = topic_tags.topic_id
|
||||
AND topics.deleted_at IS NULL
|
||||
AND topics.category_id IS NOT NULL
|
||||
GROUP BY tags.id, topics.category_id
|
||||
) x
|
||||
WHERE stats.tag_id = x.tag_id
|
||||
AND stats.category_id = x.category_id
|
||||
AND x.topic_count <> stats.topic_count
|
||||
GROUP BY topics.category_id, tags.id
|
||||
)
|
||||
INSERT INTO category_tag_stats(category_id, tag_id, topic_count)
|
||||
SELECT category_id, tag_id, topic_count FROM stats
|
||||
ON CONFLICT (category_id, tag_id) DO
|
||||
UPDATE SET topic_count = EXCLUDED.topic_count
|
||||
SQL
|
||||
|
||||
# Delete old records
|
||||
DB.exec <<~SQL
|
||||
DELETE FROM category_tag_stats
|
||||
WHERE (category_id, tag_id) NOT IN (
|
||||
SELECT topics.category_id as category_id,
|
||||
tags.id AS tag_id
|
||||
FROM tags
|
||||
INNER JOIN topic_tags ON tags.id = topic_tags.tag_id
|
||||
INNER JOIN topics ON topics.id = topic_tags.topic_id
|
||||
AND topics.deleted_at IS NULL
|
||||
AND topics.category_id IS NOT NULL
|
||||
GROUP BY topics.category_id, tags.id
|
||||
)
|
||||
SQL
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,6 +24,7 @@ task "categories:move_topics", %i[from_category to_category] => [:environment] d
|
|||
|
||||
puts "Updating category stats..."
|
||||
Category.update_stats
|
||||
CategoryTagStat.update_topic_counts
|
||||
end
|
||||
|
||||
puts "", "Done!", ""
|
||||
|
|
39
spec/models/category_tag_stat_spec.rb
Normal file
39
spec/models/category_tag_stat_spec.rb
Normal file
|
@ -0,0 +1,39 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe CategoryTagStat do
|
||||
fab!(:category) { Fabricate(:category) }
|
||||
fab!(:tag) { Fabricate(:tag) }
|
||||
fab!(:topic) { Fabricate(:topic, category: category, tags: [tag]) }
|
||||
|
||||
describe "#update_topic_counts" do
|
||||
it "creates new records" do
|
||||
CategoryTagStat.destroy_all
|
||||
|
||||
expect { CategoryTagStat.update_topic_counts }.to change { CategoryTagStat.count }.by(1)
|
||||
category_tag_stat = CategoryTagStat.last
|
||||
expect(category_tag_stat.category_id).to eq(category.id)
|
||||
expect(category_tag_stat.tag_id).to eq(tag.id)
|
||||
expect(category_tag_stat.topic_count).to eq(1)
|
||||
end
|
||||
|
||||
it "updates existing records" do
|
||||
CategoryTagStat.last.update(topic_count: 10)
|
||||
|
||||
expect { CategoryTagStat.update_topic_counts }.not_to change { CategoryTagStat.count }
|
||||
category_tag_stat = CategoryTagStat.last
|
||||
expect(category_tag_stat.category_id).to eq(category.id)
|
||||
expect(category_tag_stat.tag_id).to eq(tag.id)
|
||||
expect(category_tag_stat.topic_count).to eq(1)
|
||||
end
|
||||
|
||||
it "deletes old records" do
|
||||
CategoryTagStat.last.update(tag_id: Fabricate(:tag).id)
|
||||
|
||||
expect { CategoryTagStat.update_topic_counts }.not_to change { CategoryTagStat.count }
|
||||
category_tag_stat = CategoryTagStat.last
|
||||
expect(category_tag_stat.category_id).to eq(category.id)
|
||||
expect(category_tag_stat.tag_id).to eq(tag.id)
|
||||
expect(category_tag_stat.topic_count).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user