sorted-activerecord 0.0.1 → 0.1.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/.rspec +1 -0
- data/.travis.yml +7 -0
- data/Guardfile +14 -0
- data/README.md +22 -5
- data/lib/sorted/activerecord/builder.rb +46 -9
- data/lib/sorted/activerecord/helper.rb +11 -8
- data/lib/sorted/activerecord/version.rb +1 -1
- data/sorted-activerecord.gemspec +1 -0
- data/spec/sorted/activerecord_spec.rb +57 -7
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73c6a1710bf109f92c675c82bfb51adbae2e83fe
|
4
|
+
data.tar.gz: f839fef7e88e8ca7632f3e9055467a217d7e2a96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be76ff4089fe1a2062ad37b001f1084f76b92401ca8011b356a480a8499036b4de359fc3ae6cf1e6b62da7a9655e914b805a0c028eba102758ec0145dbb0c853
|
7
|
+
data.tar.gz: d65155d4a62a460667c0e38e8fd1a3832bba1e0f6f9b0e43a837848f21d2e92f6610bed1bcaa286d769b9ee7c01682d59faf71580f0806f578042fefe48f88a1
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
2
|
+
require "guard/rspec/dsl"
|
3
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
4
|
+
|
5
|
+
# RSpec files
|
6
|
+
rspec = dsl.rspec
|
7
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
8
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
9
|
+
watch(rspec.spec_files)
|
10
|
+
|
11
|
+
# Ruby files
|
12
|
+
ruby = dsl.ruby
|
13
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
14
|
+
end
|
data/README.md
CHANGED
@@ -24,17 +24,34 @@ Or install it yourself as:
|
|
24
24
|
|
25
25
|
## Usage
|
26
26
|
|
27
|
-
|
27
|
+
The sorted scope takes two optional arguments, `sort` and `order`, they both
|
28
|
+
conform to the [AR query
|
29
|
+
interface](http://guides.rubyonrails.org/active_record_querying.html#ordering)
|
30
|
+
except that if you provide a string to the sort argument it expects a
|
31
|
+
`Sorted::URIQuery` encoded string:
|
28
32
|
|
29
33
|
```ruby
|
30
|
-
@users = User.sorted(
|
34
|
+
@users = User.sorted(sort: 'created_asc!orders_count_asc'
|
35
|
+
order: 'orders_count ASC, created_at DESC')
|
31
36
|
```
|
32
37
|
|
33
|
-
|
34
|
-
|
38
|
+
See https://github.com/mynameisrufus/sorted-actionview for a view helper to
|
39
|
+
generate the sort string or roll your own.
|
40
|
+
|
41
|
+
A `resorted` method is also available and works the same way as the `reorder`
|
42
|
+
method in Rails. It forces the order to be the one passed in:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
@users = User.order(:id).sorted(order: 'name DESC')
|
46
|
+
.resorted(sort: params[:sort], order: 'email ASC')
|
47
|
+
```
|
48
|
+
|
49
|
+
If you want to prevent people creating 500s by messing with the sort url string
|
50
|
+
you can use a white list:
|
35
51
|
|
36
52
|
```ruby
|
37
|
-
@users = User.
|
53
|
+
@users = User.sorted(sort: 'created_asc!explode_me_asc'
|
54
|
+
whitelist: %w(created_at))
|
38
55
|
```
|
39
56
|
|
40
57
|
## Contributing
|
@@ -2,21 +2,58 @@ require 'sorted'
|
|
2
2
|
|
3
3
|
module Sorted
|
4
4
|
module ActiveRecord
|
5
|
-
Builder
|
6
|
-
|
7
|
-
|
5
|
+
class Builder
|
6
|
+
class ParseError < StandardError; end
|
7
|
+
|
8
|
+
attr_reader :set
|
9
|
+
|
10
|
+
def initialize(sort: [], order: [], whitelist: [])
|
11
|
+
uri = parse_sort(sort)
|
12
|
+
if whitelist.length > 0
|
13
|
+
uri = ::Sorted::Set.new(uri.select { |o| whitelist.include?(o[0]) })
|
14
|
+
end
|
15
|
+
sql = parse_order(order)
|
16
|
+
@set = uri + (sql - uri)
|
8
17
|
end
|
9
18
|
|
10
|
-
def
|
11
|
-
|
19
|
+
def parse_sort(sort)
|
20
|
+
case sort.class.name
|
21
|
+
when 'String'
|
22
|
+
::Sorted::URIQuery.parse(sort)
|
23
|
+
when 'Array'
|
24
|
+
parse(sort)
|
25
|
+
else
|
26
|
+
raise ParseError, "could not parse sort - #{sort}"
|
27
|
+
end
|
12
28
|
end
|
13
29
|
|
14
|
-
def
|
15
|
-
|
30
|
+
def parse_order(order)
|
31
|
+
case order.class.name
|
32
|
+
when 'String'
|
33
|
+
::Sorted::SQLQuery.parse(order)
|
34
|
+
when 'Array'
|
35
|
+
parse(order)
|
36
|
+
else
|
37
|
+
raise ParseError, "could not parse sort - #{order}"
|
38
|
+
end
|
16
39
|
end
|
17
40
|
|
18
|
-
def
|
19
|
-
|
41
|
+
def parse(values)
|
42
|
+
values.inject(Sorted::Set.new) do |memo, value|
|
43
|
+
case value.class.name
|
44
|
+
when 'Hash'
|
45
|
+
memo = memo + parse(value.to_a)
|
46
|
+
when 'String'
|
47
|
+
memo = memo + ::Sorted::SQLQuery.parse(value)
|
48
|
+
when 'Symbol'
|
49
|
+
memo = memo << [value.to_s, 'asc']
|
50
|
+
when 'Array'
|
51
|
+
memo = memo << [value[0].to_s, value[1].to_s]
|
52
|
+
else
|
53
|
+
raise ParseError, "could not parse - #{value}"
|
54
|
+
end
|
55
|
+
memo
|
56
|
+
end
|
20
57
|
end
|
21
58
|
end
|
22
59
|
end
|
@@ -7,16 +7,19 @@ module Sorted
|
|
7
7
|
module Helper
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
included do
|
10
|
-
|
11
|
-
|
12
|
-
builder = ::Sorted::ActiveRecord::Builder.new(sort
|
13
|
-
|
10
|
+
|
11
|
+
def self.sorted(sort: [], order: [], whitelist: [])
|
12
|
+
builder = ::Sorted::ActiveRecord::Builder.new(sort: sort,
|
13
|
+
order: order,
|
14
|
+
whitelist: whitelist)
|
15
|
+
order(builder.set.to_hash)
|
14
16
|
end
|
15
17
|
|
16
|
-
def self.resorted(sort, order
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
def self.resorted(sort: [], order: [], whitelist: [])
|
19
|
+
builder = ::Sorted::ActiveRecord::Builder.new(sort: sort,
|
20
|
+
order: order,
|
21
|
+
whitelist: whitelist)
|
22
|
+
reorder(builder.set.to_hash)
|
20
23
|
end
|
21
24
|
end
|
22
25
|
end
|
data/sorted-activerecord.gemspec
CHANGED
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency 'railties', '>= 4.0.0'
|
28
28
|
spec.add_development_dependency 'rubocop'
|
29
29
|
spec.add_development_dependency 'rspec'
|
30
|
+
spec.add_development_dependency 'guard-rspec'
|
30
31
|
# spec.add_development_dependency 'activerecord-jdbcsqlite3-adapter'
|
31
32
|
spec.add_development_dependency 'sqlite3', '>= 1.3.5'
|
32
33
|
end
|
@@ -15,19 +15,69 @@ describe Sorted::ActiveRecord do
|
|
15
15
|
scope :page, -> { limit(50) }
|
16
16
|
end
|
17
17
|
|
18
|
+
let(:subject) { SortedActiveRecordTest }
|
19
|
+
|
18
20
|
it 'should integrate with ActiveRecord::Base' do
|
19
|
-
expect(
|
20
|
-
expect(
|
21
|
+
expect(subject.respond_to?(:sorted)).to eq(true)
|
22
|
+
expect(subject.respond_to?(:resorted)).to eq(true)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should allow symbols and strings order' do
|
26
|
+
order_by = 'ORDER BY "sorted_active_record_tests"."created_at" ASC'
|
27
|
+
expect(subject.sorted(order: [:created_at]).to_sql).to match(order_by)
|
28
|
+
expect(subject.sorted(order: ['created_at']).to_sql).to match(order_by)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should allow symbols and strings as sort' do
|
32
|
+
order_by = 'ORDER BY "sorted_active_record_tests"."created_at" ASC'
|
33
|
+
expect(subject.sorted(sort: [:created_at]).to_sql).to match(order_by)
|
34
|
+
expect(subject.sorted(sort: ['created_at']).to_sql).to match(order_by)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should allow hash as order' do
|
38
|
+
order_by = 'ORDER BY "sorted_active_record_tests"."created_at" DESC'
|
39
|
+
expect(subject.sorted(order: [{ created_at: :desc }]).to_sql).to match(order_by)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should allow hash as sort' do
|
43
|
+
order_by = 'ORDER BY "sorted_active_record_tests"."created_at" DESC'
|
44
|
+
expect(subject.sorted(sort: [{ created_at: :desc }]).to_sql).to match(order_by)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should allow symbols and hash as order' do
|
48
|
+
order_by = 'ORDER BY "sorted_active_record_tests"."orders_count" ASC, "sorted_active_record_tests"."created_at" DESC'
|
49
|
+
expect(subject.sorted(order: [:orders_count, { created_at: :desc }]).to_sql).to match(order_by)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should allow sql' do
|
53
|
+
order_by = 'ORDER BY "sorted_active_record_tests"."orders_count" ASC, "sorted_active_record_tests"."created_at" DESC'
|
54
|
+
expect(subject.sorted(order: 'orders_count ASC, created_at DESC').to_sql).to match(order_by)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should allow uri' do
|
58
|
+
order_by = 'ORDER BY "sorted_active_record_tests"."orders_count" ASC, "sorted_active_record_tests"."created_at" DESC'
|
59
|
+
expect(subject.sorted(sort: 'orders_count_asc!created_at_desc').to_sql).to match(order_by)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should allow an array of sql' do
|
63
|
+
order_by = 'ORDER BY "sorted_active_record_tests"."orders_count" ASC, "sorted_active_record_tests"."created_at" DESC'
|
64
|
+
expect(subject.sorted(order: ['orders_count ASC', 'created_at DESC']).to_sql).to match(order_by)
|
21
65
|
end
|
22
66
|
|
23
67
|
it 'should play nice with other scopes' do
|
24
|
-
sql = "SELECT \"sorted_active_record_tests\".* FROM \"sorted_active_record_tests\" WHERE \"sorted_active_record_tests\".\"name\" = 'bob' ORDER BY \"name\" ASC LIMIT 50"
|
25
|
-
expect(
|
26
|
-
expect(
|
68
|
+
sql = "SELECT \"sorted_active_record_tests\".* FROM \"sorted_active_record_tests\" WHERE \"sorted_active_record_tests\".\"name\" = 'bob' ORDER BY \"sorted_active_record_tests\".\"name\" ASC LIMIT 50"
|
69
|
+
expect(subject.where(name: 'bob').page.sorted(order: 'name ASC').to_sql).to eq(sql)
|
70
|
+
expect(subject.page.sorted(order: 'name ASC').where(name: 'bob').to_sql).to eq(sql)
|
27
71
|
end
|
28
72
|
|
29
73
|
it 'should override the provided order' do
|
30
|
-
sql = "SELECT \"sorted_active_record_tests\".* FROM \"sorted_active_record_tests\" WHERE \"sorted_active_record_tests\".\"name\" = 'bob' ORDER BY \"name\" ASC LIMIT 50"
|
31
|
-
expect(
|
74
|
+
sql = "SELECT \"sorted_active_record_tests\".* FROM \"sorted_active_record_tests\" WHERE \"sorted_active_record_tests\".\"name\" = 'bob' ORDER BY \"sorted_active_record_tests\".\"name\" ASC LIMIT 50"
|
75
|
+
expect(subject.page.where(name: 'bob').order(:id).sorted(order: 'name DESC').resorted(order: 'name ASC').to_sql).to eq(sql)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should work with whitelist' do
|
79
|
+
order_by = 'ORDER BY "sorted_active_record_tests"."created_at" DESC'
|
80
|
+
expect(subject.sorted(sort: 'orders_count_asc!created_at_desc',
|
81
|
+
whitelist: %(created_at)).to_sql).to match(order_by)
|
32
82
|
end
|
33
83
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sorted-activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rufus Post
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: guard-rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: sqlite3
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -144,8 +158,11 @@ extensions: []
|
|
144
158
|
extra_rdoc_files: []
|
145
159
|
files:
|
146
160
|
- ".gitignore"
|
161
|
+
- ".rspec"
|
147
162
|
- ".rubocop.yml"
|
163
|
+
- ".travis.yml"
|
148
164
|
- Gemfile
|
165
|
+
- Guardfile
|
149
166
|
- LICENSE.txt
|
150
167
|
- README.md
|
151
168
|
- Rakefile
|