sortable-by 0.12.1 → 0.13.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e89dd7025ad14bfd9a012b10d68a70183692121625d14e56feea7e3484d8398
4
- data.tar.gz: 931017877555f573485ebbaecb5501ba36e5e4c3a2c7d0842ada6ff2f68cd5fb
3
+ metadata.gz: 4639f942b5f628b07367a343160d7e4301b00bf3c6e0db9f57ff43d204a85ab5
4
+ data.tar.gz: 2f424ec2cda37112ca64fdf628b7ff0aee3e223dbee81d585040eff79ee468c8
5
5
  SHA512:
6
- metadata.gz: 45ef18f0d53caa91e2e9cb0c8bcbae4bf4cdc3da59b844e1ddae2f5fa16454905d925a7212a31e4355f077fe7436b25303f17422c47f25592a3036cd623caba3
7
- data.tar.gz: 724fd46c5ea0fd379980dcfe64a58ea579d9d03edab02516862d654ccc5a472d10bc810ccf48a32d4cc96e70ed5608100596425091c7a541dae5f380f8f4a173
6
+ metadata.gz: ff08a62e083e324f9baa4118423c82d90ad93d00f42b4cd6ae74d915a637439315f4cf5ebd8b9d598075bd9565064429a06d0017bae3b5f7998c35b39a50f14c
7
+ data.tar.gz: b084242394054b896d594c923e262c6325a74c58c836e2224ee5c4f91c3bc087bedfe0b42eb7aa2438ea2a84dd41ddd54c6b5718f68e181d5869bbb5efcb2397
@@ -4,6 +4,8 @@ inherit_from:
4
4
  AllCops:
5
5
  TargetRubyVersion: 2.5
6
6
 
7
+ Naming/MethodParameterName:
8
+ MinNameLength: 2
7
9
  Naming/MemoizedInstanceVariableName:
8
10
  Enabled: false
9
11
  Naming/FileName:
@@ -2,6 +2,7 @@ sudo: false
2
2
  rvm:
3
3
  - 2.5
4
4
  - 2.6
5
+ - 2.7
5
6
  gemfile:
6
7
  - Gemfile
7
8
  before_install:
@@ -1,41 +1,42 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sortable-by (0.12.1)
4
+ sortable-by (0.13.0)
5
5
  activerecord
6
6
  activesupport
7
7
 
8
8
  GEM
9
9
  remote: http://rubygems.org/
10
10
  specs:
11
- activemodel (6.0.3.1)
12
- activesupport (= 6.0.3.1)
13
- activerecord (6.0.3.1)
14
- activemodel (= 6.0.3.1)
15
- activesupport (= 6.0.3.1)
16
- activesupport (6.0.3.1)
11
+ activemodel (6.0.3.3)
12
+ activesupport (= 6.0.3.3)
13
+ activerecord (6.0.3.3)
14
+ activemodel (= 6.0.3.3)
15
+ activesupport (= 6.0.3.3)
16
+ activesupport (6.0.3.3)
17
17
  concurrent-ruby (~> 1.0, >= 1.0.2)
18
18
  i18n (>= 0.7, < 2)
19
19
  minitest (~> 5.1)
20
20
  tzinfo (~> 1.1)
21
21
  zeitwerk (~> 2.2, >= 2.2.2)
22
- ast (2.4.0)
23
- concurrent-ruby (1.1.6)
24
- diff-lcs (1.3)
25
- i18n (1.8.2)
22
+ ast (2.4.1)
23
+ concurrent-ruby (1.1.7)
24
+ diff-lcs (1.4.4)
25
+ i18n (1.8.5)
26
26
  concurrent-ruby (~> 1.0)
27
- minitest (5.14.1)
28
- parallel (1.19.1)
29
- parser (2.7.1.3)
30
- ast (~> 2.4.0)
27
+ minitest (5.14.2)
28
+ parallel (1.19.2)
29
+ parser (2.7.2.0)
30
+ ast (~> 2.4.1)
31
31
  rainbow (3.0.0)
32
32
  rake (13.0.1)
33
+ regexp_parser (1.8.1)
33
34
  rexml (3.2.4)
34
35
  rspec (3.9.0)
35
36
  rspec-core (~> 3.9.0)
36
37
  rspec-expectations (~> 3.9.0)
37
38
  rspec-mocks (~> 3.9.0)
38
- rspec-core (3.9.2)
39
+ rspec-core (3.9.3)
39
40
  rspec-support (~> 3.9.3)
40
41
  rspec-expectations (3.9.2)
41
42
  diff-lcs (>= 1.2.0, < 2.0)
@@ -44,23 +45,24 @@ GEM
44
45
  diff-lcs (>= 1.2.0, < 2.0)
45
46
  rspec-support (~> 3.9.0)
46
47
  rspec-support (3.9.3)
47
- rubocop (0.84.0)
48
+ rubocop (0.92.0)
48
49
  parallel (~> 1.10)
49
- parser (>= 2.7.0.1)
50
+ parser (>= 2.7.1.5)
50
51
  rainbow (>= 2.2.2, < 4.0)
52
+ regexp_parser (>= 1.7)
51
53
  rexml
