ranked-model 0.4.5 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|