order_query 0.3.4 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|