Merge branch 'speed-up-relative-positioning' into 'master'
Speed up setting of relative position See merge request gitlab-org/gitlab-ce!23324
This commit is contained in:
commit
fbbe5ccd1b
|
@ -14,10 +14,12 @@ module RelativePositioning
|
|||
|
||||
class_methods do
|
||||
def move_to_end(objects)
|
||||
parent_ids = objects.map(&:parent_ids).flatten.uniq
|
||||
max_relative_position = in_parents(parent_ids).maximum(:relative_position) || START_POSITION
|
||||
objects = objects.reject(&:relative_position)
|
||||
|
||||
return if objects.empty?
|
||||
|
||||
max_relative_position = objects.first.max_relative_position
|
||||
|
||||
self.transaction do
|
||||
objects.each do |object|
|
||||
relative_position = position_between(max_relative_position, MAX_POSITION)
|
||||
|
@ -55,22 +57,21 @@ module RelativePositioning
|
|||
end
|
||||
end
|
||||
|
||||
def min_relative_position
|
||||
self.class.in_parents(parent_ids).minimum(:relative_position)
|
||||
def min_relative_position(&block)
|
||||
calculate_relative_position('MIN', &block)
|
||||
end
|
||||
|
||||
def max_relative_position
|
||||
self.class.in_parents(parent_ids).maximum(:relative_position)
|
||||
def max_relative_position(&block)
|
||||
calculate_relative_position('MAX', &block)
|
||||
end
|
||||
|
||||
def prev_relative_position
|
||||
prev_pos = nil
|
||||
|
||||
if self.relative_position
|
||||
prev_pos = self.class
|
||||
.in_parents(parent_ids)
|
||||
.where('relative_position < ?', self.relative_position)
|
||||
.maximum(:relative_position)
|
||||
prev_pos = max_relative_position do |relation|
|
||||
relation.where('relative_position < ?', self.relative_position)
|
||||
end
|
||||
end
|
||||
|
||||
prev_pos
|
||||
|
@ -80,10 +81,9 @@ module RelativePositioning
|
|||
next_pos = nil
|
||||
|
||||
if self.relative_position
|
||||
next_pos = self.class
|
||||
.in_parents(parent_ids)
|
||||
.where('relative_position > ?', self.relative_position)
|
||||
.minimum(:relative_position)
|
||||
next_pos = min_relative_position do |relation|
|
||||
relation.where('relative_position > ?', self.relative_position)
|
||||
end
|
||||
end
|
||||
|
||||
next_pos
|
||||
|
@ -165,4 +165,22 @@ module RelativePositioning
|
|||
status
|
||||
end
|
||||
# rubocop:enable Gitlab/ModuleWithInstanceVariables
|
||||
|
||||
def calculate_relative_position(calculation)
|
||||
# When calculating across projects, this is much more efficient than
|
||||
# MAX(relative_position) without the GROUP BY, due to index usage:
|
||||
# https://gitlab.com/gitlab-org/gitlab-ce/issues/54276#note_119340977
|
||||
relation = self.class
|
||||
.in_parents(parent_ids)
|
||||
.order(Gitlab::Database.nulls_last_order('position', 'DESC'))
|
||||
.limit(1)
|
||||
.group(self.class.parent_column)
|
||||
|
||||
relation = yield relation if block_given?
|
||||
|
||||
relation
|
||||
.pluck(self.class.parent_column, "#{calculation}(relative_position) AS position")
|
||||
.first&.
|
||||
last
|
||||
end
|
||||
end
|
||||
|
|
|
@ -99,6 +99,10 @@ class Issue < ActiveRecord::Base
|
|||
alias_method :in_parents, :in_projects
|
||||
end
|
||||
|
||||
def self.parent_column
|
||||
:project_id
|
||||
end
|
||||
|
||||
def self.reference_prefix
|
||||
'#'
|
||||
end
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Speed up issue board lists in groups with many projects
|
||||
merge_request:
|
||||
author:
|
||||
type: performance
|
|
@ -14,6 +14,14 @@ describe RelativePositioning do
|
|||
expect(issue.prev_relative_position).to eq nil
|
||||
expect(issue1.next_relative_position).to eq nil
|
||||
end
|
||||
|
||||
it 'does not perform any moves if all issues have their relative_position set' do
|
||||
issue.update!(relative_position: 1)
|
||||
|
||||
expect(issue).not_to receive(:save)
|
||||
|
||||
Issue.move_to_end([issue])
|
||||
end
|
||||
end
|
||||
|
||||
describe '#max_relative_position' do
|
||||
|
|
Loading…
Reference in New Issue