order_query 0.4.0 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGES.md +23 -1
- data/Gemfile +2 -8
- data/README.md +1 -1
- data/lib/order_query/column.rb +3 -2
- data/lib/order_query/nulls_direction.rb +10 -1
- data/lib/order_query/space.rb +10 -1
- data/lib/order_query/sql/order_by.rb +2 -0
- data/lib/order_query/sql/where.rb +16 -15
- data/lib/order_query/version.rb +1 -1
- data/spec/gemfiles/rails_5_0.gemfile +15 -2
- data/spec/gemfiles/rails_5_1.gemfile +13 -0
- data/spec/gemfiles/rails_5_2.gemfile +15 -2
- data/spec/gemfiles/rails_6_0.gemfile +21 -0
- data/spec/gemfiles/rails_6_1.gemfile +21 -0
- data/spec/gemfiles/rails_7_0.gemfile +21 -0
- data/spec/gemfiles/rubocop.gemfile +5 -0
- data/spec/order_query_spec.rb +47 -77
- data/spec/spec_helper.rb +5 -1
- data/spec/support/order_expectation.rb +48 -0
- metadata +26 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2f9e31c687e96f7014255acbfa4590f9495bca00b942d23c111f38a6c77646eb
|
4
|
+
data.tar.gz: ae44f4ca9d520edd2e2d3dc7eead83e9de2f8e440fa2c4ad1d9ce59f266f2756
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d570f7f7133f1475c109be472d61014b31ed0569eb77474de0658eaf6ca77053d411c9f434971a35250a703c6455041aa7d483ddd68439df727a03026ddfd263
|
7
|
+
data.tar.gz: ba16dd0f9c83246ac4f3e10d8492a30063ca12170b1619f971486ad802f1ec548d368c59c59c06befe344d4b71eb35b6feee64564fcee99e76c6e2f904d5d22f
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
## 0.5.2
|
2
|
+
|
3
|
+
* Ruby 3.0 now supported.
|
4
|
+
* Rails 7.0 now supported.
|
5
|
+
|
6
|
+
## 0.5.1
|
7
|
+
|
8
|
+
* Rails 6.1 now supported.
|
9
|
+
## 0.5.0
|
10
|
+
|
11
|
+
* Rails 6 now supported.
|
12
|
+
* Fixes support for `nil`s with explicit order, when a `nil` is neither
|
13
|
+
the first nor the last element of the explicit order,
|
14
|
+
e.g. `status: ['assigned', nil, 'fixed']`.
|
15
|
+
[#93b08877](https://github.com/glebm/order_query/commit/93b08877790a0ff02eea0d835def6ff3c40a83da)
|
16
|
+
|
17
|
+
## 0.4.1
|
18
|
+
|
19
|
+
* If a column had a `nulls:` option and there were multiple records with `NULL`,
|
20
|
+
all of these records but one were previously skipped. This is now fixed.
|
21
|
+
[#21](https://github.com/glebm/order_query/issues/21)
|
22
|
+
|
1
23
|
## 0.4.0
|
2
24
|
|
3
25
|
* Adds nulls ordering options `nulls: :first` and `nulls: :last`.
|
@@ -6,7 +28,7 @@
|
|
6
28
|
|
7
29
|
## 0.3.4
|
8
30
|
|
9
|
-
* The `before` and `after` methods now accept a boolean argument that indicates
|
31
|
+
* The `before` and `after` methods now accept a boolean argument that indicates
|
10
32
|
whether the relation should exclude the given point or not.
|
11
33
|
By default the given point is excluded, if you want to include it,
|
12
34
|
use `before(false)` / `after(false)`.
|
data/Gemfile
CHANGED
@@ -2,11 +2,5 @@
|
|
2
2
|
|
3
3
|
source 'https://rubygems.org'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
# TODO: remove these lines and update spec/gemfiles/rails_5_2.gemfile once
|
8
|
-
# Rails 5.2 is out.
|
9
|
-
gem 'activerecord', '~> 5.2.0.rc1'
|
10
|
-
gem 'activesupport', '~> 5.2.0.rc1'
|
11
|
-
|
12
|
-
eval_gemfile './shared.gemfile'
|
5
|
+
eval_gemfile 'spec/gemfiles/rails_7_0.gemfile'
|
6
|
+
eval_gemfile 'rubocop.gemfile'
|
data/README.md
CHANGED
data/lib/order_query/column.rb
CHANGED
@@ -38,8 +38,9 @@ module OrderQuery
|
|
38
38
|
"extra arguments: #{vals_and_or_dir.map(&:inspect) * ', '}"
|
39
39
|
end
|
40
40
|
@unique = unique.nil? ? (name.to_s == scope.primary_key) : unique
|
41
|
-
if @order_enum
|
41
|
+
if @order_enum&.include?(nil)
|
42
42
|
fail ArgumentError, '`nulls` cannot be set if a value is null' if nulls
|
43
|
+
|
43
44
|
@nullable = true
|
44
45
|
@nulls = if @order_enum[0].nil?
|
45
46
|
@direction == :desc ? :first : :last
|
@@ -87,7 +88,7 @@ module OrderQuery
|
|
87
88
|
# @example for [:difficulty, ['Easy', 'Normal', 'Hard']]:
|
88
89
|
# enum_side('Normal', :after) #=> ['Hard']
|
89
90
|
# enum_side('Normal', :after, false) #=> ['Normal', 'Hard']
|
90
|
-
def enum_side(value, side, strict = true)
|
91
|
+
def enum_side(value, side, strict = true) # rubocop:disable Metrics/AbcSize
|
91
92
|
ord = order_enum
|
92
93
|
pos = ord.index(value)
|
93
94
|
if pos
|
@@ -32,7 +32,7 @@ module OrderQuery
|
|
32
32
|
# @return [:first, :last] the default nulls order, based on the given
|
33
33
|
# scope's connection adapter name.
|
34
34
|
def default(scope, dir)
|
35
|
-
case scope
|
35
|
+
case connection_adapter(scope)
|
36
36
|
when /mysql|maria|sqlite|sqlserver/i
|
37
37
|
(dir == :asc ? :first : :last)
|
38
38
|
else
|
@@ -40,5 +40,14 @@ module OrderQuery
|
|
40
40
|
(dir == :asc ? :last : :first)
|
41
41
|
end
|
42
42
|
end
|
43
|
+
|
44
|
+
def connection_adapter(scope)
|
45
|
+
if scope.respond_to?(:connection_db_config)
|
46
|
+
# Rails >= 6.1.0
|
47
|
+
scope.connection_db_config.adapter
|
48
|
+
else
|
49
|
+
scope.connection_config[:adapter]
|
50
|
+
end
|
51
|
+
end
|
43
52
|
end
|
44
53
|
end
|
data/lib/order_query/space.rb
CHANGED
@@ -15,13 +15,14 @@ module OrderQuery
|
|
15
15
|
def initialize(base_scope, order_spec)
|
16
16
|
@base_scope = base_scope
|
17
17
|
@columns = order_spec.map do |cond_spec|
|
18
|
-
|
18
|
+
build_column(base_scope, cond_spec)
|
19
19
|
end
|
20
20
|
# add primary key if columns are not unique
|
21
21
|
unless @columns.last.unique?
|
22
22
|
if @columns.detect(&:unique?)
|
23
23
|
fail ArgumentError, 'Unique column must be last'
|
24
24
|
end
|
25
|
+
|
25
26
|
@columns << Column.new(base_scope, base_scope.primary_key)
|
26
27
|
end
|
27
28
|
@order_by_sql = SQL::OrderBy.new(@columns)
|
@@ -57,5 +58,13 @@ module OrderQuery
|
|
57
58
|
"#<OrderQuery::Space @columns=#{@columns.inspect} "\
|
58
59
|
"@base_scope=#{@base_scope.inspect}>"
|
59
60
|
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def build_column(base_scope, cond_spec)
|
65
|
+
column_spec = cond_spec.last.is_a?(Hash) ? cond_spec : cond_spec.push({})
|
66
|
+
attr_name, *vals_and_or_dir, options = column_spec
|
67
|
+
Column.new(base_scope, attr_name, *vals_and_or_dir, **options)
|
68
|
+
end
|
60
69
|
end
|
61
70
|
end
|
@@ -51,6 +51,7 @@ module OrderQuery
|
|
51
51
|
if optimize_enum_bools_nil?(col)
|
52
52
|
return optimize_enum_bools_nil(col, reverse)
|
53
53
|
end
|
54
|
+
|
54
55
|
clauses = []
|
55
56
|
with_nulls = false
|
56
57
|
if col.order_enum.include?(nil)
|
@@ -69,6 +70,7 @@ module OrderQuery
|
|
69
70
|
def needs_null_sort?(col, reverse,
|
70
71
|
nulls_direction = col.nulls_direction(reverse))
|
71
72
|
return false unless col.nullable?
|
73
|
+
|
72
74
|
nulls_direction != col.default_nulls_direction(reverse)
|
73
75
|
end
|
74
76
|
|
@@ -94,9 +94,11 @@ module OrderQuery
|
|
94
94
|
# @param [:before or :after] side
|
95
95
|
# @return [query, params] return query fragment for column values
|
96
96
|
# before / after the current one.
|
97
|
-
def where_side(col, side, strict
|
97
|
+
def where_side(col, side, strict, value = point.value(col))
|
98
98
|
if col.order_enum
|
99
99
|
where_in col, col.enum_side(value, side, strict)
|
100
|
+
elsif value.nil?
|
101
|
+
where_null col, side, strict
|
100
102
|
else
|
101
103
|
where_ray col, value, side, strict
|
102
104
|
end
|
@@ -126,24 +128,23 @@ module OrderQuery
|
|
126
128
|
RAY_OP = { asc: '>', desc: '<' }.freeze
|
127
129
|
NULLS_ORD = { first: 'IS NOT NULL', last: 'IS NULL' }.freeze
|
128
130
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
reverse = (mode == :before)
|
133
|
-
if from.nil?
|
134
|
-
["#{col.column_name} #{NULLS_ORD[col.nulls_direction(reverse)]}", []]
|
131
|
+
def where_null(col, mode, strict)
|
132
|
+
if strict && col.nulls_direction(mode == :before) != :last
|
133
|
+
["#{col.column_name} IS NOT NULL", []]
|
135
134
|
else
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
135
|
+
WHERE_IDENTITY
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def where_ray(col, from, mode, strict)
|
140
|
+
["#{col.column_name} "\
|
141
|
+
"#{RAY_OP[col.direction(mode == :before)]}#{'=' unless strict} ?",
|
142
|
+
[from]].tap do |ray|
|
143
|
+
if col.nullable? && col.nulls_direction(mode == :before) == :last
|
144
|
+
ray[0] = "(#{ray[0]} OR #{col.column_name} IS NULL)"
|
143
145
|
end
|
144
146
|
end
|
145
147
|
end
|
146
|
-
# rubocop:enable Metrics/AbcSize
|
147
148
|
|
148
149
|
WHERE_IDENTITY = ['', [].freeze].freeze
|
149
150
|
|
data/lib/order_query/version.rb
CHANGED
@@ -1,8 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'https://rubygems.org'
|
2
4
|
|
3
5
|
gemspec path: '../../'
|
4
6
|
|
5
|
-
gem 'activerecord', '~> 5.0.
|
6
|
-
gem 'activesupport', '~> 5.0.
|
7
|
+
gem 'activerecord', '~> 5.0.6'
|
8
|
+
gem 'activesupport', '~> 5.0.6'
|
9
|
+
|
10
|
+
platforms :mri, :rbx do
|
11
|
+
# https://github.com/rails/rails/blob/v5.0.6/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb#L4
|
12
|
+
gem 'mysql2', '< 0.5'
|
13
|
+
|
14
|
+
# https://github.com/rails/rails/blob/v5.0.6/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L2
|
15
|
+
gem 'pg', '~> 0.18'
|
16
|
+
|
17
|
+
# https://github.com/rails/rails/blob/v5.0.6/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L7
|
18
|
+
gem 'sqlite3', '~> 1.3.6'
|
19
|
+
end
|
7
20
|
|
8
21
|
eval_gemfile '../../shared.gemfile'
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'https://rubygems.org'
|
2
4
|
|
3
5
|
gemspec path: '../../'
|
@@ -5,4 +7,15 @@ gemspec path: '../../'
|
|
5
7
|
gem 'activerecord', '~> 5.1.3'
|
6
8
|
gem 'activesupport', '~> 5.1.3'
|
7
9
|
|
10
|
+
platforms :mri, :rbx do
|
11
|
+
# https://github.com/rails/rails/blob/v5.1.5/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb#L4
|
12
|
+
gem 'mysql2', '< 0.5'
|
13
|
+
|
14
|
+
# https://github.com/rails/rails/blob/v5.1.5/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L2
|
15
|
+
gem 'pg', '>= 0.18', '< 2.0'
|
16
|
+
|
17
|
+
# https://github.com/rails/rails/blob/v5.1.5/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L10
|
18
|
+
gem 'sqlite3', '~> 1.3.6'
|
19
|
+
end
|
20
|
+
|
8
21
|
eval_gemfile '../../shared.gemfile'
|
@@ -1,8 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'https://rubygems.org'
|
2
4
|
|
3
5
|
gemspec path: '../../'
|
4
6
|
|
5
|
-
gem 'activerecord', '~> 5.2.
|
6
|
-
gem 'activesupport', '~> 5.2.
|
7
|
+
gem 'activerecord', '~> 5.2.3'
|
8
|
+
gem 'activesupport', '~> 5.2.3'
|
9
|
+
|
10
|
+
platforms :mri, :rbx do
|
11
|
+
# https://github.com/rails/rails/blob/v5.2.3/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb#L6
|
12
|
+
gem 'mysql2', '>= 0.4.4', '< 0.6.0'
|
13
|
+
|
14
|
+
# https://github.com/rails/rails/blob/v5.2.3/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L4
|
15
|
+
gem 'pg', '>= 0.18', '< 2.0'
|
16
|
+
|
17
|
+
# https://github.com/rails/rails/blob/v5.2.3/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L12
|
18
|
+
gem 'sqlite3', '~> 1.3', '>= 1.3.6'
|
19
|
+
end
|
7
20
|
|
8
21
|
eval_gemfile '../../shared.gemfile'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
gemspec path: '../../'
|
6
|
+
|
7
|
+
gem 'activerecord', '~> 6.0.3'
|
8
|
+
gem 'activesupport', '~> 6.0.3'
|
9
|
+
|
10
|
+
platforms :mri, :rbx do
|
11
|
+
# https://github.com/rails/rails/blob/v6.0.0/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L13
|
12
|
+
gem 'sqlite3', '~> 1.4'
|
13
|
+
|
14
|
+
# https://github.com/rails/rails/blob/v6.0.0/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L4
|
15
|
+
gem 'pg', '>= 0.18', '< 2.0'
|
16
|
+
|
17
|
+
# https://github.com/rails/rails/blob/v6.0.0/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb#L6
|
18
|
+
gem 'mysql2', '>= 0.4.4'
|
19
|
+
end
|
20
|
+
|
21
|
+
eval_gemfile '../../shared.gemfile'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
gemspec path: '../../'
|
6
|
+
|
7
|
+
gem 'activerecord', '~> 6.1.1'
|
8
|
+
gem 'activesupport', '~> 6.1.1'
|
9
|
+
|
10
|
+
platforms :mri, :rbx do
|
11
|
+
# https://github.com/rails/rails/blob/v6.0.0/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L13
|
12
|
+
gem 'sqlite3', '~> 1.4'
|
13
|
+
|
14
|
+
# https://github.com/rails/rails/blob/v6.0.0/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L4
|
15
|
+
gem 'pg', '>= 0.18', '< 2.0'
|
16
|
+
|
17
|
+
# https://github.com/rails/rails/blob/v6.0.0/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb#L6
|
18
|
+
gem 'mysql2', '>= 0.4.4'
|
19
|
+
end
|
20
|
+
|
21
|
+
eval_gemfile '../../shared.gemfile'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
gemspec path: '../../'
|
6
|
+
|
7
|
+
gem 'activerecord', '~> 7.0.0'
|
8
|
+
gem 'activesupport', '~> 7.0.0'
|
9
|
+
|
10
|
+
platforms :mri, :rbx do
|
11
|
+
# https://github.com/rails/rails/blob/v6.0.0/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L13
|
12
|
+
gem 'sqlite3', '~> 1.4'
|
13
|
+
|
14
|
+
# https://github.com/rails/rails/blob/v6.0.0/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L4
|
15
|
+
gem 'pg', '>= 0.18', '< 2.0'
|
16
|
+
|
17
|
+
# https://github.com/rails/rails/blob/v6.0.0/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb#L6
|
18
|
+
gem 'mysql2', '>= 0.4.4'
|
19
|
+
end
|
20
|
+
|
21
|
+
eval_gemfile '../../shared.gemfile'
|
data/spec/order_query_spec.rb
CHANGED
@@ -221,20 +221,27 @@ RSpec.describe 'OrderQuery' do
|
|
221
221
|
end
|
222
222
|
|
223
223
|
context 'nil in string enum' do
|
224
|
+
display = ->(issue) { "##{issue.id}-#{issue.priority || 'NULL'}" }
|
224
225
|
priorities = [nil, 'low', 'medium', 'high']
|
225
|
-
let!(:issues)
|
226
|
-
|
227
|
-
|
228
|
-
scope = Issue.seek([:priority, p]).scope
|
229
|
-
actual = scope.all.map(&:priority)
|
230
|
-
expected = p
|
231
|
-
expect(actual).to eq(expected), scope.to_sql
|
226
|
+
let!(:issues) do
|
227
|
+
priorities.flat_map do |p|
|
228
|
+
[create_issue(priority: p), create_issue(priority: p)]
|
232
229
|
end
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
230
|
+
end
|
231
|
+
priorities.permutation do |perm|
|
232
|
+
it "works for #{perm} (desc)" do
|
233
|
+
expect_order(
|
234
|
+
Issue.seek([:priority, perm]),
|
235
|
+
issues.sort_by { |x| [perm.index(x.priority), x.id] },
|
236
|
+
&display
|
237
|
+
)
|
238
|
+
end
|
239
|
+
it "works for #{perm} (asc)" do
|
240
|
+
expect_order(
|
241
|
+
Issue.seek([:priority, perm, :asc]),
|
242
|
+
issues.sort_by { |x| [perm.index(x.priority), -x.id] }.reverse,
|
243
|
+
&display
|
244
|
+
)
|
238
245
|
end
|
239
246
|
end
|
240
247
|
end
|
@@ -340,54 +347,39 @@ RSpec.describe 'OrderQuery' do
|
|
340
347
|
end
|
341
348
|
|
342
349
|
context 'nil in boolean enum' do
|
350
|
+
display = ->(post) { "##{post.id}-#{post.pinned || 'NULL'}" }
|
343
351
|
states = [nil, false, true]
|
344
|
-
let!(:posts)
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
352
|
+
let!(:posts) do
|
353
|
+
states.flat_map do |state|
|
354
|
+
[create_post(pinned: state), create_post(pinned: state)]
|
355
|
+
end
|
356
|
+
end
|
357
|
+
states.permutation do |perm|
|
358
|
+
it "works for #{perm} (desc)" do
|
359
|
+
expect_order(
|
360
|
+
Post.seek([:pinned, perm]),
|
361
|
+
posts.sort_by { |x| [perm.index(x.pinned), x.id] },
|
362
|
+
&display
|
363
|
+
)
|
351
364
|
end
|
352
|
-
it "works for #{
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
365
|
+
it "works for #{perm} (asc)" do
|
366
|
+
expect_order(
|
367
|
+
Post.seek([:pinned, perm, :asc]),
|
368
|
+
posts.sort_by { |x| [-perm.index(x.pinned), x.id] },
|
369
|
+
&display
|
370
|
+
)
|
357
371
|
end
|
358
372
|
end
|
359
373
|
end
|
360
374
|
|
361
375
|
context 'nil published_at' do
|
362
|
-
|
363
|
-
|
364
|
-
def expect_next(space, post, next_post)
|
365
|
-
point = space.at(post)
|
366
|
-
actual = point.next
|
367
|
-
failure_message =
|
368
|
-
"expected: #{post.title}.next == #{next_post.title}\n" \
|
369
|
-
" got: #{actual ? actual.title : 'nil'}\n" \
|
370
|
-
" all: #{space.scope.all.map(&:title)}\n" \
|
371
|
-
" sql: #{space.at(older).before.limit(1).to_sql}"
|
372
|
-
expect(actual ? actual.title : nil).to eq(next_post.title),
|
373
|
-
failure_message
|
374
|
-
end
|
376
|
+
display = ->(post) { post.title }
|
375
377
|
|
376
|
-
|
377
|
-
|
378
|
-
actual = point.previous
|
379
|
-
failure_message =
|
380
|
-
"expected: #{post.title}.previous == #{prev_post.title}\n" \
|
381
|
-
" got: #{actual ? actual.title : 'nil'}\n" \
|
382
|
-
" all: #{space.scope.all.map(&:title)}\n" \
|
383
|
-
" sql: #{space.at(older).before.limit(1).to_sql}"
|
384
|
-
expect(actual ? actual.title : nil).to eq(prev_post.title),
|
385
|
-
failure_message
|
378
|
+
let! :null_1 do
|
379
|
+
Post.create!(title: 'null_1', published_at: nil).reload
|
386
380
|
end
|
387
|
-
|
388
|
-
|
389
|
-
let! :null do
|
390
|
-
Post.create!(title: 'null', published_at: nil).reload
|
381
|
+
let! :null_2 do
|
382
|
+
Post.create!(title: 'null_2', published_at: nil).reload
|
391
383
|
end
|
392
384
|
let! :older do
|
393
385
|
Post.create!(title: 'older', published_at: Time.now + 1.hour)
|
@@ -398,44 +390,22 @@ RSpec.describe 'OrderQuery' do
|
|
398
390
|
|
399
391
|
it 'orders nulls first (desc)' do
|
400
392
|
space = Post.seek([:published_at, :desc, nulls: :first])
|
401
|
-
|
402
|
-
actual = scope.all.map(&:title)
|
403
|
-
expected = [null, older, newer].map(&:title)
|
404
|
-
expect(actual).to eq(expected), scope.to_sql
|
405
|
-
expect_next space, older, newer
|
406
|
-
expect_prev space, newer, older
|
407
|
-
expect_prev space, older, null
|
408
|
-
expect_next space, null, older
|
393
|
+
expect_order space, [null_1, null_2, older, newer], &display
|
409
394
|
end
|
410
395
|
|
411
396
|
it 'orders nulls first (asc)' do
|
412
397
|
space = Post.seek([:published_at, :asc, nulls: :first])
|
413
|
-
|
414
|
-
actual = scope.all.map(&:title)
|
415
|
-
expected = [null, newer, older].map(&:title)
|
416
|
-
expect(actual).to eq(expected), scope.to_sql
|
417
|
-
expect_prev space, newer, null
|
418
|
-
expect_next space, null, newer
|
398
|
+
expect_order space, [null_1, null_2, newer, older], &display
|
419
399
|
end
|
420
400
|
|
421
401
|
it 'orders nulls last (desc)' do
|
422
402
|
space = Post.seek([:published_at, :desc, nulls: :last])
|
423
|
-
|
424
|
-
actual = scope.all.map(&:title)
|
425
|
-
expected = [older, newer, null].map(&:title)
|
426
|
-
expect(actual).to eq(expected), scope.to_sql
|
427
|
-
expect_next space, newer, null
|
428
|
-
expect_prev space, null, newer
|
403
|
+
expect_order space, [older, newer, null_1, null_2], &display
|
429
404
|
end
|
430
405
|
|
431
406
|
it 'orders nulls last (asc)' do
|
432
407
|
space = Post.seek([:published_at, :asc, nulls: :last])
|
433
|
-
|
434
|
-
actual = scope.all.map(&:title)
|
435
|
-
expected = [newer, older, null].map(&:title)
|
436
|
-
expect(actual).to eq(expected), scope.to_sql
|
437
|
-
expect_next space, older, null
|
438
|
-
expect_prev space, null, older
|
408
|
+
expect_order space, [newer, older, null_1, null_2], &display
|
439
409
|
end
|
440
410
|
end
|
441
411
|
|
data/spec/spec_helper.rb
CHANGED
@@ -8,7 +8,7 @@ if ENV['COVERAGE'] && !%w[rbx jruby].include?(RUBY_ENGINE)
|
|
8
8
|
end
|
9
9
|
require 'order_query'
|
10
10
|
|
11
|
-
|
11
|
+
require_relative './support/order_expectation'
|
12
12
|
|
13
13
|
require 'fileutils'
|
14
14
|
FileUtils.mkpath 'log' unless File.directory? 'log'
|
@@ -35,3 +35,7 @@ else
|
|
35
35
|
fail "Unknown DB adapter #{adapter}. "\
|
36
36
|
'Valid adapters are: mysql2, postgresql, sqlite3.'
|
37
37
|
end
|
38
|
+
|
39
|
+
RSpec.configure do |c|
|
40
|
+
c.include OrderExpectations
|
41
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OrderExpectations
|
4
|
+
# rubocop:disable Metrics/AbcSize
|
5
|
+
|
6
|
+
def expect_next(space, record, next_record, &display)
|
7
|
+
point = space.at(record)
|
8
|
+
actual = point.next
|
9
|
+
failure_message =
|
10
|
+
"expected: next(#{display[record]}) == #{display[next_record]}\n" \
|
11
|
+
" got: #{actual ? display[actual] : 'nil'}\n" \
|
12
|
+
" all: #{space.scope.all.map(&display)}\n" \
|
13
|
+
" sql: #{space.at(record).after.limit(1).to_sql}"
|
14
|
+
expect(actual ? display[actual] : nil).to eq(display[next_record]),
|
15
|
+
failure_message
|
16
|
+
end
|
17
|
+
|
18
|
+
def expect_prev(space, record, prev_record, &display)
|
19
|
+
point = space.at(record)
|
20
|
+
actual = point.previous
|
21
|
+
failure_message =
|
22
|
+
"expected: previous(#{display[record]}) == #{display[prev_record]}\n" \
|
23
|
+
" got: #{actual ? display[actual] : 'nil'}\n" \
|
24
|
+
" all: #{space.scope.all.map(&display)}\n" \
|
25
|
+
" sql: #{space.at(record).before.limit(1).to_sql}"
|
26
|
+
expect(actual ? display[actual] : nil).to eq(display[prev_record]),
|
27
|
+
failure_message
|
28
|
+
end
|
29
|
+
|
30
|
+
def expect_order(space, ordered, &display)
|
31
|
+
all_actual = space.scope.all.map(&display)
|
32
|
+
all_expected = ordered.map(&display)
|
33
|
+
failure_message =
|
34
|
+
"expected: #{all_expected * ', '}\n"\
|
35
|
+
" got: #{all_actual * ', '}\n"\
|
36
|
+
" sql: #{space.scope.to_sql}"
|
37
|
+
expect(all_actual).to eq(all_expected), failure_message
|
38
|
+
|
39
|
+
ordered.each_cons(2) do |record, next_record|
|
40
|
+
expect_next space, record, next_record, &display
|
41
|
+
expect_prev space, next_record, record, &display
|
42
|
+
end
|
43
|
+
expect_next space, ordered.last, ordered.first, &display
|
44
|
+
expect_prev space, ordered.first, ordered.last, &display
|
45
|
+
end
|
46
|
+
|
47
|
+
# rubocop:enable Metrics/AbcSize
|
48
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: order_query
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gleb Mazovetskiy
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-12-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: '5.0'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '7.1'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: '5.0'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '7.1'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: activesupport
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
version: '5.0'
|
40
40
|
- - "<"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: '
|
42
|
+
version: '7.1'
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -49,21 +49,21 @@ dependencies:
|
|
49
49
|
version: '5.0'
|
50
50
|
- - "<"
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: '
|
52
|
+
version: '7.1'
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: rake
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
57
|
- - "~>"
|
58
58
|
- !ruby/object:Gem::Version
|
59
|
-
version: '
|
59
|
+
version: '13.0'
|
60
60
|
type: :development
|
61
61
|
prerelease: false
|
62
62
|
version_requirements: !ruby/object:Gem::Requirement
|
63
63
|
requirements:
|
64
64
|
- - "~>"
|
65
65
|
- !ruby/object:Gem::Version
|
66
|
-
version: '
|
66
|
+
version: '13.0'
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
68
|
name: rspec
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,20 +78,6 @@ dependencies:
|
|
78
78
|
- - "~>"
|
79
79
|
- !ruby/object:Gem::Version
|
80
80
|
version: '3.4'
|
81
|
-
- !ruby/object:Gem::Dependency
|
82
|
-
name: rubocop
|
83
|
-
requirement: !ruby/object:Gem::Requirement
|
84
|
-
requirements:
|
85
|
-
- - ">="
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
version: '0'
|
88
|
-
type: :development
|
89
|
-
prerelease: false
|
90
|
-
version_requirements: !ruby/object:Gem::Requirement
|
91
|
-
requirements:
|
92
|
-
- - ">="
|
93
|
-
- !ruby/object:Gem::Version
|
94
|
-
version: '0'
|
95
81
|
- !ruby/object:Gem::Dependency
|
96
82
|
name: simplecov
|
97
83
|
requirement: !ruby/object:Gem::Requirement
|
@@ -131,14 +117,19 @@ files:
|
|
131
117
|
- spec/gemfiles/rails_5_0.gemfile
|
132
118
|
- spec/gemfiles/rails_5_1.gemfile
|
133
119
|
- spec/gemfiles/rails_5_2.gemfile
|
120
|
+
- spec/gemfiles/rails_6_0.gemfile
|
121
|
+
- spec/gemfiles/rails_6_1.gemfile
|
122
|
+
- spec/gemfiles/rails_7_0.gemfile
|
123
|
+
- spec/gemfiles/rubocop.gemfile
|
134
124
|
- spec/order_query_spec.rb
|
135
125
|
- spec/spec_helper.rb
|
126
|
+
- spec/support/order_expectation.rb
|
136
127
|
homepage: https://github.com/glebm/order_query
|
137
128
|
licenses:
|
138
129
|
- MIT
|
139
130
|
metadata:
|
140
131
|
issue_tracker: https://github.com/glebm/order_query
|
141
|
-
post_install_message:
|
132
|
+
post_install_message:
|
142
133
|
rdoc_options: []
|
143
134
|
require_paths:
|
144
135
|
- lib
|
@@ -146,21 +137,25 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
146
137
|
requirements:
|
147
138
|
- - ">="
|
148
139
|
- !ruby/object:Gem::Version
|
149
|
-
version:
|
140
|
+
version: 2.3.0
|
150
141
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
142
|
requirements:
|
152
143
|
- - ">="
|
153
144
|
- !ruby/object:Gem::Version
|
154
145
|
version: '0'
|
155
146
|
requirements: []
|
156
|
-
|
157
|
-
|
158
|
-
signing_key:
|
147
|
+
rubygems_version: 3.2.3
|
148
|
+
signing_key:
|
159
149
|
specification_version: 4
|
160
150
|
summary: Find next / previous Active Record(s) in one query
|
161
151
|
test_files:
|
162
|
-
- spec/
|
163
|
-
- spec/spec_helper.rb
|
152
|
+
- spec/gemfiles/rails_5_0.gemfile
|
164
153
|
- spec/gemfiles/rails_5_1.gemfile
|
165
154
|
- spec/gemfiles/rails_5_2.gemfile
|
166
|
-
- spec/gemfiles/
|
155
|
+
- spec/gemfiles/rails_6_0.gemfile
|
156
|
+
- spec/gemfiles/rails_6_1.gemfile
|
157
|
+
- spec/gemfiles/rails_7_0.gemfile
|
158
|
+
- spec/gemfiles/rubocop.gemfile
|
159
|
+
- spec/order_query_spec.rb
|
160
|
+
- spec/spec_helper.rb
|
161
|
+
- spec/support/order_expectation.rb
|