order_query 0.3.3 → 0.5.1

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.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module OrderQuery
2
- VERSION = '0.3.3'
4
+ VERSION = '0.5.1'
3
5
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec path: '../../'
6
+
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
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', '~> 5.1.3'
8
+ gem 'activesupport', '~> 5.1.3'
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
+
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', '~> 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
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.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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ eval_gemfile '../../rubocop.gemfile'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  # Bare model
@@ -10,23 +12,23 @@ class Post < ActiveRecord::Base
10
12
  include OrderQuery
11
13
  order_query :order_list,
12
14
  [:pinned, [true, false]],
13
- [:published_at, :desc],
14
- [:id, :desc]
15
+ %i[published_at desc],
16
+ %i[id desc]
15
17
  end
16
18
 
17
19
  def create_post(attr = {})
18
- Post.create!({pinned: false, published_at: Time.now}.merge(attr))
20
+ Post.create!({ pinned: false, published_at: Time.now }.merge(attr))
19
21
  end
20
22
 
21
23
  # Advanced model
22
24
  class Issue < ActiveRecord::Base
23
25
  DISPLAY_ORDER = [
24
- [:pinned, [true, false]],
25
- [:priority, %w(high medium low)],
26
- [:valid_votes_count, :desc, sql: '(votes - suspicious_votes)'],
27
- [:updated_at, :desc],
28
- [:id, :desc]
29
- ]
26
+ [:pinned, [true, false]],
27
+ [:priority, %w[high medium low]],
28
+ [:valid_votes_count, :desc, sql: '(votes - suspicious_votes)'],
29
+ %i[updated_at desc],
30
+ %i[id desc]
31
+ ].freeze
30
32
 
31
33
  def valid_votes_count
32
34
  votes - suspicious_votes
@@ -34,11 +36,14 @@ class Issue < ActiveRecord::Base
34
36
 
35
37
  include OrderQuery
36
38
  order_query :display_order, DISPLAY_ORDER
37
- order_query :id_order_asc, [[:id, :asc]]
39
+ order_query :id_order_asc, [%i[id asc]]
38
40
  end
39
41
 
40
42
  def create_issue(attr = {})
41
- Issue.create!({priority: 'high', votes: 3, suspicious_votes: 0, updated_at: Time.now}.merge(attr))
43
+ Issue.create!(
44
+ { priority: 'high', votes: 3, suspicious_votes: 0, updated_at: Time.now }
45
+ .merge(attr)
46
+ )
42
47
  end
43
48
 
44
49
  def wrap_top_level_or(value)
@@ -54,53 +59,84 @@ def wrap_top_level_or(value)
54
59
  end
55
60
  end
56
61
 
57
- describe 'OrderQuery' do
62
+ RSpec.describe 'OrderQuery' do
63
+ context 'Column' do
64
+ it 'fails with ArgumentError if invalid vals_and_or_dir is passed' do
65
+ expect do
66
+ OrderQuery::Column.new(Post.all, :pinned, :desc, :extra)
67
+ end.to raise_error(ArgumentError)
68
+ end
69
+ end
70
+
71
+ context 'Point' do
72
+ context '#value' do
73
+ it 'fails if nil on non-nullable column' do
74
+ post = OpenStruct.new
75
+ post.pinned = nil
76
+ space = Post.seek([:pinned])
77
+ expect do
78
+ OrderQuery::Point.new(post, space)
79
+ .value(space.columns.find { |c| c.name == :pinned })
80
+ end.to raise_error(OrderQuery::Errors::NonNullableColumnIsNullError)
81
+ end
82
+ end
83
+ end
58
84
 
59
85
  [false, true].each do |wrap_top_level_or|
60
86
  context "(wtlo: #{wrap_top_level_or})" do
61
87
  wrap_top_level_or wrap_top_level_or
62
88
 
63
89
  context 'Issue test model' do
64
- t = Time.now
65
- datasets = [
90
+ datasets = lambda {
91
+ t = Time.now
92
+ [
66
93
  [
67
- ['high', 5, 0, t, true],
68
- ['high', 5, 1, t, true],
69
- ['high', 5, 0, t],
70
- ['high', 5, 0, t - 1.day],
71
- ['high', 5, 1, t],
72
- ['medium', 10, 0, t],
73
- ['medium', 10, 5, t - 12.hours],
74
- ['low', 30, 0, t + 1.day]
94
+ ['high', 5, 0, t, true],
95
+ ['high', 5, 1, t, true],
96
+ ['high', 5, 0, t],
97
+ ['high', 5, 0, t - 1.day],
98
+ ['high', 5, 1, t],
99
+ ['medium', 10, 0, t],
100
+ ['medium', 10, 5, t - 12.hours],
101
+ ['low', 30, 0, t + 1.day]
75
102
  ],
76
103
  [
77
- ['high', 5, 0, t],
78
- ['high', 5, 1, t],
79
- ['high', 5, 1, t - 1.day],
80
- ['low', 30, 0, t + 1.day]
104
+ ['high', 5, 0, t],
105
+ ['high', 5, 1, t],
106
+ ['high', 5, 1, t - 1.day],
107
+ ['low', 30, 0, t + 1.day]
81
108
  ],
82
109
  [
83
- ['high', 5, 1, t - 1.day],
84
- ['low', 30, 0, t + 1.day]
85
- ],
86
- ]
110
+ ['high', 5, 1, t - 1.day],
111
+ ['low', 30, 0, t + 1.day]
112
+ ]
113
+ ]
114
+ }.call
87
115
 
88
116
  datasets.each_with_index do |ds, i|
89
117
  it "is ordered correctly (test data #{i})" do
90
118
  issues = ds.map do |attr|
91
- Issue.new(priority: attr[0], votes: attr[1], suspicious_votes: attr[2], updated_at: attr[3], pinned: attr[4] || false)
119
+ Issue.new(priority: attr[0], votes: attr[1],
120
+ suspicious_votes: attr[2], updated_at: attr[3],
121
+ pinned: attr[4] || false)
92
122
  end
93
123
  issues.shuffle.reverse_each(&:save!)
94
124
  expect(Issue.display_order.to_a).to eq(issues)
95
125
  expect(Issue.display_order_reverse.to_a).to eq(issues.reverse)
96
- issues.zip(issues.rotate).each_with_index do |(cur, nxt), i|
97
- expect(cur.display_order.position).to eq(i + 1)
126
+ issues.zip(issues.rotate).each_with_index do |(cur, nxt), j|
127
+ expect(cur.display_order.position).to eq(j + 1)
98
128
  expect(cur.display_order.next).to eq(nxt)
99
129
  expect(Issue.display_order_at(cur).next).to eq nxt
100
130
  expect(cur.display_order.space.count).to eq(Issue.count)
101
- expect(cur.display_order.before.count + 1 + cur.display_order.after.count).to eq(nxt.display_order.count)
131
+ expect(
132
+ cur.display_order.before.count + 1 +
133
+ cur.display_order.after.count
134
+ ).to eq(nxt.display_order.count)
102
135
  expect(nxt.display_order.previous).to eq(cur)
103
- expect(nxt.display_order.before.to_a.reverse + [nxt] + nxt.display_order.after.to_a).to eq(Issue.display_order.to_a)
136
+ expect(
137
+ nxt.display_order.before.to_a.reverse + [nxt] +
138
+ nxt.display_order.after.to_a
139
+ ).to eq(Issue.display_order.to_a)
104
140
  end
105
141
  end
106
142
  end
@@ -117,16 +153,20 @@ describe 'OrderQuery' do
117
153
  expect(a.id_order_asc.next).to eq b
118
154
  expect(b.id_order_asc.previous).to eq a
119
155
  expect([a] + a.id_order_asc.after.to_a).to eq(Issue.id_order_asc.to_a)
120
- expect(b.id_order_asc.before.reverse.to_a + [b]).to eq(Issue.id_order_asc.to_a)
156
+ expect(b.id_order_asc.before.reverse.to_a + [b]).to(
157
+ eq Issue.id_order_asc.to_a
158
+ )
121
159
  expect(Issue.id_order_asc.count).to eq(2)
122
160
  end
123
161
 
124
162
  it '.seek works on a list of ids' do
125
- ids = 3.times.map { create_issue.id }
163
+ ids = Array.new(3) { create_issue.id }
126
164
  expect(Issue.seek([[:id, ids]]).count).to eq ids.length
127
165
  expect(Issue.seek([:id, ids]).count).to eq ids.length
128
166
  expect(Issue.seek([:id, ids]).scope.pluck(:id)).to eq ids
129
- expect(Issue.seek([:id, ids]).scope_reverse.pluck(:id)).to eq ids.reverse
167
+ expect(Issue.seek([:id, ids]).scope_reverse.pluck(:id)).to(
168
+ eq(ids.reverse)
169
+ )
130
170
  end
131
171
 
132
172
  context 'partitioned on a boolean flag' do
@@ -136,7 +176,7 @@ describe 'OrderQuery' do
136
176
  create_issue(active: true)
137
177
  end
138
178
 
139
- let!(:order) { [[:id, :desc]] }
179
+ let!(:order) { [%i[id desc]] }
140
180
  let!(:active) { Issue.where(active: true).seek(order) }
141
181
  let!(:inactive) { Issue.where(active: false).seek(order) }
142
182
 
@@ -172,7 +212,38 @@ describe 'OrderQuery' do
172
212
  it '#seek falls back to scope when order column is missing self' do
173
213
  a = create_issue(priority: 'medium')
174
214
  b = create_issue(priority: 'high')
175
- expect(a.seek(Issue.display_order, [[:priority, ['wontfix', 'askbob']], [:id, :desc]]).next).to eq(b)
215
+ expect(
216
+ a.seek(
217
+ Issue.display_order,
218
+ [[:priority, %w[wontfix askbob]], %i[id desc]]
219
+ ).next
220
+ ).to eq(b)
221
+ end
222
+
223
+ context 'nil in string enum' do
224
+ display = ->(issue) { "##{issue.id}-#{issue.priority || 'NULL'}" }
225
+ priorities = [nil, 'low', 'medium', 'high']
226
+ let!(:issues) do
227
+ priorities.flat_map do |p|
228
+ [create_issue(priority: p), create_issue(priority: p)]
229
+ end
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
+ )
245
+ end
246
+ end
176
247
  end
177
248
 
178
249
  before do
@@ -217,28 +288,33 @@ describe 'OrderQuery' do
217
288
 
218
289
  context '#inspect' do
219
290
  it 'Column' do
220
- expect(OrderQuery::Column.new([:id, :desc], Post).inspect).to eq '(id unique desc)'
221
- expect(OrderQuery::Column.new([:virtual, :desc, sql: 'SIN(id)'], Post).inspect).to eq '(virtual SIN(id) desc)'
291
+ expect(OrderQuery::Column.new(Post, :id, :desc).inspect)
292
+ .to eq '(id unique desc)'
293
+ expect(
294
+ OrderQuery::Column.new(Post, :virtual, :desc, sql: 'SIN(id)')
295
+ .inspect
296
+ ).to eq '(virtual SIN(id) desc)'
222
297
  end
223
298
 
224
- let(:space) {
299
+ let(:space) do
225
300
  OrderQuery::Space.new(Post, [[:pinned, [true, false]]])
226
- }
301
+ end
227
302
 
228
303
  it 'Point' do
229
- post = create_post
304
+ post = create_post
230
305
  point = OrderQuery::Point.new(post, space)
231
- expect(point.inspect).to(
232
- eq %Q(#<OrderQuery::Point @record=#<Post id: #{post.id}, pinned: false, published_at: #{post.attribute_for_inspect(:published_at)}> @space=#<OrderQuery::Space @columns=[(pinned [true, false] desc), (id unique asc)] @base_scope=Post(id: integer, pinned: boolean, published_at: datetime)>>)
233
- )
306
+ # rubocop:disable Metrics/LineLength
307
+ expect(point.inspect).to eq %(#<OrderQuery::Point @record=#<Post id: #{post.id}, title: nil, pinned: false, published_at: #{post.attribute_for_inspect(:published_at)}> @space=#<OrderQuery::Space @columns=[(pinned [true, false] desc), (id unique asc)] @base_scope=Post(id: integer, title: string, pinned: boolean, published_at: datetime)>>)
308
+ # rubocop:enable Metrics/LineLength
234
309
  end
235
310
 
236
311
  it 'Space' do
237
- expect(space.inspect).to eq '#<OrderQuery::Space @columns=[(pinned [true, false] desc), (id unique asc)] @base_scope=Post(id: integer, pinned: boolean, published_at: datetime)>'
312
+ # rubocop:disable Metrics/LineLength
313
+ expect(space.inspect).to eq '#<OrderQuery::Space @columns=[(pinned [true, false] desc), (id unique asc)] @base_scope=Post(id: integer, title: string, pinned: boolean, published_at: datetime)>'
314
+ # rubocop:enable Metrics/LineLength
238
315
  end
239
316
  end
240
317
 
241
-
242
318
  context 'boolean enum order' do
243
319
  before do
244
320
  create_post pinned: true
@@ -248,29 +324,141 @@ describe 'OrderQuery' do
248
324
  Post.delete_all
249
325
  end
250
326
  it 'ORDER BY is collapsed' do
251
- expect(Post.seek([:pinned, [true, false]]).scope.to_sql).to include('ORDER BY "posts"."pinned" DESC')
327
+ expect(Post.seek([:pinned, [true, false]]).scope.to_sql).to(
328
+ match(/ORDER BY .posts.\..pinned. DESC/)
329
+ )
252
330
  end
253
331
  it 'enum asc' do
254
- expect(Post.seek([:pinned, [false, true], :asc]).scope.pluck(:pinned)).to eq([true, false])
255
- expect(Post.seek([:pinned, [true, false], :asc]).scope.pluck(:pinned)).to eq([false, true])
332
+ expect(
333
+ Post.seek([:pinned, [false, true], :asc]).scope.pluck(:pinned)
334
+ ).to eq([true, false])
335
+ expect(
336
+ Post.seek([:pinned, [true, false], :asc]).scope.pluck(:pinned)
337
+ ).to eq([false, true])
256
338
  end
257
339
  it 'enum desc' do
258
- expect(Post.seek([:pinned, [false, true], :desc]).scope.pluck(:pinned)).to eq([false, true])
259
- expect(Post.seek([:pinned, [true, false], :desc]).scope.pluck(:pinned)).to eq([true, false])
340
+ expect(
341
+ Post.seek([:pinned, [false, true], :desc]).scope.pluck(:pinned)
342
+ ).to eq([false, true])
343
+ expect(
344
+ Post.seek([:pinned, [true, false], :desc]).scope.pluck(:pinned)
345
+ ).to eq([true, false])
260
346
  end
261
347
  end
262
348
 
263
- xcontext 'nil in enum' do
349
+ context 'nil in boolean enum' do
350
+ display = ->(post) { "##{post.id}-#{post.pinned || 'NULL'}" }
264
351
  states = [nil, false, true]
265
- let!(:posts) { states.map { |state| create_post(pinned: state) } }
266
- states.permutation do |p|
267
- # There is no cross-DB SQL that can be generated to position nil results
268
- # http://use-the-index-luke.com/sql/sorting-grouping/order-by-asc-desc-nulls-last
269
- next unless p.first.nil? || p.last.nil?
270
- # Positioning NULLs first or last can be achieved, but remains on the ToDo / contributions welcome list
271
- it "nil in enum works for #{p}" do
272
- expect(Post.seek([:pinned, p]).scope.all.map(&:pinned)).to eq(p)
273
- expect(Post.seek([:pinned, p, :asc]).scope.all.map(&:pinned)).to eq(p.reverse)
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
+ )
364
+ end
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
+ )
371
+ end
372
+ end
373
+ end
374
+
375
+ context 'nil published_at' do
376
+ display = ->(post) { post.title }
377
+
378
+ let! :null_1 do
379
+ Post.create!(title: 'null_1', published_at: nil).reload
380
+ end
381
+ let! :null_2 do
382
+ Post.create!(title: 'null_2', published_at: nil).reload
383
+ end
384
+ let! :older do
385
+ Post.create!(title: 'older', published_at: Time.now + 1.hour)
386
+ end
387
+ let! :newer do
388
+ Post.create!(title: 'newer', published_at: Time.now - 1.hour)
389
+ end
390
+
391
+ it 'orders nulls first (desc)' do
392
+ space = Post.seek([:published_at, :desc, nulls: :first])
393
+ expect_order space, [null_1, null_2, older, newer], &display
394
+ end
395
+
396
+ it 'orders nulls first (asc)' do
397
+ space = Post.seek([:published_at, :asc, nulls: :first])
398
+ expect_order space, [null_1, null_2, newer, older], &display
399
+ end
400
+
401
+ it 'orders nulls last (desc)' do
402
+ space = Post.seek([:published_at, :desc, nulls: :last])
403
+ expect_order space, [older, newer, null_1, null_2], &display
404
+ end
405
+
406
+ it 'orders nulls last (asc)' do
407
+ space = Post.seek([:published_at, :asc, nulls: :last])
408
+ expect_order space, [newer, older, null_1, null_2], &display
409
+ end
410
+ end
411
+
412
+ context 'after/before no strict' do
413
+ context 'by middle attribute in search order' do
414
+ let! :base do
415
+ Post.create! pinned: true, published_at: Time.now
416
+ end
417
+ let! :older do
418
+ Post.create! pinned: true, published_at: Time.now + 1.hour
419
+ end
420
+ let! :newer do
421
+ Post.create! pinned: true, published_at: Time.now - 1.hour
422
+ end
423
+
424
+ it 'includes first element' do
425
+ point = Post.order_list_at(base)
426
+
427
+ expect(point.after.count).to eq 1
428
+ expect(point.after.to_a).to eq [newer]
429
+
430
+ expect(point.after(false).count).to eq 2
431
+ expect(point.after(false).to_a).to eq [base, newer]
432
+ expect(point.before(false).to_a).to eq [base, older]
433
+ end
434
+ end
435
+
436
+ context 'by last attribute in search order' do
437
+ let!(:base) do
438
+ Post.create! pinned: true,
439
+ published_at: Time.new(2016, 5, 1, 5, 4, 3),
440
+ id: 6
441
+ end
442
+ let!(:previous) do
443
+ Post.create! pinned: true,
444
+ published_at: Time.new(2016, 5, 1, 5, 4, 3),
445
+ id: 4
446
+ end
447
+ let!(:next_one) do
448
+ Post.create! pinned: true,
449
+ published_at: Time.new(2016, 5, 1, 5, 4, 3),
450
+ id: 9
451
+ end
452
+
453
+ it 'includes first element' do
454
+ point = Post.order_list_at(base)
455
+
456
+ expect(point.after.count).to eq 1
457
+ expect(point.after.to_a).to eq [previous]
458
+
459
+ expect(point.after(false).count).to eq 2
460
+ expect(point.after(false).to_a).to eq [base, previous]
461
+ expect(point.before(false).to_a).to eq [base, next_one]
274
462
  end
