diff --git a/app/lib/annual_report/percentiles.rb b/app/lib/annual_report/percentiles.rb index 2b0305c4155..c6929d9f472 100644 --- a/app/lib/annual_report/percentiles.rb +++ b/app/lib/annual_report/percentiles.rb @@ -2,15 +2,7 @@ class AnnualReport::Percentiles < AnnualReport::Source def self.prepare(year) - AnnualReport::StatusesPerAccountCount.connection.exec_query(<<~SQL.squish, nil, [year, Mastodon::Snowflake.id_at(DateTime.new(year).beginning_of_year), Mastodon::Snowflake.id_at(DateTime.new(year).end_of_year)]) - INSERT INTO annual_report_statuses_per_account_counts (year, account_id, statuses_count) - SELECT $1, account_id, count(*) - FROM statuses - WHERE id BETWEEN $2 AND $3 - AND (local OR uri IS NULL) - GROUP BY account_id - ON CONFLICT (year, account_id) DO NOTHING - SQL + AnnualReport::StatusesPerAccountCount.refresh(year) end def generate diff --git a/app/models/annual_report/statuses_per_account_count.rb b/app/models/annual_report/statuses_per_account_count.rb index 05a2f53c9d5..dfebac075f5 100644 --- a/app/models/annual_report/statuses_per_account_count.rb +++ b/app/models/annual_report/statuses_per_account_count.rb @@ -11,5 +11,35 @@ # class AnnualReport::StatusesPerAccountCount < ApplicationRecord - # This table facilitates percentile calculations + def self.refresh(year) + connection.exec_query(<<~SQL.squish) + INSERT INTO #{table_name} (year, account_id, statuses_count) + #{AccountStatusCountQuery.new(year).to_sql} + ON CONFLICT (year, account_id) DO NOTHING + SQL + end + + class AccountStatusCountQuery + def initialize(year) + @year = year + end + + def to_sql + Status + .unscoped + .local + .where(id: beginning_of_year..end_of_year) + .group(:account_id) + .select(@year, :account_id, Arel.star.count) + .to_sql + end + + def beginning_of_year + Mastodon::Snowflake.id_at(DateTime.new(@year).beginning_of_year, with_random: false) + end + + def end_of_year + Mastodon::Snowflake.id_at(DateTime.new(@year).end_of_year, with_random: false) + end + end end diff --git a/spec/fabricators/annual_report/statuses_per_account_count_fabricator.rb b/spec/fabricators/annual_report/statuses_per_account_count_fabricator.rb new file mode 100644 index 00000000000..92739c08587 --- /dev/null +++ b/spec/fabricators/annual_report/statuses_per_account_count_fabricator.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +Fabricator :annual_report_statuses_per_account_count, from: 'AnnualReport::StatusesPerAccountCount' do + year { Time.zone.now.year } + account_id { Fabricate(:account).id } + statuses_count { 123 } +end diff --git a/spec/lib/annual_report/percentiles_spec.rb b/spec/lib/annual_report/percentiles_spec.rb index 11df81cfb6c..87ba012f6f7 100644 --- a/spec/lib/annual_report/percentiles_spec.rb +++ b/spec/lib/annual_report/percentiles_spec.rb @@ -7,13 +7,10 @@ RSpec.describe AnnualReport::Percentiles do subject { described_class.new(account, year) } let(:year) { Time.zone.now.year } + let(:account) { Fabricate :account } - context 'with an inactive account' do - let(:account) { Fabricate :account } - + context 'with no status data' do it 'builds a report for an account' do - described_class.prepare(year) - expect(subject.generate) .to include( percentiles: include( @@ -23,17 +20,16 @@ RSpec.describe AnnualReport::Percentiles do end end - context 'with an active account' do - let(:account) { Fabricate :account } - + context 'with status count data' do before do - Fabricate.times 2, :status # Others as `account` + # Simulate scenario where other accounts have each made one status + Fabricate.times 2, :annual_report_statuses_per_account_count, statuses_count: 1 + Fabricate.times 2, :status, account: account + Fabricate :annual_report_statuses_per_account_count, account_id: account.id, statuses_count: 2 end it 'builds a report for an account' do - described_class.prepare(year) - expect(subject.generate) .to include( percentiles: include( diff --git a/spec/models/annual_report/statuses_per_account_count_spec.rb b/spec/models/annual_report/statuses_per_account_count_spec.rb new file mode 100644 index 00000000000..56e98fcea49 --- /dev/null +++ b/spec/models/annual_report/statuses_per_account_count_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe AnnualReport::StatusesPerAccountCount do + describe '.refresh' do + subject { described_class.refresh(year) } + + let(:year) { Time.zone.now.year } + + context 'with an inactive account' do + let(:account) { Fabricate :account } + + it 'does not build a status count record' do + expect { subject } + .to not_change(described_class, :count).from(0) + end + end + + context 'with an active account' do + let(:account) { Fabricate :account } + + before do + Fabricate :status + Fabricate.times 2, :status, account: account + end + + it 'builds a status count record' do + expect { subject } + .to change(described_class, :count).by(2) + expect(described_class.where(account_id: account).first) + .to have_attributes(statuses_count: 2) + end + end + end +end