Class: CategoryTagStat

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/category_tag_stat.rb

Class Method Summary collapse

Class Method Details

.ensure_consistency!Object



41
42
43
# File 'app/models/category_tag_stat.rb', line 41

def self.ensure_consistency!
  self.update_topic_counts
end

.topic_deleted(topic) ⇒ Object



33
34
35
# File 'app/models/category_tag_stat.rb', line 33

def self.topic_deleted(topic)
  topic_moved(topic, topic.category_id, nil)
end

.topic_moved(topic, from_category_id, to_category_id) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'app/models/category_tag_stat.rb', line 7

def self.topic_moved(topic, from_category_id, to_category_id)
  if from_category_id
    self
      .where(tag_id: topic.tags.map(&:id), category_id: from_category_id)
      .where("topic_count > 0")
      .update_all("topic_count = topic_count - 1")
  end

  if to_category_id
    sql = <<~SQL
      UPDATE #{self.table_name}
         SET topic_count = topic_count + 1
       WHERE tag_id in (:tag_ids)
         AND category_id = :category_id
   RETURNING tag_id
    SQL

    tag_ids = topic.tags.map(&:id)
    updated_tag_ids = DB.query_single(sql, tag_ids: tag_ids, category_id: to_category_id)

    (tag_ids - updated_tag_ids).each do |tag_id|
      CategoryTagStat.create!(tag_id: tag_id, category_id: to_category_id, topic_count: 1)
    end
  end
end

.topic_recovered(topic) ⇒ Object



37
38
39
# File 'app/models/category_tag_stat.rb', line 37

def self.topic_recovered(topic)
  topic_moved(topic, nil, topic.category_id)
end

.update_topic_countsObject

Recalculate all topic counts if they got out of sync



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'app/models/category_tag_stat.rb', line 46

def self.update_topic_counts
  # Add new records or update existing records
  DB.exec <<~SQL
    WITH stats AS (
      SELECT topics.category_id as category_id,
             tags.id AS tag_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 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