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
@@ -1,85 +1,85 @@
|
|
1
|
-
require 'spec_helper_data_mapper'
|
2
|
-
|
3
|
-
module Trailblazer
|
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
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
end
|
1
|
+
# require 'spec_helper_data_mapper'
|
2
|
+
#
|
3
|
+
# module Trailblazer
|
4
|
+
# class Finder
|
5
|
+
# module Adapters
|
6
|
+
# module DataMapper
|
7
|
+
# describe Sorting do
|
8
|
+
# def finder_class
|
9
|
+
# Class.new do
|
10
|
+
# include Trailblazer::Finder::Base
|
11
|
+
# include Trailblazer::Finder::Features::Sorting
|
12
|
+
# include Trailblazer::Finder::Adapters::DataMapper
|
13
|
+
#
|
14
|
+
# entity_type { DProduct }
|
15
|
+
#
|
16
|
+
# sortable_by :name, :price, :created_at
|
17
|
+
#
|
18
|
+
# filter_by :name
|
19
|
+
# filter_by :price
|
20
|
+
#
|
21
|
+
# # # Need to find a fix for this, not sure how to handle joins with data mapper properly
|
22
|
+
# # filter_by(:d_category) { |entity_type, _| entity_type }
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# def finder_with_sort(sort = nil, filters = {})
|
27
|
+
# finder_class.new filter: { sort: sort }.merge(filters)
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# it 'can be inherited' do
|
31
|
+
# child_class = Class.new(finder_class)
|
32
|
+
# expect(child_class.new.sort_attribute).to eq 'name'
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# describe 'sorting' do
|
36
|
+
# after do
|
37
|
+
# DProduct.all.destroy
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# it 'sorts results based on the sort option desc' do
|
41
|
+
# 5.times { |i| DProduct.create price: i }
|
42
|
+
#
|
43
|
+
# finder = finder_with_sort 'price desc'
|
44
|
+
# expect(finder.results.map(&:price)).to eq [4, 3, 2, 1, 0]
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# it 'sorts results based on the sort option asc' do
|
48
|
+
# 5.times { |i| DProduct.create price: i }
|
49
|
+
#
|
50
|
+
# finder = finder_with_sort 'price asc'
|
51
|
+
# expect(finder.results.map(&:price)).to eq [0, 1, 2, 3, 4]
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# it 'defaults to first sort by option' do
|
55
|
+
# 5.times { |i| DProduct.create name: "Name#{i}" }
|
56
|
+
#
|
57
|
+
# finder = finder_with_sort
|
58
|
+
# expect(finder.results.map(&:name)).to eq %w[Name4 Name3 Name2 Name1 Name0]
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# it 'ignores invalid sort values' do
|
62
|
+
# finder = finder_with_sort 'invalid attribute'
|
63
|
+
# expect { finder.results.to_a }.not_to raise_error
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# # TODO: Need to find a fix for this, not sure how to handle joins with data mapper properly
|
67
|
+
# it 'can handle renames of sorting in joins' do
|
68
|
+
# # older_category = DCategory.create title: 'older'
|
69
|
+
# # newer_category = DCategory.create title: 'newer'
|
70
|
+
# #
|
71
|
+
# # product_of_newer_category = DProduct.create name: 'older product', d_category: newer_category
|
72
|
+
# # product_of_older_category = DProduct.create name: 'newer product', d_category: older_category
|
73
|
+
# #
|
74
|
+
# # finder = finder_with_sort 'created_at desc', d_category: ''
|
75
|
+
# #
|
76
|
+
# # expect(finder.results.map(&:name)).to eq [product_of_older_category.name, product_of_newer_category.name]
|
77
|
+
# end
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# it_behaves_like 'a sorting feature'
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
# end
|
@@ -2,7 +2,7 @@ require 'spec_helper_sequel'
|
|
2
2
|
# require 'spec_helper'
|
3
3
|
|
4
4
|
describe "Trailblazer::Finder::Adapters::Sequel::Predicates" do
|
5
|
-
class
|
5
|
+
class TestSequelFinder < Trailblazer::Finder
|
6
6
|
features Predicate
|
7
7
|
adapters Sequel
|
8
8
|
|
@@ -14,7 +14,7 @@ require 'spec_helper_sequel'
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def finder_with_predicate(filter = nil, value = nil, filters = {})
|
17
|
-
|
17
|
+
TestSequelFinder.new filter: { filter => value }.merge(filters)
|
18
18
|
end
|
19
19
|
|
20
20
|
describe 'equals' do
|
@@ -1,86 +1,107 @@
|
|
1
1
|
require 'spec_helper_sequel'
|
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
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
3
|
+
describe 'Trailblazer::Finder::Adapters::Sequel::Sorting', :sorting do
|
4
|
+
after do
|
5
|
+
SProduct.order(:id).delete
|
6
|
+
end
|
7
|
+
|
8
|
+
before do
|
9
|
+
SProduct.order(:id).delete
|
10
|
+
end
|
11
|
+
|
12
|
+
class TestSequelSortFinder < Trailblazer::Finder
|
13
|
+
features Sorting
|
14
|
+
adapters Sequel
|
15
|
+
|
16
|
+
entity_type { SProduct }
|
17
|
+
|
18
|
+
sortable_by :name, :price, :created_at
|
19
|
+
|
20
|
+
filter_by :name
|
21
|
+
filter_by :price
|
22
|
+
filter_by(:s_category) { |entity_type, _| entity_type.association_join(:s_category) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def finder_with_sort(sort = nil, filters = {})
|
26
|
+
TestSequelSortFinder.new filter: (sort.nil? ? {} : { sort: sort }).merge(filters)
|
27
|
+
end
|
28
|
+
|
29
|
+
def finder_with_nil_sort
|
30
|
+
TestSequelSortFinder.new filter: { sort: nil }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'sorting' do
|
34
|
+
it 'loads results if no sort options are supplied in the params' do
|
35
|
+
5.times { |i| SProduct.create price: i }
|
36
|
+
finder = finder_with_nil_sort
|
37
|
+
expect(finder.results.map(&:price)).to eq [0, 1, 2, 3, 4]
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'sorts results based on the sort option desc' do
|
41
|
+
5.times { |i| SProduct.create price: i }
|
42
|
+
|
43
|
+
finder = finder_with_sort 'price desc'
|
44
|
+
expect(finder.results.map(&:price)).to eq [4, 3, 2, 1, 0]
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'sorts results based on the sort option asc' do
|
48
|
+
5.times { |i| SProduct.create price: i }
|
49
|
+
|
50
|
+
finder = finder_with_sort 'price asc'
|
51
|
+
expect(finder.results.map(&:price)).to eq [0, 1, 2, 3, 4]
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'defaults to first sort by option' do
|
55
|
+
5.times { |i| SProduct.create name: "Name#{i}" }
|
56
|
+
|
57
|
+
finder = finder_with_sort
|
58
|
+
expect(finder.results.map(&:name)).to eq %w[Name0 Name1 Name2 Name3 Name4]
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'ignores invalid sort values' do
|
62
|
+
finder = finder_with_sort 'invalid attribute'
|
63
|
+
expect { finder.results.to_a }.not_to raise_error
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'can handle renames of sorting in joins' do
|
67
|
+
older_category = SCategory.create title: 'older'
|
68
|
+
newer_category = SCategory.create title: 'newer'
|
69
|
+
|
70
|
+
product_of_newer_category = SProduct.create name: 'older product', s_category: newer_category
|
71
|
+
product_of_older_category = SProduct.create name: 'newer product', s_category: older_category
|
72
|
+
|
73
|
+
finder = finder_with_sort 'created_at desc', s_category: ''
|
74
|
+
|
75
|
+
expect(finder.results.map(&:name)).to eq [product_of_older_category.name, product_of_newer_category.name]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'sorting by multiple' do
|
80
|
+
before do
|
81
|
+
5.times do |i|
|
82
|
+
SProduct.create name: "Name#{i}", price: "1#{i}"
|
83
83
|
end
|
84
|
+
SProduct.create name: 'Name3', price: '8'
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'sorts by multiple columns name asc and price asc' do
|
88
|
+
finder = finder_with_sort 'name asc, price asc'
|
89
|
+
expect(finder.results.map(&:name)).to eq %w[Name0 Name1 Name2 Name3 Name3 Name4]
|
90
|
+
expect(finder.results.map(&:price)).to eq [10, 11, 12, 8, 13, 14]
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'sorts by multiple columns name asc and price desc' do
|
94
|
+
finder = finder_with_sort 'name asc, price desc'
|
95
|
+
expect(finder.results.map(&:name)).to eq %w[Name0 Name1 Name2 Name3 Name3 Name4]
|
96
|
+
expect(finder.results.map(&:price)).to eq [10, 11, 12, 13, 8, 14]
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'sorts by multiple columns name desc and price desc' do
|
100
|
+
finder = finder_with_sort 'name desc, price desc'
|
101
|
+
expect(finder.results.map(&:name)).to eq %w[Name4 Name3 Name3 Name2 Name1 Name0]
|
102
|
+
expect(finder.results.map(&:price)).to eq [14, 13, 8, 12, 11, 10]
|
84
103
|
end
|
85
104
|
end
|
105
|
+
|
106
|
+
it_behaves_like 'a sorting feature'
|
86
107
|
end
|
@@ -1,89 +1,65 @@
|
|
1
|
+
# require 'spec_helper_sequel'
|
1
2
|
require 'spec_helper'
|
2
|
-
require 'support/sorting_shared_example'
|
3
3
|
|
4
4
|
module Trailblazer
|
5
5
|
class Finder
|
6
6
|
module Features
|
7
|
-
describe Sorting do
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
describe Sorting, :sorting do
|
8
|
+
class TestSortingFinder < Trailblazer::Finder
|
9
|
+
features Sorting
|
10
|
+
|
11
|
+
def create_product(id, name, price)
|
12
|
+
{
|
13
|
+
id: id,
|
14
|
+
name: name,
|
15
|
+
price: price,
|
16
|
+
created_at: Time.now,
|
17
|
+
updated_at: Time.now
|
18
|
+
}
|
19
|
+
end
|
11
20
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
{
|
19
|
-
id: 1,
|
20
|
-
name: 'product_1',
|
21
|
-
price: '11',
|
22
|
-
created_at: Time.now,
|
23
|
-
updated_at: Time.now
|
24
|
-
},
|
25
|
-
{
|
26
|
-
id: 2,
|
27
|
-
name: 'product_2',
|
28
|
-
price: '12',
|
29
|
-
created_at: Time.now,
|
30
|
-
updated_at: Time.now
|
31
|
-
},
|
32
|
-
{
|
33
|
-
id: 3,
|
34
|
-
name: 'product_3',
|
35
|
-
price: '13',
|
36
|
-
created_at: Time.now,
|
37
|
-
updated_at: Time.now
|
38
|
-
},
|
39
|
-
{
|
40
|
-
id: 4,
|
41
|
-
name: 'product_4',
|
42
|
-
price: '14',
|
43
|
-
created_at: Time.now,
|
44
|
-
updated_at: Time.now
|
45
|
-
},
|
46
|
-
{
|
47
|
-
id: 5,
|
48
|
-
name: 'product_5',
|
49
|
-
price: '15',
|
50
|
-
created_at: Time.now,
|
51
|
-
updated_at: Time.now
|
52
|
-
}
|
53
|
-
]
|
54
|
-
end
|
55
|
-
|
56
|
-
sortable_by :name, :price, :created_at
|
57
|
-
|
58
|
-
filter_by :name
|
59
|
-
filter_by :price
|
60
|
-
filter_by(:category) { |entity_type, _| entity_type.joins(:category) }
|
21
|
+
entity_type do
|
22
|
+
Array.new(5) do |i|
|
23
|
+
next create_product(i + 1, '', "1#{i}".to_i) if i == 7
|
24
|
+
next create_product(i + 1, 'Name4', "1#{i}".to_i) if i == 9
|
25
|
+
create_product(i + 1, "Name#{i}", "1#{i}".to_i)
|
26
|
+
end.push(create_product(6, 'Name3', 8))
|
61
27
|
end
|
28
|
+
|
29
|
+
sortable_by :name, :price, :created_at, :id
|
30
|
+
|
31
|
+
filter_by :name
|
32
|
+
filter_by :price
|
33
|
+
filter_by(:category) { |entity_type, _| entity_type.joins(:category) }
|
62
34
|
end
|
63
35
|
|
64
36
|
def finder_with_sort(sort = nil, filters = {})
|
65
|
-
|
37
|
+
TestSortingFinder.new filter: (sort.nil? ? {} : { sort: sort }).merge(filters)
|
66
38
|
end
|
67
39
|
|
68
|
-
|
69
|
-
|
70
|
-
expect(child_class.new.sort_attribute).to eq 'name'
|
40
|
+
def finder_with_nil_sort
|
41
|
+
TestSortingFinder.new filter: { sort: nil }
|
71
42
|
end
|
72
43
|
|
73
44
|
describe 'sorting' do
|
45
|
+
it 'loads results if no sort options are supplied in the params' do
|
46
|
+
finder = finder_with_nil_sort
|
47
|
+
expect(finder.results.map { |n| n[:price] }).to eq [14, 13, 8, 12, 11, 10]
|
48
|
+
end
|
49
|
+
|
74
50
|
it 'sorts results based on the sort option desc' do
|
75
51
|
finder = finder_with_sort 'price desc'
|
76
|
-
expect(finder.results.map { |n| n[:price] }).to eq
|
52
|
+
expect(finder.results.map { |n| n[:price] }).to eq [14, 13, 12, 11, 10, 8]
|
77
53
|
end
|
78
54
|
|
79
55
|
it 'sorts results based on the sort option asc' do
|
80
56
|
finder = finder_with_sort 'price asc'
|
81
|
-
expect(finder.results.map { |n| n[:price] }).to eq
|
57
|
+
expect(finder.results.map { |n| n[:price] }).to eq [8, 10, 11, 12, 13, 14]
|
82
58
|
end
|
83
59
|
|
84
|
-
it 'defaults to
|
60
|
+
it 'defaults to original sorted hash' do
|
85
61
|
finder = finder_with_sort
|
86
|
-
expect(finder.results.map { |n| n[:name] }).to eq
|
62
|
+
expect(finder.results.map { |n| n[:name] }).to eq ['Name0', 'Name1', 'Name2', 'Name3', 'Name4', 'Name3']
|
87
63
|
end
|
88
64
|
|
89
65
|
it 'ignores invalid sort values' do
|
@@ -92,6 +68,27 @@ module Trailblazer
|
|
92
68
|
end
|
93
69
|
end
|
94
70
|
|
71
|
+
describe 'sorting by multiple' do
|
72
|
+
|
73
|
+
it 'sorts by multiple columns name asc and price asc' do
|
74
|
+
finder = finder_with_sort 'name asc, price asc'
|
75
|
+
expect(finder.results.map { |n| n[:name] }).to eq ['Name0', 'Name1', 'Name2', 'Name3', 'Name3', 'Name4']
|
76
|
+
expect(finder.results.map { |n| n[:price] }).to eq [10, 11, 12, 8, 13, 14]
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'sorts by multiple columns name asc and price desc' do
|
80
|
+
finder = finder_with_sort 'name asc, price desc'
|
81
|
+
expect(finder.results.map { |n| n[:name] }).to eq ['Name0', 'Name1', 'Name2', 'Name3', 'Name3', 'Name4']
|
82
|
+
expect(finder.results.map { |n| n[:price] }).to eq [10, 11, 12, 13, 8, 14]
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'sorts by multiple columns name desc and price desc' do
|
86
|
+
finder = finder_with_sort 'name desc, price desc'
|
87
|
+
expect(finder.results.map { |n| n[:name] }).to eq ['Name4', 'Name3', 'Name3', 'Name2', 'Name1', 'Name0']
|
88
|
+
expect(finder.results.map { |n| n[:price] }).to eq [14, 13, 8, 12, 11, 10]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
95
92
|
it_behaves_like 'a sorting feature'
|
96
93
|
end
|
97
94
|
end
|