diff options
Diffstat (limited to 'lib/gitlab/search_results.rb')
-rw-r--r-- | lib/gitlab/search_results.rb | 106 |
1 files changed, 68 insertions, 38 deletions
diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb index efe8095beea..1e45d074e0a 100644 --- a/lib/gitlab/search_results.rb +++ b/lib/gitlab/search_results.rb @@ -1,15 +1,19 @@ module Gitlab class SearchResults class FoundBlob - attr_reader :id, :filename, :basename, :ref, :startline, :data + include EncodingHelper + + attr_reader :id, :filename, :basename, :ref, :startline, :data, :project_id def initialize(opts = {}) @id = opts.fetch(:id, nil) - @filename = opts.fetch(:filename, nil) - @basename = opts.fetch(:basename, nil) + @filename = encode_utf8(opts.fetch(:filename, nil)) + @basename = encode_utf8(opts.fetch(:basename, nil)) @ref = opts.fetch(:ref, nil) @startline = opts.fetch(:startline, nil) - @data = opts.fetch(:data, nil) + @data = encode_utf8(opts.fetch(:data, nil)) + @per_page = opts.fetch(:per_page, 20) + @project_id = opts.fetch(:project_id, nil) end def path @@ -21,61 +25,86 @@ module Gitlab end end - attr_reader :current_user, :query + attr_reader :current_user, :query, :per_page # Limit search results by passed projects # It allows us to search only for projects user has access to attr_reader :limit_projects - def initialize(current_user, limit_projects, query) + # Whether a custom filter is used to restrict scope of projects. + # If the default filter (which lists all projects user has access to) + # is used, we can skip it when filtering merge requests and optimize the + # query + attr_reader :default_project_filter + + def initialize(current_user, limit_projects, query, default_project_filter: false, per_page: 20) @current_user = current_user @limit_projects = limit_projects || Project.all - @query = Shellwords.shellescape(query) if query.present? + @query = query + @default_project_filter = default_project_filter + @per_page = per_page end - def objects(scope, page = nil) - case scope - when 'projects' - projects.page(page).per(per_page) - when 'issues' - issues.page(page).per(per_page) - when 'merge_requests' - merge_requests.page(page).per(per_page) - when 'milestones' - milestones.page(page).per(per_page) - else - Kaminari.paginate_array([]).page(page).per(per_page) - end + def objects(scope, page = nil, without_count = true) + collection = case scope + when 'projects' + projects.page(page).per(per_page) + when 'issues' + issues.page(page).per(per_page) + when 'merge_requests' + merge_requests.page(page).per(per_page) + when 'milestones' + milestones.page(page).per(per_page) + else + Kaminari.paginate_array([]).page(page).per(per_page) + end + + without_count ? collection.without_count : collection end - def projects_count - @projects_count ||= projects.count + def limited_projects_count + @limited_projects_count ||= projects.limit(count_limit).count end - def issues_count - @issues_count ||= issues.count + def limited_issues_count + return @limited_issues_count if @limited_issues_count + + # By default getting limited count (e.g. 1000+) is fast on issuable + # collections except for issues, where filtering both not confidential + # and confidential issues user has access to, is too complex. + # It's faster to try to fetch all public issues first, then only + # if necessary try to fetch all issues. + sum = issues(public_only: true).limit(count_limit).count + @limited_issues_count = sum < count_limit ? issues.limit(count_limit).count : sum end - def merge_requests_count - @merge_requests_count ||= merge_requests.count + def limited_merge_requests_count + @limited_merge_requests_count ||= merge_requests.limit(count_limit).count end - def milestones_count - @milestones_count ||= milestones.count + def limited_milestones_count + @limited_milestones_count ||= milestones.limit(count_limit).count end def single_commit_result? false end + def count_limit + 1001 + end + private def projects limit_projects.search(query) end - def issues - issues = IssuesFinder.new(current_user).execute.where(project_id: project_ids_relation) + def issues(finder_params = {}) + issues = IssuesFinder.new(current_user, finder_params).execute + unless default_project_filter + issues = issues.where(project_id: project_ids_relation) + end issues = if query =~ /#(\d+)\z/ @@ -84,34 +113,35 @@ module Gitlab issues.full_search(query) end - issues.order('updated_at DESC') + issues.reorder('updated_at DESC') end def milestones milestones = Milestone.where(project_id: project_ids_relation) milestones = milestones.search(query) - milestones.order('updated_at DESC') + milestones.reorder('updated_at DESC') end def merge_requests - merge_requests = MergeRequestsFinder.new(current_user).execute.in_projects(project_ids_relation) + merge_requests = MergeRequestsFinder.new(current_user).execute + unless default_project_filter + merge_requests = merge_requests.in_projects(project_ids_relation) + end + merge_requests = if query =~ /[#!](\d+)\z/ merge_requests.where(iid: $1) else merge_requests.full_search(query) end - merge_requests.order('updated_at DESC') + + merge_requests.reorder('updated_at DESC') end def default_scope 'projects' end - def per_page - 20 - end - def project_ids_relation limit_projects.select(:id).reorder(nil) end |