Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-06-18 14:18:50 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-06-18 14:18:50 +0300
commit8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch)
treea77e7fe7a93de11213032ed4ab1f33a3db51b738 /lib/gitlab/issuable_metadata.rb
parent00b35af3db1abfe813a778f643dad221aad51fca (diff)
Add latest changes from gitlab-org/gitlab@13-1-stable-ee
Diffstat (limited to 'lib/gitlab/issuable_metadata.rb')
-rw-r--r--lib/gitlab/issuable_metadata.rb101
1 files changed, 76 insertions, 25 deletions
diff --git a/lib/gitlab/issuable_metadata.rb b/lib/gitlab/issuable_metadata.rb
index 6f760751b0f..e946fc00c4d 100644
--- a/lib/gitlab/issuable_metadata.rb
+++ b/lib/gitlab/issuable_metadata.rb
@@ -1,8 +1,52 @@
# frozen_string_literal: true
module Gitlab
- module IssuableMetadata
- def issuable_meta_data(issuable_collection, collection_type, user = nil)
+ class IssuableMetadata
+ include Gitlab::Utils::StrongMemoize
+
+ # data structure to store issuable meta data like
+ # upvotes, downvotes, notes and closing merge requests counts for issues and merge requests
+ # this avoiding n+1 queries when loading issuable collections on frontend
+ IssuableMeta = Struct.new(:upvotes, :downvotes, :user_notes_count, :mrs_count) do
+ def merge_requests_count(user = nil)
+ mrs_count
+ end
+ end
+
+ attr_reader :current_user, :issuable_collection
+
+ def initialize(current_user, issuable_collection)
+ @current_user = current_user
+ @issuable_collection = issuable_collection
+
+ validate_collection!
+ end
+
+ def data
+ return {} if issuable_ids.empty?
+
+ issuable_ids.each_with_object({}) do |id, issuable_meta|
+ issuable_meta[id] = metadata_for_issuable(id)
+ end
+ end
+
+ private
+
+ def metadata_for_issuable(id)
+ downvotes = group_issuable_votes_count.find { |votes| votes.awardable_id == id && votes.downvote? }
+ upvotes = group_issuable_votes_count.find { |votes| votes.awardable_id == id && votes.upvote? }
+ notes = grouped_issuable_notes_count.find { |notes| notes.noteable_id == id }
+ merge_requests = grouped_issuable_merge_requests_count.find { |mr| mr.first == id }
+
+ IssuableMeta.new(
+ upvotes.try(:count).to_i,
+ downvotes.try(:count).to_i,
+ notes.try(:count).to_i,
+ merge_requests.try(:last).to_i
+ )
+ end
+
+ def validate_collection!
# ActiveRecord uses Object#extend for null relations.
if !(issuable_collection.singleton_class < ActiveRecord::NullRelation) &&
issuable_collection.respond_to?(:limit_value) &&
@@ -10,36 +54,43 @@ module Gitlab
raise 'Collection must have a limit applied for preloading meta-data'
end
+ end
- # map has to be used here since using pluck or select will
- # throw an error when ordering issuables by priority which inserts
- # a new order into the collection.
- # We cannot use reorder to not mess up the paginated collection.
- issuable_ids = issuable_collection.map(&:id)
+ def issuable_ids
+ strong_memoize(:issuable_ids) do
+ # map has to be used here since using pluck or select will
+ # throw an error when ordering issuables by priority which inserts
+ # a new order into the collection.
+ # We cannot use reorder to not mess up the paginated collection.
+ issuable_collection.map(&:id)
+ end
+ end
- return {} if issuable_ids.empty?
+ def collection_type
+ # Supports relations or paginated arrays
+ issuable_collection.try(:model)&.name ||
+ issuable_collection.first&.model_name.to_s
+ end
- issuable_notes_count = ::Note.count_for_collection(issuable_ids, collection_type)
- issuable_votes_count = ::AwardEmoji.votes_for_collection(issuable_ids, collection_type)
- issuable_merge_requests_count =
+ def group_issuable_votes_count
+ strong_memoize(:group_issuable_votes_count) do
+ AwardEmoji.votes_for_collection(issuable_ids, collection_type)
+ end
+ end
+
+ def grouped_issuable_notes_count
+ strong_memoize(:grouped_issuable_notes_count) do
+ ::Note.count_for_collection(issuable_ids, collection_type)
+ end
+ end
+
+ def grouped_issuable_merge_requests_count
+ strong_memoize(:grouped_issuable_merge_requests_count) do
if collection_type == 'Issue'
- ::MergeRequestsClosingIssues.count_for_collection(issuable_ids, user)
+ ::MergeRequestsClosingIssues.count_for_collection(issuable_ids, current_user)
else
[]
end
-
- issuable_ids.each_with_object({}) do |id, issuable_meta|
- downvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.downvote? }
- upvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.upvote? }
- notes = issuable_notes_count.find { |notes| notes.noteable_id == id }
- merge_requests = issuable_merge_requests_count.find { |mr| mr.first == id }
-
- issuable_meta[id] = ::Issuable::IssuableMeta.new(
- upvotes.try(:count).to_i,
- downvotes.try(:count).to_i,
- notes.try(:count).to_i,
- merge_requests.try(:last).to_i
- )
end
end
end