52
- rubocop-ast (>= 0.0.3)
54
+ rubocop-ast (>= 0.5.0)
53
55
  ruby-progressbar (~> 1.7)
54
56
  unicode-display_width (>= 1.4.0, < 2.0)
55
- rubocop-ast (0.0.3)
56
- parser (>= 2.7.0.1)
57
+ rubocop-ast (0.7.1)
58
+ parser (>= 2.7.1.5)
57
59
  ruby-progressbar (1.10.1)
58
60
  sqlite3 (1.4.2)
59
61
  thread_safe (0.3.6)
60
62
  tzinfo (1.2.7)
61
63
  thread_safe (~> 0.1)
62
64
  unicode-display_width (1.7.0)
63
- zeitwerk (2.3.0)
65
+ zeitwerk (2.4.0)
64
66
 
65
67
  PLATFORMS
66
68
  ruby
@@ -74,4 +76,4 @@ DEPENDENCIES
74
76
  sqlite3
75
77
 
76
78
  BUNDLED WITH
77
- 2.1.2
79
+ 2.1.4
data/README.md CHANGED
@@ -20,23 +20,23 @@ class Post < ActiveRecord::Base
20
20
  sortable_by :title, :id
21
21
  end
22
22
 
23
- Post.sorted_by('title') # => ORDER BY posts.title ASC
24
- Post.sorted_by('-title') # => ORDER BY posts.title DESC
25
- Post.sorted_by('bad,title') # => ORDER BY posts.title ASC
26
- Post.sorted_by(nil) # => ORDER BY posts.title ASC
23
+ Post.sorted_by('title') # => ORDER BY LOWER(posts.title) ASC
24
+ Post.sorted_by('-title') # => ORDER BY LOWER(posts.title) DESC
25
+ Post.sorted_by('bad,title') # => ORDER BY LOWER(posts.title) ASC
26
+ Post.sorted_by(nil) # => ORDER BY LOWER(posts.title) ASC
27
27
  ```
28
28
 
29
- Case-insensitive:
29
+ Case-sensitive:
30
30
 
31
31
  ```ruby
32
32
  class Post < ActiveRecord::Base
33
33
  sortable_by do |x|
34
- x.field :title, as: arel_table[:title].lower
34
+ x.field :title, case_sensitive: true
35
35
  x.field :id
36
36
  end
37
37
  end
38
38
 
39
- Post.sorted_by('title') # => ORDER BY LOWER(posts.title) ASC
39
+ Post.sorted_by('title') # => ORDER BY posts.title ASC
40
40
  ```
41
41
 
42
42
  With custom default:
@@ -46,7 +46,7 @@ class Post < ActiveRecord::Base
46
46
  sortable_by :id, :topic, :created_at, default: 'topic,-created_at'
47
47
  end
48
48
 
49
- Post.sorted_by(nil) # => ORDER BY posts.topic ASC, posts.created_at DESC
49
+ Post.sorted_by(nil) # => ORDER BY LOWER(posts.topic) ASC, posts.created_at DESC
50
50
  ```
51
51
 
52
52
  Composition:
@@ -68,8 +68,8 @@ Associations (eager load):
68
68
  class Product < ActiveRecord::Base
69
69
  belongs_to :shop
70
70
  sortable_by do |x|
71
- x.field :name, as: arel_table[:name].lower
72
- x.field :shop, as: Shop.arel_table[:name].lower, eager_load: :shop
71
+ x.field :name
72
+ x.field :shop, as: Shop.arel_table[:name], eager_load: :shop
73
73
  x.default 'shop,name'
74
74
  end
75
75
  end
@@ -77,11 +77,11 @@ end
77
77
 
78
78
  Associations (custom scope):
79
79
 
80
- ```
80
+ ```ruby
81
81
  class Product < ActiveRecord::Base
82
82
  belongs_to :shop
83
83
  sortable_by do |x|
84
- x.field :shop, as: Shop.arel_table[:name].lower, scope: -> { joins(:shop) }
84
+ x.field :shop, as: Shop.arel_table[:name], scope: -> { joins(:shop) }
85
85
  end
86
86
  end
