filterameter 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -34
- data/lib/filterameter/declarative_filters.rb +18 -8
- data/lib/filterameter/filter_coordinator.rb +60 -0
- data/lib/filterameter/filters/conditional_scope_filter.rb +1 -1
- data/lib/filterameter/filters/scope_filter.rb +1 -1
- data/lib/filterameter/version.rb +1 -1
- metadata +3 -6
- data/lib/filterameter/coordinators/base.rb +0 -36
- data/lib/filterameter/coordinators/controller_coordinator.rb +0 -40
- data/lib/filterameter/coordinators/query_coordinator.rb +0 -18
- data/lib/filterameter/declarative_controller_filters.rb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f44f6d30fd92e15bc7652df41d75e2d620740fb19f146cbb253274460c3686f2
|
4
|
+
data.tar.gz: 84109580ba0079787e3bcc0e20054a71c2eb2ae7efc512d511124172f19c69fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b8606c20e87f96b25876da9b670f555b1c95b40bc5fa13368174d1e4264ea1a535a93ea714111171710de12e301876aa59081f327a9cbd8e4f5a6735f2c0406
|
7
|
+
data.tar.gz: 1f848be8b42e68845cebaabadd04b0e9019dab54d9cfdfa2628048215cb6ed5c5e37360fa99a473208cf4539a5963a065f0790a75ecc5d795e45037ae35f7347
|
data/README.md
CHANGED
@@ -4,10 +4,10 @@
|
|
4
4
|
[![Maintainability](https://api.codeclimate.com/v1/badges/d9d87f9ce8020eb6e656/maintainability)](https://codeclimate.com/github/RockSolt/filterameter/maintainability)
|
5
5
|
|
6
6
|
# Filterameter
|
7
|
-
Declarative filter parameters provide clean and clear filters for
|
7
|
+
Declarative filter parameters provide clean and clear filters for Rails controllers.
|
8
8
|
|
9
9
|
## Usage
|
10
|
-
Declare filters in
|
10
|
+
Declare filters in controllers to increase readability and reduce boilerplate code. Filters can be declared for attributes, scopes, or attributes from singular associations (`belongs_to` or `has_one`). Validations can also be assigned.
|
11
11
|
|
12
12
|
```ruby
|
13
13
|
filter :color
|
@@ -85,39 +85,9 @@ filter :sale_price, range: :max_only
|
|
85
85
|
|
86
86
|
In the first example, query parameters could include <tt>price</tt>, <tt>price_min</tt>, and <tt>price_max</tt>.
|
87
87
|
|
88
|
-
### Query Classes
|
89
|
-
|
90
|
-
Include module `Filterameter::DeclarativeFilters` in the query class. The model must be declared using `model`, and a default query can optionally be declared using `default_query`. If no default query is provided, then the default is `.all`.
|
91
|
-
|
92
|
-
#### Example
|
93
|
-
|
94
|
-
Here's what a query class for the Widgets model with filters on size and color might look like:
|
95
|
-
|
96
|
-
```ruby
|
97
|
-
class WidgetQuery
|
98
|
-
include Filterameter::DeclarativeFilters
|
99
|
-
|
100
|
-
model Widget
|
101
|
-
filter :size
|
102
|
-
filter :color
|
103
|
-
end
|
104
|
-
```
|
105
|
-
|
106
|
-
Build the query using class method `build_query`. The method takes two parameters:
|
107
|
-
|
108
|
-
- filter: the hash of filter parameters
|
109
|
-
- starting_query: any scope to build on (if not provided, the default query is the starting point)
|
110
|
-
|
111
|
-
Here's how the query might be invoked:
|
112
|
-
|
113
|
-
```ruby
|
114
|
-
filters = { size: 'large', color: 'blue' }
|
115
|
-
widgets = WidgetQuery.build_query(filters, Widget.limit(10))
|
116
|
-
```
|
117
|
-
|
118
88
|
### Controllers
|
119
89
|
|
120
|
-
Include module `Filterameter::
|
90
|
+
Include module `Filterameter::DeclarativeFilters` in the controller. Add before action callback `build_filtered_query` for controller actions that should build the query.
|
121
91
|
|
122
92
|
Rails conventions are used to determine the controller's model as well as the name of the instance variable to apply the filters to. For example, the PhotosController will use the variable `@photos` to store a query against the Photo model. **If the conventions do not provide the correct info**, they can be overridden with the following two methods:
|
123
93
|
|
@@ -141,7 +111,7 @@ In the happy path, the WidgetsController serves Widgets and can filter on size a
|
|
141
111
|
|
142
112
|
```ruby
|
143
113
|
class WidgetController < ApplicationController
|
144
|
-
include Filterameter::
|
114
|
+
include Filterameter::DeclarativeFilters
|
145
115
|
before_action :build_filtered_query, only: :index
|
146
116
|
|
147
117
|
filter :size
|
@@ -1,27 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Filterameter
|
4
|
-
# = Declarative Filters
|
4
|
+
# = Declarative Controller Filters
|
5
5
|
#
|
6
|
-
# Mixin DeclarativeFilters
|
6
|
+
# Mixin DeclarativeFilters can included in controllers to enable the filter DSL.
|
7
7
|
module DeclarativeFilters
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
include Filterameter::Filterable
|
10
10
|
|
11
11
|
class_methods do
|
12
|
-
|
13
|
-
|
14
|
-
def model(model_class)
|
12
|
+
def filter_model(model_class, query_var_name = nil)
|
15
13
|
filter_coordinator.model_class = model_class
|
14
|
+
filter_query_var_name(query_var_name) if query_var_name.present?
|
16
15
|
end
|
17
16
|
|
18
|
-
def
|
19
|
-
filter_coordinator.
|
17
|
+
def filter_query_var_name(query_variable_name)
|
18
|
+
filter_coordinator.query_variable_name = query_variable_name
|
20
19
|
end
|
21
20
|
|
22
21
|
def filter_coordinator
|
23
|
-
@filter_coordinator ||= Filterameter::
|
22
|
+
@filter_coordinator ||= Filterameter::FilterCoordinator.new(controller_name, controller_path)
|
24
23
|
end
|
25
24
|
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def build_filtered_query
|
29
|
+
var_name = "@#{self.class.filter_coordinator.query_variable_name}"
|
30
|
+
instance_variable_set(
|
31
|
+
var_name,
|
32
|
+
self.class.filter_coordinator.build_query(params.to_unsafe_h.fetch(:filter, {}),
|
33
|
+
instance_variable_get(var_name))
|
34
|
+
)
|
35
|
+
end
|
26
36
|
end
|
27
37
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/inflector'
|
4
|
+
|
5
|
+
require 'active_support/rails'
|
6
|
+
require 'action_dispatch'
|
7
|
+
require 'action_controller/metal/live'
|
8
|
+
require 'action_controller/metal/strong_parameters'
|
9
|
+
|
10
|
+
module Filterameter
|
11
|
+
# = Filter Coordinator
|
12
|
+
#
|
13
|
+
# Class FilterCoordinator stores the configuration declared via class-level method calls such as the list of
|
14
|
+
# filters and the optionally declared model class. Each controller will have one instance of the coordinator
|
15
|
+
# stored as a class variable.
|
16
|
+
#
|
17
|
+
# The coordinators encapsulate references to the Query Builder and Filter Registry to keep the namespace clean for
|
18
|
+
# controllers that implement filter parameters.
|
19
|
+
class FilterCoordinator
|
20
|
+
attr_writer :query_variable_name
|
21
|
+
|
22
|
+
delegate :add_filter, to: :registry
|
23
|
+
delegate :build_query, to: :query_builder
|
24
|
+
|
25
|
+
def initialize(controller_name, controller_path)
|
26
|
+
@controller_name = controller_name
|
27
|
+
@controller_path = controller_path
|
28
|
+
end
|
29
|
+
|
30
|
+
def model_class=(model_class)
|
31
|
+
@model_class = model_class.is_a?(String) ? model_class.constantize : model_class
|
32
|
+
end
|
33
|
+
|
34
|
+
def query_builder
|
35
|
+
@query_builder ||= Filterameter::QueryBuilder.new(default_query, registry)
|
36
|
+
end
|
37
|
+
|
38
|
+
def query_variable_name
|
39
|
+
@query_variable_name ||= model_class.model_name.plural
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def model_class
|
45
|
+
@model_class ||= @controller_name.classify.safe_constantize ||
|
46
|
+
@controller_path.classify.safe_constantize ||
|
47
|
+
raise(Filterameter::Exceptions::CannotDetermineModelError.new(@controller_name,
|
48
|
+
@controller_path))
|
49
|
+
end
|
50
|
+
|
51
|
+
def default_query
|
52
|
+
model_class.all
|
53
|
+
end
|
54
|
+
|
55
|
+
# lazy so that model_class can be optionally set
|
56
|
+
def registry
|
57
|
+
@registry ||= Filterameter::FilterRegistry.new(Filterameter::FilterFactory.new(model_class))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/filterameter/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: filterameter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Todd Kummer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-05-
|
11
|
+
date: 2024-05-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -175,15 +175,12 @@ files:
|
|
175
175
|
- Rakefile
|
176
176
|
- lib/filterameter.rb
|
177
177
|
- lib/filterameter/configuration.rb
|
178
|
-
- lib/filterameter/coordinators/base.rb
|
179
|
-
- lib/filterameter/coordinators/controller_coordinator.rb
|
180
|
-
- lib/filterameter/coordinators/query_coordinator.rb
|
181
|
-
- lib/filterameter/declarative_controller_filters.rb
|
182
178
|
- lib/filterameter/declarative_filters.rb
|
183
179
|
- lib/filterameter/exceptions.rb
|
184
180
|
- lib/filterameter/exceptions/cannot_determine_model_error.rb
|
185
181
|
- lib/filterameter/exceptions/undeclared_parameter_error.rb
|
186
182
|
- lib/filterameter/exceptions/validation_error.rb
|
183
|
+
- lib/filterameter/filter_coordinator.rb
|
187
184
|
- lib/filterameter/filter_declaration.rb
|
188
185
|
- lib/filterameter/filter_factory.rb
|
189
186
|
- lib/filterameter/filter_registry.rb
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Filterameter
|
4
|
-
module Coordinators
|
5
|
-
# = Coordinators Base
|
6
|
-
#
|
7
|
-
# The main responsibility of the Coordinators classes is to keep the namespace clean for controllers and query
|
8
|
-
# objects that implement filter parameters. The coordinators encapsulate references to the Query Builder and
|
9
|
-
# Filter Registry.
|
10
|
-
class Base
|
11
|
-
attr_reader :model_class
|
12
|
-
|
13
|
-
delegate :add_filter, to: :registry
|
14
|
-
delegate :build_query, to: :query_builder
|
15
|
-
|
16
|
-
def model_class=(model_class)
|
17
|
-
@model_class = model_class.is_a?(String) ? model_class.constantize : model_class
|
18
|
-
end
|
19
|
-
|
20
|
-
def query_builder
|
21
|
-
@query_builder ||= Filterameter::QueryBuilder.new(default_query, registry)
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def default_query
|
27
|
-
model_class.all
|
28
|
-
end
|
29
|
-
|
30
|
-
# lazy so that model_class can be optionally set
|
31
|
-
def registry
|
32
|
-
@registry ||= Filterameter::FilterRegistry.new(Filterameter::FilterFactory.new(model_class))
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/inflector'
|
4
|
-
|
5
|
-
require 'active_support/rails'
|
6
|
-
require 'action_dispatch'
|
7
|
-
require 'action_controller/metal/live'
|
8
|
-
require 'action_controller/metal/strong_parameters'
|
9
|
-
|
10
|
-
module Filterameter
|
11
|
-
module Coordinators
|
12
|
-
# = Controller Filters
|
13
|
-
#
|
14
|
-
# Class ControllerFilters stores the configuration declared via class-level method calls such as the list of
|
15
|
-
# filters and the optionally declared model class. Each controller will have one instance of the controller
|
16
|
-
# declarations stored as a class variable.
|
17
|
-
class ControllerCoordinator < Filterameter::Coordinators::Base
|
18
|
-
attr_writer :query_variable_name
|
19
|
-
|
20
|
-
def initialize(controller_name, controller_path)
|
21
|
-
@controller_name = controller_name
|
22
|
-
@controller_path = controller_path
|
23
|
-
super()
|
24
|
-
end
|
25
|
-
|
26
|
-
def query_variable_name
|
27
|
-
@query_variable_name ||= model_class.model_name.plural
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def model_class
|
33
|
-
@model_class ||= @controller_name.classify.safe_constantize ||
|
34
|
-
@controller_path.classify.safe_constantize ||
|
35
|
-
raise(Filterameter::Exceptions::CannotDetermineModelError.new(@controller_name,
|
36
|
-
@controller_path))
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Filterameter
|
4
|
-
module Coordinators
|
5
|
-
# = Query Coordinator
|
6
|
-
#
|
7
|
-
# Class QueryCoordinator coordinates the filter logic for query classes.
|
8
|
-
class QueryCoordinator < Filterameter::Coordinators::Base
|
9
|
-
attr_writer :default_query
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
def default_query
|
14
|
-
@default_query || super
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Filterameter
|
4
|
-
# = Declarative Controller Filters
|
5
|
-
#
|
6
|
-
# Mixin DeclarativeControllerFilters can included in controllers to enable the filter DSL.
|
7
|
-
module DeclarativeControllerFilters
|
8
|
-
extend ActiveSupport::Concern
|
9
|
-
include Filterameter::Filterable
|
10
|
-
|
11
|
-
class_methods do
|
12
|
-
def filter_model(model_class, query_var_name = nil)
|
13
|
-
filter_coordinator.model_class = model_class
|
14
|
-
filter_query_var_name(query_var_name) if query_var_name.present?
|
15
|
-
end
|
16
|
-
|
17
|
-
def filter_query_var_name(query_variable_name)
|
18
|
-
filter_coordinator.query_variable_name = query_variable_name
|
19
|
-
end
|
20
|
-
|
21
|
-
def filter_coordinator
|
22
|
-
@filter_coordinator ||= Filterameter::Coordinators::ControllerCoordinator.new(controller_name, controller_path)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def build_filtered_query
|
29
|
-
var_name = "@#{self.class.filter_coordinator.query_variable_name}"
|
30
|
-
instance_variable_set(
|
31
|
-
var_name,
|
32
|
-
self.class.filter_coordinator.build_query(params.to_unsafe_h.fetch(:filter, {}),
|
33
|
-
instance_variable_get(var_name))
|
34
|
-
)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|