trailblazer-finder 0.1.2 → 0.1.3
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/.rubocop_todo.yml +22 -11
- data/.travis.yml +0 -2
- data/CHANGES.md +4 -0
- data/README.md +70 -58
- data/lib/trailblazer/finder/adapters/active_record/sorting.rb +6 -2
- data/lib/trailblazer/finder/adapters/data_mapper.rb +2 -2
- data/lib/trailblazer/finder/adapters/data_mapper/sorting.rb +25 -25
- data/lib/trailblazer/finder/adapters/sequel/sorting.rb +9 -7
- data/lib/trailblazer/finder/base.rb +0 -2
- data/lib/trailblazer/finder/features/predicate.rb +4 -9
- data/lib/trailblazer/finder/features/sorting.rb +70 -28
- data/lib/trailblazer/finder/utils/deep_locate.rb +4 -19
- data/lib/trailblazer/finder/utils/parse.rb +6 -6
- data/lib/trailblazer/finder/version.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/spec_helper_active_record.rb +0 -1
- data/spec/support/sorting_shared_example.rb +67 -37
- data/spec/trailblazer/finder/adapters/active_record/predicates_spec.rb +5 -2
- data/spec/trailblazer/finder/adapters/active_record/sorting_spec.rb +93 -80
- data/spec/trailblazer/finder/adapters/data_mapper/base_spec.rb +1 -1
- data/spec/trailblazer/finder/adapters/data_mapper/sorting_spec.rb +85 -85
- data/spec/trailblazer/finder/adapters/sequel/predicates_spec.rb +2 -2
- data/spec/trailblazer/finder/adapters/sequel/sorting_spec.rb +101 -80
- data/spec/trailblazer/finder/features/sorting_spec.rb +59 -62
- data/trailblazer-finder.gemspec +1 -1
- metadata +2 -2
@@ -2,6 +2,8 @@ module Trailblazer
|
|
2
2
|
class Finder
|
3
3
|
module Features
|
4
4
|
module Predicate
|
5
|
+
PREDICATES = %w[eq not_eq blank not_blank lt lte gt gte].freeze
|
6
|
+
|
5
7
|
def self.included(base)
|
6
8
|
base.extend ClassMethods
|
7
9
|
base.instance_eval do
|
@@ -10,7 +12,7 @@ module Trailblazer
|
|
10
12
|
end
|
11
13
|
|
12
14
|
module ClassMethods
|
13
|
-
def
|
15
|
+
def predicate_filter(attribute, predicate)
|
14
16
|
filter_by "#{attribute}_#{predicate}" do |entity_type, value|
|
15
17
|
splitter = Utils::Splitter.new "#{attribute}_#{predicate}", value
|
16
18
|
splitter.split_key predicate.to_sym
|
@@ -20,14 +22,7 @@ module Trailblazer
|
|
20
22
|
|
21
23
|
def predicates_for(*attributes)
|
22
24
|
attributes.each do |attribute|
|
23
|
-
|
24
|
-
do_filters(attribute, "not_eq")
|
25
|
-
do_filters(attribute, "blank")
|
26
|
-
do_filters(attribute, "not_blank")
|
27
|
-
do_filters(attribute, "gt")
|
28
|
-
do_filters(attribute, "gte")
|
29
|
-
do_filters(attribute, "lt")
|
30
|
-
do_filters(attribute, "lte")
|
25
|
+
PREDICATES.each { |predicate| predicate_filter(attribute, predicate) }
|
31
26
|
end
|
32
27
|
end
|
33
28
|
end
|
@@ -5,55 +5,97 @@ module Trailblazer
|
|
5
5
|
def self.included(base)
|
6
6
|
base.extend ClassMethods
|
7
7
|
base.instance_eval do
|
8
|
-
filter_by :sort do |entity_type,
|
9
|
-
sort_it(entity_type, sort_attribute, sort_direction)
|
8
|
+
filter_by :sort do |entity_type, value|
|
9
|
+
next sort_it(entity_type, [sort_orders(sort_attribute(value), sort_direction(value))]) if value.nil?
|
10
|
+
sort_attributes = value.split(',')
|
11
|
+
sorters = []
|
12
|
+
sort_attributes.each do |sort_attr|
|
13
|
+
sorters << sort_orders(sort_attribute(sort_attr), sort_direction(sort_attr))
|
14
|
+
end
|
15
|
+
sort_it(entity_type, sorters)
|
10
16
|
end
|
11
17
|
end
|
12
18
|
end
|
13
19
|
|
14
|
-
# Adapters will overwite this method
|
15
|
-
def sort_it(entity_type, sort_attribute, sort_direction)
|
16
|
-
case sort_direction
|
17
|
-
when 'asc', 'ascending'
|
18
|
-
entity_type.sort_by { |a| a[sort_attribute.to_sym] }
|
19
|
-
when 'desc', 'descending'
|
20
|
-
entity_type.sort_by { |a| a[sort_attribute.to_sym] }.reverse
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
20
|
def sort?(attribute)
|
25
|
-
|
21
|
+
sort.include?(attribute.to_s)
|
26
22
|
end
|
27
23
|
|
28
|
-
def
|
29
|
-
|
24
|
+
def sort_direction_for(attribute)
|
25
|
+
return 'asc' if !sort.nil? && sort.include?("#{attribute} asc")
|
26
|
+
'desc'
|
30
27
|
end
|
31
28
|
|
32
|
-
def
|
33
|
-
|
29
|
+
def reverse_sort_direction_for(attribute)
|
30
|
+
return 'desc' if sort_direction_for(attribute) == 'asc'
|
31
|
+
'asc'
|
34
32
|
end
|
35
33
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
def sort_params_for(attribute, options = {})
|
35
|
+
options['sort'] = if sort.nil?
|
36
|
+
"#{attribute} #{sort_direction_for(attribute)}"
|
37
|
+
elsif sort.include?(attribute.to_s)
|
38
|
+
sort
|
39
|
+
else
|
40
|
+
"#{attribute} #{sort_direction_for(attribute)}"
|
41
|
+
end
|
42
|
+
params options
|
42
43
|
end
|
43
44
|
|
44
|
-
def
|
45
|
+
def new_sort_params_for(attribute, options = {})
|
45
46
|
options['sort'] = "#{attribute} #{sort_direction_for(attribute)}"
|
46
47
|
params options
|
47
48
|
end
|
48
49
|
|
49
|
-
def
|
50
|
-
|
50
|
+
def add_sort_params_for(attribute, options = {})
|
51
|
+
options['sort'] = if sort.nil?
|
52
|
+
"#{attribute} #{sort_direction_for(attribute)}"
|
53
|
+
elsif sort.include?(attribute.to_s)
|
54
|
+
sort.gsub(/#{attribute} #{sort_direction_for(attribute)}/, "#{attribute} #{reverse_sort_direction_for(attribute)}")
|
55
|
+
else
|
56
|
+
"#{sort}, #{attribute} #{sort_direction_for(attribute)}"
|
57
|
+
end
|
58
|
+
params options
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# ORM Adapters will overwite this method
|
64
|
+
def sort_it(entity_type, sort_attributes)
|
65
|
+
entity_type.sort do |this, that|
|
66
|
+
sort_attributes.reduce(0) do |diff, order|
|
67
|
+
next diff if diff != 0 # this and that have differed at an earlier order entry
|
68
|
+
key, direction = order
|
69
|
+
# deal with nil cases
|
70
|
+
next 0 if this[key].nil? && that[key].nil?
|
71
|
+
next 1 if this[key].nil?
|
72
|
+
next -1 if that[key].nil?
|
73
|
+
# do the actual comparison
|
74
|
+
comparison = this[key] <=> that[key]
|
75
|
+
comparison * direction
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# ORM Adapters will overwite this method
|
81
|
+
def sort_orders(sort_attr, sort_dir)
|
82
|
+
[sort_attr.to_sym, (sort_dir.to_sym == :asc ? 1 : -1)]
|
83
|
+
end
|
84
|
+
|
85
|
+
def sort_attribute(attribute)
|
86
|
+
result = Utils::Extra.ensure_included attribute.to_s.split(' ', 2).first, self.class.sort_attributes
|
87
|
+
result
|
88
|
+
end
|
89
|
+
|
90
|
+
def sort_direction(attribute)
|
91
|
+
return Utils::Extra.ensure_included attribute.to_s.split(' ', 2).last, %w[desc asc] unless attribute.nil?
|
92
|
+
'desc'
|
51
93
|
end
|
52
94
|
|
53
95
|
module ClassMethods
|
96
|
+
attr_accessor :sorted_attributes
|
54
97
|
def sortable_by(*attributes)
|
55
|
-
config[:sort_attributes]
|
56
|
-
config[:defaults]['sort'] = "#{config[:sort_attributes].first} desc"
|
98
|
+
config[:sort_attributes] = attributes.map(&:to_s)
|
57
99
|
end
|
58
100
|
|
59
101
|
def sort_attributes
|
@@ -2,35 +2,20 @@ module Trailblazer
|
|
2
2
|
class Finder
|
3
3
|
module Utils
|
4
4
|
module DeepLocate
|
5
|
-
def self.deep_locate(comparator, object)
|
6
|
-
comparator = _construct_key_comparator(comparator, object) unless comparator.respond_to?(:call)
|
7
|
-
|
8
|
-
_deep_locate(comparator, object)
|
9
|
-
end
|
10
|
-
|
11
|
-
def self._construct_key_comparator(search_key, object)
|
12
|
-
search_key = search_key.to_s if defined?(::ActiveSupport::HashWithIndifferentAccess) && object.is_a?(::ActiveSupport::HashWithIndifferentAccess)
|
13
|
-
search_key = search_key.to_s if object.respond_to?(:indifferent_access?) && object.indifferent_access?
|
14
|
-
|
15
|
-
lambda do |non_callable_object|
|
16
|
-
->(key, _, _) { key == non_callable_object }
|
17
|
-
end.call(search_key)
|
18
|
-
end
|
19
|
-
|
20
|
-
def self._deep_locate(comparator, object, result = [])
|
5
|
+
def self.deep_locate(comparator, object, result = [])
|
21
6
|
if object.is_a?(::Enumerable)
|
22
|
-
if object.any? { |value|
|
7
|
+
if object.any? { |value| match_comparator?(value, comparator, object) }
|
23
8
|
result.push object
|
24
9
|
end
|
25
10
|
(object.respond_to?(:values) ? object.values : object.entries).each do |value|
|
26
|
-
|
11
|
+
deep_locate(comparator, value, result)
|
27
12
|
end
|
28
13
|
end
|
29
14
|
|
30
15
|
result
|
31
16
|
end
|
32
17
|
|
33
|
-
def self.
|
18
|
+
def self.match_comparator?(value, comparator, object)
|
34
19
|
if object.is_a?(::Hash)
|
35
20
|
key, value = value
|
36
21
|
else
|
@@ -7,13 +7,13 @@ module Trailblazer
|
|
7
7
|
class Parse
|
8
8
|
# Need a replacement for this
|
9
9
|
def self.date(value)
|
10
|
-
return
|
11
|
-
return if [true, false].include? value
|
12
|
-
return if value.is_a? Integer
|
13
|
-
return if value =~ /[[:alpha:]]/
|
10
|
+
return unless valid_date(value)
|
14
11
|
Date.parse(value).strftime('%Y-%m-%d')
|
15
|
-
|
16
|
-
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.valid_date(date)
|
15
|
+
date_hash = Date._parse(date.to_s)
|
16
|
+
Date.valid_date?(date_hash[:year].to_i, date_hash[:mon].to_i, date_hash[:mday].to_i)
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.term(value)
|
data/spec/spec_helper.rb
CHANGED
@@ -1,71 +1,90 @@
|
|
1
1
|
shared_examples_for 'a sorting feature' do
|
2
2
|
describe '#sort?' do
|
3
|
-
it '
|
3
|
+
it 'says if the requested item is sorted on, for single sort' do
|
4
4
|
finder = finder_with_sort 'price desc'
|
5
5
|
|
6
6
|
expect(finder).to be_sort :price
|
7
7
|
expect(finder).not_to be_sort :name
|
8
8
|
end
|
9
9
|
|
10
|
-
it '
|
10
|
+
it 'says if the requested item is sorted on for multiple sorts' do
|
11
|
+
finder = finder_with_sort 'price desc, name asc, id desc'
|
12
|
+
|
13
|
+
expect(finder).to be_sort :price
|
14
|
+
expect(finder).to be_sort :name
|
15
|
+
expect(finder).to be_sort :id
|
16
|
+
expect(finder).not_to be_sort :created_at
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'matches string also, for single sort' do
|
11
20
|
finder = finder_with_sort 'price desc'
|
12
21
|
|
13
22
|
expect(finder).to be_sort 'price'
|
14
23
|
expect(finder).not_to be_sort 'name'
|
15
24
|
end
|
16
25
|
|
17
|
-
it 'matches
|
18
|
-
finder = finder_with_sort 'price desc'
|
26
|
+
it 'matches string also, for multiple sorts' do
|
27
|
+
finder = finder_with_sort 'price desc, name asc, id desc'
|
19
28
|
|
20
|
-
expect(finder).to be_sort 'price
|
21
|
-
expect(finder).
|
29
|
+
expect(finder).to be_sort 'price'
|
30
|
+
expect(finder).to be_sort 'name'
|
31
|
+
expect(finder).to be_sort 'id'
|
32
|
+
expect(finder).not_to be_sort 'created_at'
|
22
33
|
end
|
23
|
-
end
|
24
34
|
|
25
|
-
|
26
|
-
it 'returns sort option attribute' do
|
35
|
+
it 'matches exact strings, for single sort' do
|
27
36
|
finder = finder_with_sort 'price desc'
|
28
|
-
expect(finder.sort_attribute).to eq 'price'
|
29
|
-
end
|
30
37
|
|
31
|
-
|
32
|
-
finder
|
33
|
-
expect(finder.sort_attribute).to eq 'name'
|
38
|
+
expect(finder).to be_sort 'price desc'
|
39
|
+
expect(finder).not_to be_sort 'price asc'
|
34
40
|
end
|
35
41
|
|
36
|
-
it '
|
37
|
-
finder = finder_with_sort '
|
38
|
-
|
42
|
+
it 'matches exact strings, for multiple sort' do
|
43
|
+
finder = finder_with_sort 'price desc, name asc'
|
44
|
+
|
45
|
+
expect(finder).to be_sort 'price desc'
|
46
|
+
expect(finder).to be_sort 'name asc'
|
47
|
+
expect(finder).not_to be_sort 'name desc'
|
39
48
|
end
|
40
49
|
end
|
41
50
|
|
42
|
-
describe '#
|
43
|
-
it 'returns
|
44
|
-
expect(finder_with_sort('price desc').
|
45
|
-
expect(finder_with_sort('price asc').sort_direction).to eq 'asc'
|
51
|
+
describe '#sort_direction_for' do
|
52
|
+
it 'returns desc if current sort attribute is not the given attribute' do
|
53
|
+
expect(finder_with_sort('price desc').sort_direction_for('name')).to eq 'desc'
|
46
54
|
end
|
47
55
|
|
48
|
-
it '
|
49
|
-
expect(finder_with_sort.
|
50
|
-
expect(finder_with_sort('price').sort_direction).to eq 'desc'
|
56
|
+
it 'returns asc if current sort attribute is the given attribute' do
|
57
|
+
expect(finder_with_sort('name desc').sort_direction_for('name')).to eq 'desc'
|
51
58
|
end
|
52
59
|
|
53
|
-
it '
|
54
|
-
expect(finder_with_sort('
|
60
|
+
it 'returns desc if current sort attribute is the given attribute, but asc with direction' do
|
61
|
+
expect(finder_with_sort('name asc').sort_direction_for('name')).to eq 'asc'
|
55
62
|
end
|
56
63
|
end
|
57
64
|
|
58
|
-
describe '#
|
65
|
+
describe '#reverse_sort_direction_for' do
|
59
66
|
it 'returns desc if current sort attribute is not the given attribute' do
|
60
|
-
expect(finder_with_sort('price desc').
|
67
|
+
expect(finder_with_sort('price desc').reverse_sort_direction_for('name')).to eq 'asc'
|
61
68
|
end
|
62
69
|
|
63
70
|
it 'returns asc if current sort attribute is the given attribute' do
|
64
|
-
expect(finder_with_sort('name desc').
|
71
|
+
expect(finder_with_sort('name desc').reverse_sort_direction_for('name')).to eq 'asc'
|
65
72
|
end
|
66
73
|
|
67
74
|
it 'returns desc if current sort attribute is the given attribute, but asc with direction' do
|
68
|
-
expect(finder_with_sort('name asc').
|
75
|
+
expect(finder_with_sort('name asc').reverse_sort_direction_for('name')).to eq 'desc'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#new_sort_params_for' do
|
80
|
+
it 'adds new sort parmas when none are present' do
|
81
|
+
finder = finder_with_sort
|
82
|
+
expect(finder.new_sort_params_for(:price)).to eq 'sort' => 'price desc'
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'adds new sort params when multiple ones exists (replaces them all)' do
|
86
|
+
finder = finder_with_sort 'name desc, price desc, id asc', name: 'test'
|
87
|
+
expect(finder.new_sort_params_for(:name)).to eq 'sort' => 'name desc', 'name' => 'test'
|
69
88
|
end
|
70
89
|
end
|
71
90
|
|
@@ -75,9 +94,10 @@ shared_examples_for 'a sorting feature' do
|
|
75
94
|
expect(finder.sort_params_for(:price)).to eq 'sort' => 'price desc', 'name' => 'test'
|
76
95
|
end
|
77
96
|
|
78
|
-
it '
|
79
|
-
finder = finder_with_sort 'name desc', name: 'test'
|
80
|
-
expect(finder.sort_params_for(:name)).to eq 'sort' => 'name asc', 'name' => 'test'
|
97
|
+
it 'finds params for multiple sorts' do
|
98
|
+
finder = finder_with_sort 'name desc, price desc, id asc', name: 'test'
|
99
|
+
expect(finder.sort_params_for(:name)).to eq 'sort' => 'name desc, price desc, id asc', 'name' => 'test'
|
100
|
+
expect(finder.sort_params_for(:price)).to eq 'sort' => 'name desc, price desc, id asc', 'name' => 'test'
|
81
101
|
end
|
82
102
|
|
83
103
|
it 'accepts additional options' do
|
@@ -86,10 +106,20 @@ shared_examples_for 'a sorting feature' do
|
|
86
106
|
end
|
87
107
|
end
|
88
108
|
|
89
|
-
describe '#
|
90
|
-
it '
|
91
|
-
|
92
|
-
expect(
|
109
|
+
describe '#add_sort_params_for' do
|
110
|
+
it 'adds sort params when none exists' do
|
111
|
+
finder = finder_with_sort
|
112
|
+
expect(finder.add_sort_params_for(:price)).to eq 'sort' => 'price desc'
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'adds sort params when one already exists' do
|
116
|
+
finder = finder_with_sort 'name', name: 'test'
|
117
|
+
expect(finder.add_sort_params_for(:price)).to eq 'sort' => 'name, price desc', 'name' => 'test'
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'adds sort params when current attribute already exists, but change it' do
|
121
|
+
finder = finder_with_sort 'name asc, price asc', name: 'test'
|
122
|
+
expect(finder.add_sort_params_for(:price)).to eq 'sort' => 'name asc, price desc', 'name' => 'test'
|
93
123
|
end
|
94
124
|
end
|
95
125
|
end
|
@@ -6,6 +6,11 @@ module Trailblazer
|
|
6
6
|
module Adapters
|
7
7
|
module ActiveRecord
|
8
8
|
describe Predicates do
|
9
|
+
after do
|
10
|
+
Product.delete_all
|
11
|
+
Product.reset_pk_sequence
|
12
|
+
end
|
13
|
+
|
9
14
|
class TestFinder < Trailblazer::Finder
|
10
15
|
features Predicate
|
11
16
|
adapters ActiveRecord
|
@@ -23,8 +28,6 @@ module Trailblazer
|
|
23
28
|
|
24
29
|
describe 'equals' do
|
25
30
|
before do
|
26
|
-
Product.delete_all
|
27
|
-
Product.reset_pk_sequence
|
28
31
|
10.times do |i|
|
29
32
|
next Product.create name: "", price: "1#{i}" if i == 7
|
30
33
|
next Product.create name: nil, price: "1#{i}" if i == 8
|
@@ -1,86 +1,99 @@
|
|
1
1
|
require 'spec_helper_active_record'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
finder = finder_with_sort 'created_at desc', category: ''
|
76
|
-
|
77
|
-
expect(finder.results.map(&:name)).to eq [product_of_older_category.name, product_of_newer_category.name]
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
it_behaves_like 'a sorting feature'
|
82
|
-
end
|
3
|
+
describe "Trailblazer::Finder::Adapters::ActiveRecord::Sorting", :sorting do
|
4
|
+
after do
|
5
|
+
Product.delete_all
|
6
|
+
Product.reset_pk_sequence
|
7
|
+
end
|
8
|
+
|
9
|
+
before do
|
10
|
+
Product.delete_all
|
11
|
+
Product.reset_pk_sequence
|
12
|
+
end
|
13
|
+
|
14
|
+
class TestARFinder < Trailblazer::Finder
|
15
|
+
features Sorting
|
16
|
+
adapters ActiveRecord
|
17
|
+
|
18
|
+
entity_type { Product.all }
|
19
|
+
|
20
|
+
sortable_by :name, :price, :created_at
|
21
|
+
|
22
|
+
filter_by :name
|
23
|
+
filter_by :price
|
24
|
+
end
|
25
|
+
|
26
|
+
def finder_with_sort(sort = nil, filters = {})
|
27
|
+
TestARFinder.new filter: (sort.nil? ? {} : { sort: sort }).merge(filters)
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'sorting' do
|
31
|
+
|
32
|
+
it 'sorts results based on the sort option desc' do
|
33
|
+
5.times { |i| Product.create! price: i }
|
34
|
+
|
35
|
+
finder = finder_with_sort 'price desc'
|
36
|
+
expect(finder.results.map(&:price)).to eq [4, 3, 2, 1, 0]
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'sorts results based on the sort option asc' do
|
40
|
+
5.times { |i| Product.create! price: i }
|
41
|
+
|
42
|
+
finder = finder_with_sort 'price asc'
|
43
|
+
expect(finder.results.map(&:price)).to eq [0, 1, 2, 3, 4]
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'defaults to defaulted database sort if none is set' do
|
47
|
+
5.times { |i| Product.create! name: "Name#{i}" }
|
48
|
+
|
49
|
+
finder = finder_with_sort
|
50
|
+
expect(finder.results.map(&:name)).to eq %w[Name0 Name1 Name2 Name3 Name4]
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'ignores invalid sort values' do
|
54
|
+
finder = finder_with_sort 'invalid attribute'
|
55
|
+
expect { finder.results.to_a }.not_to raise_error
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'can handle renames of sorting in joins' do
|
59
|
+
older_category = Category.create! title: 'older'
|
60
|
+
newer_category = Category.create! title: 'newer'
|
61
|
+
|
62
|
+
product_of_newer_category = Product.create! name: 'older product', category: newer_category
|
63
|
+
product_of_older_category = Product.create! name: 'newer product', category: older_category
|
64
|
+
|
65
|
+
finder = finder_with_sort 'created_at desc', category: ''
|
66
|
+
|
67
|
+
expect(finder.results.map(&:name)).to eq [product_of_older_category.name, product_of_newer_category.name]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'sorting by multiple' do
|
72
|
+
before do
|
73
|
+
5.times do |i|
|
74
|
+
Product.create name: "Name#{i}", price: "1#{i}"
|
83
75
|
end
|
76
|
+
Product.create name: 'Name3', price: '8'
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'sorts by multiple columns name asc and price asc' do
|
80
|
+
finder = finder_with_sort 'name asc, price asc'
|
81
|
+
expect(finder.results.map(&:name)).to eq %w[Name0 Name1 Name2 Name3 Name3 Name4]
|
82
|
+
expect(finder.results.map(&:price)).to eq [10, 11, 12, 8, 13, 14]
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'sorts by multiple columns name asc and price desc' do
|
86
|
+
finder = finder_with_sort 'name asc, price desc'
|
87
|
+
expect(finder.results.map(&:name)).to eq %w[Name0 Name1 Name2 Name3 Name3 Name4]
|
88
|
+
expect(finder.results.map(&:price)).to eq [10, 11, 12, 13, 8, 14]
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'sorts by multiple columns name desc and price desc' do
|
92
|
+
finder = finder_with_sort 'name desc, price desc'
|
93
|
+
expect(finder.results.map(&:name)).to eq %w[Name4 Name3 Name3 Name2 Name1 Name0]
|
94
|
+
expect(finder.results.map(&:price)).to eq [14, 13, 8, 12, 11, 10]
|
84
95
|
end
|
85
96
|
end
|
97
|
+
|
98
|
+
it_behaves_like 'a sorting feature'
|
86
99
|
end
|