trailblazer-finder 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.rubocop.yml +45 -0
  4. data/.rubocop_todo.yml +52 -0
  5. data/.travis.yml +15 -0
  6. data/Gemfile +12 -0
  7. data/LICENSE.txt +23 -0
  8. data/README.md +494 -0
  9. data/Rakefile +29 -0
  10. data/lib/trailblazer/finder/adapters/active_record/paging.rb +20 -0
  11. data/lib/trailblazer/finder/adapters/active_record/sorting.rb +20 -0
  12. data/lib/trailblazer/finder/adapters/active_record.rb +30 -0
  13. data/lib/trailblazer/finder/adapters/data_mapper/paging.rb +20 -0
  14. data/lib/trailblazer/finder/adapters/data_mapper/sorting.rb +25 -0
  15. data/lib/trailblazer/finder/adapters/data_mapper.rb +30 -0
  16. data/lib/trailblazer/finder/adapters/friendly_id.rb +33 -0
  17. data/lib/trailblazer/finder/adapters/kaminari.rb +18 -0
  18. data/lib/trailblazer/finder/adapters/sequel/paging.rb +20 -0
  19. data/lib/trailblazer/finder/adapters/sequel/sorting.rb +25 -0
  20. data/lib/trailblazer/finder/adapters/sequel.rb +30 -0
  21. data/lib/trailblazer/finder/adapters/will_paginate.rb +18 -0
  22. data/lib/trailblazer/finder/adapters.rb +26 -0
  23. data/lib/trailblazer/finder/base.rb +98 -0
  24. data/lib/trailblazer/finder/errors/block_ignored.rb +11 -0
  25. data/lib/trailblazer/finder/errors/invalid_defined_by_value.rb +11 -0
  26. data/lib/trailblazer/finder/errors/invalid_number.rb +16 -0
  27. data/lib/trailblazer/finder/errors/missing_entity_type.rb +11 -0
  28. data/lib/trailblazer/finder/errors/with_ignored.rb +11 -0
  29. data/lib/trailblazer/finder/features/paging.rb +55 -0
  30. data/lib/trailblazer/finder/features/sorting.rb +66 -0
  31. data/lib/trailblazer/finder/features.rb +22 -0
  32. data/lib/trailblazer/finder/filter.rb +66 -0
  33. data/lib/trailblazer/finder/find.rb +29 -0
  34. data/lib/trailblazer/finder/utils/extra.rb +31 -0
  35. data/lib/trailblazer/finder/utils/params.rb +28 -0
  36. data/lib/trailblazer/finder/utils/parse.rb +25 -0
  37. data/lib/trailblazer/finder/utils/string.rb +35 -0
  38. data/lib/trailblazer/finder/version.rb +5 -0
  39. data/lib/trailblazer/finder.rb +29 -0
  40. data/lib/trailblazer/operation/finder.rb +61 -0
  41. data/spec/spec_helper.rb +15 -0
  42. data/spec/spec_helper_active_record.rb +50 -0
  43. data/spec/spec_helper_data_mapper.rb +35 -0
  44. data/spec/spec_helper_sequel.rb +32 -0
  45. data/spec/support/paging_shared_example.rb +65 -0
  46. data/spec/support/sorting_shared_example.rb +95 -0
  47. data/spec/trailblazer/finder/adapters/active_record/base_spec.rb +112 -0
  48. data/spec/trailblazer/finder/adapters/active_record/paging_spec.rb +64 -0
  49. data/spec/trailblazer/finder/adapters/active_record/sorting_spec.rb +82 -0
  50. data/spec/trailblazer/finder/adapters/data_mapper/base_spec.rb +112 -0
  51. data/spec/trailblazer/finder/adapters/data_mapper/paging_spec.rb +64 -0
  52. data/spec/trailblazer/finder/adapters/data_mapper/sorting_spec.rb +85 -0
  53. data/spec/trailblazer/finder/adapters/friendly_id_spec.rb +46 -0
  54. data/spec/trailblazer/finder/adapters/kaminari_spec.rb +64 -0
  55. data/spec/trailblazer/finder/adapters/sequel/base_spec.rb +112 -0
  56. data/spec/trailblazer/finder/adapters/sequel/paging_spec.rb +64 -0
  57. data/spec/trailblazer/finder/adapters/sequel/sorting_spec.rb +82 -0
  58. data/spec/trailblazer/finder/adapters/will_paginate_spec.rb +71 -0
  59. data/spec/trailblazer/finder/adapters_spec.rb +110 -0
  60. data/spec/trailblazer/finder/base_spec.rb +329 -0
  61. data/spec/trailblazer/finder/features/paging_spec.rb +104 -0
  62. data/spec/trailblazer/finder/features/sorting_spec.rb +100 -0
  63. data/spec/trailblazer/finder/features_spec.rb +55 -0
  64. data/spec/trailblazer/finder/filter_spec.rb +133 -0
  65. data/spec/trailblazer/finder/find_spec.rb +72 -0
  66. data/spec/trailblazer/finder/utils/extra_spec.rb +41 -0
  67. data/spec/trailblazer/finder/utils/params_spec.rb +39 -0
  68. data/spec/trailblazer/finder/utils/parse_spec.rb +33 -0
  69. data/spec/trailblazer/finder/utils/string_spec.rb +25 -0
  70. data/spec/trailblazer/operation/finder_spec.rb +103 -0
  71. data/spec/trailblazer/operation/paging_spec.rb +68 -0
  72. data/spec/trailblazer/operation/sorting_spec.rb +80 -0
  73. data/trailblazer-finder.gemspec +41 -0
  74. 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