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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d3d5bb8b4f22e2ed2f205ed413e75a41edd4348d
4
- data.tar.gz: 1f216dcc1ec1d112126c68af4a20e28e949663de
2
+ SHA256:
3
+ metadata.gz: 2f9e31c687e96f7014255acbfa4590f9495bca00b942d23c111f38a6c77646eb
4
+ data.tar.gz: ae44f4ca9d520edd2e2d3dc7eead83e9de2f8e440fa2c4ad1d9ce59f266f2756
5
5
  SHA512:
6
- metadata.gz: c3f31357b9b6c3d53d3003c90fdce074bb80bd8f314d81c34e2f096da1d61b18d79b9ea053d3f103c11d962daa155ff4b941c54c23e1b91e7d3d170a43afc054
7
- data.tar.gz: c1c644de117104e827dbc58422c313f77d892f2d6671533e852fa4e64ae26feb57274a1415b1f9a30696f943541501e522b6de7fd36f060fee1eb880ba165388
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
- gemspec
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
@@ -11,7 +11,7 @@ This gem finds the next or previous record(s) relative to the current one effici
11
11
  Add to Gemfile:
12
12
 
13
13
  ```ruby
14
- gem 'order_query', '~> 0.4.0'
14
+ gem 'order_query', '~> 0.5.2'
15
15
  ```
16
16
 
17
17
  ## Usage
@@ -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 && (@order_enum[0].nil? || @order_enum[-1].nil?)
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.connection_config[:adapter]
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
@@ -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
- Column.new(base_scope, *cond_spec)
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 = true, value = point.value(col))
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
- # rubocop:disable Metrics/AbcSize
130
-
131
- def where_ray(col, from, mode, strict = true)
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
- ["#{col.column_name} " \
137
- "#{RAY_OP[col.direction(reverse)]}#{'=' unless strict} ?",
138
- [from]].tap do |ray|
139
- if col.nullable? && col.nulls_direction(reverse) == :last
140
- ray[0] += " OR #{col.column_name} IS NULL"
141
- ray[0] = "(#{ray[0]})"
142
- end
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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OrderQuery
4
- VERSION = '0.4.0'
4
+ VERSION = '0.5.2'
5
5
  end
@@ -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.5'
6
- gem 'activesupport', '~> 5.0.5'
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.0.rc1'
6
- gem 'activesupport', '~> 5.2.0.rc1'
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'
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ eval_gemfile '../../rubocop.gemfile'
@@ -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) { priorities.map { |p| create_issue(priority: p) } }
226
- priorities.permutation do |p|
227
- it "works for #{p} (desc)" do
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
- it "works for #{p} (asc)" do
234
- scope = Issue.seek([:priority, p, :asc]).scope
235
- actual = scope.all.map(&:priority)
236
- expected = p.reverse
237
- expect(actual).to eq(expected), scope.to_sql
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) { states.map { |state| create_post(pinned: state) } }
345
- states.permutation do |p|
346
- it "works for #{p} (desc)" do
347
- scope = Post.seek([:pinned, p]).scope
348
- actual = scope.all.map(&:pinned)
349
- expected = p
350
- expect(actual).to eq(expected), scope.to_sql
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 #{p} (asc)" do
353
- scope = Post.seek([:pinned, p, :asc]).scope
354
- actual = scope.all.map(&:pinned)
355
- expected = p.reverse
356
- expect(actual).to eq(expected), scope.to_sql
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
- # rubocop:disable Metrics/AbcSize
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
- def expect_prev(space, post, prev_post)
377
- point = space.at(post)
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
- # rubocop:enable Metrics/AbcSize
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
- scope = space.scope
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
- scope = space.scope
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
- scope = space.scope
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
- scope = space.scope
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
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
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.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: 2018-02-06 00:00:00.000000000 Z
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: '6.0'
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: '6.0'
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: '6.0'
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: '6.0'
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: '10.2'
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: '10.2'
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: '0'
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
- rubyforge_project:
157
- rubygems_version: 2.6.13
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/order_query_spec.rb
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/rails_5_0.gemfile
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