summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Brandl <abrandl@gitlab.com>2018-02-19 20:16:45 +0100
committerAndreas Brandl <abrandl@gitlab.com>2018-02-19 20:52:46 +0100
commit50c301adc7235ab56aa411b9efe2ec668bc378f4 (patch)
tree6380bca9dc6773ae85d58813ce2311daaa014c21
parent9f414e05de85dfbc53ba5147d157cd467ab4dca8 (diff)
downloadgitlab-ce-42877-snippets-dashboard-slow-2.tar.gz
Allow choice between #where or #from.42877-snippets-dashboard-slow-2
Immediately using #from here requires a lot of changes in other finders (e.g. IssuableFinder, TodosFinder). In all places where we use #merge, this goes completely the wrong way when passed in a relation that was built with `#from(...)`: The original query's FROM part gets completely replaced. This avoids changing all other places and focuses on improving SnippetFinder with the downside of two (small) codepaths to do the same thing.
-rw-r--r--app/finders/snippets_finder.rb2
-rw-r--r--app/models/project.rb17
2 files changed, 14 insertions, 5 deletions
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb
index c4a84d88dbd..581cd5f47a7 100644
--- a/app/finders/snippets_finder.rb
+++ b/app/finders/snippets_finder.rb
@@ -56,7 +56,7 @@ class SnippetsFinder < UnionFinder
end
def feature_available_projects
- projects = Project.public_or_visible_to_user(current_user) do |part|
+ projects = Project.public_or_visible_to_user(current_user, use_conditions_only: false) do |part|
part.with_feature_available_for_user(:snippets, current_user)
end.select(:id)
diff --git a/app/models/project.rb b/app/models/project.rb
index 5c6088d120f..2e126bd50c1 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -321,7 +321,10 @@ class Project < ActiveRecord::Base
# the query, e.g. to apply .with_feature_available_for_user on top of it.
# This is useful for performance as we can stick those additional filters
# at the bottom of e.g. the UNION.
- def self.public_or_visible_to_user(user = nil, &block)
+ #
+ # Optionally, turning `use_conditions_only` off leads to returning a
+ # relation using #from instead of #where.
+ def self.public_or_visible_to_user(user = nil, use_conditions_only: true, &block)
# If we don't get a block passed, use identity to avoid if/else repetitions
block = ->(part) { part } unless block_given?
@@ -344,9 +347,15 @@ class Project < ActiveRecord::Base
# We use a UNION here instead of OR clauses since this results in better
# performance.
- union = Gitlab::SQL::Union.new([authorized_projects.select('projects.id'), visible_projects.select('projects.id')])
- # TODO: from("(#{union.to_sql}) AS #{table_name}")
- where("projects.id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
+ union_branches = [authorized_projects, visible_projects]
+
+ if use_conditions_only
+ union = Gitlab::SQL::Union.new(union_branches.map { |b| b.select('projects.id') })
+ where("projects.id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
+ else
+ union = Gitlab::SQL::Union.new(union_branches)
+ from("(#{union.to_sql}) AS #{table_name}")
+ end
else
block.call(public_to_user)
end