Refactor Gitlab::SearchResults
Instead of plucking IDs this class now uses ActiveRecord::Relation objects. Plucking IDs is problematic as searching for projects can lead to a huge amount of IDs being loaded into memory only to be used as an argument for another query (instead of just using a sub-query).
This commit is contained in:
parent
2cf7f3f410
commit
013542965c
3 changed files with 72 additions and 11 deletions
|
@ -10,9 +10,8 @@ module Search
|
||||||
group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
|
group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
|
||||||
projects = ProjectsFinder.new.execute(current_user)
|
projects = ProjectsFinder.new.execute(current_user)
|
||||||
projects = projects.in_namespace(group.id) if group
|
projects = projects.in_namespace(group.id) if group
|
||||||
project_ids = projects.pluck(:id)
|
|
||||||
|
|
||||||
Gitlab::SearchResults.new(project_ids, params[:search])
|
Gitlab::SearchResults.new(projects, params[:search])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,12 +2,12 @@ module Gitlab
|
||||||
class SearchResults
|
class SearchResults
|
||||||
attr_reader :query
|
attr_reader :query
|
||||||
|
|
||||||
# Limit search results by passed project ids
|
# Limit search results by passed projects
|
||||||
# It allows us to search only for projects user has access to
|
# It allows us to search only for projects user has access to
|
||||||
attr_reader :limit_project_ids
|
attr_reader :limit_projects
|
||||||
|
|
||||||
def initialize(limit_project_ids, query)
|
def initialize(limit_projects, query)
|
||||||
@limit_project_ids = limit_project_ids || Project.all
|
@limit_projects = limit_projects || Project.all
|
||||||
@query = Shellwords.shellescape(query) if query.present?
|
@query = Shellwords.shellescape(query) if query.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -27,7 +27,8 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def total_count
|
def total_count
|
||||||
@total_count ||= projects_count + issues_count + merge_requests_count + milestones_count
|
@total_count ||= projects_count + issues_count + merge_requests_count +
|
||||||
|
milestones_count
|
||||||
end
|
end
|
||||||
|
|
||||||
def projects_count
|
def projects_count
|
||||||
|
@ -53,27 +54,29 @@ module Gitlab
|
||||||
private
|
private
|
||||||
|
|
||||||
def projects
|
def projects
|
||||||
Project.where(id: limit_project_ids).search(query)
|
limit_projects.search(query)
|
||||||
end
|
end
|
||||||
|
|
||||||
def issues
|
def issues
|
||||||
issues = Issue.where(project_id: limit_project_ids)
|
issues = Issue.where(project_id: project_ids_relation)
|
||||||
|
|
||||||
if query =~ /#(\d+)\z/
|
if query =~ /#(\d+)\z/
|
||||||
issues = issues.where(iid: $1)
|
issues = issues.where(iid: $1)
|
||||||
else
|
else
|
||||||
issues = issues.full_search(query)
|
issues = issues.full_search(query)
|
||||||
end
|
end
|
||||||
|
|
||||||
issues.order('updated_at DESC')
|
issues.order('updated_at DESC')
|
||||||
end
|
end
|
||||||
|
|
||||||
def milestones
|
def milestones
|
||||||
milestones = Milestone.where(project_id: limit_project_ids)
|
milestones = Milestone.where(project_id: project_ids_relation)
|
||||||
milestones = milestones.search(query)
|
milestones = milestones.search(query)
|
||||||
milestones.order('updated_at DESC')
|
milestones.order('updated_at DESC')
|
||||||
end
|
end
|
||||||
|
|
||||||
def merge_requests
|
def merge_requests
|
||||||
merge_requests = MergeRequest.in_projects(limit_project_ids)
|
merge_requests = MergeRequest.in_projects(project_ids_relation)
|
||||||
if query =~ /[#!](\d+)\z/
|
if query =~ /[#!](\d+)\z/
|
||||||
merge_requests = merge_requests.where(iid: $1)
|
merge_requests = merge_requests.where(iid: $1)
|
||||||
else
|
else
|
||||||
|
@ -89,5 +92,9 @@ module Gitlab
|
||||||
def per_page
|
def per_page
|
||||||
20
|
20
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def project_ids_relation
|
||||||
|
limit_projects.select(:id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
55
spec/lib/gitlab/search_results_spec.rb
Normal file
55
spec/lib/gitlab/search_results_spec.rb
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Gitlab::SearchResults do
|
||||||
|
let!(:project) { create(:project, name: 'foo') }
|
||||||
|
let!(:issue) { create(:issue, project: project, title: 'foo') }
|
||||||
|
|
||||||
|
let!(:merge_request) do
|
||||||
|
create(:merge_request, source_project: project, title: 'foo')
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:milestone) { create(:milestone, project: project, title: 'foo') }
|
||||||
|
let(:results) { described_class.new(Project.all, 'foo') }
|
||||||
|
|
||||||
|
describe '#total_count' do
|
||||||
|
it 'returns the total amount of search hits' do
|
||||||
|
expect(results.total_count).to eq(4)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#projects_count' do
|
||||||
|
it 'returns the total amount of projects' do
|
||||||
|
expect(results.projects_count).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#issues_count' do
|
||||||
|
it 'returns the total amount of issues' do
|
||||||
|
expect(results.issues_count).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#merge_requests_count' do
|
||||||
|
it 'returns the total amount of merge requests' do
|
||||||
|
expect(results.merge_requests_count).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#milestones_count' do
|
||||||
|
it 'returns the total amount of milestones' do
|
||||||
|
expect(results.milestones_count).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#empty?' do
|
||||||
|
it 'returns true when there are no search results' do
|
||||||
|
allow(results).to receive(:total_count).and_return(0)
|
||||||
|
|
||||||
|
expect(results.empty?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns false when there are search results' do
|
||||||
|
expect(results.empty?).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue