118 lines
3.5 KiB
Ruby
118 lines
3.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module OptimizedIssuableLabelFilter
|
|
extend ActiveSupport::Concern
|
|
|
|
prepended do
|
|
extend Gitlab::Cache::RequestCache
|
|
|
|
# Avoid repeating label queries times when the finder is instantiated multiple times during the request.
|
|
request_cache(:find_label_ids) { [root_namespace.id, params.label_names] }
|
|
end
|
|
|
|
def by_label(items)
|
|
return items unless params.labels?
|
|
|
|
return super if Feature.disabled?(:optimized_issuable_label_filter, default_enabled: :yaml)
|
|
|
|
target_model = items.model
|
|
|
|
if params.filter_by_no_label?
|
|
items.where('NOT EXISTS (?)', optimized_any_label_query(target_model))
|
|
elsif params.filter_by_any_label?
|
|
items.where('EXISTS (?)', optimized_any_label_query(target_model))
|
|
else
|
|
issuables_with_selected_labels(items, target_model)
|
|
end
|
|
end
|
|
|
|
# Taken from IssuableFinder
|
|
def count_by_state
|
|
return super if root_namespace.nil?
|
|
return super if Feature.disabled?(:optimized_issuable_label_filter, default_enabled: :yaml)
|
|
|
|
count_params = params.merge(state: nil, sort: nil, force_cte: true)
|
|
finder = self.class.new(current_user, count_params)
|
|
|
|
state_counts = finder
|
|
.execute
|
|
.reorder(nil)
|
|
.group(:state_id)
|
|
.count
|
|
|
|
counts = state_counts.transform_keys { |key| count_key(key) }
|
|
|
|
counts[:all] = counts.values.sum
|
|
counts.with_indifferent_access
|
|
end
|
|
|
|
private
|
|
|
|
def issuables_with_selected_labels(items, target_model)
|
|
if root_namespace
|
|
all_label_ids = find_label_ids
|
|
# Found less labels in the DB than we were searching for. Return nothing.
|
|
return items.none if all_label_ids.size != params.label_names.size
|
|
|
|
all_label_ids.each do |label_ids|
|
|
items = items.where('EXISTS (?)', optimized_label_query_by_label_ids(target_model, label_ids))
|
|
end
|
|
else
|
|
params.label_names.each do |label_name|
|
|
items = items.where('EXISTS (?)', optimized_label_query_by_label_name(target_model, label_name))
|
|
end
|
|
end
|
|
|
|
items
|
|
end
|
|
|
|
def find_label_ids
|
|
group_labels = Label
|
|
.where(project_id: nil)
|
|
.where(title: params.label_names)
|
|
.where(group_id: root_namespace.self_and_descendants.select(:id))
|
|
|
|
project_labels = Label
|
|
.where(group_id: nil)
|
|
.where(title: params.label_names)
|
|
.where(project_id: Project.select(:id).where(namespace_id: root_namespace.self_and_descendants.select(:id)))
|
|
|
|
Label
|
|
.from_union([group_labels, project_labels], remove_duplicates: false)
|
|
.reorder(nil)
|
|
.pluck(:title, :id)
|
|
.group_by(&:first)
|
|
.values
|
|
.map { |labels| labels.map(&:last) }
|
|
end
|
|
|
|
def root_namespace
|
|
strong_memoize(:root_namespace) do
|
|
(params.project || params.group)&.root_ancestor
|
|
end
|
|
end
|
|
|
|
def optimized_any_label_query(target_model)
|
|
LabelLink
|
|
.where(target_type: target_model.name)
|
|
.where(LabelLink.arel_table['target_id'].eq(target_model.arel_table['id']))
|
|
.limit(1)
|
|
end
|
|
|
|
def optimized_label_query_by_label_ids(target_model, label_ids)
|
|
LabelLink
|
|
.where(target_type: target_model.name)
|
|
.where(LabelLink.arel_table['target_id'].eq(target_model.arel_table['id']))
|
|
.where(label_id: label_ids)
|
|
.limit(1)
|
|
end
|
|
|
|
def optimized_label_query_by_label_name(target_model, label_name)
|
|
LabelLink
|
|
.joins(:label)
|
|
.where(target_type: target_model.name)
|
|
.where(LabelLink.arel_table['target_id'].eq(target_model.arel_table['id']))
|
|
.where(labels: { name: label_name })
|
|
.limit(1)
|
|
end
|
|
end
|