From f88ca4a206767e6ce1e33ee9702087e46aaccdb0 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 21 Nov 2016 16:10:42 +0100 Subject: [PATCH] Performance improvement for notifications API --- app/controllers/api/v1/apps_controller.rb | 2 +- app/controllers/api/v1/notifications_controller.rb | 5 ++++- app/controllers/api_controller.rb | 13 +++++++++++++ app/views/api/v1/accounts/show.rabl | 6 +++--- app/views/api/v1/statuses/_show.rabl | 4 ++-- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/v1/apps_controller.rb b/app/controllers/api/v1/apps_controller.rb index fb95928a8b..1b33770f4e 100644 --- a/app/controllers/api/v1/apps_controller.rb +++ b/app/controllers/api/v1/apps_controller.rb @@ -4,6 +4,6 @@ class Api::V1::AppsController < ApiController respond_to :json def create - @app = Doorkeeper::Application.create!(name: params[:client_name], redirect_uri: params[:redirect_uris], scopes: params[:scopes]) + @app = Doorkeeper::Application.create!(name: params[:client_name], redirect_uri: params[:redirect_uris], scopes: (params[:scopes] || Doorkeeper.configuration.default_scopes)) end end diff --git a/app/controllers/api/v1/notifications_controller.rb b/app/controllers/api/v1/notifications_controller.rb index 63abee6b52..c76189e875 100644 --- a/app/controllers/api/v1/notifications_controller.rb +++ b/app/controllers/api/v1/notifications_controller.rb @@ -8,8 +8,11 @@ class Api::V1::NotificationsController < ApiController def index @notifications = Notification.where(account: current_account).with_includes.paginate_by_max_id(20, params[:max_id], params[:since_id]) + statuses = @notifications.select { |n| !n.target_status.nil? }.map(&:target_status) - set_maps(@notifications.select { |n| !n.target_status.nil? }.map(&:target_status)) + set_maps(statuses) + set_counters_maps(statuses) + set_account_counters_maps(@notifications.map(&:from_account)) next_path = api_v1_notifications_url(max_id: @notifications.last.id) if @notifications.size == 20 prev_path = api_v1_notifications_url(since_id: @notifications.first.id) unless @notifications.empty? diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index aafaf843cb..d880400a8f 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -89,4 +89,17 @@ class ApiController < ApplicationController @reblogs_map = Status.reblogs_map(status_ids, current_account) @favourites_map = Status.favourites_map(status_ids, current_account) end + + def set_counters_maps(statuses) # rubocop:disable Style/AccessorMethodName + status_ids = statuses.map { |s| s.reblog? ? s.reblog_of_id : s.id }.uniq + @favourites_counts_map = Favourite.select('status_id, COUNT(id) AS favourites_count').group('status_id').where(status_id: status_ids).map { |f| [f.status_id, f.favourites_count] }.to_h + @reblogs_counts_map = Status.select('statuses.id, COUNT(reblogs.id) AS reblogs_count').joins('LEFT OUTER JOIN statuses AS reblogs ON statuses.id = reblogs.reblog_of_id').where(id: status_ids).group('statuses.id').map { |r| [r.id, r.reblogs_count] }.to_h + end + + def set_account_counters_maps(accounts) # rubocop:disable Style/AccessorMethodName + account_ids = accounts.map(&:id) + @followers_counts_map = Follow.unscoped.select('target_account_id, COUNT(account_id) AS followers_count').group('target_account_id').where(target_account_id: account_ids).map { |f| [f.target_account_id, f.followers_count] }.to_h + @following_counts_map = Follow.unscoped.select('account_id, COUNT(target_account_id) AS following_count').group('account_id').where(account_id: account_ids).map { |f| [f.account_id, f.following_count] }.to_h + @statuses_counts_map = Status.unscoped.select('account_id, COUNT(id) AS statuses_count').group('account_id').where(account_id: account_ids).map { |s| [s.account_id, s.statuses_count] }.to_h + end end diff --git a/app/views/api/v1/accounts/show.rabl b/app/views/api/v1/accounts/show.rabl index 6233290590..c01349ef23 100644 --- a/app/views/api/v1/accounts/show.rabl +++ b/app/views/api/v1/accounts/show.rabl @@ -6,6 +6,6 @@ node(:note) { |account| Formatter.instance.simplified_format(account) node(:url) { |account| TagManager.instance.url_for(account) } node(:avatar) { |account| full_asset_url(account.avatar.url(:large, false)) } node(:header) { |account| full_asset_url(account.header.url(:medium, false)) } -node(:followers_count) { |account| account.try(:followers_count) || account.followers.count } -node(:following_count) { |account| account.try(:following_count) || account.following.count } -node(:statuses_count) { |account| account.try(:statuses_count) || account.statuses.count } +node(:followers_count) { |account| defined?(@followers_counts_map) ? (@followers_counts_map[account.id] || 0) : (account.try(:followers_count) || account.followers.count) } +node(:following_count) { |account| defined?(@following_counts_map) ? (@following_counts_map[account.id] || 0) : (account.try(:following_count) || account.following.count) } +node(:statuses_count) { |account| defined?(@statuses_counts_map) ? (@statuses_counts_map[account.id] || 0) : (account.try(:statuses_count) || account.statuses.count) } diff --git a/app/views/api/v1/statuses/_show.rabl b/app/views/api/v1/statuses/_show.rabl index 3435d1039c..90457eca93 100644 --- a/app/views/api/v1/statuses/_show.rabl +++ b/app/views/api/v1/statuses/_show.rabl @@ -3,8 +3,8 @@ attributes :id, :created_at, :in_reply_to_id node(:uri) { |status| TagManager.instance.uri_for(status) } node(:content) { |status| Formatter.instance.format(status) } node(:url) { |status| TagManager.instance.url_for(status) } -node(:reblogs_count) { |status| status.reblogs_count } -node(:favourites_count) { |status| status.favourites_count } +node(:reblogs_count) { |status| defined?(@reblogs_counts_map) ? (@reblogs_counts_map[status.id] || 0) : status.reblogs_count } +node(:favourites_count) { |status| defined?(@favourites_counts_map) ? (@favourites_counts_map[status.id] || 0) : status.favourites_count } child :account do extends 'api/v1/accounts/show'