275
463
  end
276
464
  end
@@ -282,10 +470,12 @@ describe 'OrderQuery' do
282
470
  ActiveRecord::Schema.define do
283
471
  self.verbose = false
284
472
  create_table :posts do |t|
473
+ t.string :title
285
474
  t.boolean :pinned
286
475
  t.datetime :published_at
287
476
  end
288
477
  end
478
+ Post.reset_column_information
289
479
  end
290
480
  after :all do
291
481
  ActiveRecord::Migration.drop_table :posts
@@ -298,7 +488,8 @@ describe 'OrderQuery' do
298
488
  context 'wrap top-level OR on' do
299
489
  wrap_top_level_or true
300
490
  it 'wraps top-level OR' do
301
- after_scope = User.create!(updated_at: Date.parse('2014-09-06')).seek([[:updated_at, :desc], [:id, :desc]]).after
491
+ after_scope = User.create!(updated_at: Date.parse('2014-09-06'))
492
+ .seek([%i[updated_at desc], %i[id desc]]).after
302
493
  expect(after_scope.to_sql).to include('<=')
303
494
  end
304
495
  end
@@ -306,7 +497,8 @@ describe 'OrderQuery' do
306
497
  context 'wrap top-level OR off' do
307
498
  wrap_top_level_or false
308
499
  it 'does not wrap top-level OR' do
309
- after_scope = User.create!(updated_at: Date.parse('2014-09-06')).seek([[:updated_at, :desc], [:id, :desc]]).after
500
+ after_scope = User.create!(updated_at: Date.parse('2014-09-06'))
501
+ .seek([%i[updated_at desc], %i[id desc]]).after
310
502
  expect(after_scope.to_sql).to_not include('<=')
311
503
  end
312
504
  end
@@ -322,6 +514,7 @@ describe 'OrderQuery' do
322
514
  t.datetime :updated_at, null: false
323
515
  end
324
516
  end
517
+ User.reset_column_information
325
518
  end
326
519
 
327
520
  after :all do