Fix multiple N+1s in ConversationsController (#25134)
This commit is contained in:
parent
bc8592627b
commit
3e1724e972
2 changed files with 44 additions and 14 deletions
|
@ -11,7 +11,7 @@ class Api::V1::ConversationsController < Api::BaseController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@conversations = paginated_conversations
|
@conversations = paginated_conversations
|
||||||
render json: @conversations, each_serializer: REST::ConversationSerializer
|
render json: @conversations, each_serializer: REST::ConversationSerializer, relationships: StatusRelationshipsPresenter.new(@conversations.map(&:last_status), current_user&.account_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def read
|
def read
|
||||||
|
@ -32,7 +32,20 @@ class Api::V1::ConversationsController < Api::BaseController
|
||||||
|
|
||||||
def paginated_conversations
|
def paginated_conversations
|
||||||
AccountConversation.where(account: current_account)
|
AccountConversation.where(account: current_account)
|
||||||
.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
.includes(
|
||||||
|
account: :account_stat,
|
||||||
|
last_status: [
|
||||||
|
:media_attachments,
|
||||||
|
:preview_cards,
|
||||||
|
:status_stat,
|
||||||
|
:tags,
|
||||||
|
{
|
||||||
|
active_mentions: [account: :account_stat],
|
||||||
|
account: :account_stat,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
.to_a_paginated_by_id(limit_param(LIMIT), **params_slice(:max_id, :since_id, :min_id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
def insert_pagination_headers
|
||||||
|
|
|
@ -16,36 +16,53 @@
|
||||||
class AccountConversation < ApplicationRecord
|
class AccountConversation < ApplicationRecord
|
||||||
include Redisable
|
include Redisable
|
||||||
|
|
||||||
|
attr_writer :participant_accounts
|
||||||
|
|
||||||
|
before_validation :set_last_status
|
||||||
after_commit :push_to_streaming_api
|
after_commit :push_to_streaming_api
|
||||||
|
|
||||||
belongs_to :account
|
belongs_to :account
|
||||||
belongs_to :conversation
|
belongs_to :conversation
|
||||||
belongs_to :last_status, class_name: 'Status'
|
belongs_to :last_status, class_name: 'Status'
|
||||||
|
|
||||||
before_validation :set_last_status
|
|
||||||
|
|
||||||
def participant_account_ids=(arr)
|
def participant_account_ids=(arr)
|
||||||
self[:participant_account_ids] = arr.sort
|
self[:participant_account_ids] = arr.sort
|
||||||
|
@participant_accounts = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def participant_accounts
|
def participant_accounts
|
||||||
|
@participant_accounts ||= begin
|
||||||
if participant_account_ids.empty?
|
if participant_account_ids.empty?
|
||||||
[account]
|
[account]
|
||||||
else
|
else
|
||||||
participants = Account.where(id: participant_account_ids)
|
participants = Account.where(id: participant_account_ids).to_a
|
||||||
participants.empty? ? [account] : participants
|
participants.empty? ? [account] : participants
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def to_a_paginated_by_id(limit, options = {})
|
def to_a_paginated_by_id(limit, min_id: nil, max_id: nil, since_id: nil, preload_participants: true)
|
||||||
if options[:min_id]
|
array = begin
|
||||||
paginate_by_min_id(limit, options[:min_id], options[:max_id]).reverse
|
if min_id
|
||||||
|
paginate_by_min_id(limit, min_id, max_id).reverse
|
||||||
else
|
else
|
||||||
paginate_by_max_id(limit, options[:max_id], options[:since_id]).to_a
|
paginate_by_max_id(limit, max_id, since_id).to_a
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if preload_participants
|
||||||
|
participant_ids = array.flat_map(&:participant_account_ids)
|
||||||
|
accounts_by_id = Account.where(id: participant_ids).index_by(&:id)
|
||||||
|
|
||||||
|
array.each do |conversation|
|
||||||
|
conversation.participant_accounts = conversation.participant_account_ids.filter_map { |id| accounts_by_id[id] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
array
|
||||||
|
end
|
||||||
|
|
||||||
def paginate_by_min_id(limit, min_id = nil, max_id = nil)
|
def paginate_by_min_id(limit, min_id = nil, max_id = nil)
|
||||||
query = order(arel_table[:last_status_id].asc).limit(limit)
|
query = order(arel_table[:last_status_id].asc).limit(limit)
|
||||||
query = query.where(arel_table[:last_status_id].gt(min_id)) if min_id.present?
|
query = query.where(arel_table[:last_status_id].gt(min_id)) if min_id.present?
|
||||||
|
|
Loading…
Reference in a new issue