Commit 4aba5a43 authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Add OR filtering for issuable assignees

Allows OR filtering of assignees for issues and merge requests
parent e9cfca05
......@@ -4,6 +4,7 @@ module Issuables
class AssigneeFilter < BaseFilter
def filter(issuables)
filtered = by_assignee(issuables)
filtered = by_assignee_union(filtered)
by_negated_assignee(filtered)
end
......@@ -27,6 +28,12 @@ module Issuables
end
end
def by_assignee_union(issuables)
return issuables unless or_filters_enabled? && has_assignee_param?(or_params)
issuables.assigned_to(assignee_ids(or_params))
end
def by_negated_assignee(issuables)
return issuables unless has_assignee_param?(not_params)
......
......@@ -21,7 +21,7 @@ module Issuables
end
def by_author_union(issuables)
return issuables unless or_filters_enabled? && or_params&.fetch(:author_username).present?
return issuables unless or_filters_enabled? && or_params&.fetch(:author_username, false).present?
issuables.authored(User.by_username(or_params[:author_username]))
end
......
......@@ -101,20 +101,19 @@ module Issuable
scope :unassigned, -> do
where("NOT EXISTS (SELECT TRUE FROM #{to_ability_name}_assignees WHERE #{to_ability_name}_id = #{to_ability_name}s.id)")
end
scope :assigned_to, ->(u) do
assignees_table = Arel::Table.new("#{to_ability_name}_assignees")
sql = assignees_table.project('true').where(assignees_table[:user_id].in(u.id)).where(Arel::Nodes::SqlLiteral.new("#{to_ability_name}_id = #{to_ability_name}s.id"))
where("EXISTS (#{sql.to_sql})")
end
# rubocop:enable GitlabSecurity/SqlInjection
scope :assigned_to, ->(users) do
assignees_class = self.reflect_on_association("#{to_ability_name}_assignees").klass
condition = assignees_class.where(user_id: users).where(Arel.sql("#{to_ability_name}_id = #{to_ability_name}s.id"))
where(condition.arel.exists)
end
scope :not_assigned_to, ->(users) do
assignees_table = Arel::Table.new("#{to_ability_name}_assignees")
sql = assignees_table.project('true')
.where(assignees_table[:user_id].in(users))
.where(Arel::Nodes::SqlLiteral.new("#{to_ability_name}_id = #{to_ability_name}s.id"))
where(sql.exists.not)
assignees_class = self.reflect_on_association("#{to_ability_name}_assignees").klass
condition = assignees_class.where(user_id: users).where(Arel.sql("#{to_ability_name}_id = #{to_ability_name}s.id"))
where(condition.arel.exists.not)
end
# rubocop:enable GitlabSecurity/SqlInjection
scope :without_particular_labels, ->(label_names) do
labels_table = Label.arel_table
......
......@@ -85,6 +85,8 @@ RSpec.describe Admin::CredentialsController, type: :request do
create(:gpg_key, user: control_user, key: GpgHelpers::User1.public_key)
create(:gpg_key, user: control_user, key: GpgHelpers::User1.public_key2)
get admin_credentials_path(filter: 'gpg_keys')
control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
get admin_credentials_path(filter: 'gpg_keys')
end.count
......
......@@ -49,6 +49,11 @@ RSpec.describe IssuesFinder do
let(:expected_issuables) { [issue3, issue4] }
end
it_behaves_like 'assignee OR filter' do
let(:params) { { or: { assignee_id: [user.id, user2.id] } } }
let(:expected_issuables) { [issue1, issue2, issue3, issue5] }
end
context 'when assignee_id does not exist' do
it_behaves_like 'assignee NOT ID filter' do
let(:params) { { not: { assignee_id: -100 } } }
......@@ -79,6 +84,11 @@ RSpec.describe IssuesFinder do
let(:expected_issuables) { [issue3, issue4] }
end
it_behaves_like 'assignee OR filter' do
let(:params) { { or: { assignee_username: [user2.username, user3.username] } } }
let(:expected_issuables) { [issue2, issue3] }
end
context 'when assignee_username does not exist' do
it_behaves_like 'assignee NOT username filter' do
before do
......
......@@ -24,6 +24,12 @@ RSpec.shared_examples 'assignee NOT username filter' do
end
end
RSpec.shared_examples 'assignee OR filter' do
it 'returns issuables assigned to the given users' do
expect(issuables).to contain_exactly(*expected_issuables)
end
end
RSpec.shared_examples 'no assignee filter' do
let(:params) { { assignee_id: 'None' } }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment