order_query 0.4.0 → 0.5.2
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 +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
|