Merge remote-tracking branch 'parent/main' into upstream-20231204
This commit is contained in:
commit
94c2396a34
179 changed files with 1036 additions and 775 deletions
89
app/models/concerns/account/counters.rb
Normal file
89
app/models/concerns/account/counters.rb
Normal file
|
@ -0,0 +1,89 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Account::Counters
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
ALLOWED_COUNTER_KEYS = %i(statuses_count following_count followers_count).freeze
|
||||
|
||||
included do
|
||||
has_one :account_stat, inverse_of: :account, dependent: nil
|
||||
after_save :save_account_stat
|
||||
end
|
||||
|
||||
delegate :statuses_count,
|
||||
:statuses_count=,
|
||||
:following_count,
|
||||
:following_count=,
|
||||
:followers_count,
|
||||
:followers_count=,
|
||||
:group_activitypub_count,
|
||||
:group_activitypub_count=,
|
||||
:last_status_at,
|
||||
to: :account_stat
|
||||
|
||||
# @param [Symbol] key
|
||||
def increment_count!(key)
|
||||
update_count!(key, 1)
|
||||
end
|
||||
|
||||
# @param [Symbol] key
|
||||
def decrement_count!(key)
|
||||
update_count!(key, -1)
|
||||
end
|
||||
|
||||
# @param [Symbol] key
|
||||
# @param [Integer] value
|
||||
def update_count!(key, value)
|
||||
raise ArgumentError, "Invalid key #{key}" unless ALLOWED_COUNTER_KEYS.include?(key)
|
||||
raise ArgumentError, 'Do not call update_count! on dirty objects' if association(:account_stat).loaded? && account_stat&.changed? && account_stat.changed_attribute_names_to_save == %w(id)
|
||||
|
||||
value = value.to_i
|
||||
default_value = value.positive? ? value : 0
|
||||
|
||||
# We do an upsert using manually written SQL, as Rails' upsert method does
|
||||
# not seem to support writing expressions in the UPDATE clause, but only
|
||||
# re-insert the provided values instead.
|
||||
# Even ARel seem to be missing proper handling of upserts.
|
||||
sql = if value.positive? && key == :statuses_count
|
||||
<<-SQL.squish
|
||||
INSERT INTO account_stats(account_id, #{key}, created_at, updated_at, last_status_at)
|
||||
VALUES (:account_id, :default_value, now(), now(), now())
|
||||
ON CONFLICT (account_id) DO UPDATE
|
||||
SET #{key} = account_stats.#{key} + :value,
|
||||
last_status_at = now(),
|
||||
updated_at = now()
|
||||
RETURNING id;
|
||||
SQL
|
||||
else
|
||||
<<-SQL.squish
|
||||
INSERT INTO account_stats(account_id, #{key}, created_at, updated_at)
|
||||
VALUES (:account_id, :default_value, now(), now())
|
||||
ON CONFLICT (account_id) DO UPDATE
|
||||
SET #{key} = account_stats.#{key} + :value,
|
||||
updated_at = now()
|
||||
RETURNING id;
|
||||
SQL
|
||||
end
|
||||
|
||||
sql = AccountStat.sanitize_sql([sql, account_id: id, default_value: default_value, value: value])
|
||||
account_stat_id = AccountStat.connection.exec_query(sql)[0]['id']
|
||||
|
||||
# Reload account_stat if it was loaded, taking into account newly-created unsaved records
|
||||
if association(:account_stat).loaded?
|
||||
account_stat.id = account_stat_id if account_stat.new_record?
|
||||
account_stat.reload
|
||||
end
|
||||
end
|
||||
|
||||
def account_stat
|
||||
super || build_account_stat
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def save_account_stat
|
||||
return unless association(:account_stat).loaded? && account_stat&.changed?
|
||||
|
||||
account_stat.save
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue