From 788289011f8817a7e21ae45eda5c356009fc7844 Mon Sep 17 00:00:00 2001 From: noellabo Date: Sat, 3 Jul 2021 18:48:27 +0900 Subject: [PATCH] Add optimizations to reduce the number of relationships queries --- .../v1/accounts/relationships_controller.rb | 2 +- app/controllers/api/v1/accounts_controller.rb | 8 +- .../api/v1/follow_requests_controller.rb | 4 +- app/javascript/mastodon/actions/accounts.js | 2 +- app/models/concerns/account_interactions.rb | 85 ------------- .../concerns/status_threading_concern.rb | 13 +- app/models/status.rb | 2 - .../account_relationships_presenter.rb | 119 ++++++++++++++---- .../status_relationships_presenter.rb | 28 ++++- .../rest/relationship_serializer.rb | 14 +-- .../account_full_text_search_service.rb | 16 +-- app/services/import_service.rb | 5 +- app/services/search_service.rb | 17 ++- spec/models/account_spec.rb | 24 ---- .../concerns/account_interactions_spec.rb | 83 ------------ 15 files changed, 159 insertions(+), 263 deletions(-) diff --git a/app/controllers/api/v1/accounts/relationships_controller.rb b/app/controllers/api/v1/accounts/relationships_controller.rb index 503f85c97..ae4e2c2b0 100644 --- a/app/controllers/api/v1/accounts/relationships_controller.rb +++ b/app/controllers/api/v1/accounts/relationships_controller.rb @@ -19,6 +19,6 @@ class Api::V1::Accounts::RelationshipsController < Api::BaseController end def account_ids - Array(params[:id]).map(&:to_i) + Array(params[:id]).uniq.map(&:to_i) end end diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index b69b75b63..4558a5bdd 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -39,7 +39,13 @@ class Api::V1::AccountsController < Api::BaseController def follow follow = FollowService.new.call(current_user.account, @account, reblogs: params.key?(:reblogs) ? truthy_param?(:reblogs) : nil, notify: params.key?(:notify) ? truthy_param?(:notify) : nil, delivery: params.key?(:delivery) ? truthy_param?(:delivery) : nil, with_rate_limit: true) - options = @account.locked? || current_user.account.silenced? ? {} : { following_map: { @account.id => { reblogs: follow.show_reblogs?, notify: follow.notify?, delivery: follow.delivery? } }, requested_map: { @account.id => false } } + options = @account.locked? || current_user.account.silenced? ? {} : { + following_map: { @account.id => true }, + showing_reblogs_map: { @account.id => follow.show_reblogs? }, + notifying_map: { @account.id => follow.notify? }, + delivery_following_map: { @account.id => follow.delivery? }, + requested_map: { @account.id => false } + } render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships(**options) end diff --git a/app/controllers/api/v1/follow_requests_controller.rb b/app/controllers/api/v1/follow_requests_controller.rb index f4b2a74d0..7e34a9d09 100644 --- a/app/controllers/api/v1/follow_requests_controller.rb +++ b/app/controllers/api/v1/follow_requests_controller.rb @@ -28,8 +28,8 @@ class Api::V1::FollowRequestsController < Api::BaseController Account.find(params[:id]) end - def relationships(**options) - AccountRelationshipsPresenter.new([params[:id]], current_user.account_id, **options) + def relationships + AccountRelationshipsPresenter.new([params[:id]], current_user.account_id) end def load_accounts diff --git a/app/javascript/mastodon/actions/accounts.js b/app/javascript/mastodon/actions/accounts.js index ce2a68976..7bd7b116f 100644 --- a/app/javascript/mastodon/actions/accounts.js +++ b/app/javascript/mastodon/actions/accounts.js @@ -684,7 +684,7 @@ export function expandSubscribeFail(id, error) { export function fetchRelationships(accountIds) { return (dispatch, getState) => { const loadedRelationships = getState().get('relationships'); - const newAccountIds = accountIds.filter(id => loadedRelationships.get(id, null) === null); + const newAccountIds = Array.from(new Set(accountIds)).filter(id => loadedRelationships.get(id, null) === null); if (newAccountIds.length === 0) { return; diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb index bc856deac..dd4ab4504 100644 --- a/app/models/concerns/account_interactions.rb +++ b/app/models/concerns/account_interactions.rb @@ -3,91 +3,6 @@ module AccountInteractions extend ActiveSupport::Concern - class_methods do - def following_map(target_account_ids, account_id) - Follow.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |follow, mapping| - mapping[follow.target_account_id] = { - reblogs: follow.show_reblogs?, - notify: follow.notify?, - delivery: follow.delivery?, - } - end - end - - def followed_by_map(target_account_ids, account_id) - Follow.where(account_id: target_account_ids, target_account_id: account_id).each_with_object({}) do |follow, mapping| - mapping[follow.account_id] = { - delivery: follow.delivery?, - } - end - follow_mapping(Follow.where(account_id: target_account_ids, target_account_id: account_id), :account_id) - end - - def subscribing_map(target_account_ids, account_id) - AccountSubscribe.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |subscribe, mapping| - mapping[subscribe.target_account_id] = (mapping[subscribe.target_account_id] || {}).merge({ - subscribe.list_id || -1 => { - reblogs: subscribe.show_reblogs?, - } - }) - end - end - - def blocking_map(target_account_ids, account_id) - follow_mapping(Block.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id) - end - - def blocked_by_map(target_account_ids, account_id) - follow_mapping(Block.where(account_id: target_account_ids, target_account_id: account_id), :account_id) - end - - def muting_map(target_account_ids, account_id) - Mute.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |mute, mapping| - mapping[mute.target_account_id] = { - notifications: mute.hide_notifications?, - } - end - end - - def requested_map(target_account_ids, account_id) - FollowRequest.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |follow_request, mapping| - mapping[follow_request.target_account_id] = { - reblogs: follow_request.show_reblogs?, - notify: follow_request.notify?, - delivery: follow_request.delivery?, - } - end - end - - def endorsed_map(target_account_ids, account_id) - follow_mapping(AccountPin.where(account_id: account_id, target_account_id: target_account_ids), :target_account_id) - end - - def account_note_map(target_account_ids, account_id) - AccountNote.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |note, mapping| - mapping[note.target_account_id] = { - comment: note.comment, - } - end - end - - def domain_blocking_map(target_account_ids, account_id) - accounts_map = Account.where(id: target_account_ids).select('id, domain').each_with_object({}) { |a, h| h[a.id] = a.domain } - blocked_domains = domain_blocking_map_by_domain(accounts_map.values.compact, account_id) - accounts_map.reduce({}) { |h, (id, domain)| h.merge(id => blocked_domains[domain]) } - end - - def domain_blocking_map_by_domain(target_domains, account_id) - follow_mapping(AccountDomainBlock.where(account_id: account_id, domain: target_domains), :domain) - end - - private - - def follow_mapping(query, field) - query.pluck(field).index_with(true) - end - end - included do # Follow relations has_many :follow_requests, dependent: :destroy diff --git a/app/models/concerns/status_threading_concern.rb b/app/models/concerns/status_threading_concern.rb index 008dc1b60..72ff190bd 100644 --- a/app/models/concerns/status_threading_concern.rb +++ b/app/models/concerns/status_threading_concern.rb @@ -117,13 +117,14 @@ module StatusThreadingConcern def relations_map_for_account(account, account_ids, domains) return {} if account.nil? + presenter = AccountRelationshipsPresenter.new(account_ids, account) { - blocking: Account.blocking_map(account_ids, account.id), - blocked_by: Account.blocked_by_map(account_ids, account.id), - muting: Account.muting_map(account_ids, account.id), - following: Account.following_map(account_ids, account.id), - subscribing: Account.subscribing_map(account_ids, account.id), - domain_blocking_by_domain: Account.domain_blocking_map_by_domain(domains, account.id), + blocking: presenter.blocking, + blocked_by: presenter.blocked_by, + muting: presenter.muting, + following: presenter.following, + subscribing: presenter.subscribing, + domain_blocking_by_domain: presenter.domain_blocking, } end end diff --git a/app/models/status.rb b/app/models/status.rb index 3b5e6c9e0..dbd82de9d 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -129,7 +129,6 @@ class Status < ApplicationRecord cache_associated :application, :media_attachments, - :emoji_reactions, :conversation, :status_stat, :tags, @@ -142,7 +141,6 @@ class Status < ApplicationRecord :tags, :preview_cards, :media_attachments, - :emoji_reactions, :conversation, :status_stat, :preloadable_poll, diff --git a/app/presenters/account_relationships_presenter.rb b/app/presenters/account_relationships_presenter.rb index 0423f1409..314f95010 100644 --- a/app/presenters/account_relationships_presenter.rb +++ b/app/presenters/account_relationships_presenter.rb @@ -1,28 +1,77 @@ # frozen_string_literal: true class AccountRelationshipsPresenter - attr_reader :following, :followed_by, :subscribing, :blocking, :blocked_by, - :muting, :requested, :domain_blocking, + attr_reader :following, :showing_reblogs, :notifying, :delivery_following, :followed_by, :subscribing, :blocking, :blocked_by, + :muting, :muting_notifications, :requested, :domain_blocking, :endorsed, :account_note def initialize(account_ids, current_account_id, **options) @account_ids = account_ids.map { |a| a.is_a?(Account) ? a.id : a.to_i } @current_account_id = current_account_id - @following = cached[:following].merge(Account.following_map(@uncached_account_ids, @current_account_id)) - @followed_by = cached[:followed_by].merge(Account.followed_by_map(@uncached_account_ids, @current_account_id)) - @subscribing = cached[:subscribing].merge(Account.subscribing_map(@uncached_account_ids, @current_account_id)) - @blocking = cached[:blocking].merge(Account.blocking_map(@uncached_account_ids, @current_account_id)) - @blocked_by = cached[:blocked_by].merge(Account.blocked_by_map(@uncached_account_ids, @current_account_id)) - @muting = cached[:muting].merge(Account.muting_map(@uncached_account_ids, @current_account_id)) - @requested = cached[:requested].merge(Account.requested_map(@uncached_account_ids, @current_account_id)) - @domain_blocking = cached[:domain_blocking].merge(Account.domain_blocking_map(@uncached_account_ids, @current_account_id)) - @endorsed = cached[:endorsed].merge(Account.endorsed_map(@uncached_account_ids, @current_account_id)) - @account_note = cached[:account_note].merge(Account.account_note_map(@uncached_account_ids, @current_account_id)) + @following = cached[:following] + @showing_reblogs = cached[:showing_reblogs] + @notifying = cached[:notifying] + @delivery_following = cached[:delivery_following] + @followed_by = cached[:followed_by] + @subscribing = cached[:subscribing] + @blocking = cached[:blocking] + @blocked_by = cached[:blocked_by] + @muting = cached[:muting] + @muting_notifications = cached[:muting_notifications] + @requested = cached[:requested] + @domain_blocking = cached[:domain_blocking] + @endorsed = cached[:endorsed] + @account_note = cached[:account_note] - cache_uncached! + if current_account_id.present? && !account_ids.empty? + result = ActiveRecord::Base.connection.select_all(ActiveRecord::Base.sanitize_sql_array([<<-SQL.squish, account_ids: @uncached_account_ids, current_account_id: @current_account_id])).to_a.first + with + followings as (select * from follows where account_id = :current_account_id and target_account_id in (:account_ids)), + follow_requesteds as (select * from follow_requests where account_id = :current_account_id and target_account_id in (:account_ids)), + filter_mutes as (select * from mutes where account_id = :current_account_id and target_account_id in (:account_ids)), + subscribe_lists as (select target_account_id, coalesce(list_id, -1) as id, json_object_agg('reblogs', show_reblogs) as reblogs from account_subscribes where account_id = :current_account_id and target_account_id in (:account_ids) group by target_account_id, id) + select + (select string_agg(target_account_id::text, ',') from followings) as following, + (select string_agg(target_account_id::text, ',') from (select target_account_id from followings where show_reblogs union all select target_account_id from follow_requesteds where show_reblogs) a) as showing_reblogs, + (select string_agg(target_account_id::text, ',') from (select target_account_id from followings where notify union all select target_account_id from follow_requesteds where notify) a) as notifying, + (select string_agg(target_account_id::text, ',') from (select target_account_id from followings where delivery union all select target_account_id from follow_requesteds where delivery) a) as delivery_following, + (select string_agg(target_account_id::text, ',') from follow_requesteds) as requested, + (select string_agg(account_id::text, ',') from follows where target_account_id = :current_account_id and account_id in (:account_ids)) as followed_by, + (select json_object_agg(list.target_account_id, list.val) + from (select target_account_id, json_object_agg(lists.id, lists.reblogs) as val from subscribe_lists as lists group by target_account_id) as list) as subscribing, + (select string_agg(target_account_id::text, ',') from blocks where account_id = :current_account_id and target_account_id in (:account_ids)) as blocking, + (select string_agg(account_id::text, ',') from blocks where target_account_id = :current_account_id and account_id in (:account_ids)) as blocked_by, + (select string_agg(target_account_id::text, ',') from filter_mutes) as muting, + (select string_agg(target_account_id::text, ',') from filter_mutes where hide_notifications) as muting_notifications, + (select string_agg(adb.account_id::text, ',') from accounts a join account_domain_blocks adb on a.domain = adb.domain where adb.account_id = :current_account_id and a.id in (:account_ids)) as domain_blocking, + (select string_agg(target_account_id::text, ',') from account_pins where account_id = :current_account_id and target_account_id in (:account_ids)) as endorsed, + (select json_object_agg(n.target_account_id, n.val) + from (select target_account_id, json_object_agg('comment', comment) as val from account_notes where account_id = :current_account_id and target_account_id in (:account_ids) group by target_account_id) as n) as account_note + SQL + + @following.merge!(mapping_from_string(result['following'])) + @showing_reblogs.merge!(mapping_from_string(result['showing_reblogs'])) + @notifying.merge!(mapping_from_string(result['notifying'])) + @delivery_following.merge!(mapping_from_string(result['delivery_following'])) + @followed_by.merge!(mapping_from_string(result['followed_by'])) + @subscribing.merge!(mapping_from_json(result['subscribing'])) + @blocking.merge!(mapping_from_string(result['blocking'])) + @blocked_by.merge!(mapping_from_string(result['blocked_by'])) + @muting.merge!(mapping_from_string(result['muting'])) + @muting_notifications.merge!(mapping_from_string(result['muting_notifications'])) + @requested.merge!(mapping_from_string(result['requested'])) + @domain_blocking.merge!(mapping_from_string(result['domain_blocking'])) + @endorsed.merge!(mapping_from_string(result['endorsed'])) + @account_note.merge!(mapping_from_json(result['account_note'])) + + cache_uncached! + end @following.merge!(options[:following_map] || {}) + @showing_reblogs.merge!(options[:showing_reblogs_map] || {}) + @notifying.merge!(options[:notifying_map] || {}) + @delivery_following.merge!(options[:delivery_following_map] || {}) @followed_by.merge!(options[:followed_by_map] || {}) @subscribing.merge!(options[:subscribing_map] || {}) @blocking.merge!(options[:blocking_map] || {}) @@ -36,16 +85,36 @@ class AccountRelationshipsPresenter private + def mapping_from_string(string) + return {} if string.blank? + + string&.split(',')&.map(&:to_i)&.index_with(true) || {} + end + + def mapping_from_json(json) + return {} if json.blank? + + (Oj.load(json, mode: :strict, symbol_keys: true) || {}).tap do |json_data| + json_data.keys.each do |key| + json_data[(Integer(key.to_s) rescue key) || key] = json_data.delete(key) + end + end + end + def cached return @cached if defined?(@cached) @cached = { following: {}, + showing_reblogs: {}, + notifying: {}, + delivery_following: {}, followed_by: {}, subscribing: {}, blocking: {}, blocked_by: {}, muting: {}, + muting_notifications: {}, requested: {}, domain_blocking: {}, endorsed: {}, @@ -70,16 +139,20 @@ class AccountRelationshipsPresenter def cache_uncached! @uncached_account_ids.each do |account_id| maps_for_account = { - following: { account_id => following[account_id] }, - followed_by: { account_id => followed_by[account_id] }, - subscribing: { account_id => subscribing[account_id] }, - blocking: { account_id => blocking[account_id] }, - blocked_by: { account_id => blocked_by[account_id] }, - muting: { account_id => muting[account_id] }, - requested: { account_id => requested[account_id] }, - domain_blocking: { account_id => domain_blocking[account_id] }, - endorsed: { account_id => endorsed[account_id] }, - account_note: { account_id => account_note[account_id] }, + following: { account_id => following[account_id] }, + showing_reblogs: { account_id => showing_reblogs[account_id] }, + notifying: { account_id => notifying[account_id] }, + delivery_following: { account_id => delivery_following[account_id] }, + followed_by: { account_id => followed_by[account_id] }, + subscribing: { account_id => subscribing[account_id] }, + blocking: { account_id => blocking[account_id] }, + blocked_by: { account_id => blocked_by[account_id] }, + muting: { account_id => muting[account_id] }, + muting_notifications: { account_id => muting_notifications[account_id] }, + requested: { account_id => requested[account_id] }, + domain_blocking: { account_id => domain_blocking[account_id] }, + endorsed: { account_id => endorsed[account_id] }, + account_note: { account_id => account_note[account_id] }, } Rails.cache.write("relationship:#{@current_account_id}:#{account_id}", maps_for_account, expires_in: 1.day) diff --git a/app/presenters/status_relationships_presenter.rb b/app/presenters/status_relationships_presenter.rb index 8aa4fdc39..384fafffd 100644 --- a/app/presenters/status_relationships_presenter.rb +++ b/app/presenters/status_relationships_presenter.rb @@ -18,12 +18,28 @@ class StatusRelationshipsPresenter conversation_ids = statuses.filter_map(&:conversation_id).uniq pinnable_status_ids = statuses.map(&:proper).filter_map { |s| s.id if s.account_id == current_account_id && %w(public unlisted).include?(s.visibility) } - @reblogs_map = Status.reblogs_map(status_ids, current_account_id).merge(options[:reblogs_map] || {}) - @favourites_map = Status.favourites_map(status_ids, current_account_id).merge(options[:favourites_map] || {}) - @bookmarks_map = Status.bookmarks_map(status_ids, current_account_id).merge(options[:bookmarks_map] || {}) - @emoji_reactions_map = Status.emoji_reactions_map(status_ids, current_account_id).merge(options[:emoji_reactions_map] || {}) - @mutes_map = Status.mutes_map(conversation_ids, current_account_id).merge(options[:mutes_map] || {}) - @pins_map = Status.pins_map(pinnable_status_ids, current_account_id).merge(options[:pins_map] || {}) + result = ActiveRecord::Base.connection.select_all(ActiveRecord::Base.sanitize_sql_array([<<-SQL.squish, account_id: current_account_id, status_ids: status_ids, conversation_ids: conversation_ids, pinnable_status_ids: pinnable_status_ids])).to_a.first + select + (select string_agg(reblog_of_id::text, ',') from statuses where account_id = :account_id and reblog_of_id in (:status_ids)) as reblogs, + (select string_agg(status_id::text, ',') from favourites where account_id = :account_id and status_id IN (:status_ids)) as favourites, + (select string_agg(status_id::text, ',') from bookmarks where account_id = :account_id and status_id in (:status_ids)) as bookmarks, + (select string_agg(status_id::text, ',') from emoji_reactions where account_id = :account_id and status_id in (:status_ids)) as emoji_reactions, + (select string_agg(conversation_id::text, ',') from conversation_mutes where account_id = :account_id and conversation_id in (:conversation_ids)) as mutes, + (select string_agg(status_id::text, ',') from status_pins where account_id = :account_id and status_id in (:pinnable_status_ids)) as pins + SQL + + @reblogs_map = mapping(result['reblogs'], options[:reblogs_map]) + @favourites_map = mapping(result['favourites'], options[:favourites_map]) + @bookmarks_map = mapping(result['bookmarks'], options[:bookmarks_map]) + @emoji_reactions_map = mapping(result['emoji_reactions'], options[:emoji_reactions_map]) + @mutes_map = mapping(result['mutes'], options[:mutes_map]) + @pins_map = mapping(result['pins'], options[:pins_map]) end end + + private + + def mapping(result, additional) + (result&.split(',')&.map(&:to_i)&.index_with(true) || {}).merge(additional || {}) + end end diff --git a/app/serializers/rest/relationship_serializer.rb b/app/serializers/rest/relationship_serializer.rb index 774712960..6345ab569 100644 --- a/app/serializers/rest/relationship_serializer.rb +++ b/app/serializers/rest/relationship_serializer.rb @@ -14,21 +14,15 @@ class REST::RelationshipSerializer < ActiveModel::Serializer end def delivery_following - (instance_options[:relationships].following[object.id] || {})[:delivery] || - (instance_options[:relationships].requested[object.id] || {})[:delivery] || - false + instance_options[:relationships].delivery_following[object.id] ? true : false end def showing_reblogs - (instance_options[:relationships].following[object.id] || {})[:reblogs] || - (instance_options[:relationships].requested[object.id] || {})[:reblogs] || - false + instance_options[:relationships].showing_reblogs[object.id] ? true : false end def notifying - (instance_options[:relationships].following[object.id] || {})[:notify] || - (instance_options[:relationships].requested[object.id] || {})[:notify] || - false + instance_options[:relationships].notifying[object.id] ? true : false end def followed_by @@ -52,7 +46,7 @@ class REST::RelationshipSerializer < ActiveModel::Serializer end def muting_notifications - (instance_options[:relationships].muting[object.id] || {})[:notifications] || false + instance_options[:relationships].muting_notifications[object.id] ? true : false end def requested diff --git a/app/services/account_full_text_search_service.rb b/app/services/account_full_text_search_service.rb index ec3b1ab41..8b7695753 100644 --- a/app/services/account_full_text_search_service.rb +++ b/app/services/account_full_text_search_service.rb @@ -20,21 +20,21 @@ class AccountFullTextSearchService < BaseService results = definition.limit(@limit).offset(@offset).objects.compact account_ids = results.map(&:id) - account_domains = results.map(&:domain).uniq.compact - preloaded_relations = relations_map_for_account(@account, account_ids, account_domains) + preloaded_relations = relations_map_for_account(@account, account_ids) results.reject { |target_account| AccountSearchFilter.new(target_account, @account, preloaded_relations).filtered? } rescue Faraday::ConnectionFailed, Parslet::ParseFailed [] end - def relations_map_for_account(account, account_ids, domains) + def relations_map_for_account(account, account_ids) + presenter = AccountRelationshipsPresenter.new(account_ids, account) { - blocking: Account.blocking_map(account_ids, account.id), - blocked_by: Account.blocked_by_map(account_ids, account.id), - muting: Account.muting_map(account_ids, account.id), - following: Account.following_map(account_ids, account.id), - domain_blocking_by_domain: Account.domain_blocking_map_by_domain(domains, account.id), + blocking: presenter.blocking, + blocked_by: presenter.blocked_by, + muting: presenter.muting, + following: presenter.following, + domain_blocking_by_domain: presenter.domain_blocking, } end diff --git a/app/services/import_service.rb b/app/services/import_service.rb index 74ad5b79f..0b7cfd6b3 100644 --- a/app/services/import_service.rb +++ b/app/services/import_service.rb @@ -135,11 +135,12 @@ class ImportService < BaseService end def relations_map_for_account(account, account_ids) + presenter = AccountRelationshipsPresenter.new(account_ids, account) { blocking: {}, - blocked_by: Account.blocked_by_map(account_ids, account.id), + blocked_by: presenter.blocked_by, muting: {}, - following: Account.following_map(account_ids, account.id), + following: presenter.following, domain_blocking_by_domain: {}, } end diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 132fd36fc..d05325d33 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -50,8 +50,7 @@ class SearchService < BaseService results = definition.limit(@limit).offset(@offset).objects.compact account_ids = results.map(&:account_id) - account_domains = results.map(&:account_domain) - preloaded_relations = relations_map_for_account(@account, account_ids, account_domains) + preloaded_relations = relations_map_for_account(@account, account_ids) results.reject { |status| StatusFilter.new(status, @account, preloaded_relations).filtered? } rescue Faraday::ConnectionFailed, Parslet::ParseFailed @@ -113,14 +112,14 @@ class SearchService < BaseService @options[:type].blank? || @options[:type] == 'statuses' end - def relations_map_for_account(account, account_ids, domains) + def relations_map_for_account(account, account_ids) + presenter = AccountRelationshipsPresenter.new(account_ids, account) { - blocking: Account.blocking_map(account_ids, account.id), - blocked_by: Account.blocked_by_map(account_ids, account.id), - muting: Account.muting_map(account_ids, account.id), - following: Account.following_map(account_ids, account.id), - subscribing: Account.subscribing_map(account_ids, account.id), - domain_blocking_by_domain: Account.domain_blocking_map_by_domain(domains, account.id), + blocking: presenter.blocking, + blocked_by: presenter.blocked_by, + muting: presenter.muting, + following: presenter.following, + domain_blocking_by_domain: presenter.domain_blocking, } end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 03d6f5fb0..c1199b0dc 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -459,30 +459,6 @@ RSpec.describe Account, type: :model do end end - describe '.following_map' do - it 'returns an hash' do - expect(Account.following_map([], 1)).to be_a Hash - end - end - - describe '.followed_by_map' do - it 'returns an hash' do - expect(Account.followed_by_map([], 1)).to be_a Hash - end - end - - describe '.blocking_map' do - it 'returns an hash' do - expect(Account.blocking_map([], 1)).to be_a Hash - end - end - - describe '.requested_map' do - it 'returns an hash' do - expect(Account.requested_map([], 1)).to be_a Hash - end - end - describe 'MENTION_RE' do subject { Account::MENTION_RE } diff --git a/spec/models/concerns/account_interactions_spec.rb b/spec/models/concerns/account_interactions_spec.rb index ca243ebc5..c6b3af1a5 100644 --- a/spec/models/concerns/account_interactions_spec.rb +++ b/spec/models/concerns/account_interactions_spec.rb @@ -8,89 +8,6 @@ describe AccountInteractions do let(:target_account_id) { target_account.id } let(:target_account_ids) { [target_account_id] } - describe '.following_map' do - subject { Account.following_map(target_account_ids, account_id) } - - context 'account with Follow' do - it 'returns { target_account_id => true }' do - Fabricate(:follow, account: account, target_account: target_account) - is_expected.to eq(target_account_id => { reblogs: true, notify: false }) - end - end - - context 'account without Follow' do - it 'returns {}' do - is_expected.to eq({}) - end - end - end - - describe '.followed_by_map' do - subject { Account.followed_by_map(target_account_ids, account_id) } - - context 'account with Follow' do - it 'returns { target_account_id => true }' do - Fabricate(:follow, account: target_account, target_account: account) - is_expected.to eq(target_account_id => true) - end - end - - context 'account without Follow' do - it 'returns {}' do - is_expected.to eq({}) - end - end - end - - describe '.blocking_map' do - subject { Account.blocking_map(target_account_ids, account_id) } - - context 'account with Block' do - it 'returns { target_account_id => true }' do - Fabricate(:block, account: account, target_account: target_account) - is_expected.to eq(target_account_id => true) - end - end - - context 'account without Block' do - it 'returns {}' do - is_expected.to eq({}) - end - end - end - - describe '.muting_map' do - subject { Account.muting_map(target_account_ids, account_id) } - - context 'account with Mute' do - before do - Fabricate(:mute, target_account: target_account, account: account, hide_notifications: hide) - end - - context 'if Mute#hide_notifications?' do - let(:hide) { true } - - it 'returns { target_account_id => { notifications: true } }' do - is_expected.to eq(target_account_id => { notifications: true }) - end - end - - context 'unless Mute#hide_notifications?' do - let(:hide) { false } - - it 'returns { target_account_id => { notifications: false } }' do - is_expected.to eq(target_account_id => { notifications: false }) - end - end - end - - context 'account without Mute' do - it 'returns {}' do - is_expected.to eq({}) - end - end - end - describe '#follow!' do it 'creates and returns Follow' do expect do