trailblazer-finder 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![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.
|