Skip to content
Snippets Groups Projects
Unverified Commit de68b422 authored by Markus Koller's avatar Markus Koller
Browse files

Use correct order when repositioning existing designs

Unpositioned designs are sorted by ID, so we need to explictly specify
that order when calling `move_nulls_to_end`.

We also always need to reload the design objects in case their position
was changed in the DB by the `move_nulls_to_end` call.
parent f2202de3
No related branches found
No related tags found
1 merge request!39826Use correct order when repositioning existing designs
......@@ -137,9 +137,10 @@ def gap_size(object, gaps:, at_end:, starting_from:)
# If `true`, then all objects with `null` positions are placed _after_
# all siblings with positions. If `false`, all objects with `null`
# positions are placed _before_ all siblings with positions.
# @returns [Number] The number of moved records.
def move_nulls(objects, at_end:)
objects = objects.reject(&:relative_position)
return if objects.empty?
return 0 if objects.empty?
representative = objects.first
number_of_gaps = objects.size + 1 # 1 at left, one between each, and one at right
......@@ -186,6 +187,8 @@ def move_nulls(objects, at_end:)
end
end
end
objects.size
end
end
......
......@@ -87,10 +87,12 @@ class Design < ApplicationRecord
# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17788/diffs#note_230875678
order(:relative_position, :id)
else
order(:id)
in_creation_order
end
end
scope :in_creation_order, -> { reorder(:id) }
scope :with_filename, -> (filenames) { where(filename: filenames) }
scope :on_issue, ->(issue) { where(issue_id: issue) }
......
......@@ -39,9 +39,12 @@ def success
delegate :issue, :project, to: :current_design
def move_nulls_to_end
current_design.class.move_nulls_to_end(issue.designs)
next_design.reset if next_design && next_design.relative_position.nil?
previous_design.reset if previous_design && previous_design.relative_position.nil?
moved_records = current_design.class.move_nulls_to_end(issue.designs.in_creation_order)
return if moved_records == 0
current_design.reset
next_design&.reset
previous_design&.reset
end
def neighbors
......
---
title: Use correct order when repositioning existing designs
merge_request: 39826
author:
type: fixed
......@@ -185,6 +185,12 @@
end
end
describe '.in_creation_order' do
it 'sorts by ID in ascending order' do
expect(described_class.in_creation_order).to eq([design1, design2, design3, deleted_design])
end
end
describe '.with_filename' do
it 'returns correct design when passed a single filename' do
expect(described_class.with_filename(design1.filename)).to eq([design1])
......
......@@ -117,9 +117,30 @@
let(:previous_design) { designs.second }
let(:next_design) { designs.third }
it 'calls move_between and is successful' do
expect(current_design).to receive(:move_between).with(previous_design, next_design)
it 'repositions existing designs and correctly places the given design' do
other_design1 = create(:design, issue: issue, relative_position: 10)
other_design2 = create(:design, issue: issue, relative_position: 20)
other_design3, other_design4 = create_list(:design, 2, issue: issue)
expect(subject).to be_success
expect(issue.designs.ordered(issue.project)).to eq([
# Existing designs which already had a relative_position set.
# These should stay at the beginning, in the same order.
other_design1,
other_design2,
# The designs we're passing into the service.
# These should be placed between the existing designs, in the correct order.
previous_design,
current_design,
next_design,
# Existing designs which didn't have a relative_position set.
# These should be placed at the end, in the order of their IDs.
other_design3,
other_design4
])
end
end
end
......
......@@ -24,7 +24,7 @@ def create_items_with_positions(positions)
item3.update!(relative_position: nil)
items = [item1, item2, item3]
described_class.move_nulls_to_end(items)
expect(described_class.move_nulls_to_end(items)).to be(2)
expect(items.sort_by(&:relative_position)).to eq(items)
expect(item1.relative_position).to be(1000)
......@@ -53,9 +53,8 @@ def create_items_with_positions(positions)
it 'does not perform any moves if all items have their relative_position set' do
item1.update!(relative_position: 1)
expect do
described_class.move_nulls_to_end([item1])
end.not_to change { item1.reset.relative_position }
expect(described_class.move_nulls_to_start([item1])).to be(0)
expect(item1.reload.relative_position).to be(1)
end
it 'manages to move nulls to the end even if there is a sequence at the end' do
......@@ -97,7 +96,7 @@ def create_items_with_positions(positions)
item3.update!(relative_position: 1000)
items = [item1, item2, item3]
described_class.move_nulls_to_start(items)
expect(described_class.move_nulls_to_start(items)).to be(2)
items.map(&:reload)
expect(items.sort_by(&:relative_position)).to eq(items)
......@@ -128,10 +127,8 @@ def create_items_with_positions(positions)
it 'does not perform any moves if all items have their relative_position set' do
item1.update!(relative_position: 1)
described_class.move_nulls_to_start([item1])
item1.reload
expect(item1.relative_position).to be(1)
expect(described_class.move_nulls_to_start([item1])).to be(0)
expect(item1.reload.relative_position).to be(1)
end
end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment