ranked-model 0.4.5 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Appraisals +1 -0
- data/gemfiles/rails_4_2.gemfile +1 -0
- data/lib/ranked-model/ranker.rb +27 -19
- data/lib/ranked-model/version.rb +1 -1
- data/spec/duck-model/duck_spec.rb +29 -21
- data/spec/duck-model/lots_of_ducks_spec.rb +18 -22
- data/spec/support/active_record.rb +2 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 608245c9f9eeed1d195c18efd1df0b32d5593465d581f269e20fb8b8867a1260
|
4
|
+
data.tar.gz: 83a935d3b960f7acf48ada59f9e87962ab04b40d75c9af50b3ddf5dc6c5dfe5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ea50e38ff89431cfcf314144141f44b7aec03dc91aa8d45db24975f2a191bc0457c032511a8cc798fc10646ca29e8e35c011dcaed5adbf0d1344bb84e5469ef
|
7
|
+
data.tar.gz: 9e2d0cadcc12b87d1602d40ef0eb8a6e2f23eff6270a841ffcdd2cd06ed74b49d40e8bfd9c49ace0680f08b73f06a3980de413aec425e2104b16fa5b5a9b7e71
|
data/Appraisals
CHANGED
data/gemfiles/rails_4_2.gemfile
CHANGED
data/lib/ranked-model/ranker.rb
CHANGED
@@ -69,6 +69,10 @@ module RankedModel
|
|
69
69
|
update_all(ranker.column => value)
|
70
70
|
end
|
71
71
|
|
72
|
+
def reset_ranks!
|
73
|
+
finder.update_all(ranker.column => nil)
|
74
|
+
end
|
75
|
+
|
72
76
|
def position
|
73
77
|
instance.send "#{ranker.name}_position"
|
74
78
|
end
|
@@ -209,31 +213,35 @@ module RankedModel
|
|
209
213
|
end
|
210
214
|
|
211
215
|
def rebalance_ranks
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
216
|
+
ActiveRecord::Base.transaction do
|
217
|
+
if rank && instance.persisted?
|
218
|
+
origin = current_order.index { |item| item.instance.id == instance.id }
|
219
|
+
if origin
|
220
|
+
destination = current_order.index { |item| rank <= item.rank }
|
221
|
+
destination -= 1 if origin < destination
|
222
|
+
|
223
|
+
current_order.insert destination, current_order.delete_at(origin)
|
224
|
+
end
|
219
225
|
end
|
220
|
-
end
|
221
226
|
|
222
|
-
|
223
|
-
|
224
|
-
|
227
|
+
gaps = current_order.size + 1
|
228
|
+
range = (RankedModel::MAX_RANK_VALUE - RankedModel::MIN_RANK_VALUE).to_f
|
229
|
+
gap_size = (range / gaps).ceil
|
225
230
|
|
226
|
-
|
227
|
-
new_rank = (gap_size * position) + RankedModel::MIN_RANK_VALUE
|
231
|
+
reset_ranks!
|
228
232
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
item.
|
233
|
+
current_order.each.with_index(1) do |item, position|
|
234
|
+
new_rank = (gap_size * position) + RankedModel::MIN_RANK_VALUE
|
235
|
+
|
236
|
+
if item.instance.id == instance.id
|
237
|
+
rank_at new_rank
|
238
|
+
else
|
239
|
+
item.update_rank! new_rank
|
240
|
+
end
|
233
241
|
end
|
234
|
-
end
|
235
242
|
|
236
|
-
|
243
|
+
reset_cache
|
244
|
+
end
|
237
245
|
end
|
238
246
|
|
239
247
|
def finder(order = :asc)
|
data/lib/ranked-model/version.rb
CHANGED
@@ -780,33 +780,41 @@ describe Duck do
|
|
780
780
|
end
|
781
781
|
|
782
782
|
describe "when moving between ponds should work when rebalancing" do
|
783
|
-
|
784
|
-
before {
|
783
|
+
before do
|
785
784
|
[:feathers, :wingy, :webby, :waddly, :beaky].each_with_index do |name, i|
|
786
|
-
Duck.where(id: @ducks[name].id)
|
787
|
-
|
785
|
+
Duck.where(id: @ducks[name].id)
|
786
|
+
.update_all(age: RankedModel::MIN_RANK_VALUE + i, pond: "Boyden")
|
788
787
|
end
|
789
788
|
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
context {
|
794
|
-
subject { Duck.find_by(id: @ducks[:feathers]).age_rank }
|
795
|
-
|
796
|
-
it { should == 0 }
|
797
|
-
}
|
798
|
-
|
799
|
-
context {
|
800
|
-
subject { Duck.find_by(id: @ducks[:quacky]).age_rank }
|
789
|
+
@ducks[:quacky].update!(age_position: 2, pond: "Boyden")
|
790
|
+
end
|
801
791
|
|
802
|
-
|
803
|
-
|
792
|
+
it 'rebalances ranks correctly' do
|
793
|
+
expect(@ducks[:feathers].reload.age_rank).to eq 0
|
794
|
+
expect(@ducks[:quacky].reload.age_rank).to eq 2
|
795
|
+
expect(@ducks[:beaky].reload.age_rank).to eq 5
|
796
|
+
end
|
804
797
|
|
805
|
-
context
|
806
|
-
|
798
|
+
context 'when attempting to update position to a non-unique value' do
|
799
|
+
before do
|
800
|
+
@duck_one = Duck.create(landing_order: RankedModel::MIN_RANK_VALUE,
|
801
|
+
lake_id: 42, flock_id: 42)
|
802
|
+
# Duck one's landing order will be rebalanced to -715_827_883.
|
803
|
+
# Given a unique index on [:landing_order, :lake_id, :flock_id] we
|
804
|
+
# verify that the operation succeeds despite the value already being
|
805
|
+
# occupied by duck two.
|
806
|
+
@duck_two = Duck.create(landing_order: -715_827_883,
|
807
|
+
lake_id: 42, flock_id: 42)
|
808
|
+
end
|
807
809
|
|
808
|
-
it
|
809
|
-
|
810
|
+
it 'rebalances ranks correctly' do
|
811
|
+
@ducks[:quacky].update!(landing_order_position: :first,
|
812
|
+
lake_id: 42, flock_id: 42)
|
813
|
+
expect(@ducks[:quacky].reload.landing_order_rank).to eq 0
|
814
|
+
expect(@duck_one.reload.landing_order_rank).to eq 1
|
815
|
+
expect(@duck_two.reload.landing_order_rank).to eq 2
|
816
|
+
end
|
817
|
+
end
|
810
818
|
end
|
811
819
|
|
812
820
|
end
|
@@ -5,7 +5,7 @@ describe Duck do
|
|
5
5
|
before {
|
6
6
|
200.times do |i|
|
7
7
|
Duck.create \
|
8
|
-
:name => "Duck #{i}"
|
8
|
+
:name => "Duck #{i + 1}"
|
9
9
|
end
|
10
10
|
}
|
11
11
|
|
@@ -149,34 +149,30 @@ describe Duck do
|
|
149
149
|
|
150
150
|
describe "with no more gaps" do
|
151
151
|
|
152
|
-
before
|
152
|
+
before do
|
153
153
|
@first = Duck.rank(:row).first
|
154
154
|
@second = Duck.rank(:row).offset(1).first
|
155
155
|
@third = Duck.rank(:row).offset(2).first
|
156
|
-
@fourth = Duck.rank(:row).offset(
|
157
|
-
@fifth = Duck.rank(:row).offset(5).first
|
156
|
+
@fourth = Duck.rank(:row).offset(3).first
|
158
157
|
@lower = Duck.rank(:row).
|
159
|
-
where(Duck.arel_table[:id].not_in([@first.id, @second.id, @third.id, @fourth.id
|
158
|
+
where(Duck.arel_table[:id].not_in([@first.id, @second.id, @third.id, @fourth.id])).
|
160
159
|
where(Duck.arel_table[:row].lt(RankedModel::MAX_RANK_VALUE / 2)).
|
161
|
-
|
160
|
+
pluck(:id)
|
162
161
|
@upper = Duck.rank(:row).
|
163
|
-
where(Duck.arel_table[:id].not_in([@first.id, @second.id, @third.id, @fourth.id
|
162
|
+
where(Duck.arel_table[:id].not_in([@first.id, @second.id, @third.id, @fourth.id])).
|
164
163
|
where(Duck.arel_table[:row].gteq(RankedModel::MAX_RANK_VALUE / 2)).
|
165
|
-
|
166
|
-
@first.update
|
167
|
-
@second.update
|
168
|
-
@third.update
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
it { is_expected.to eq([@first.id] + @lower + [@fourth.id, @third.id, @fifth.id] + @upper + [@second.id]) }
|
178
|
-
|
179
|
-
}
|
164
|
+
pluck(:id)
|
165
|
+
@first.update(row: RankedModel::MIN_RANK_VALUE)
|
166
|
+
@second.update(row: RankedModel::MAX_RANK_VALUE)
|
167
|
+
@third.update(row: (RankedModel::MAX_RANK_VALUE / 2))
|
168
|
+
@fourth.update(row: @third.row)
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'works correctly' do
|
172
|
+
result = Duck.rank(:row).pluck(:id)
|
173
|
+
expected = [@first.id, *@lower, @fourth.id, @third.id, *@upper, @second.id]
|
174
|
+
expect(result).to eq(expected)
|
175
|
+
end
|
180
176
|
|
181
177
|
end
|
182
178
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ranked-model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Beale
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-03-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|