order_query 0.3.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +6 -0
- data/Gemfile +7 -0
- data/README.md +21 -14
- data/Rakefile +15 -6
- data/lib/order_query.rb +12 -3
- data/lib/order_query/column.rb +72 -24
- data/lib/order_query/direction.rb +9 -7
- data/lib/order_query/errors.rb +11 -0
- data/lib/order_query/nulls_direction.rb +44 -0
- data/lib/order_query/point.rb +20 -6
- data/lib/order_query/space.rb +17 -8
- data/lib/order_query/sql/column.rb +9 -5
- data/lib/order_query/sql/order_by.rb +83 -11
- data/lib/order_query/sql/where.rb +59 -26
- data/lib/order_query/version.rb +3 -1
- data/spec/gemfiles/rails_5_0.gemfile +1 -1
- data/spec/gemfiles/rails_5_1.gemfile +1 -1
- data/spec/gemfiles/rails_5_2.gemfile +8 -0
- data/spec/order_query_spec.rb +259 -72
- data/spec/spec_helper.rb +24 -1
- metadata +30 -14
- data/spec/gemfiles/rails_4_2.gemfile +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3d5bb8b4f22e2ed2f205ed413e75a41edd4348d
|
4
|
+
data.tar.gz: 1f216dcc1ec1d112126c68af4a20e28e949663de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3f31357b9b6c3d53d3003c90fdce074bb80bd8f314d81c34e2f096da1d61b18d79b9ea053d3f103c11d962daa155ff4b941c54c23e1b91e7d3d170a43afc054
|
7
|
+
data.tar.gz: c1c644de117104e827dbc58422c313f77d892f2d6671533e852fa4e64ae26feb57274a1415b1f9a30696f943541501e522b6de7fd36f060fee1eb880ba165388
|
data/CHANGES.md
CHANGED
data/Gemfile
CHANGED
@@ -1,5 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'https://rubygems.org'
|
2
4
|
|
3
5
|
gemspec
|
4
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
|
+
|
5
12
|
eval_gemfile './shared.gemfile'
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# order_query [![Build Status][travis-badge]][travis] [![
|
1
|
+
# order_query [![Build Status][travis-badge]][travis] [![Coverage Status][coverage-badge]][coverage]
|
2
2
|
|
3
3
|
<a href="http://use-the-index-luke.com/no-offset">
|
4
4
|
<img src="http://use-the-index-luke.com/img/no-offset.q200.png" alt="100% offset-free" align="right" width="106" height="106">
|
@@ -11,33 +11,35 @@ 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.
|
14
|
+
gem 'order_query', '~> 0.4.0'
|
15
15
|
```
|
16
16
|
|
17
17
|
## Usage
|
18
18
|
|
19
|
-
|
19
|
+
Use `order_query(scope_name, *order_option)` to create scopes and class methods
|
20
|
+
in your model and specify how you want results ordered. A basic example:
|
20
21
|
|
21
22
|
```ruby
|
22
23
|
class Post < ActiveRecord::Base
|
23
24
|
include OrderQuery
|
24
25
|
order_query :order_home,
|
25
|
-
[:pinned, [true, false]],
|
26
|
-
[:published_at, :desc]
|
26
|
+
[:pinned, [true, false]], # First sort by :pinned over t/f in :desc order
|
27
|
+
[:published_at, :desc] # Next sort :published_at in :desc order
|
27
28
|
end
|
28
29
|
```
|
29
30
|
|
30
|
-
Each
|
31
|
+
Each order option specified in `order_query` is an array in the following form:
|
31
32
|
|
32
|
-
1.
|
33
|
-
2.
|
34
|
-
3. Sort direction, `:asc` or `:desc
|
35
|
-
4.
|
33
|
+
1. Symbol of the attribute name (required).
|
34
|
+
2. An array of values to order by, such as `%w(high medium low)` or `[true, false]` (optional).
|
35
|
+
3. Sort direction, `:asc` or `:desc` (optional). Default: `:asc`; `:desc` when values to order by are specified.
|
36
|
+
4. A hash (optional):
|
36
37
|
|
37
38
|
| option | description |
|
38
39
|
|------------|----------------------------------------------------------------------------|
|
39
40
|
| unique | Unique attribute. Default: `true` for primary key, `false` otherwise. |
|
40
41
|
| sql | Customize column SQL. |
|
42
|
+
| nulls | If set to `:first` or `:last`, orders `NULL`s accordingly. |
|
41
43
|
|
42
44
|
If no unique column is specified, `[primary_key, :asc]` is used. Unique column must be last.
|
43
45
|
|
@@ -66,11 +68,18 @@ p.next #=> #<Post>
|
|
66
68
|
p.position #=> 5
|
67
69
|
```
|
68
70
|
|
69
|
-
The `before` and `after` methods also accept a boolean argument that indicates
|
71
|
+
The `before` and `after` methods also accept a boolean argument that indicates
|
70
72
|
whether the relation should exclude the given point or not.
|
71
73
|
By default the given point is excluded, if you want to include it,
|
72
74
|
use `before(false)` / `after(false)`.
|
73
75
|
|
76
|
+
If you want to obtain only a chunk (i.e., a page), use `before` or `after`
|
77
|
+
with ActiveRecord's `limit` method:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
p.after.limit(20) #=> #<ActiveRecord::Relation>
|
81
|
+
```
|
82
|
+
|
74
83
|
Looping to the first / last record is enabled for `next` / `previous` by default. Pass `false` to disable:
|
75
84
|
|
76
85
|
```ruby
|
@@ -175,7 +184,5 @@ This project uses MIT license.
|
|
175
184
|
[travis]: http://travis-ci.org/glebm/order_query
|
176
185
|
[travis-badge]: http://img.shields.io/travis/glebm/order_query.svg
|
177
186
|
[gemnasium]: https://gemnasium.com/glebm/order_query
|
178
|
-
[codeclimate]: https://codeclimate.com/github/glebm/order_query
|
179
|
-
[codeclimate-badge]: http://img.shields.io/codeclimate/github/glebm/order_query.svg
|
180
187
|
[coverage]: https://codeclimate.com/github/glebm/order_query
|
181
|
-
[coverage-badge]: https://codeclimate.com/
|
188
|
+
[coverage-badge]: https://api.codeclimate.com/v1/badges/82e424e9ee2acb02292c/test_coverage
|
data/Rakefile
CHANGED
@@ -1,14 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
4
|
require 'bundler/setup'
|
3
5
|
rescue LoadError
|
4
6
|
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
7
|
end
|
6
8
|
|
9
|
+
require 'bundler/gem_tasks'
|
7
10
|
require 'rspec/core/rake_task'
|
8
11
|
RSpec::Core::RakeTask.new(:spec)
|
9
12
|
|
10
13
|
task default: :spec
|
11
14
|
|
15
|
+
# rubocop:disable Metrics/BlockLength,Style/StderrPuts
|
16
|
+
|
12
17
|
desc 'Test all Gemfiles from spec/*.gemfile'
|
13
18
|
task :test_all_gemfiles do
|
14
19
|
require 'pty'
|
@@ -16,25 +21,29 @@ task :test_all_gemfiles do
|
|
16
21
|
cmd = 'bundle install --quiet && bundle exec rake --trace'
|
17
22
|
statuses = Dir.glob('./spec/gemfiles/*{[!.lock]}').map do |gemfile|
|
18
23
|
Bundler.with_clean_env do
|
19
|
-
env = {'BUNDLE_GEMFILE' => gemfile}
|
20
|
-
$stderr.puts "Testing #{File.basename(gemfile)}
|
24
|
+
env = { 'BUNDLE_GEMFILE' => gemfile }
|
25
|
+
$stderr.puts "Testing #{File.basename(gemfile)}:
|
26
|
+
export #{env.map { |k, v| "#{k}=#{Shellwords.escape v}" } * ' '}; #{cmd}"
|
21
27
|
PTY.spawn(env, cmd) do |r, _w, pid|
|
22
28
|
begin
|
23
29
|
r.each_line { |l| puts l }
|
24
|
-
rescue Errno::EIO
|
30
|
+
rescue Errno::EIO # rubocop:disable Lint/HandleExceptions
|
25
31
|
# Errno:EIO error means that the process has finished giving output.
|
26
32
|
ensure
|
27
33
|
::Process.wait pid
|
28
34
|
end
|
29
35
|
end
|
30
|
-
[
|
36
|
+
[$CHILD_STATUS&.exitstatus&.zero?, gemfile]
|
31
37
|
end
|
32
38
|
end
|
33
|
-
failed_gemfiles = statuses.reject(&:first).map { |(
|
39
|
+
failed_gemfiles = statuses.reject(&:first).map { |(_, gemfile)| gemfile }
|
34
40
|
if failed_gemfiles.empty?
|
35
41
|
$stderr.puts "✓ Tests pass with all #{statuses.size} gemfiles"
|
36
42
|
else
|
37
|
-
$stderr.puts "❌ FAILING (#{failed_gemfiles.size} / #{statuses.size})
|
43
|
+
$stderr.puts "❌ FAILING (#{failed_gemfiles.size} / #{statuses.size})
|
44
|
+
#{failed_gemfiles * "\n"}"
|
38
45
|
exit 1
|
39
46
|
end
|
40
47
|
end
|
48
|
+
|
49
|
+
# rubocop:enable Metrics/BlockLength,Style/StderrPuts
|
data/lib/order_query.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support'
|
2
4
|
require 'active_record'
|
3
5
|
require 'order_query/space'
|
4
6
|
require 'order_query/point'
|
5
7
|
|
8
|
+
# This gem finds the next or previous record(s) relative to the current one
|
9
|
+
# efficiently using keyset pagination, e.g. for navigation or infinite scroll.
|
6
10
|
module OrderQuery
|
7
11
|
extend ActiveSupport::Concern
|
8
12
|
|
9
|
-
# @param [ActiveRecord::Relation] scope optional first argument
|
13
|
+
# @param [ActiveRecord::Relation] scope optional first argument
|
14
|
+
# (default: self.class.all)
|
10
15
|
# @param [Array<Array<Symbol,String>>, OrderQuery::Spec] order_spec
|
11
16
|
# @return [OrderQuery::Point]
|
12
17
|
# @example
|
@@ -15,13 +20,15 @@ module OrderQuery
|
|
15
20
|
# next_user = user.seek(users, [:activated_at, :desc], [:id, :desc]).next
|
16
21
|
def seek(*spec)
|
17
22
|
fst = spec.first
|
18
|
-
if fst.nil? || fst.is_a?(ActiveRecord::Relation) ||
|
23
|
+
if fst.nil? || fst.is_a?(ActiveRecord::Relation) ||
|
24
|
+
fst.is_a?(ActiveRecord::Base)
|
19
25
|
scope = spec.shift
|
20
26
|
end
|
21
27
|
scope ||= self.class.all
|
22
28
|
scope.seek(*spec).at(self)
|
23
29
|
end
|
24
30
|
|
31
|
+
# Top-level functions.
|
25
32
|
module ClassMethods
|
26
33
|
# @return [OrderQuery::Space]
|
27
34
|
def seek(*spec)
|
@@ -31,7 +38,9 @@ module OrderQuery
|
|
31
38
|
end
|
32
39
|
|
33
40
|
#= DSL
|
41
|
+
|
34
42
|
protected
|
43
|
+
|
35
44
|
# @param [Symbol] name
|
36
45
|
# @param [Array<Array<Symbol,String>>] order_spec
|
37
46
|
# @example
|
@@ -60,7 +69,7 @@ module OrderQuery
|
|
60
69
|
# #<OrderQuery::Point...>
|
61
70
|
def order_query(name, *spec)
|
62
71
|
define_singleton_method(:"#{name}_space") { seek(*spec) }
|
63
|
-
class_eval <<-RUBY, __FILE__, __LINE__
|
72
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
64
73
|
scope :#{name}, -> { #{name}_space.scope }
|
65
74
|
scope :#{name}_reverse, -> { #{name}_space.scope_reverse }
|
66
75
|
def self.#{name}_at(record)
|
data/lib/order_query/column.rb
CHANGED
@@ -1,41 +1,89 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'order_query/direction'
|
4
|
+
require 'order_query/nulls_direction'
|
3
5
|
require 'order_query/sql/column'
|
4
6
|
module OrderQuery
|
5
7
|
# An order column (sort column)
|
6
8
|
class Column
|
7
|
-
attr_reader :name, :order_enum, :
|
8
|
-
delegate :column_name, :quote, to: :@
|
9
|
+
attr_reader :name, :order_enum, :custom_sql
|
10
|
+
delegate :column_name, :quote, :scope, to: :@sql_builder
|
9
11
|
|
10
|
-
#
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
12
|
+
# rubocop:disable Metrics/ParameterLists,Metrics/AbcSize
|
13
|
+
# rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
14
|
+
# rubocop:disable Metrics/MethodLength
|
15
|
+
|
16
|
+
# @param scope [ActiveRecord::Relation]
|
17
|
+
# @param attr_name [Symbol] the name of the column, or the method providing
|
18
|
+
# the value to sort by.
|
19
|
+
# @param vals_and_or_dir [Array] optionally, values in the desired order,
|
20
|
+
# and / or one of `:asc`, `:desc`. Default order is `:desc` if the values
|
21
|
+
# are given (so the result is ordered like the values), `:asc` otherwise.
|
22
|
+
# @param unique [Boolean] mark the attribute as unique to avoid redundant
|
23
|
+
# columns. Default: `true` for primary key.
|
24
|
+
# @param nulls [:first, :last, false] whether to consider NULLS to be
|
25
|
+
# ordered first or last. If false, assumes that a column is not nullable
|
26
|
+
# and raises [Errors::NonNullableColumnIsNullError] if a null is
|
27
|
+
# encountered.
|
28
|
+
# @param sql [String, nil] a custom sql fragment.
|
29
|
+
def initialize(scope, attr_name, *vals_and_or_dir,
|
30
|
+
unique: nil, nulls: false, sql: nil)
|
31
|
+
@name = attr_name
|
32
|
+
@order_enum = vals_and_or_dir.shift if vals_and_or_dir[0].is_a?(Array)
|
33
|
+
@direction = Direction.parse!(
|
34
|
+
vals_and_or_dir.shift || (@order_enum ? :desc : :asc)
|
23
35
|
)
|
24
|
-
|
25
|
-
|
36
|
+
unless vals_and_or_dir.empty?
|
37
|
+
fail ArgumentError,
|
38
|
+
"extra arguments: #{vals_and_or_dir.map(&:inspect) * ', '}"
|
39
|
+
end
|
40
|
+
@unique = unique.nil? ? (name.to_s == scope.primary_key) : unique
|
41
|
+
if @order_enum && (@order_enum[0].nil? || @order_enum[-1].nil?)
|
42
|
+
fail ArgumentError, '`nulls` cannot be set if a value is null' if nulls
|
43
|
+
@nullable = true
|
44
|
+
@nulls = if @order_enum[0].nil?
|
45
|
+
@direction == :desc ? :first : :last
|
46
|
+
else
|
47
|
+
@direction == :desc ? :last : :first
|
48
|
+
end
|
49
|
+
else
|
50
|
+
@nullable = !!nulls # rubocop:disable Style/DoubleNegation
|
51
|
+
@nulls = NullsDirection.parse!(
|
52
|
+
nulls || NullsDirection.default(scope, @direction)
|
53
|
+
)
|
54
|
+
end
|
55
|
+
@custom_sql = sql
|
56
|
+
@sql_builder = SQL::Column.new(scope, self)
|
26
57
|
end
|
58
|
+
# rubocop:enable Metrics/ParameterLists,Metrics/AbcSize
|
59
|
+
# rubocop:enable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
60
|
+
# rubocop:enable Metrics/MethodLength
|
27
61
|
|
28
62
|
def direction(reverse = false)
|
29
63
|
reverse ? Direction.reverse(@direction) : @direction
|
30
64
|
end
|
31
65
|
|
66
|
+
# @return [:first, :last]
|
67
|
+
def nulls_direction(reverse = false)
|
68
|
+
reverse ? NullsDirection.reverse(@nulls) : @nulls
|
69
|
+
end
|
70
|
+
|
71
|
+
# @return [:first, :last]
|
72
|
+
def default_nulls_direction(reverse = false)
|
73
|
+
NullsDirection.default(scope, direction(reverse))
|
74
|
+
end
|
75
|
+
|
76
|
+
def nullable?
|
77
|
+
@nullable
|
78
|
+
end
|
79
|
+
|
32
80
|
def unique?
|
33
81
|
@unique
|
34
82
|
end
|
35
83
|
|
36
84
|
# @param [Object] value
|
37
85
|
# @param [:before, :after] side
|
38
|
-
# @return [Array] valid order values before / after
|
86
|
+
# @return [Array] valid order values before / after the given value.
|
39
87
|
# @example for [:difficulty, ['Easy', 'Normal', 'Hard']]:
|
40
88
|
# enum_side('Normal', :after) #=> ['Hard']
|
41
89
|
# enum_side('Normal', :after, false) #=> ['Normal', 'Hard']
|
@@ -57,11 +105,11 @@ module OrderQuery
|
|
57
105
|
|
58
106
|
def inspect
|
59
107
|
parts = [
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
108
|
+
@name,
|
109
|
+
(@order_enum.inspect if order_enum),
|
110
|
+
('unique' if @unique),
|
111
|
+
(column_name if @custom_sql),
|
112
|
+
@direction
|
65
113
|
].compact
|
66
114
|
"(#{parts.join(' ')})"
|
67
115
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module OrderQuery
|
2
4
|
# Responsible for handling :asc and :desc
|
3
5
|
module Direction
|
4
|
-
|
6
|
+
module_function
|
5
7
|
|
6
|
-
DIRECTIONS = [
|
8
|
+
DIRECTIONS = %i[asc desc].freeze
|
7
9
|
|
8
10
|
def all
|
9
11
|
DIRECTIONS
|
@@ -15,14 +17,14 @@ module OrderQuery
|
|
15
17
|
all[(all.index(direction) + 1) % 2].to_sym
|
16
18
|
end
|
17
19
|
|
18
|
-
# @param [:asc, :desc
|
20
|
+
# @param [:asc, :desc] direction
|
19
21
|
# @raise [ArgumentError]
|
20
22
|
# @return [:asc, :desc]
|
21
23
|
def parse!(direction)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
all.include?(direction) && direction or
|
25
|
+
fail ArgumentError,
|
26
|
+
"sort direction must be in #{all.map(&:inspect).join(', ')}, "\
|
27
|
+
"is #{direction.inspect}"
|
26
28
|
end
|
27
29
|
end
|
28
30
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OrderQuery
|
4
|
+
# All the exceptions that can be raised by order query methods.
|
5
|
+
module Errors
|
6
|
+
# Raised when a column that OrderQuery assumes to never contain NULLs
|
7
|
+
# contains a null.
|
8
|
+
class NonNullableColumnIsNullError < RuntimeError
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OrderQuery
|
4
|
+
# Handles nulls :first and :last direction.
|
5
|
+
module NullsDirection
|
6
|
+
module_function
|
7
|
+
|
8
|
+
DIRECTIONS = %i[first last].freeze
|
9
|
+
|
10
|
+
def all
|
11
|
+
DIRECTIONS
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param [:first, :last] direction
|
15
|
+
# @return [:first, :last]
|
16
|
+
def reverse(direction)
|
17
|
+
all[(all.index(direction) + 1) % 2].to_sym
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param [:first, :last] direction
|
21
|
+
# @raise [ArgumentError]
|
22
|
+
# @return [:first, :last]
|
23
|
+
def parse!(direction)
|
24
|
+
all.include?(direction) && direction or
|
25
|
+
fail ArgumentError,
|
26
|
+
"`nulls` must be in #{all.map(&:inspect).join(', ')}, "\
|
27
|
+
"is #{direction.inspect}"
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param scope [ActiveRecord::Relation]
|
31
|
+
# @param dir [:asc, :desc]
|
32
|
+
# @return [:first, :last] the default nulls order, based on the given
|
33
|
+
# scope's connection adapter name.
|
34
|
+
def default(scope, dir)
|
35
|
+
case scope.connection_config[:adapter]
|
36
|
+
when /mysql|maria|sqlite|sqlserver/i
|
37
|
+
(dir == :asc ? :first : :last)
|
38
|
+
else
|
39
|
+
# Oracle, Postgres
|
40
|
+
(dir == :asc ? :last : :first)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/order_query/point.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'order_query/space'
|
2
4
|
require 'order_query/sql/where'
|
5
|
+
require 'order_query/errors'
|
3
6
|
|
4
7
|
module OrderQuery
|
5
8
|
# Search around a record in an order space
|
@@ -15,7 +18,8 @@ module OrderQuery
|
|
15
18
|
@where_sql = SQL::Where.new(self)
|
16
19
|
end
|
17
20
|
|
18
|
-
# @
|
21
|
+
# @param [true, false] loop if true, loops as if the last and the first
|
22
|
+
# records were adjacent, unless there is only one record.
|
19
23
|
# @return [ActiveRecord::Base]
|
20
24
|
def next(loop = true)
|
21
25
|
unless_record_eq after.first || (first if loop)
|
@@ -31,20 +35,23 @@ module OrderQuery
|
|
31
35
|
space.count - after.count
|
32
36
|
end
|
33
37
|
|
34
|
-
# @param [true, false] strict
|
38
|
+
# @param [true, false] strict if false, the given scope will include the
|
39
|
+
# record at this point.
|
35
40
|
# @return [ActiveRecord::Relation]
|
36
41
|
def after(strict = true)
|
37
42
|
side :after, strict
|
38
43
|
end
|
39
44
|
|
40
|
-
# @param [true, false] strict
|
45
|
+
# @param [true, false] strict if false, the given scope will include the
|
46
|
+
# record at this point.
|
41
47
|
# @return [ActiveRecord::Relation]
|
42
48
|
def before(strict = true)
|
43
49
|
side :before, strict
|
44
50
|
end
|
45
51
|
|
46
52
|
# @param [:before, :after] side
|
47
|
-
# @param [true, false] strict
|
53
|
+
# @param [true, false] strict if false, the given scope will include the
|
54
|
+
# record at this point.
|
48
55
|
# @return [ActiveRecord::Relation]
|
49
56
|
def side(side, strict = true)
|
50
57
|
query, query_args = @where_sql.build(side, strict)
|
@@ -56,8 +63,15 @@ module OrderQuery
|
|
56
63
|
scope.where(query, *query_args)
|
57
64
|
end
|
58
65
|
|
59
|
-
|
60
|
-
|
66
|
+
# @param column [Column]
|
67
|
+
def value(column)
|
68
|
+
v = record.send(column.name)
|
69
|
+
if v.nil? && !column.nullable?
|
70
|
+
fail Errors::NonNullableColumnIsNullError,
|
71
|
+
"Column #{column.inspect} is NULL on record #{@record.inspect}. "\
|
72
|
+
'Set the `nulls` option to :first or :last.'
|
73
|
+
end
|
74
|
+
v
|
61
75
|
end
|
62
76
|
|
63
77
|
def inspect
|