Skip to content
Snippets Groups Projects
Select Git revision
  • 552e886b648faa2a2229d86c7fd9abc8bb5ff99c
  • main default protected
  • mathstodon-4.3.6
  • mathstodon-4.3.x
  • mathstodon-4.2.15
  • mathstodon-4.2.10
  • mathstodon-4.2.7
  • mathstodon-4.2.6
  • v4.2.5
  • v4.2.2
  • mathstodon-4.2.5
  • mathstodon-4.2
  • mathstodon-4.1
  • mastodon-4.1.3
  • v4.1.3
  • v4.1.0-diff
  • mathstodon-4.1.0
  • mastodon-v4.1.0
  • v4.0.2
  • mathstodon-4.0.2
  • mathstodon-3.5.3
  • v4.0.0rc3
  • v4.0.0rc2
  • v4.0.0rc1
  • v3.5.3
  • v3.4.8
  • v3.5.2
  • v3.5.1
  • v3.4.7
  • v3.3.3
  • v3.5.0
  • v3.5.0rc3
  • v3.5.0rc2
  • v3.5.0rc1
  • v3.4.6
  • v3.3.2
  • v3.3.1
  • v3.4.5
  • v3.4.4
  • v3.4.3
  • v3.4.2
41 results

favourites_controller.rb

Blame
  • user avatar
    Akihiko Odaki authored and GitHub committed
    The old implementation had two queries:
    1. The query constructed in Api::V1::FavouritesController#results
    2. The query constructed in #cached_favourites, which is merged with 1.
    
    Both of them are issued againt PostgreSQL. The combination of the two
    queries caused the following problems:
    - The small window between the two queries involves race conditions.
    - Minor performance inefficiency.
    
    Moreover, the construction of query 2, which involves merging with query
    1 has a bug. Query 1 is finalized with paginate_by_id, but paginate_by_id
    returns an array when min_id parameter is specified. The behavior prevents
    from merging the query, and in the real world, ActiveRecord simply ignores
    the merge (!), which results in querying the entire scan of statuses and
    favourites table.
    
    This change fixes these issues by simply letting query 1 get all the works
    done.
    552e886b
    History
    favourites_controller.rb 1.45 KiB
    # frozen_string_literal: true
    
    class Api::V1::FavouritesController < Api::BaseController
      before_action -> { doorkeeper_authorize! :read, :'read:favourites' }
      before_action :require_user!
      after_action :insert_pagination_headers
    
      def index
        @statuses = load_statuses
        render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
      end
    
      private
    
      def load_statuses
        cached_favourites
      end
    
      def cached_favourites
        cache_collection(results.map(&:status), Status)
      end
    
      def results
        @_results ||= account_favourites.eager_load(:status).paginate_by_id(
          limit_param(DEFAULT_STATUSES_LIMIT),
          params_slice(:max_id, :since_id, :min_id)
        )
      end
    
      def account_favourites
        current_account.favourites
      end
    
      def insert_pagination_headers
        set_pagination_headers(next_path, prev_path)
      end
    
      def next_path
        if records_continue?
          api_v1_favourites_url pagination_params(max_id: pagination_max_id)
        end
      end
    
      def prev_path
        unless results.empty?
          api_v1_favourites_url pagination_params(min_id: pagination_since_id)
        end
      end
    
      def pagination_max_id
        results.last.id
      end
    
      def pagination_since_id
        results.first.id
      end
    
      def records_continue?
        results.size == limit_param(DEFAULT_STATUSES_LIMIT)
      end
    
      def pagination_params(core_params)
        params.slice(:limit).permit(:limit).merge(core_params)
      end
    end