Skip to content

Commit 495aa6b

Browse files
authored
Merge pull request #1040 from indentlabs/2021-10-07
Add word count caches
2 parents 3563da5 + 72049a1 commit 495aa6b

13 files changed

+162
-3
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
class CacheAttributeWordCountJob < ApplicationJob
2+
queue_as :cache
3+
4+
def perform(*args)
5+
attribute_id = args.shift
6+
attribute = Attribute.find_by(id: attribute_id)
7+
8+
return if attribute.nil?
9+
return if attribute.value.nil? || attribute.value.blank?
10+
11+
word_count = WordCountAnalyzer::Counter.new(
12+
ellipsis: 'no_special_treatment',
13+
hyperlink: 'count_as_one',
14+
contraction: 'count_as_one',
15+
hyphenated_word: 'count_as_one',
16+
date: 'no_special_treatment',
17+
number: 'count',
18+
numbered_list: 'ignore',
19+
xhtml: 'remove',
20+
forward_slash: 'count_as_multiple_except_dates',
21+
backslash: 'count_as_one',
22+
dotted_line: 'ignore',
23+
dashed_line: 'ignore',
24+
underscore: 'ignore',
25+
stray_punctuation: 'ignore'
26+
).count(attribute.value)
27+
28+
attribute.update!(word_count_cache: word_count)
29+
end
30+
end
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class CacheSumAttributeWordCountJob < ApplicationJob
2+
queue_as :cache
3+
4+
def perform(*args)
5+
entity_type = args.shift
6+
entity_id = args.shift
7+
8+
entity = entity_type.constantize.find_by(id: entity_id)
9+
sum_attribute_word_count = Attribute.where(entity_type: entity_type, entity_id: entity_id).sum(:word_count_cache)
10+
11+
update = entity.word_count_updates.find_or_initialize_by(
12+
for_date: DateTime.current,
13+
)
14+
update.word_count = sum_attribute_word_count
15+
update.user_id ||= entity.user_id
16+
17+
update.save!
18+
end
19+
end

app/jobs/save_document_revision_job.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,21 @@ class SaveDocumentRevisionJob < ApplicationJob
44
def perform(*args)
55
document_id = args.shift
66

7-
document = Document.find(document_id)
8-
return unless document.present?
7+
document = Document.find_by(id: document_id)
8+
return unless document
99

1010
# Update cached word count for the document regardless of how often this is called
1111
new_word_count = document.computed_word_count
1212
document.update(cached_word_count: new_word_count)
1313

14+
# Save a WordCountUpdate for this document for today
15+
update = document.word_count_updates.find_or_initialize_by(
16+
for_date: DateTime.current,
17+
)
18+
update.word_count = new_word_count
19+
update.user_id ||= document.user_id
20+
update.save!
21+
1422
# Make sure we're only storing revisions at least every 5 min
1523
latest_revision = document.document_revisions.order('created_at DESC').limit(1).first
1624
if latest_revision.present? && latest_revision.created_at > 5.minutes.ago

app/models/concerns/is_content_page.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ module IsContentPage
1818
has_many :timeline_events, through: :timeline_event_entities
1919
has_many :timelines, -> { distinct }, through: :timeline_events
2020

21+
has_many :word_count_updates, as: :entity, dependent: :destroy
22+
def latest_word_count_cache
23+
word_count_updates.order('for_date DESC').limit(1).first.try(:word_count) || 0
24+
end
25+
2126
scope :unarchived, -> { where(archived_at: nil) }
2227
def archive!
2328
update!(archived_at: DateTime.now)

app/models/documents/document.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ class Document < ApplicationRecord
2626

2727
attr_accessor :tagged_text
2828

29+
# Duplicated from is_content_page since we don't include that here yet
30+
has_many :word_count_updates, as: :entity, dependent: :destroy
31+
def latest_word_count_cache
32+
word_count_updates.order('for_date DESC').limit(1).first.try(:word_count) || 0
33+
end
34+
2935
KEYS_TO_TRIGGER_REVISION_ON_CHANGE = %w(title body synopsis notes_text)
3036

3137
def self.color

app/models/page_data/attribute.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ class Attribute < ApplicationRecord
1919
end
2020
end
2121

22+
after_commit do
23+
if saved_changes.key?('value')
24+
# Cache the updated word count on this attribute
25+
CacheAttributeWordCountJob.perform_later(self.id)
26+
27+
# Cache the updated word count on the page this attribute belongs to
28+
CacheSumAttributeWordCountJob.perform_later(self.entity_type, self.entity_id)
29+
end
30+
end
31+
2232
after_save do
2333
entity.touch
2434
end

app/models/word_count_update.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class WordCountUpdate < ApplicationRecord
2+
belongs_to :user
3+
belongs_to :entity, polymorphic: true
4+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class AddWordCountCacheToAttributes < ActiveRecord::Migration[6.0]
2+
def change
3+
add_column :attributes, :word_count_cache, :integer
4+
end
5+
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class CreateWordCountUpdates < ActiveRecord::Migration[6.0]
2+
def change
3+
create_table :word_count_updates do |t|
4+
t.references :user, null: false, foreign_key: true
5+
t.references :entity, polymorphic: true, null: false
6+
t.integer :word_count
7+
t.date :for_date
8+
9+
t.timestamps
10+
end
11+
end
12+
end

db/schema.rb

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema.define(version: 2021_09_15_030031) do
13+
ActiveRecord::Schema.define(version: 2021_10_07_234707) do
1414

1515
create_table "active_storage_attachments", force: :cascade do |t|
1616
t.string "name", null: false
@@ -165,6 +165,7 @@
165165
t.datetime "created_at"
166166
t.datetime "updated_at"
167167
t.datetime "deleted_at"
168+
t.integer "word_count_cache"
168169
t.index ["attribute_field_id", "deleted_at", "entity_id", "entity_type"], name: "attributes_afi_deleted_at_entity_id_entity_type"
169170
t.index ["attribute_field_id", "deleted_at"], name: "index_attributes_on_attribute_field_id_and_deleted_at"
170171
t.index ["attribute_field_id", "user_id", "entity_type", "entity_id", "deleted_at"], name: "attributes_afi_ui_et_ei_da"
@@ -3636,6 +3637,18 @@
36363637
t.integer "habitat_id"
36373638
end
36383639

3640+
create_table "word_count_updates", force: :cascade do |t|
3641+
t.integer "user_id", null: false
3642+
t.string "entity_type", null: false
3643+
t.integer "entity_id", null: false
3644+
t.integer "word_count"
3645+
t.date "for_date"
3646+
t.datetime "created_at", precision: 6, null: false
3647+
t.datetime "updated_at", precision: 6, null: false
3648+
t.index ["entity_type", "entity_id"], name: "index_word_count_updates_on_entity_type_and_entity_id"
3649+
t.index ["user_id"], name: "index_word_count_updates_on_user_id"
3650+
end
3651+
36393652
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
36403653
add_foreign_key "api_keys", "users"
36413654
add_foreign_key "api_requests", "application_integrations"
@@ -4047,4 +4060,5 @@
40474060
add_foreign_key "vehicles", "users"
40484061
add_foreign_key "votes", "users"
40494062
add_foreign_key "votes", "votables"
4063+
add_foreign_key "word_count_updates", "users"
40504064
end

0 commit comments

Comments
 (0)