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
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
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
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
|
+
[](https://gitter.im/trailblazer/chat) [](https://travis-ci.org/trailblazer/trailblazer-finder) [](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.
|