Skip to content
Snippets Groups Projects

Draft: Test N+1 fix

Closed Pedro Pombeiro requested to merge pedropombeiro/test/96070 into master
1 unresolved thread
1 file
+ 14
8
Compare changes
  • Side-by-side
  • Inline
@@ -89,7 +89,7 @@ def membership
@@ -89,7 +89,7 @@ def membership
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: enable CodeReuse/ActiveRecord
def project?
def project?
object.is_a?(Project)
object.is_a?(Project) && preload_project_associations
end
end
def type
def type
@@ -117,18 +117,14 @@ def last_pipeline
@@ -117,18 +117,14 @@ def last_pipeline
return unless project? && can?(request.current_user, :read_build, object)
return unless project? && can?(request.current_user, :read_build, object)
BatchLoader.for(object).batch do |projects, loader|
BatchLoader.for(object).batch do |projects, loader|
# rubocop: disable CodeReuse/ActiveRecord
# This will load the project_feature association for all the projects for the line after next line
ActiveRecord::Associations::Preloader.new.preload(projects, :project_feature)
builds_enabled_projects = projects.select(&:builds_enabled?)
builds_enabled_projects = projects.select(&:builds_enabled?)
# Prefill nil for all the projects
# Prefill nil for all the projects
projects.each { |project| loader.call(project, nil) }
projects.each { |project| loader.call(project, nil) }
# This is to load last_pipeline for all the builds-enabled projects in one SQL
# This is to load last_pipeline for all the builds-enabled projects in one SQL
Ci::Pipeline # The DISTINCT select statement will work with the below ORDER statement to return the last pipeline
Ci::Pipeline # The DISTINCT select statement will work with the below ORDER statement to return the last pipeline
.select("DISTINCT ON (project_id) *")
.select("DISTINCT ON (project_id) id, project_id, status").ci_sources
.where(project_id: builds_enabled_projects.map(&:id)).ci_sources
.where(project_id: builds_enabled_projects.map(&:id)).order(:project_id, id: :desc) # rubocop: disable CodeReuse/ActiveRecord
.order(:project_id, id: :desc)
# `each` is used instead of `find_each` because `find_each` will overwrite the above ORDER statement that we
# `each` is used instead of `find_each` because `find_each` will overwrite the above ORDER statement that we
# need for the last pipelines query to work.
# need for the last pipelines query to work.
.each do |pipeline|
.each do |pipeline|
@@ -141,9 +137,19 @@ def last_pipeline
@@ -141,9 +137,19 @@ def last_pipeline
text: pipeline.status
text: pipeline.status
})
})
end
end
# rubocop: enable CodeReuse/ActiveRecord
end
end
end
end
 
 
def preload_project_associations
 
@preload_project_associations ||=
 
BatchLoader.for(object).batch do |projects, loader|
 
# This will load the associations for all the projects for the later serialization
 
preloader = ActiveRecord::Associations::Preloader.new
 
preloader.preload(projects, :project_feature) # rubocop:disable CodeReuse/ActiveRecord
 
# NOTE: we just need to fill `nil` to fulfill the loader
 
projects.each { |project| loader.call(project, nil) }
 
end && true
 
end
end
end
GroupChildEntity.prepend_mod_with('GroupChildEntity')
GroupChildEntity.prepend_mod_with('GroupChildEntity')
Loading