trailblazer-finder 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 +7 -0
- data/.gitignore +19 -0
- data/.rubocop.yml +45 -0
- data/.rubocop_todo.yml +52 -0
- data/.travis.yml +15 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +23 -0
- data/README.md +494 -0
- data/Rakefile +29 -0
- data/lib/trailblazer/finder/adapters/active_record/paging.rb +20 -0
- data/lib/trailblazer/finder/adapters/active_record/sorting.rb +20 -0
- data/lib/trailblazer/finder/adapters/active_record.rb +30 -0
- data/lib/trailblazer/finder/adapters/data_mapper/paging.rb +20 -0
- data/lib/trailblazer/finder/adapters/data_mapper/sorting.rb +25 -0
- data/lib/trailblazer/finder/adapters/data_mapper.rb +30 -0
- data/lib/trailblazer/finder/adapters/friendly_id.rb +33 -0
- data/lib/trailblazer/finder/adapters/kaminari.rb +18 -0
- data/lib/trailblazer/finder/adapters/sequel/paging.rb +20 -0
- data/lib/trailblazer/finder/adapters/sequel/sorting.rb +25 -0
- data/lib/trailblazer/finder/adapters/sequel.rb +30 -0
- data/lib/trailblazer/finder/adapters/will_paginate.rb +18 -0
- data/lib/trailblazer/finder/adapters.rb +26 -0
- data/lib/trailblazer/finder/base.rb +98 -0
- data/lib/trailblazer/finder/errors/block_ignored.rb +11 -0
- data/lib/trailblazer/finder/errors/invalid_defined_by_value.rb +11 -0
- data/lib/trailblazer/finder/errors/invalid_number.rb +16 -0
- data/lib/trailblazer/finder/errors/missing_entity_type.rb +11 -0
- data/lib/trailblazer/finder/errors/with_ignored.rb +11 -0
- data/lib/trailblazer/finder/features/paging.rb +55 -0
- data/lib/trailblazer/finder/features/sorting.rb +66 -0
- data/lib/trailblazer/finder/features.rb +22 -0
- data/lib/trailblazer/finder/filter.rb +66 -0
- data/lib/trailblazer/finder/find.rb +29 -0
- data/lib/trailblazer/finder/utils/extra.rb +31 -0
- data/lib/trailblazer/finder/utils/params.rb +28 -0
- data/lib/trailblazer/finder/utils/parse.rb +25 -0
- data/lib/trailblazer/finder/utils/string.rb +35 -0
- data/lib/trailblazer/finder/version.rb +5 -0
- data/lib/trailblazer/finder.rb +29 -0
- data/lib/trailblazer/operation/finder.rb +61 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/spec_helper_active_record.rb +50 -0
- data/spec/spec_helper_data_mapper.rb +35 -0
- data/spec/spec_helper_sequel.rb +32 -0
- data/spec/support/paging_shared_example.rb +65 -0
- data/spec/support/sorting_shared_example.rb +95 -0
- data/spec/trailblazer/finder/adapters/active_record/base_spec.rb +112 -0
- data/spec/trailblazer/finder/adapters/active_record/paging_spec.rb +64 -0
- data/spec/trailblazer/finder/adapters/active_record/sorting_spec.rb +82 -0
- data/spec/trailblazer/finder/adapters/data_mapper/base_spec.rb +112 -0
- data/spec/trailblazer/finder/adapters/data_mapper/paging_spec.rb +64 -0
- data/spec/trailblazer/finder/adapters/data_mapper/sorting_spec.rb +85 -0
- data/spec/trailblazer/finder/adapters/friendly_id_spec.rb +46 -0
- data/spec/trailblazer/finder/adapters/kaminari_spec.rb +64 -0
- data/spec/trailblazer/finder/adapters/sequel/base_spec.rb +112 -0
- data/spec/trailblazer/finder/adapters/sequel/paging_spec.rb +64 -0
- data/spec/trailblazer/finder/adapters/sequel/sorting_spec.rb +82 -0
- data/spec/trailblazer/finder/adapters/will_paginate_spec.rb +71 -0
- data/spec/trailblazer/finder/adapters_spec.rb +110 -0
- data/spec/trailblazer/finder/base_spec.rb +329 -0
- data/spec/trailblazer/finder/features/paging_spec.rb +104 -0
- data/spec/trailblazer/finder/features/sorting_spec.rb +100 -0
- data/spec/trailblazer/finder/features_spec.rb +55 -0
- data/spec/trailblazer/finder/filter_spec.rb +133 -0
- data/spec/trailblazer/finder/find_spec.rb +72 -0
- data/spec/trailblazer/finder/utils/extra_spec.rb +41 -0
- data/spec/trailblazer/finder/utils/params_spec.rb +39 -0
- data/spec/trailblazer/finder/utils/parse_spec.rb +33 -0
- data/spec/trailblazer/finder/utils/string_spec.rb +25 -0
- data/spec/trailblazer/operation/finder_spec.rb +103 -0
- data/spec/trailblazer/operation/paging_spec.rb +68 -0
- data/spec/trailblazer/operation/sorting_spec.rb +80 -0
- data/trailblazer-finder.gemspec +41 -0
- metadata +402 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'spec_helper_sequel'
|
2
|
+
|
3
|
+
module Trailblazer
|
4
|
+
class Finder
|
5
|
+
module Adapters
|
6
|
+
describe Sequel do
|
7
|
+
# it_behaves_like 'a base orm adapter'
|
8
|
+
|
9
|
+
after do
|
10
|
+
SProduct.order(:id).delete
|
11
|
+
end
|
12
|
+
|
13
|
+
def define_finder_class(&block)
|
14
|
+
Class.new(Trailblazer::Finder) do
|
15
|
+
class_eval(&block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def finder_class(&block) # rubocop:disable Metrics/MethodLength
|
20
|
+
define_finder_class do
|
21
|
+
adapters ActiveRecord
|
22
|
+
|
23
|
+
entity_type { SProduct }
|
24
|
+
|
25
|
+
filter_by :id
|
26
|
+
filter_by :name
|
27
|
+
filter_by :slug
|
28
|
+
|
29
|
+
if block.nil?
|
30
|
+
filter_by :value do |entity_type, value|
|
31
|
+
entity_type.where(slug: value)
|
32
|
+
end
|
33
|
+
else
|
34
|
+
class_eval(&block)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def finder_with_filter(key = nil, name = nil, &block)
|
40
|
+
finder_class(&block).new filter: { key => name }
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'filter_by' do
|
44
|
+
it 'has a default filter' do
|
45
|
+
10.times { |i| SProduct.create name: "product_#{i}" }
|
46
|
+
finder = finder_with_filter :name, 'product_2'
|
47
|
+
|
48
|
+
expect(finder.results.first.name).to eq 'product_2'
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'has another default filter' do
|
52
|
+
10.times { |i| SProduct.create slug: "product_#{i}" }
|
53
|
+
finder = finder_with_filter :value, 'product_2'
|
54
|
+
|
55
|
+
expect(finder.results.first.slug).to eq 'product_2'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'can use methods from the object' do
|
60
|
+
2.times { |i| SProduct.create name: "product_#{i}" }
|
61
|
+
finder1 = finder_with_filter :id, 1 do
|
62
|
+
filter_by :id do |entity_type, value|
|
63
|
+
some_instance_method(entity_type, value)
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def some_instance_method(entity_type, value)
|
69
|
+
entity_type.where(id: value)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
expect(finder1.results.first.id).to eq 1
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'can dispatch with instance methods' do
|
77
|
+
10.times { |i| SProduct.create slug: "product_#{i}" }
|
78
|
+
finder = finder_with_filter :slug, 'product_5' do
|
79
|
+
filter_by :slug, with: :some_instance_method
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def some_instance_method(entity_type, value)
|
84
|
+
entity_type.where(slug: value)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
expect(finder.results.first.slug).to eq 'product_5'
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'filter_by attributes' do
|
92
|
+
it 'accesses filter values' do
|
93
|
+
finder = finder_with_filter :value, 1
|
94
|
+
expect(finder.value).to eq 1
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'returns default filter value if filter_by is not specified' do
|
98
|
+
finder = finder_with_filter do
|
99
|
+
filter_by :value, 1
|
100
|
+
end
|
101
|
+
expect(finder.value).to eq 1
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'does not include invalid filters' do
|
105
|
+
finder = finder_with_filter invalid: 'option'
|
106
|
+
expect { finder.invalid }.to raise_error NoMethodError
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper_sequel'
|
2
|
+
|
3
|
+
module Trailblazer
|
4
|
+
class Finder
|
5
|
+
module Adapters
|
6
|
+
module Sequel
|
7
|
+
describe Paging do
|
8
|
+
it_behaves_like 'a paging feature'
|
9
|
+
|
10
|
+
after do
|
11
|
+
SProduct.order(:id).delete
|
12
|
+
end
|
13
|
+
|
14
|
+
def define_finder_class(&block)
|
15
|
+
Class.new do
|
16
|
+
include Trailblazer::Finder::Base
|
17
|
+
include Trailblazer::Finder::Features::Paging
|
18
|
+
include Trailblazer::Finder::Adapters::Sequel
|
19
|
+
|
20
|
+
instance_eval(&block) if block_given?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def finder_class
|
25
|
+
define_finder_class do
|
26
|
+
entity_type { SProduct }
|
27
|
+
|
28
|
+
per_page 2
|
29
|
+
|
30
|
+
min_per_page 2
|
31
|
+
max_per_page 10
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def finder_with_page(page = nil, per_page = nil)
|
36
|
+
finder_class.new page: page, per_page: per_page
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'can be inherited' do
|
40
|
+
child_class = Class.new(finder_class)
|
41
|
+
expect(child_class.new.per_page).to eq 2
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#results' do
|
45
|
+
it 'paginates results' do
|
46
|
+
6.times { |i| SProduct.create name: "product_#{i}" }
|
47
|
+
finder = finder_with_page 2, 2
|
48
|
+
|
49
|
+
expect(finder.results.map(&:name)).to eq %w[product_2 product_3]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#count' do
|
54
|
+
it 'gives the real count' do
|
55
|
+
10.times { |i| SProduct.create name: "product_#{i}" }
|
56
|
+
finder = finder_with_page 1
|
57
|
+
expect(finder.count).to eq 10
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper_sequel'
|
2
|
+
|
3
|
+
module Trailblazer
|
4
|
+
class Finder
|
5
|
+
module Adapters
|
6
|
+
module Sequel
|
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::Sequel
|
13
|
+
|
14
|
+
entity_type { SProduct }
|
15
|
+
|
16
|
+
sortable_by :name, :price, :created_at
|
17
|
+
|
18
|
+
filter_by :name
|
19
|
+
filter_by :price
|
20
|
+
filter_by(:s_category) { |entity_type, _| entity_type.association_join(:s_category) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def finder_with_sort(sort = nil, filters = {})
|
25
|
+
finder_class.new filter: { sort: sort }.merge(filters)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'can be inherited' do
|
29
|
+
child_class = Class.new(finder_class)
|
30
|
+
expect(child_class.new.sort_attribute).to eq 'name'
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'sorting' do
|
34
|
+
after do
|
35
|
+
SProduct.order(:id).delete
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'sorts results based on the sort option desc' do
|
39
|
+
5.times { |i| SProduct.create price: i }
|
40
|
+
|
41
|
+
finder = finder_with_sort 'price desc'
|
42
|
+
expect(finder.results.map(&:price)).to eq [4, 3, 2, 1, 0]
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'sorts results based on the sort option asc' do
|
46
|
+
5.times { |i| SProduct.create price: i }
|
47
|
+
|
48
|
+
finder = finder_with_sort 'price asc'
|
49
|
+
expect(finder.results.map(&:price)).to eq [0, 1, 2, 3, 4]
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'defaults to first sort by option' do
|
53
|
+
5.times { |i| SProduct.create name: "Name#{i}" }
|
54
|
+
|
55
|
+
finder = finder_with_sort
|
56
|
+
expect(finder.results.map(&:name)).to eq %w[Name4 Name3 Name2 Name1 Name0]
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'ignores invalid sort values' do
|
60
|
+
finder = finder_with_sort 'invalid attribute'
|
61
|
+
expect { finder.results.to_a }.not_to raise_error
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'can handle renames of sorting in joins' do
|
65
|
+
older_category = SCategory.create title: 'older'
|
66
|
+
newer_category = SCategory.create title: 'newer'
|
67
|
+
|
68
|
+
product_of_newer_category = SProduct.create name: 'older product', s_category: newer_category
|
69
|
+
product_of_older_category = SProduct.create name: 'newer product', s_category: older_category
|
70
|
+
|
71
|
+
finder = finder_with_sort 'created_at desc', s_category: ''
|
72
|
+
|
73
|
+
expect(finder.results.map(&:name)).to eq [product_of_older_category.name, product_of_newer_category.name]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it_behaves_like 'a sorting feature'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper_active_record'
|
2
|
+
|
3
|
+
require 'will_paginate'
|
4
|
+
require 'will_paginate/active_record'
|
5
|
+
|
6
|
+
module Trailblazer
|
7
|
+
class Finder
|
8
|
+
module Adapters
|
9
|
+
describe WillPaginate do
|
10
|
+
it_behaves_like 'a paging feature' do
|
11
|
+
after do
|
12
|
+
Product.delete_all
|
13
|
+
end
|
14
|
+
|
15
|
+
def define_finder_class(&block)
|
16
|
+
Class.new do
|
17
|
+
include Trailblazer::Finder::Base
|
18
|
+
include Trailblazer::Finder::Features::Paging
|
19
|
+
include Trailblazer::Finder::Adapters::ActiveRecord
|
20
|
+
include Trailblazer::Finder::Adapters::WillPaginate
|
21
|
+
|
22
|
+
instance_eval(&block) if block_given?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def finder_class
|
27
|
+
define_finder_class do
|
28
|
+
entity_type { Product }
|
29
|
+
|
30
|
+
per_page 2
|
31
|
+
|
32
|
+
min_per_page 2
|
33
|
+
max_per_page 10
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def finder_with_page(page = nil, per_page = nil)
|
38
|
+
finder_class.new page: page, per_page: per_page
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'can be inherited' do
|
42
|
+
child_class = Class.new(finder_class)
|
43
|
+
expect(child_class.new.per_page).to eq 2
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#results' do
|
47
|
+
it 'paginates results' do
|
48
|
+
6.times { |i| Product.create name: "product_#{i}" }
|
49
|
+
finder = finder_with_page 2, 2
|
50
|
+
|
51
|
+
expect(finder.results.map(&:name)).to eq %w[product_2 product_3]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#count' do
|
56
|
+
it 'gives the real count' do
|
57
|
+
10.times { |i| Product.create name: "product_#{i}" }
|
58
|
+
finder = finder_with_page 1
|
59
|
+
expect(finder.count).to eq 10
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'uses will_paginate gem' do
|
64
|
+
finder = finder_with_page
|
65
|
+
expect(finder.results).to be_respond_to :total_entries
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
module Trailblazer
|
5
|
+
class Finder
|
6
|
+
describe Adapters do
|
7
|
+
def define_finder_class(&block)
|
8
|
+
Class.new do
|
9
|
+
include Trailblazer::Finder::Base
|
10
|
+
include Trailblazer::Finder::Adapters
|
11
|
+
|
12
|
+
instance_eval(&block) if block_given?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.adapters' do
|
17
|
+
it 'responds to adapters method' do
|
18
|
+
finder_class = define_finder_class do
|
19
|
+
entity_type { 'entity_type' }
|
20
|
+
end
|
21
|
+
|
22
|
+
expect(finder_class).to respond_to(:adapters)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe ActiveRecord do
|
27
|
+
it 'can load ActiveRecord adapter' do
|
28
|
+
expect do
|
29
|
+
define_finder_class do
|
30
|
+
entity_type { 'entity_type' }
|
31
|
+
adapters ActiveRecord
|
32
|
+
end
|
33
|
+
end.not_to raise_error
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe Sequel do
|
38
|
+
it 'can load Sequel adapter' do
|
39
|
+
expect do
|
40
|
+
define_finder_class do
|
41
|
+
entity_type { 'entity_type' }
|
42
|
+
adapters Sequel
|
43
|
+
end
|
44
|
+
end.not_to raise_error
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe DataMapper do
|
49
|
+
it 'can load DataMapper adapter' do
|
50
|
+
expect do
|
51
|
+
define_finder_class do
|
52
|
+
entity_type { 'entity_type' }
|
53
|
+
adapters DataMapper
|
54
|
+
end
|
55
|
+
end.not_to raise_error
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe Kaminari do
|
60
|
+
it 'can load Kaminari adapter' do
|
61
|
+
expect do
|
62
|
+
define_finder_class do
|
63
|
+
entity_type { 'entity_type' }
|
64
|
+
adapters Kaminari
|
65
|
+
end
|
66
|
+
end.not_to raise_error
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe WillPaginate do
|
71
|
+
it 'can load WillPaginate adapter' do
|
72
|
+
expect do
|
73
|
+
define_finder_class do
|
74
|
+
entity_type { 'entity_type' }
|
75
|
+
adapters WillPaginate
|
76
|
+
end
|
77
|
+
end.not_to raise_error
|
78
|
+
end
|
79
|
+
end
|
80
|
+
describe FriendlyId do
|
81
|
+
it 'can load FriendlyId adapter' do
|
82
|
+
expect do
|
83
|
+
define_finder_class do
|
84
|
+
entity_type { 'entity_type' }
|
85
|
+
adapters FriendlyId
|
86
|
+
end
|
87
|
+
end.not_to raise_error
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'raises an error on non-existing adapter' do
|
92
|
+
expect do
|
93
|
+
define_finder_class do
|
94
|
+
entity_type { 'entity_type' }
|
95
|
+
adapters Unknown
|
96
|
+
end
|
97
|
+
end.to raise_error NameError
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'can load multiple adapters' do
|
101
|
+
expect do
|
102
|
+
define_finder_class do
|
103
|
+
entity_type { 'entity_type' }
|
104
|
+
adapters ActiveRecord, Kaminari
|
105
|
+
end
|
106
|
+
end.not_to raise_error
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|