diff --git a/app/models/rubygem.rb b/app/models/rubygem.rb index c17a5df221d..80427763f34 100644 --- a/app/models/rubygem.rb +++ b/app/models/rubygem.rb @@ -183,6 +183,15 @@ def downloads gem_download&.count || 0 end + def gem_rank + gem_ranking = update_gems_ranking + + return gem_ranking[id] if gem_ranking.key?(id) + + Rails.cache.delete("gems_ranking") + update_gems_ranking[id] + end + def most_recent_version versions.most_recent end @@ -446,4 +455,17 @@ def bulk_reorder_versions sanitized_query = ActiveRecord::Base.send(:sanitize_sql_array, update_query) ActiveRecord::Base.connection.execute(sanitized_query) end + + def update_gems_ranking + Rails.cache.fetch("gems_ranking", expires_in: 24.hours) do + update_query = <<-SQL.squish + SELECT rubygem_id, row_number() OVER(ORDER BY count DESC) AS position + FROM gem_downloads + WHERE version_id = 0 AND rubygem_id <> 0 + SQL + sanitized_query = ActiveRecord::Base.send(:sanitize_sql_array, [update_query]) + pg_result = ActiveRecord::Base.connection.execute(sanitized_query) + pg_result.to_h { |row| [row["rubygem_id"], row["position"]] } + end + end end diff --git a/test/models/rubygem_test.rb b/test/models/rubygem_test.rb index 5b752a09e99..487d515280c 100644 --- a/test/models/rubygem_test.rb +++ b/test/models/rubygem_test.rb @@ -1102,4 +1102,41 @@ class RubygemTest < ActiveSupport::TestCase refute_predicate @version_three, :yanked? end end + + context "#gem_rank" do + setup do + @rank_one = create(:rubygem, downloads: 5) + @rank_two = create(:rubygem, downloads: 1) + + @dummy_rank = { @rank_one.id => 1, @rank_two.id => 2 } + end + + should "write to cache" do + @rank_one.gem_rank + + assert_equal Rails.cache.read("gems_ranking"), @dummy_rank + end + + should "read from cache" do + @rank_two.gem_rank + + GemDownload.increment(10, rubygem_id: @rank_two.id) + + @rank_two.gem_rank + + assert_equal Rails.cache.read("gems_ranking"), @dummy_rank + end + + should "return the gem rank" do + assert_equal 1, @rank_one.gem_rank + end + + should "update when rubygem not ranked" do + @rank_two.gem_rank + + @rank_three = create(:rubygem, downloads: 3) + + assert_equal(2, @rank_three.gem_rank) + end + end end