diff options
Diffstat (limited to 'app/finders/autocomplete/users_finder.rb')
-rw-r--r-- | app/finders/autocomplete/users_finder.rb | 50 |
1 files changed, 40 insertions, 10 deletions
diff --git a/app/finders/autocomplete/users_finder.rb b/app/finders/autocomplete/users_finder.rb index e7a24cde2bd..ddd68524a04 100644 --- a/app/finders/autocomplete/users_finder.rb +++ b/app/finders/autocomplete/users_finder.rb @@ -9,6 +9,7 @@ module Autocomplete # consistent and removes the need for implementing keyset pagination to # ensure good performance. LIMIT = 20 + BATCH_SIZE = 1000 attr_reader :current_user, :project, :group, :search, :author_id, :todo_filter, :todo_state_filter, @@ -62,7 +63,19 @@ module Autocomplete # When changing the order of these method calls, make sure that # reorder_by_name() is called _before_ optionally_search(), otherwise # reorder_by_name will break the ORDER BY applied in optionally_search(). - find_users + if project + project.authorized_users.union_with_user(author_id).merge(users_relation) + elsif group + find_group_users(group) + elsif current_user + users_relation + else + User.none + end.to_a + end + + def users_relation + User .where(state: states) .non_internal .reorder_by_name @@ -73,7 +86,6 @@ module Autocomplete todo_state: todo_state_filter ) .limit(LIMIT) - .to_a end # rubocop: enable CodeReuse/ActiveRecord @@ -85,15 +97,33 @@ module Autocomplete author_id.present? && current_user end - def find_users - if project - project.authorized_users.union_with_user(author_id) - elsif group - ::Autocomplete::GroupUsersFinder.new(group: group).execute # rubocop: disable CodeReuse/Finder - elsif current_user - User.all + def find_group_users(group) + if Feature.enabled?(:group_users_autocomplete_using_batch_reduction, current_user) + members_relation = ::Autocomplete::GroupUsersFinder.new(group: group, members_relation: true).execute # rubocop: disable CodeReuse/Finder + + user_ids = Set.new + members_relation.each_batch(of: BATCH_SIZE) do |relation| + user_ids += relation.pluck_user_ids + end + + user_relations = [] + user_ids.to_a.in_groups_of(BATCH_SIZE, false) do |batch_user_ids| + user_relations << users_relation.id_in(batch_user_ids) + end + + # When there is more than 1 batch, we need to apply users_relation again on + # the top results per-batch so that we return results in the correct order. + if user_relations.empty? + User.none + elsif user_relations.one? + user_relations.first + else + # We pluck the ids per batch so that we don't send an unbounded number of ids in one query + user_ids = user_relations.flat_map(&:pluck_primary_key) + users_relation.id_in(user_ids) + end else - User.none + ::Autocomplete::GroupUsersFinder.new(group: group).execute.merge(users_relation) # rubocop: disable CodeReuse/Finder end end |