ranked-model 0.4.8 → 0.4.11
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/.github/FUNDING.yml +3 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/ci.yml +107 -0
- data/.gitignore +1 -0
- data/Appraisals +14 -45
- data/CHANGELOG.md +9 -0
- data/Readme.mkd +54 -1
- data/gemfiles/rails_5_2.gemfile +3 -3
- data/gemfiles/rails_6_0.gemfile +2 -2
- data/gemfiles/rails_6_1.gemfile +2 -2
- data/gemfiles/rails_7_0.gemfile +22 -0
- data/lib/ranked-model/ranker.rb +367 -356
- data/lib/ranked-model/version.rb +1 -1
- data/ranked-model.gemspec +3 -1
- data/spec/duck-model/inferred_ducks_spec.rb +71 -0
- data/spec/notifications_spec.rb +89 -0
- data/spec/support/database.yml +2 -0
- metadata +15 -8
- data/gemfiles/rails_4_2.gemfile +0 -23
- data/gemfiles/rails_5_0.gemfile +0 -22
- data/gemfiles/rails_5_1.gemfile +0 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c219aee4691eca3a788bd590e056349623685e2dac26405247eccc807b3b580b
|
|
4
|
+
data.tar.gz: 7d50bd015aa1f38ead1a4a4c795d3fc3f5f7ad101e416f37c66415d50251e010
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 75a9f1e64091a37289aa2c3f6f35bd30be059237121e8f00af61196be089de2df645304854fb9a80bd1fc1de91d6014e741839b91714cc70ab9e7562e6367451
|
|
7
|
+
data.tar.gz: f8a6ac22945db1b7c609c776db78445f3dd60c550e7b421b4530c974af51fb4e0040375c676f72c7920240cff143b8ac236ec258f7c76f5cdbd418748e493243
|
data/.github/FUNDING.yml
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: CI
|
|
3
|
+
on: [push, pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
tests:
|
|
7
|
+
name: Ruby ${{ matrix.ruby }}, ${{ matrix.gemfile }}, DB ${{ matrix.db }}
|
|
8
|
+
runs-on: ${{ matrix.os }}
|
|
9
|
+
strategy:
|
|
10
|
+
fail-fast: false
|
|
11
|
+
matrix:
|
|
12
|
+
ruby:
|
|
13
|
+
- 2.5
|
|
14
|
+
- 2.6
|
|
15
|
+
- 2.7
|
|
16
|
+
- '3.0'
|
|
17
|
+
- 3.1
|
|
18
|
+
- 3.2
|
|
19
|
+
- 3.3
|
|
20
|
+
gemfile:
|
|
21
|
+
- gemfiles/rails_5_2.gemfile
|
|
22
|
+
- gemfiles/rails_6_0.gemfile
|
|
23
|
+
- gemfiles/rails_6_1.gemfile
|
|
24
|
+
- gemfiles/rails_7_0.gemfile
|
|
25
|
+
db:
|
|
26
|
+
- sqlite
|
|
27
|
+
- mysql
|
|
28
|
+
- postgresql
|
|
29
|
+
exclude:
|
|
30
|
+
- ruby: 2.5
|
|
31
|
+
gemfile: gemfiles/rails_7_0.gemfile
|
|
32
|
+
- ruby: 2.6
|
|
33
|
+
gemfile: gemfiles/rails_7_0.gemfile
|
|
34
|
+
- ruby: '3.0'
|
|
35
|
+
gemfile: gemfiles/rails_5_2.gemfile
|
|
36
|
+
- ruby: 3.1
|
|
37
|
+
gemfile: gemfiles/rails_5_2.gemfile
|
|
38
|
+
- ruby: 3.2
|
|
39
|
+
gemfile: gemfiles/rails_4_2.gemfile
|
|
40
|
+
- ruby: 3.2
|
|
41
|
+
gemfile: gemfiles/rails_5_0.gemfile
|
|
42
|
+
- ruby: 3.2
|
|
43
|
+
gemfile: gemfiles/rails_5_1.gemfile
|
|
44
|
+
- ruby: 3.2
|
|
45
|
+
gemfile: gemfiles/rails_5_2.gemfile
|
|
46
|
+
- ruby: 3.2
|
|
47
|
+
gemfile: gemfiles/rails_6_0.gemfile
|
|
48
|
+
- ruby: 3.2
|
|
49
|
+
gemfile: gemfiles/rails_6_1.gemfile
|
|
50
|
+
- ruby: 3.3
|
|
51
|
+
gemfile: gemfiles/rails_4_2.gemfile
|
|
52
|
+
- ruby: 3.3
|
|
53
|
+
gemfile: gemfiles/rails_5_0.gemfile
|
|
54
|
+
- ruby: 3.3
|
|
55
|
+
gemfile: gemfiles/rails_5_1.gemfile
|
|
56
|
+
- ruby: 3.3
|
|
57
|
+
gemfile: gemfiles/rails_5_2.gemfile
|
|
58
|
+
- ruby: 3.3
|
|
59
|
+
gemfile: gemfiles/rails_6_0.gemfile
|
|
60
|
+
- ruby: 3.3
|
|
61
|
+
gemfile: gemfiles/rails_6_1.gemfile
|
|
62
|
+
os:
|
|
63
|
+
- ubuntu-latest
|
|
64
|
+
services:
|
|
65
|
+
mysql:
|
|
66
|
+
image: mysql:5.7
|
|
67
|
+
env:
|
|
68
|
+
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
|
69
|
+
ports:
|
|
70
|
+
- 3306:3306
|
|
71
|
+
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
|
72
|
+
|
|
73
|
+
postgres:
|
|
74
|
+
# Docker Hub image
|
|
75
|
+
image: postgres
|
|
76
|
+
# Provide the password for postgres
|
|
77
|
+
env:
|
|
78
|
+
POSTGRES_USER: postgres
|
|
79
|
+
POSTGRES_HOST_AUTH_METHOD: trust
|
|
80
|
+
ports:
|
|
81
|
+
- 5432:5432
|
|
82
|
+
# Set health checks to wait until postgres has started
|
|
83
|
+
options: >-
|
|
84
|
+
--health-cmd pg_isready
|
|
85
|
+
--health-interval 10s
|
|
86
|
+
--health-timeout 5s
|
|
87
|
+
--health-retries 5
|
|
88
|
+
env:
|
|
89
|
+
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
|
90
|
+
DB: ${{ matrix.db }}
|
|
91
|
+
steps:
|
|
92
|
+
- uses: actions/checkout@v4
|
|
93
|
+
- name: Set up Ruby
|
|
94
|
+
uses: ruby/setup-ruby@v1
|
|
95
|
+
with:
|
|
96
|
+
ruby-version: ${{ matrix.ruby }}
|
|
97
|
+
bundler-cache: true
|
|
98
|
+
- name: "Create MySQL database"
|
|
99
|
+
if: ${{ env.DB == 'mysql' }}
|
|
100
|
+
run: |
|
|
101
|
+
mysql -h 127.0.0.1 -u root -e 'create database ranked_model_test;'
|
|
102
|
+
- name: "Create PostgreSQL database"
|
|
103
|
+
if: ${{ env.DB == 'postgresql' }}
|
|
104
|
+
run: |
|
|
105
|
+
psql -c 'create database ranked_model_test;' -h localhost -U postgres
|
|
106
|
+
- name: Run tests
|
|
107
|
+
run: bundle exec rake
|
data/.gitignore
CHANGED
data/Appraisals
CHANGED
|
@@ -1,48 +1,3 @@
|
|
|
1
|
-
appraise "rails-4-2" do
|
|
2
|
-
group :sqlite do
|
|
3
|
-
gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.24", platform: :jruby
|
|
4
|
-
end
|
|
5
|
-
group :mysql do
|
|
6
|
-
gem "mysql2", "~> 0.4.0", platform: :ruby
|
|
7
|
-
gem "jdbc-mysql", "~> 5.1.47", platform: :jruby
|
|
8
|
-
gem "activerecord-jdbcmysql-adapter", "~> 1.3.24", platform: :jruby
|
|
9
|
-
end
|
|
10
|
-
group :postgresql do
|
|
11
|
-
gem "pg", "~> 0.18.4", platform: :ruby
|
|
12
|
-
gem "activerecord-jdbcpostgresql-adapter", "~> 1.3.24", platform: :jruby
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
gem "activerecord", "~> 4.2.0"
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
appraise "rails-5-0" do
|
|
19
|
-
group :sqlite do
|
|
20
|
-
gem "activerecord-jdbcsqlite3-adapter", "~> 50.0", platform: :jruby
|
|
21
|
-
end
|
|
22
|
-
group :mysql do
|
|
23
|
-
gem "activerecord-jdbcmysql-adapter", "~> 50.0", platform: :jruby
|
|
24
|
-
end
|
|
25
|
-
group :postgresql do
|
|
26
|
-
gem "activerecord-jdbcpostgresql-adapter", "~> 50.0", platform: :jruby
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
gem "activerecord", "~> 5.0.0"
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
appraise "rails-5-1" do
|
|
33
|
-
group :sqlite do
|
|
34
|
-
gem "activerecord-jdbcsqlite3-adapter", "~> 51.0", platform: :jruby
|
|
35
|
-
end
|
|
36
|
-
group :mysql do
|
|
37
|
-
gem "activerecord-jdbcmysql-adapter", "~> 51.0", platform: :jruby
|
|
38
|
-
end
|
|
39
|
-
group :postgresql do
|
|
40
|
-
gem "activerecord-jdbcpostgresql-adapter", "~> 51.0", platform: :jruby
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
gem "activerecord", "~> 5.1.0"
|
|
44
|
-
end
|
|
45
|
-
|
|
46
1
|
appraise "rails-5-2" do
|
|
47
2
|
group :sqlite do
|
|
48
3
|
gem "activerecord-jdbcsqlite3-adapter", "~> 52.0", platform: :jruby
|
|
@@ -84,3 +39,17 @@ appraise "rails-6-1" do
|
|
|
84
39
|
end
|
|
85
40
|
gem "activerecord", "~> 6.1.0"
|
|
86
41
|
end
|
|
42
|
+
|
|
43
|
+
appraise "rails-7-0" do
|
|
44
|
+
group :sqlite do
|
|
45
|
+
gem "sqlite3", "~> 1.4", platform: :ruby
|
|
46
|
+
gem "activerecord-jdbcsqlite3-adapter", "~> 61.0", platform: :jruby
|
|
47
|
+
end
|
|
48
|
+
group :mysql do
|
|
49
|
+
gem "activerecord-jdbcmysql-adapter", "~> 61.0", platform: :jruby
|
|
50
|
+
end
|
|
51
|
+
group :postgresql do
|
|
52
|
+
gem "activerecord-jdbcpostgresql-adapter", "~> 61.0", platform: :jruby
|
|
53
|
+
end
|
|
54
|
+
gem "activerecord", "~> 7.0.0"
|
|
55
|
+
end
|
data/CHANGELOG.md
ADDED
data/Readme.mkd
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
**ranked-model** is a modern row sorting library built for Rails 4.2+. It uses ARel aggressively and is better optimized than most other libraries.
|
|
2
2
|
|
|
3
|
-
[](https://github.com/brendon/ranked-model/actions/workflows/ci.yml)
|
|
4
|
+
|
|
5
|
+
ANNOUNCING: Positioning, the gem
|
|
6
|
+
--------------------------------
|
|
7
|
+
|
|
8
|
+
As maintainer of both Acts As List and the Ranked Model gems, I've become intimately aquainted with the strengths and weaknesses of each. I ended up writing a small scale Rails Concern for positioning database rows for a recent project and it worked really well so I've decided to release it as a gem: [Positioning](https://github.com/brendon/positioning)
|
|
9
|
+
|
|
10
|
+
Positioning works similarly to Acts As List in that it maintains a sequential list of integer values as positions. It differs in that it encourages a unique constraints on the position column and supports multiple lists per database table. It borrows Ranked Model's concept of relative positioning. I encourage you to check it out and give it a whirl on your project!
|
|
4
11
|
|
|
5
12
|
Installation
|
|
6
13
|
------------
|
|
@@ -136,6 +143,37 @@ Pond.first.ducks.rank(:swimming_order)
|
|
|
136
143
|
Duck.walking.rank(:walking)
|
|
137
144
|
```
|
|
138
145
|
|
|
146
|
+
Drawbacks
|
|
147
|
+
---------
|
|
148
|
+
|
|
149
|
+
While ranked-model is performant when storing data, it might cause N+1s depending on how you write your code. Consider this snippet:
|
|
150
|
+
|
|
151
|
+
```ruby
|
|
152
|
+
ducks = Duck.all
|
|
153
|
+
ducks.map do |duck|
|
|
154
|
+
{
|
|
155
|
+
id: duck.id,
|
|
156
|
+
position: duck.row_order_rank # This causes N+1!
|
|
157
|
+
}
|
|
158
|
+
end
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Every call to `duck.row_order_rank` will make a call to the DB to check the rank of that
|
|
162
|
+
particular element. If you have a long list of elements this might cause issues to your DB.
|
|
163
|
+
|
|
164
|
+
In order to avoid that, you can use the `rank(:your_rank)` scope and some Ruby code to get
|
|
165
|
+
the element's position:
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
ducks = Duck.rank(:row_order).all
|
|
169
|
+
ducks.map.with_index do |duck, index|
|
|
170
|
+
{
|
|
171
|
+
id: duck.id,
|
|
172
|
+
position: index
|
|
173
|
+
}
|
|
174
|
+
end
|
|
175
|
+
```
|
|
176
|
+
|
|
139
177
|
Single Table Inheritance (STI)
|
|
140
178
|
------------------------------
|
|
141
179
|
|
|
@@ -231,6 +269,21 @@ this occurs, ranked-model will try to shift other records out of the way. If ite
|
|
|
231
269
|
shifted anymore, it will rebalance the distribution of rank numbers across all members
|
|
232
270
|
of the ranked group.
|
|
233
271
|
|
|
272
|
+
Record updates to rebalance ranks do not trigger ActiveRecord callbacks. If you need to react to these updates
|
|
273
|
+
(to index them in a secondary data store, for example), you can subscribe to the `ranked_model.ranks_updated`
|
|
274
|
+
[ActiveSupport notification](https://api.rubyonrails.org/v7.1/classes/ActiveSupport/Notifications.html).
|
|
275
|
+
Subscribed consumers receive an event for each rearrangement or rebalancing, the payload of which includes the
|
|
276
|
+
triggering instance and the `scope` and `with_same` options for the ranking, which can be used to retrieve the
|
|
277
|
+
affected records.
|
|
278
|
+
|
|
279
|
+
```ruby
|
|
280
|
+
ActiveSupport::Notifications.subscribe("ranked_model.ranks_updated") do |_name, _start, _finish, _id, payload|
|
|
281
|
+
# payload[:instance] - the instance whose update triggered the rebalance
|
|
282
|
+
# payload[:scope] - the scope applied to the ranking
|
|
283
|
+
# payload[:with_same] - the with_same option applied to the ranking
|
|
284
|
+
end
|
|
285
|
+
```
|
|
286
|
+
|
|
234
287
|
Contributing
|
|
235
288
|
------------
|
|
236
289
|
|
data/gemfiles/rails_5_2.gemfile
CHANGED
|
@@ -5,17 +5,17 @@ source "https://rubygems.org"
|
|
|
5
5
|
gem "activerecord", "~> 5.2.0"
|
|
6
6
|
|
|
7
7
|
group :sqlite do
|
|
8
|
-
gem "sqlite3",
|
|
8
|
+
gem "sqlite3", platform: :ruby
|
|
9
9
|
gem "activerecord-jdbcsqlite3-adapter", "~> 52.0", platform: :jruby
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
group :postgresql do
|
|
13
|
-
gem "pg",
|
|
13
|
+
gem "pg", platform: :ruby
|
|
14
14
|
gem "activerecord-jdbcpostgresql-adapter", "~> 52.0", platform: :jruby
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
group :mysql do
|
|
18
|
-
gem "mysql2",
|
|
18
|
+
gem "mysql2", platform: :ruby
|
|
19
19
|
gem "activerecord-jdbcmysql-adapter", "~> 52.0", platform: :jruby
|
|
20
20
|
end
|
|
21
21
|
|
data/gemfiles/rails_6_0.gemfile
CHANGED
|
@@ -10,12 +10,12 @@ group :sqlite do
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
group :postgresql do
|
|
13
|
-
gem "pg",
|
|
13
|
+
gem "pg", platform: :ruby
|
|
14
14
|
gem "activerecord-jdbcpostgresql-adapter", "~> 60.0", platform: :jruby
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
group :mysql do
|
|
18
|
-
gem "mysql2",
|
|
18
|
+
gem "mysql2", platform: :ruby
|
|
19
19
|
gem "activerecord-jdbcmysql-adapter", "~> 60.0", platform: :jruby
|
|
20
20
|
end
|
|
21
21
|
|
data/gemfiles/rails_6_1.gemfile
CHANGED
|
@@ -10,12 +10,12 @@ group :sqlite do
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
group :postgresql do
|
|
13
|
-
gem "pg",
|
|
13
|
+
gem "pg", platform: :ruby
|
|
14
14
|
gem "activerecord-jdbcpostgresql-adapter", "~> 61.0", platform: :jruby
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
group :mysql do
|
|
18
|
-
gem "mysql2",
|
|
18
|
+
gem "mysql2", platform: :ruby
|
|
19
19
|
gem "activerecord-jdbcmysql-adapter", "~> 61.0", platform: :jruby
|
|
20
20
|
end
|
|
21
21
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gem "activerecord", "~> 7.0.0"
|
|
6
|
+
|
|
7
|
+
group :sqlite do
|
|
8
|
+
gem "sqlite3", "~> 1.4", platform: :ruby
|
|
9
|
+
gem "activerecord-jdbcsqlite3-adapter", "~> 61.0", platform: :jruby
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
group :postgresql do
|
|
13
|
+
gem "pg", platform: :ruby
|
|
14
|
+
gem "activerecord-jdbcpostgresql-adapter", "~> 61.0", platform: :jruby
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
group :mysql do
|
|
18
|
+
gem "mysql2", platform: :ruby
|
|
19
|
+
gem "activerecord-jdbcmysql-adapter", "~> 61.0", platform: :jruby
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
gemspec path: "../"
|