diff options
author | Valery Sizov <valery@gitlab.com> | 2017-03-09 16:51:20 +0200 |
---|---|---|
committer | Valery Sizov <valery@gitlab.com> | 2017-03-14 14:11:18 +0200 |
commit | 96fe1856da46517b028fe0ddac89f314f25c8855 (patch) | |
tree | 6e4a7ebf58e706a5e3957090638f6cfa5bb9c56b | |
parent | b3eda944454cb180cdefb8ddff35fdeb729e3ed5 (diff) | |
download | gitlab-ce-96fe1856da46517b028fe0ddac89f314f25c8855.tar.gz |
Fix relative position calculation
-rw-r--r-- | app/models/concerns/relative_positioning.rb | 20 | ||||
-rw-r--r-- | spec/models/concerns/relative_positioning_spec.rb | 27 |
2 files changed, 39 insertions, 8 deletions
diff --git a/app/models/concerns/relative_positioning.rb b/app/models/concerns/relative_positioning.rb index 603f2dd7e5d..ec23c8a08fb 100644 --- a/app/models/concerns/relative_positioning.rb +++ b/app/models/concerns/relative_positioning.rb @@ -3,6 +3,7 @@ module RelativePositioning MIN_POSITION = 0 MAX_POSITION = Gitlab::Database::MAX_INT_VALUE + DISTANCE = 500 included do after_save :save_positionable_neighbours @@ -49,7 +50,9 @@ module RelativePositioning pos_before = before.relative_position pos_after = after.relative_position - if pos_after && (pos_before == pos_after) + # We can't insert an issue between two other if the distance is 1 or 0 + # so we need to handle this collision properly + if pos_after && (pos_after - pos_before).abs <= 1 self.relative_position = pos_before before.move_before(self) after.move_after(self) @@ -75,19 +78,20 @@ module RelativePositioning private # This method takes two integer values (positions) and - # calculates some random position between them. The range is huge as - # the maximum integer value is 2147483647. Ideally, the calculated value would be - # exactly between those terminating values, but this will introduce possibility of a race condition - # so two or more issues can get the same value, we want to avoid that and we also want to avoid - # using a lock here. If we have two issues with distance more than one thousand, we are OK. - # Given the huge range of possible values that integer can fit we shoud never face a problem. + # calculates the position between them. The range is huge as + # the maximum integer value is 2147483647. We are incrementing position by 1000 every time + # when we have enough space. If distance is less then 500 we are calculating an average number def position_between(pos_before, pos_after) pos_before ||= MIN_POSITION pos_after ||= MAX_POSITION pos_before, pos_after = [pos_before, pos_after].sort - rand(pos_before.next..pos_after.pred) + if pos_after - pos_before > DISTANCE * 2 + pos_before + DISTANCE + else + pos_before + (pos_after - pos_before) / 2 + end end def save_positionable_neighbours diff --git a/spec/models/concerns/relative_positioning_spec.rb b/spec/models/concerns/relative_positioning_spec.rb index 69906382545..12f44bfe0a5 100644 --- a/spec/models/concerns/relative_positioning_spec.rb +++ b/spec/models/concerns/relative_positioning_spec.rb @@ -100,5 +100,32 @@ describe Issue, 'RelativePositioning' do 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 closer to before-issue if distance is big enough' do + issue.update relative_position: 100 + issue1.update relative_position: 6000 + + new_issue.move_between(issue, issue1) + + expect(new_issue.relative_position).to eq(100 + RelativePositioning::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 end end |