eb15e4dfc2
1. When every issue has a relative position set, we don't need to perform any updates, or calculate the maximum position in the parent. 2. If we do need to calculate the maximum position in the parent, many parents (specifically, groups with lots of projects) leads to a slow query where only the index on issues.relative_position is used, not the index on issues.project_id. Adding the GROUP BY forces Postgres to use both indices.
240 lines
6.8 KiB
Ruby
240 lines
6.8 KiB
Ruby
require 'spec_helper'
|
|
|
|
describe RelativePositioning do
|
|
let(:project) { create(:project) }
|
|
let(:issue) { create(:issue, project: project) }
|
|
let(:issue1) { create(:issue, project: project) }
|
|
let(:new_issue) { create(:issue, project: project) }
|
|
|
|
describe '.move_to_end' do
|
|
it 'moves the object to the end' do
|
|
Issue.move_to_end([issue, issue1])
|
|
|
|
expect(issue1.prev_relative_position).to eq issue.relative_position
|
|
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
|
|
it 'returns maximum position' do
|
|
expect(issue.max_relative_position).to eq issue1.relative_position
|
|
end
|
|
end
|
|
|
|
describe '#prev_relative_position' do
|
|
it 'returns previous position if there is an issue above' do
|
|
expect(issue1.prev_relative_position).to eq issue.relative_position
|
|
end
|
|
|
|
it 'returns nil if there is no issue above' do
|
|
expect(issue.prev_relative_position).to eq nil
|
|
end
|
|
end
|
|
|
|
describe '#next_relative_position' do
|
|
it 'returns next position if there is an issue below' do
|
|
expect(issue.next_relative_position).to eq issue1.relative_position
|
|
end
|
|
|
|
it 'returns nil if there is no issue below' do
|
|
expect(issue1.next_relative_position).to eq nil
|
|
end
|
|
end
|
|
|
|
describe '#move_before' do
|
|
it 'moves issue before' do
|
|
[issue1, issue].each(&:move_to_end)
|
|
|
|
issue.move_before(issue1)
|
|
|
|
expect(issue.relative_position).to be < issue1.relative_position
|
|
end
|
|
end
|
|
|
|
describe '#move_after' do
|
|
it 'moves issue after' do
|
|
[issue, issue1].each(&:move_to_end)
|
|
|
|
issue.move_after(issue1)
|
|
|
|
expect(issue.relative_position).to be > issue1.relative_position
|
|
end
|
|
end
|
|
|
|
describe '#move_to_end' do
|
|
before do
|
|
[issue, issue1].each do |issue|
|
|
issue.move_to_end && issue.save
|
|
end
|
|
end
|
|
|
|
it 'moves issue to the end' do
|
|
new_issue.move_to_end
|
|
|
|
expect(new_issue.relative_position).to be > issue1.relative_position
|
|
end
|
|
end
|
|
|
|
describe '#shift_after?' do
|
|
before do
|
|
[issue, issue1].each do |issue|
|
|
issue.move_to_end && issue.save
|
|
end
|
|
end
|
|
|
|
it 'returns true' do
|
|
issue.update(relative_position: issue1.relative_position - 1)
|
|
|
|
expect(issue.shift_after?).to be_truthy
|
|
end
|
|
|
|
it 'returns false' do
|
|
issue.update(relative_position: issue1.relative_position - 2)
|
|
|
|
expect(issue.shift_after?).to be_falsey
|
|
end
|
|
end
|
|
|
|
describe '#shift_before?' do
|
|
before do
|
|
[issue, issue1].each do |issue|
|
|
issue.move_to_end && issue.save
|
|
end
|
|
end
|
|
|
|
it 'returns true' do
|
|
issue.update(relative_position: issue1.relative_position + 1)
|
|
|
|
expect(issue.shift_before?).to be_truthy
|
|
end
|
|
|
|
it 'returns false' do
|
|
issue.update(relative_position: issue1.relative_position + 2)
|
|
|
|
expect(issue.shift_before?).to be_falsey
|
|
end
|
|
end
|
|
|
|
describe '#move_between' do
|
|
before do
|
|
[issue, issue1].each do |issue|
|
|
issue.move_to_end && issue.save
|
|
end
|
|
end
|
|
|
|
it 'positions issue between two other' do
|
|
new_issue.move_between(issue, issue1)
|
|
|
|
expect(new_issue.relative_position).to be > issue.relative_position
|
|
expect(new_issue.relative_position).to be < issue1.relative_position
|
|
end
|
|
|
|
it 'positions issue between on top' do
|
|
new_issue.move_between(nil, issue)
|
|
|
|
expect(new_issue.relative_position).to be < issue.relative_position
|
|
end
|
|
|
|
it 'positions issue between to end' do
|
|
new_issue.move_between(issue1, nil)
|
|
|
|
expect(new_issue.relative_position).to be > issue1.relative_position
|
|
end
|
|
|
|
it 'positions issues even when after and before positions are the same' do
|
|
issue1.update relative_position: issue.relative_position
|
|
|
|
new_issue.move_between(issue, issue1)
|
|
|
|
expect(new_issue.relative_position).to be > issue.relative_position
|
|
expect(issue.relative_position).to be < issue1.relative_position
|
|
end
|
|
|
|
it 'positions issues between other two if distance is 1' do
|
|
issue1.update relative_position: issue.relative_position + 1
|
|
|
|
new_issue.move_between(issue, issue1)
|
|
|
|
expect(new_issue.relative_position).to be > issue.relative_position
|
|
expect(issue.relative_position).to be < issue1.relative_position
|
|
end
|
|
|
|
it 'positions issue in the middle of other two if distance is big enough' do
|
|
issue.update relative_position: 6000
|
|
issue1.update relative_position: 10000
|
|
|
|
new_issue.move_between(issue, issue1)
|
|
|
|
expect(new_issue.relative_position).to eq(8000)
|
|
end
|
|
|
|
it 'positions issue closer to the middle if we are at the very top' do
|
|
issue1.update relative_position: 6000
|
|
|
|
new_issue.move_between(nil, issue1)
|
|
|
|
expect(new_issue.relative_position).to eq(6000 - RelativePositioning::IDEAL_DISTANCE)
|
|
end
|
|
|
|
it 'positions issue closer to the middle if we are at the very bottom' do
|
|
issue.update relative_position: 6000
|
|
issue1.update relative_position: nil
|
|
|
|
new_issue.move_between(issue, nil)
|
|
|
|
expect(new_issue.relative_position).to eq(6000 + RelativePositioning::IDEAL_DISTANCE)
|
|
end
|
|
|
|
it 'positions issue in the middle of other two if distance is not big enough' do
|
|
issue.update relative_position: 100
|
|
issue1.update relative_position: 400
|
|
|
|
new_issue.move_between(issue, issue1)
|
|
|
|
expect(new_issue.relative_position).to eq(250)
|
|
end
|
|
|
|
it 'positions issue in the middle of other two is there is no place' do
|
|
issue.update relative_position: 100
|
|
issue1.update relative_position: 101
|
|
|
|
new_issue.move_between(issue, issue1)
|
|
|
|
expect(new_issue.relative_position).to be_between(issue.relative_position, issue1.relative_position)
|
|
end
|
|
|
|
it 'uses rebalancing if there is no place' do
|
|
issue.update relative_position: 100
|
|
issue1.update relative_position: 101
|
|
issue2 = create(:issue, relative_position: 102, project: project)
|
|
new_issue.update relative_position: 103
|
|
|
|
new_issue.move_between(issue1, issue2)
|
|
new_issue.save!
|
|
|
|
expect(new_issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
|
|
expect(issue.reload.relative_position).not_to eq(100)
|
|
end
|
|
|
|
it 'positions issue right if we pass none-sequential parameters' do
|
|
issue.update relative_position: 99
|
|
issue1.update relative_position: 101
|
|
issue2 = create(:issue, relative_position: 102, project: project)
|
|
new_issue.update relative_position: 103
|
|
|
|
new_issue.move_between(issue, issue2)
|
|
new_issue.save!
|
|
|
|
expect(new_issue.relative_position).to be(100)
|
|
end
|
|
end
|
|
end
|