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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bfa32409fa9cd5e7f8573fac437141c7a53ada65
4
+ data.tar.gz: a08dd296e2660da08cfb5785fd17c215d9aec2e0
5
+ SHA512:
6
+ metadata.gz: 402be8f3aa3855ecd06513c19de2cabb6ccecf7f0cd138d261cc4660adcdc9e2af06a37c597ca425a6038a9885a3335be85df53114caeb64c5944e8e1a2e24b7
7
+ data.tar.gz: 2531ad3dcce5f87ec7668532d8754f91a6f318cd1b3a6bbc65ad421d2366ea4a70515c4bb7b1d4fc948eb22d01daa8c91a4ff12a3bd36890505c9c786a158da0
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ test-reports
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+ bitbucket-pipelines.yml
data/.rubocop.yml ADDED
@@ -0,0 +1,45 @@
1
+ require: rubocop-rspec
2
+
3
+ inherit_from: .rubocop_todo.yml
4
+
5
+ AllCops:
6
+ Exclude:
7
+ - Rakefile
8
+ - coverage
9
+ - test-reports
10
+ - bitbucket-pipelines.yml
11
+ - trailblazer-finder.gemspec
12
+ - spec/trailblazer/finder/base_spec.rb
13
+ - lib/trailblazer/operation/finder.rb
14
+
15
+ # Disables "Line is too long"
16
+ LineLength:
17
+ Enabled: false
18
+
19
+ # Disables Module has too many lines
20
+ ModuleLength:
21
+ Enabled: false
22
+
23
+ # Disables "Missing top-level class documentation comment"
24
+ Documentation:
25
+ Enabled: false
26
+
27
+ # Disables "Use each_with_object instead of inject"
28
+ Style/EachWithObject:
29
+ Enabled: false
30
+
31
+ # Disables "Prefer reduce over inject."
32
+ Style/CollectionMethods:
33
+ Enabled: false
34
+
35
+ # Disables "Block has too many lines."
36
+ Metrics/BlockLength:
37
+ Enabled: false
38
+
39
+ # Disables "Example has too many lines."
40
+ RSpec/ExampleLength:
41
+ Enabled: false
42
+
43
+ # Disables "Too many expectations."
44
+ RSpec/MultipleExpectations:
45
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,52 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2018-03-05 19:59:14 +0100 using RuboCop version 0.53.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Cop supports --auto-correct.
11
+ # Configuration parameters: Include, TreatCommentsAsGroupSeparators.
12
+ # Include: **/*.gemfile, **/Gemfile, **/gems.rb
13
+ Bundler/OrderedGems:
14
+ Exclude:
15
+ - 'Gemfile'
16
+
17
+ # Offense count: 1
18
+ # Cop supports --auto-correct.
19
+ Layout/EmptyLines:
20
+ Exclude:
21
+ - 'spec/trailblazer/operation/finder_spec.rb'
22
+
23
+ # Offense count: 3
24
+ RSpec/DescribeClass:
25
+ Exclude:
26
+ - 'spec/trailblazer/operation/finder_spec.rb'
27
+ - 'spec/trailblazer/operation/paging_spec.rb'
28
+ - 'spec/trailblazer/operation/sorting_spec.rb'
29
+
30
+ # Offense count: 14
31
+ # Cop supports --auto-correct.
32
+ # Configuration parameters: AutoCorrect, EnforcedStyle.
33
+ # SupportedStyles: nested, compact
34
+ Style/ClassAndModuleChildren:
35
+ Exclude:
36
+ - 'spec/trailblazer/operation/finder_spec.rb'
37
+ - 'spec/trailblazer/operation/paging_spec.rb'
38
+ - 'spec/trailblazer/operation/sorting_spec.rb'
39
+
40
+ # Offense count: 10
41
+ # Cop supports --auto-correct.
42
+ # Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
43
+ # SupportedStyles: single_quotes, double_quotes
44
+ Style/StringLiterals:
45
+ Exclude:
46
+ - 'Gemfile'
47
+
48
+ # Offense count: 89
49
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
50
+ # URISchemes: http, https
51
+ Metrics/LineLength:
52
+ Max: 128
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ before_install:
3
+ - gem install bundler
4
+ matrix:
5
+ include:
6
+ - rvm: 2.1
7
+ gemfile: Gemfile
8
+ - rvm: 2.2
9
+ gemfile: Gemfile
10
+ - rvm: 2.3.1
11
+ gemfile: Gemfile
12
+ - rvm: 2.4.1
13
+ gemfile: Gemfile
14
+ - rvm: 2.5.0
15
+ gemfile: Gemfile
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'coveralls', require: false
6
+
7
+ # Had to add this for a bit, since none of the latest changes have been pushed to gems yet
8
+ gem "trailblazer", github: "trailblazer/trailblazer"
9
+ gem "trailblazer-operation", github: "trailblazer/trailblazer-operation"
10
+ gem "trailblazer-activity", github: "trailblazer/trailblazer-activity"
11
+ gem "trailblazer-macro", github: "trailblazer/trailblazer-macro"
12
+ gem "trailblazer-macro-contract", github: "trailblazer/trailblazer-macro-contract"
data/LICENSE.txt ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2018 Trailblazer GmbH and contributors, released under the MIT
2
+ license.
3
+
4
+ MIT License
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,494 @@
1
+
2
+ # Trailblazer Finder
3
+
4
+ Description should come here
5
+
6
+ [![Gitter Chat](https://badges.gitter.im/trailblazer/chat.svg)](https://gitter.im/trailblazer/chat) [![Build Status](https://secure.travis-ci.org/trailblazer/trailblazer-finder.svg)](https://travis-ci.org/trailblazer/trailblazer-finder) [![Coverage Status](https://coveralls.io/repos/github/trailblazer/trailblazer-finder/badge.svg?branch=master)](https://coveralls.io/github/trailblazer/trailblazer-finder?branch=master)
7
+
8
+ ## Table of Contents
9
+
10
+ * [Installation](#installation)
11
+ * [Dependencies](#dependencies)
12
+ * [Usage](#usage)
13
+ * [Finder](#finder)
14
+ * [Finder Example](#finder-example)
15
+ * [Operation](#operation)
16
+ * [Operation Example](#operation-example)
17
+ * [Usable without Trailblazer](#usable-without-trailblazer)
18
+ * [Example without Trailblazer](#example-without-trailblazer)
19
+ * [Example Project](#example-project)
20
+ * [Features](#features)
21
+ * [Paging](#paging)
22
+ * [Paging Example](#paging-example)
23
+ * [Sorting](#sorting)
24
+ * [Sorting Example](#sorting-example)
25
+ * [Adapters](#adapters)
26
+ * [Adapters Example](#adapters-example)
27
+ * [ActiveRecord](#active_record)
28
+ * [Active Record Example](#active-record-example)
29
+ * [DataMapper](#data_mapper)
30
+ * [Data Mapper Example](#data-mapper-example)
31
+ * [Sequel](#sequel)
32
+ * [Sequel Example](#sequel-example)
33
+ * [Kaminari](#kaminari)
34
+ * [Kaminari Example](#kaminari-example)
35
+ * [WillPaginate](#will_paginate)
36
+ * [Will Paginate Example](#will-paginate-example)
37
+ * [FriendlyId](#friendly_id)
38
+ * [Friendly Id Example](#friendly-id-example)
39
+ * [Tips & Tricks](#tips--tricks)
40
+ * [ORM's are not required](#results-shortcut)
41
+ * [Passing Entity Type as Argument](#passing-entity_type-as-argument)
42
+ * [Contributing](#contributing)
43
+ * [License](#license)
44
+
45
+ ## Installation
46
+
47
+ Add this line to your application's Gemfile:
48
+
49
+ ```ruby
50
+ gem 'trailblazer-finder'
51
+ ```
52
+
53
+ And then execute:
54
+
55
+ $ bundle
56
+
57
+ Or install it yourself as:
58
+
59
+ $ gem install trailblazer-finder
60
+
61
+ ###
62
+ * [Hashie](https://github.com/intridea/hashie) - used to search deep within hashes/arrays
63
+ * [Trailblazer](https://github.com/trailblazer/trailblazer) - [actually optional, but requires 2.1+](https://github.com/trailblazer/trailblazer-finder#usable-without-trailblazer)
64
+
65
+ ## Usage
66
+
67
+ ### Finder
68
+ Just inherit from the ```Trailblazer::Finder``` class.
69
+
70
+ Features and adapters are optional. However.
71
+
72
+ NOTE: features only work if they're specified on top of your Finder class
73
+
74
+ An Entity Type is required, but can:
75
+ * be defined in the inherited Finder class
76
+ * be given as an option in the call
77
+
78
+ Basically for most use cases, Entity Type is the entity/model/array of hashes you wish to use finder on
79
+
80
+ #### Finder Example
81
+
82
+ ```ruby
83
+ class Post::Finder < Trailblazer::Finder
84
+ # Optional features
85
+ features Paging, Sorting
86
+
87
+ # Optional if you use it as option in the caller, Model/Entity or Array with Hashes
88
+ entity_type { Post }
89
+
90
+ # Without defining an ORM everything defaults to dealing with an
91
+ # array with Hashes
92
+ adapters ActiveRecord, Kaminari
93
+
94
+ # Pagination settings (remove if not using the Paging feature)
95
+ per_page 25
96
+ min_per_page 10
97
+ max_per_page 100
98
+
99
+ # Sortable attributes (remove if not using the Sorting feature)
100
+ sortable_by :id, :title, :created_at
101
+
102
+ # Runs filter_by to filter results
103
+ #
104
+ # Params:
105
+ # * +attribute+:: The attribute to be filtered on
106
+ #
107
+ # * Following is optional, matches exact value if not specified
108
+ # * +with:+:: Filter method defined in Finder class
109
+ # * +defined_by:+:: Array of filter Methods defined in Finder class
110
+ # method name: apply_filter_name_with_array_value
111
+ # * block:: A block can be given with the code to filter with
112
+ filter_by :id
113
+ filter_by :body, with: :apply_body_filter
114
+ filter_by :created_after, with: :apply_created_after
115
+ filter_by :created_before, with: :apply_created_before
116
+ filter_by :is_hot, defined_by: %i[true false]
117
+ filter_by(:title) { |entity_type, value| entity_type.where title: value }
118
+ filter_by(:published, false) do |entity_type, value|
119
+ value ? entity_type.where('published = false') : entity_type.where('published = true')
120
+ end
121
+
122
+ private
123
+
124
+ def apply_body_filter(entity_type, value)
125
+ return unless value.present?
126
+ entity_type.where 'lower(body) LIKE ?', Utils::Parse.term(value.downcase)
127
+ end
128
+
129
+ def apply_created_after(entity_type, value)
130
+ entity_type.where('DATE(created_at) >= ?', value) if value.present?
131
+ end
132
+
133
+ def apply_created_before(entity_type, value)
134
+ entity_type.where('DATE(created_at) <= ?', value) if value.present?
135
+ end
136
+
137
+ def apply_is_hot_with_true(entity_type)
138
+ entity_type.where 'views > 100'
139
+ end
140
+
141
+ def apply_is_hot_with_false(entity_type)
142
+ entity_type.where 'views < 100'
143
+ end
144
+ end
145
+ ```
146
+
147
+ ### Operation
148
+ The only tie this has to [Trailblazer 2.1](https://github.com/trailblazer/trailblazer), is this part to be honest, which doesn't get loaded in case [Trailblazer](https://github.com/trailblazer/trailblazer) isn't loaded in your environment. The idea was actually to create it specifically for use with [Trailblazer 2.1](https://github.com/trailblazer/trailblazer), hence the name Trailblazer-Finder.
149
+
150
+ #### Operation Example using Finder Macro
151
+ ```ruby
152
+ class Post::Index < Trailblazer::Operation
153
+ # Runs a Trailblazer Task with a Finder object
154
+ # Params:
155
+ # +finder_class+:: Finder class to be used
156
+ # +action+:: :all, :single (optional, defaults to :all)
157
+ # +entity_type+:: Entity/Model or array (optional if specified in Finder Class, overwrites Finder class entity_type)
158
+ step Finder(Post::Finder, :all, Post)
159
+ end
160
+ ```
161
+
162
+ #### Operation Example using custom step
163
+ ```ruby
164
+ class Post::Index < Trailblazer::Operation
165
+ step :finder!
166
+
167
+ # Find all matching results and extend model object with required methods
168
+ def finder!(options, params:, **)
169
+ options[:finder] = Post::Finder.new(filter: params['f'], page: params['page'], per_page: params['per_page'])
170
+ end
171
+
172
+ # Find first matching row, no method extension on model object
173
+ def single_finder!(options, params:, **)
174
+
175
+ # Since ID's are usually given directly, patch it into filter
176
+ apply_id(params)
177
+
178
+ # No paging, sorting, no methods and only returns the first matched result
179
+ options[:finder] = Post::Finder.new(filter: params['f']).results.first
180
+ end
181
+
182
+ # Since ID's are usually given directly, patch it into filter
183
+ def apply_id(params)
184
+ return if params[:id].nil?
185
+ params[:f] = {} unless params.key?('f')
186
+ params[:f][:id] = params[:id] unless params[:f].key?('id')
187
+ end
188
+ end
189
+ ```
190
+
191
+ When using this, result[:finder] will be extended with (not available for :single row)
192
+ ```ruby
193
+ # accessing filters
194
+ .name # => name filter
195
+ .created_at # => created at filter
196
+
197
+ # accessing results
198
+ .count # => number of found results
199
+ .results? # => are there any results found
200
+ .results # => fetched results
201
+
202
+ # params for url generations
203
+ .params # => filter values
204
+ .params active: false # => overwrites the 'active' filter
205
+ ```
206
+
207
+
208
+ ### Usable without Trailblazer
209
+ It's not really tied to [Trailblazer](https://github.com/trailblazer/trailblazer), you can actually use it anywhere by calling the below example directly.
210
+ If Trailblazer isn't loaded, the ties to [Trailblazer](https://github.com/trailblazer/trailblazer) won't be executed.
211
+
212
+ #### Example without Trailblazer
213
+ ```ruby
214
+ result = Post::Finder.new(filter: params[:f], page: params[:page], per_page: params[:per_page])
215
+ ```
216
+
217
+ When using this, result will be extended with (not available for :single row)
218
+ ```ruby
219
+ # accessing filters
220
+ .name # => name filter
221
+ .created_at # => created at filter
222
+
223
+ # accessing results
224
+ .count # => number of found results
225
+ .results? # => are there any results found
226
+ .results # => fetched results
227
+
228
+ # params for url generations
229
+ .params # => filter values
230
+ .params active: false # => overwrites the 'active' filter
231
+ ```
232
+
233
+ ### Example Project
234
+ Coming soon!
235
+
236
+ ## Features
237
+ Aside of the default filtering behaviour, it offers the following optional features as well.
238
+
239
+ NOTE: FEATURES NEED TO BE SPECIFIED ON TOP OF YOUR CLASS
240
+
241
+ ### Paging
242
+
243
+ Really simple pagination plugin, which uses the plain ```.limit``` and ```.offset``` methods.
244
+
245
+ #### Paging Example
246
+ ```ruby
247
+ class Post::Finder < Trailblazer::Finder
248
+ features Paging
249
+
250
+ filter_by :name
251
+ filter_by :category_name
252
+
253
+ # per page defaults to 25 (so not required)
254
+ per_page 10
255
+
256
+ # Minimum items per page (not required)
257
+ min_per_page 5
258
+
259
+ # Maximum items per page (not required)
260
+ max_per_page 100
261
+ end
262
+ ```
263
+
264
+ This feature extends the result[:finder] object with the following methods
265
+ ```ruby
266
+ .page # => page number
267
+ .per_page # => per page (10)
268
+ .results # => paginated page results
269
+ ```
270
+
271
+ ### Sorting Plugin
272
+
273
+ Fixing the pain of dealing with sorting attributes and directions.
274
+
275
+
276
+ #### Sorting Example
277
+ ```ruby
278
+ class Post::Finder < Trailblazer::Finder
279
+ features Sorting
280
+
281
+ sortable_by :name, :body
282
+ end
283
+ ```
284
+
285
+ This feature extends the result[:finder] object with the following methods
286
+ ```ruby
287
+ .results # => Posts sorted by title DESC
288
+ .sort_attribute # => 'title'
289
+ .sort_direction # => 'desc'
290
+
291
+ # Smart sort checking
292
+ .sort?('title') # => true
293
+ .sort?('title desc') # => true
294
+ .sort?('title asc') # => false
295
+
296
+ # Helpers for dealing with reversing sort direction
297
+ .reverted_sort_direction # => 'asc'
298
+ .sort_direction_for('title') # => 'asc'
299
+ .sort_direction_for('body') # => 'desc'
300
+
301
+ # Params for sorting links
302
+ .sort_params_for('title')
303
+ ```
304
+
305
+ ## Adapters
306
+ By default, everything works with an array of hashes. You can change the default behaviour by using adapters. Adapters are not just tied to the ORM's, we also have a few adapters included that make it easier to work along with existing gems such as [Kaminari](https://github.com/kaminari/kaminari), [WillPaginate](https://github.com/mislav/will_paginate/) and [FriendlyId](https://github.com/norman/friendly_id).
307
+
308
+ Currently supported ORM's:
309
+ * [ActiveRecord](https://github.com/rails/rails/tree/master/activerecord)
310
+ * [DataMapper](https://github.com/datamapper)
311
+ * [Sequel](https://github.com/jeremyevans/sequel)
312
+
313
+ You can specify the adapters you wish to use inside your enherited Finder class.
314
+
315
+ ### Adapters Example
316
+ ```ruby
317
+ class Post::Finder < Trailblazer::Finder
318
+ # Features, in case you use any, need to be specified before adapters
319
+ adapters ActiveRecord, Kaminari, FriendlyId
320
+ end
321
+ ```
322
+
323
+ ### ActiveRecord
324
+ The only thing the [ActiveRecord](https://github.com/rails/rails/tree/master/activerecord) adapter does, is overwrite one specific method for Paging (limit/offset) and Sorting (order) each, as well as change the default filter behaviour (from select to where). These are overwritten by the adapter to match the specific use case of [ActiveRecord](https://github.com/rails/rails/tree/master/activerecord).
325
+
326
+ #### Active Record Example
327
+ ```ruby
328
+ class Post::Finder < Trailblazer::Finder
329
+ # Features, in case you use any, need to be specified before adapters
330
+ adapters ActiveRecord
331
+ end
332
+ ```
333
+
334
+ ### DataMapper
335
+ The only thing the [DataMapper](https://github.com/datamapper) adapter does, is overwrite one specific method for Paging (limit/offset) and Sorting (order) each, as well as change the default filter behaviour (from select to where). These are overwritten by the adapter to match the specific use case of [DataMapper](https://github.com/datamapper).
336
+
337
+ #### Data Mapper Example
338
+ ```ruby
339
+ class Post::Finder < Trailblazer::Finder
340
+ # Features, in case you use any, need to be specified before adapters
341
+ adapters DataMapper
342
+ end
343
+ ```
344
+
345
+ ### Sequel
346
+ The only thing the [Sequel](https://github.com/jeremyevans/sequel) adapter does, is overwrite one specific method for Paging (limit/offset) and Sorting (order) each, as well as change the default filter behaviour (from select to where). These are overwritten by the adapter to match the specific use case of [Sequel](https://github.com/jeremyevans/sequel).
347
+
348
+ #### Sequel Example
349
+ ```ruby
350
+ class Post::Finder < Trailblazer::Finder
351
+ # Features, in case you use any, need to be specified before adapters
352
+ adapters Sequel
353
+ end
354
+ ```
355
+
356
+ ### Kaminari
357
+ The only thing the [Kaminari](https://github.com/kaminari/kaminari) adapter does, is overwrite one specific method for Paging (limit/offset). These are overwritten by the adapter to match the specific use case of [Kaminari](https://github.com/kaminari/kaminari).
358
+
359
+ **Note**
360
+ Not usable without the Paging feature enabled, and requires an ORM that's supported by [Kaminari](https://github.com/kaminari/kaminari), directly or by using additional gems.
361
+
362
+ #### Kaminari Example
363
+ ```ruby
364
+ class Post::Finder < Trailblazer::Finder
365
+ features Paging
366
+ adapters ActiveRecord, Kaminari
367
+ end
368
+ ```
369
+ **Note**
370
+ To use [Kaminari](https://github.com/kaminari/kaminari) in combination with [Cells](https://github.com/trailblazer/cells), you'll currently have to use [kaminari-cells](https://github.com/apotonick/kaminari-cells) and monkey-patch Kaminari by using in an initiliazer:
371
+ ```ruby
372
+ Kaminari::Helpers::Paginator.class_eval do
373
+ def render(&block)
374
+ instance_eval(&block) if @options[:total_pages] > 1
375
+ end
376
+ end
377
+ ```
378
+
379
+ ### WillPaginate
380
+ The only thing the [WillPaginate](https://github.com/mislav/will_paginate/) adapter does, is overwrite one specific method for Paging (limit/offset). These are overwritten by the adapter to match the specific use case of [WillPaginate](https://github.com/mislav/will_paginate/).
381
+
382
+ **Note**
383
+ Not usable without the Paging feature enabled, and requires an ORM that's supported by [WillPaginate](https://github.com/mislav/will_paginate/), directly or by using additional gems.
384
+
385
+ #### Will Paginate Example
386
+ ```ruby
387
+ class Post::Finder < Trailblazer::Finder
388
+ features Paging
389
+ adapters ActiveRecord, WillPaginate
390
+ end
391
+ ```
392
+
393
+ ### FriendlyId
394
+ The [FriendlyId](https://github.com/norman/friendly_id) adapter was written cause I personally use it a lot, as well as to show an example of what kind of adapters we could potentially write in the future to compliment the filters with.
395
+
396
+ Basically the [FriendlyId](https://github.com/norman/friendly_id) adapter adds the following filter, which automatically checks wether the id is an integer or slug and makes sure the right filter is applied on the row set:
397
+ ```ruby
398
+ filter_by :id, with: :apply_slug_filter
399
+ ```
400
+
401
+ **Note**
402
+ Currently only tested with ActiveRecord.
403
+
404
+ **Note**
405
+ Do not set a filter_by for id or slug when using this adapter.
406
+
407
+ #### Friendly Id Example
408
+ ```ruby
409
+ class Post::Finder < Trailblazer::Finder
410
+ # Features, in case you use any, need to be specified before adapters
411
+ adapters ActiveRecord, FriendlyId
412
+ end
413
+ ```
414
+
415
+ ## Tips & Tricks
416
+ ### ORM's are not required
417
+ Not even for the Paging and Sorting features, however using additional adapters such as Kaminari, WillPaginate and FriendlyId won't work well with this.
418
+
419
+ ```ruby
420
+ class Post::Finder < Trailblazer::Finder
421
+ # Features, in case you use any, need to be specified before adapters
422
+ entity_type { fetch_product_as_hashes }
423
+
424
+ filter_by(:name) { |entity_type, value| entity_type.select { |product| product[:name] == value } }
425
+ filter_by(:category) { |entity_type, value| entity_type.select { |product| product[:category] == value } }
426
+ end
427
+ ```
428
+
429
+ ### Overwriting Methods
430
+ You can have fine grained entity_type, by overwriting ```initialize``` method:
431
+
432
+ ```ruby
433
+ class Post::Finder < Trailblazer::Finder
434
+ # Features, in case you use any, need to be specified before adapters
435
+
436
+ filter_by :name
437
+ filter_by :category_name
438
+
439
+ def initialize(user, options = {})
440
+ super options.merge(entity_type: Product.visible_to(user))
441
+ end
442
+ end
443
+ ```
444
+
445
+ ### Utils / Helpers
446
+ Coming soon
447
+
448
+ ## Contributing
449
+ 1. Fork it
450
+ 2. Create your feature branch
451
+ 3. Commit your changes
452
+ 4. Push to the branch
453
+ 5. Run the tests (`rake`)
454
+ 6. Make sure all tests pass, rubocop has no offenses and coverage is 100%
455
+ 7. Create new Pull Request
456
+
457
+ ## Bugs
458
+ Please report them on the [Github issue tracker](http://github.com/trailblazer/trailblazer-finder) for this project.
459
+
460
+ If you have a bug to report, please include the following information:
461
+
462
+ * **Version information for Trailblazer-Finder, Trailblazer, used Adapters and Ruby.**
463
+ * Full stack trace and error message (if you have them).
464
+ * Any snippets of relevant model, view or controller code that shows how you are using Trailblazer-Finder.
465
+
466
+ If you are able to, it helps even more if you can fork Trailblazer-Finder on Github,
467
+ and add a test that reproduces the error you are experiencing.
468
+
469
+ For more info on how to report bugs, please see [this article](http://yourbugreportneedsmore.info/).
470
+
471
+ ## License
472
+ Copyright (c) 2018 Trailblazer GmbH and contributors, released under the MIT
473
+ license.
474
+
475
+ MIT License
476
+
477
+ Permission is hereby granted, free of charge, to any person obtaining
478
+ a copy of this software and associated documentation files (the
479
+ "Software"), to deal in the Software without restriction, including
480
+ without limitation the rights to use, copy, modify, merge, publish,
481
+ distribute, sublicense, and/or sell copies of the Software, and to
482
+ permit persons to whom the Software is furnished to do so, subject to
483
+ the following conditions:
484
+
485
+ The above copyright notice and this permission notice shall be
486
+ included in all copies or substantial portions of the Software.
487
+
488
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
489
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
490
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
491
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
492
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
493
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
494
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.