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.
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