87
87
  ```
@@ -17,9 +17,9 @@ module ActiveRecord # :nodoc:
17
17
  duplicate
18
18
  end
19
19
 
20
- def field(name, opts = {})
20
+ def field(name, **opts)
21
21
  name = name.to_s
22
- @_fields[name] = Field.new(name, opts)
22
+ @_fields[name] = Field.new(name, **opts)
23
23
  @_default ||= name
24
24
  end
25
25
 
@@ -36,7 +36,7 @@ module ActiveRecord # :nodoc:
36
36
 
37
37
  protected
38
38
 
39
- def order(relation, expr, fallback = true)
39
+ def order(relation, expr, fallback: true)
40
40
  matched = false
41
41
  expr.to_s.split(',').each do |name|
42
42
  name.strip!
@@ -50,22 +50,25 @@ module ActiveRecord # :nodoc:
50
50
  field = _fields[name]
51
51
  next unless field
52
52
 
53
- matched = true
53
+ matched = true
54
54
  relation = field.order(relation, rank)
55
55
  end
56
56
 
57
- relation = order(relation, _default, false) if fallback && !matched && _default
57
+ relation = order(relation, _default, fallback: false) if fallback && !matched && _default
58
58
  relation
59
59
  end
60
60
  end
61
61
 
62
62
  class Field # :nodoc:
63
- def initialize(name, opts = {})
64
- @cols = Array.wrap(opts[:as])
65
- @eager_load = Array.wrap(opts[:eager_load]).presence
63
+ STRING_TYPES = %i[string text].freeze # :nodoc:
64
+
65
+ def initialize(name, as: nil, scope: nil, eager_load: nil, case_sensitive: false)
66
+ @cols = Array.wrap(as)
67
+ @eager_load = Array.wrap(eager_load).presence
68
+ @case_sensitive = case_sensitive == true
66
69
 
67
70
  # validate custom_scope
68
- @custom_scope = opts[:scope]
71
+ @custom_scope = scope
69
72
  raise ArgumentError, "Invalid sortable-by field '#{name}': scope must be a Proc." if @custom_scope && !@custom_scope.is_a?(Proc)
70
73
 
71
74
  # normalize cols
@@ -86,7 +89,10 @@ module ActiveRecord # :nodoc:
86
89
  @cols.each do |col|
87
90
  case col
88
91
  when String, Symbol
89
- relation = relation.order(col => rank)
92
+ type = relation.columns_hash[col.to_s].type
93
+ col = relation.arel_table[col]
94
+ col = col.lower if STRING_TYPES.include?(type) && !@case_sensitive
95
+ relation = relation.order(col.send(rank))
90
96
  when Arel::Nodes::Node, Arel::Attributes::Attribute
91
97
  relation = relation.order(col.send(rank))
92
98
  when Proc
@@ -117,10 +123,10 @@ module ActiveRecord # :nodoc:
117
123
  # sortable_by :title, :id
118
124
  # end
119
125
  #
120
- # # Case-insensitive
126
+ # # Case-sensitive
121
127
  # class Post < ActiveRecord::Base
122
128
  # sortable_by do |x|
123
- # x.field :title, as: arel_table[:title].lower
129
+ # x.field :title, case_sensitive: true
124
130
  # x.field :id
125
131
  # end
126
132
  # end
@@ -144,7 +150,7 @@ module ActiveRecord # :nodoc:
144
150
  #
145
151
  # sortable_by do |x|
146
152
  # x.field :name
147
- # x.field :shop, as: Shop.arel_table[:name].lower, eager_load: :shop
153
+ # x.field :shop, as: Shop.arel_table[:name], eager_load: :shop
148
154
  # x.default 'shop,name'
149
155
  # end
150
156
  # end
@@ -154,17 +160,16 @@ module ActiveRecord # :nodoc:
154
160
  # belongs_to :shop
155
161
  #
156
162
  # sortable_by do |x|
157
- # x.field :shop, as: Shop.arel_table[:name].lower, scope: -> { joins(:shop) }
163
+ # x.field :shop, as: Shop.arel_table[:name], scope: -> { joins(:shop) }
158
164
  # end
159
165
  # end
160
166
  #
161
- def sortable_by(*attributes)
167
+ def sortable_by(*attributes, **opts)
162
168
  config = _sortable_by_config
163
- opts = attributes.extract_options!
164
169
  default = opts.delete(:default)
165
170
 
166
171
  attributes.each do |name|
167
- config.field(name, opts)
172
+ config.field(name, **opts)
168
173
  end
169
174
  config.default(default) if default
170
175
  yield config if block_given?
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'sortable-by'
3
- s.version = '0.12.1'
3
+ s.version = '0.13.0'
4
4
  s.authors = ['Dimitrij Denissenko']
5
5
  s.email = ['dimitrij@blacksquaremedia.com']
6
6
  s.summary = 'Generate white-listed sort scopes from URL parameter values'
@@ -17,14 +17,14 @@ ActiveRecord::Base.connection.create_table :posts do |t|
17
17
  end
18
18
 
19
19
  class Post < ActiveRecord::Base
20
- sortable_by :title, default: '-created' do |s|
20
+ sortable_by :title, default: '-created', case_sensitive: true do |s|
21
21
  s.field :created, as: arel_table[:created_at]
22
22
  end
23
23
  end
24
24
 
25
25
  class SubPost < Post
26
26
  sortable_by do |s|
27
- s.field :title, as: arel_table[:title].lower
27
+ s.field :title
28
28
  end
29
29
  end
30
30
 
@@ -65,8 +65,8 @@ class Product < ActiveRecord::Base
65
65
  belongs_to :shop
66
66
 
67
67
  sortable_by do |s|
68
- s.field :name, as: arel_table[:name].lower
69
- s.field :shop, as: Shop.arel_table[:name].lower, eager_load: :shop
68
+ s.field :name
69
+ s.field :shop, as: Shop.arel_table[:name], eager_load: :shop
70
70
  s.default 'shop,name'
71
71
  end
72
72
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sortable-by
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitrij Denissenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-27 00:00:00.000000000 Z
11
+ date: 2020-10-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord