filterameter 1.0.3 → 1.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 +4 -4
- data/README.md +15 -0
- data/lib/filterameter/declarative_filters.rb +2 -2
- data/lib/filterameter/filter_declaration.rb +3 -2
- data/lib/filterameter/filter_factory.rb +16 -10
- data/lib/filterameter/filters/arel_filter.rb +2 -1
- data/lib/filterameter/filters/attribute_filter.rb +3 -1
- data/lib/filterameter/filters/conditional_scope_filter.rb +3 -1
- data/lib/filterameter/filters/matches_filter.rb +3 -1
- data/lib/filterameter/filters/maximum_filter.rb +1 -0
- data/lib/filterameter/filters/minimum_filter.rb +1 -0
- data/lib/filterameter/filters/scope_filter.rb +3 -1
- data/lib/filterameter/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 02daf1402e83a27c8b13ed7e548dfe269b7a1e6c7c5085f9aad2220509793253
|
|
4
|
+
data.tar.gz: 1ddcce714232b71be40272ac3e84f116e38af380928407936a082ade5395c743
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b33c74905694f9a1682a4c7faefb6e11cbeff81a7c2bae32dd3a39f25393d50a7eb86fc766825f9296c2ce19440aed296eab17bebfd6f1eac77a41aa749dbeeb
|
|
7
|
+
data.tar.gz: 36f85f875a0c15258988cbbf97062caa75e1e47de1142484eaa96b8bae7f757d5a94e5fd5ac07b2137db7f1d8cb146adb76b3d6aa2849ad3507707e22b87b783
|
data/README.md
CHANGED
|
@@ -42,6 +42,7 @@ Simplify and speed development of Rails controllers by making filter parameters
|
|
|
42
42
|
- [Partial](#partial)
|
|
43
43
|
- [Range](#range)
|
|
44
44
|
- [Sortable](#sortable)
|
|
45
|
+
- [Converters](#converters)
|
|
45
46
|
- [Scope Filters](#scope-filters)
|
|
46
47
|
- [Sorting](#sorting)
|
|
47
48
|
- [Building the Query](#building-the-query)
|
|
@@ -82,6 +83,9 @@ Include module `Filterameter::DeclarativeFilters` in the controller to provide t
|
|
|
82
83
|
filter :brand_name, association: :brand, name: :name
|
|
83
84
|
filter :on_sale, association: :price, validates: [{ numericality: { greater_than: 0 } },
|
|
84
85
|
{ numericality: { less_than: 100 } }]
|
|
86
|
+
filter :amount do |value|
|
|
87
|
+
value.is_a?(String) ? value.delete(",") : value
|
|
88
|
+
end
|
|
85
89
|
```
|
|
86
90
|
|
|
87
91
|
Filters without options can be declared all at once with `filters`:
|
|
@@ -185,6 +189,17 @@ The following filters are not sortable:
|
|
|
185
189
|
- scope filters (see [_Sorting with a Scope_](#sorting-with-a-scope))
|
|
186
190
|
- filters with collection associations
|
|
187
191
|
|
|
192
|
+
#### Converters
|
|
193
|
+
|
|
194
|
+
If the filter value needs to be converted before being applied to the query, a converter block can be provided. The block should take the parameter value as an argument and return the converted value.
|
|
195
|
+
|
|
196
|
+
For example, if the amount filter should remove commas from the value before applying it to the query, the declaration would look like this:
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
filter :amount do |value|
|
|
200
|
+
value.is_a?(String) ? value.delete(",") : value
|
|
201
|
+
end
|
|
202
|
+
```
|
|
188
203
|
|
|
189
204
|
### Scope Filters
|
|
190
205
|
|
|
@@ -61,8 +61,8 @@ module Filterameter
|
|
|
61
61
|
# filter :department_name, partial: :from_start
|
|
62
62
|
# filter :reason, partial: { match: :dynamic, case_sensitive: true }
|
|
63
63
|
# filter :price, range: true
|
|
64
|
-
def filter(name, options = {})
|
|
65
|
-
filter_coordinator.add_filter(name, options)
|
|
64
|
+
def filter(name, options = {}, &converter)
|
|
65
|
+
filter_coordinator.add_filter(name, options.merge(converter:))
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
# Declares a list of filters without options. Filters that require options must be declared with `filter`.
|
|
@@ -16,7 +16,7 @@ module Filterameter
|
|
|
16
16
|
class FilterDeclaration
|
|
17
17
|
VALID_RANGE_OPTIONS = [true, :min_only, :max_only].freeze
|
|
18
18
|
|
|
19
|
-
attr_reader :name, :parameter_name, :association, :validations
|
|
19
|
+
attr_reader :name, :parameter_name, :association, :validations, :converter
|
|
20
20
|
|
|
21
21
|
def initialize(parameter_name, options, range_type: nil)
|
|
22
22
|
@parameter_name = parameter_name.to_s
|
|
@@ -29,6 +29,7 @@ module Filterameter
|
|
|
29
29
|
@raw_range = options[:range]
|
|
30
30
|
@range_type = range_type
|
|
31
31
|
@sortable = options.fetch(:sortable, true)
|
|
32
|
+
@converter = options[:converter]
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
def nested?
|
|
@@ -88,7 +89,7 @@ module Filterameter
|
|
|
88
89
|
private
|
|
89
90
|
|
|
90
91
|
def validate_options(options)
|
|
91
|
-
options.assert_valid_keys(:name, :association, :validates, :partial, :range, :sortable)
|
|
92
|
+
options.assert_valid_keys(:name, :association, :validates, :partial, :range, :sortable, :converter)
|
|
92
93
|
validate_range(options[:range]) if options.key?(:range)
|
|
93
94
|
end
|
|
94
95
|
|
|
@@ -15,7 +15,7 @@ module Filterameter
|
|
|
15
15
|
if declaration.nested?
|
|
16
16
|
build_nested_filter(declaration, context)
|
|
17
17
|
else
|
|
18
|
-
|
|
18
|
+
build_filter_or_scope_filter(@model_class, declaration, context.scope?)
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
@@ -23,23 +23,29 @@ module Filterameter
|
|
|
23
23
|
|
|
24
24
|
def build_nested_filter(declaration, context)
|
|
25
25
|
model = context.model_from_association
|
|
26
|
-
filter =
|
|
26
|
+
filter = build_filter_or_scope_filter(model, declaration, context.scope?)
|
|
27
27
|
nested_filter_class = context.any_collections? ? Filters::NestedCollectionFilter : Filters::NestedFilter
|
|
28
28
|
|
|
29
29
|
nested_filter_class.new(declaration.association, model, filter)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
def
|
|
32
|
+
def build_filter_or_scope_filter(model, declaration, declaration_is_a_scope)
|
|
33
33
|
if declaration_is_a_scope
|
|
34
34
|
build_scope_filter(model, declaration)
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
else
|
|
36
|
+
build_filter(model, declaration)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def build_filter(model, declaration)
|
|
41
|
+
if declaration.partial_search?
|
|
42
|
+
Filterameter::Filters::MatchesFilter.new(declaration.name, declaration.partial_options, &declaration.converter)
|
|
37
43
|
elsif declaration.minimum_range?
|
|
38
|
-
Filterameter::Filters::MinimumFilter.new(model, declaration.name)
|
|
44
|
+
Filterameter::Filters::MinimumFilter.new(model, declaration.name, &declaration.converter)
|
|
39
45
|
elsif declaration.maximum_range?
|
|
40
|
-
Filterameter::Filters::MaximumFilter.new(model, declaration.name)
|
|
46
|
+
Filterameter::Filters::MaximumFilter.new(model, declaration.name, &declaration.converter)
|
|
41
47
|
else
|
|
42
|
-
Filterameter::Filters::AttributeFilter.new(declaration.name)
|
|
48
|
+
Filterameter::Filters::AttributeFilter.new(declaration.name, &declaration.converter)
|
|
43
49
|
end
|
|
44
50
|
end
|
|
45
51
|
|
|
@@ -48,9 +54,9 @@ module Filterameter
|
|
|
48
54
|
def build_scope_filter(model, declaration)
|
|
49
55
|
number_of_arguments = model.method(declaration.name).arity
|
|
50
56
|
if number_of_arguments < 1
|
|
51
|
-
Filterameter::Filters::ConditionalScopeFilter.new(declaration.name)
|
|
57
|
+
Filterameter::Filters::ConditionalScopeFilter.new(declaration.name, &declaration.converter)
|
|
52
58
|
elsif number_of_arguments == 1
|
|
53
|
-
Filterameter::Filters::ScopeFilter.new(declaration.name)
|
|
59
|
+
Filterameter::Filters::ScopeFilter.new(declaration.name, &declaration.converter)
|
|
54
60
|
else
|
|
55
61
|
raise Filterameter::DeclarationErrors::FilterScopeArgumentError.new(model.name, declaration.name)
|
|
56
62
|
end
|
|
@@ -10,9 +10,10 @@ module Filterameter
|
|
|
10
10
|
include Filterameter::Errors
|
|
11
11
|
include Filterameter::Filters::AttributeValidator
|
|
12
12
|
|
|
13
|
-
def initialize(model, attribute_name)
|
|
13
|
+
def initialize(model, attribute_name, &converter)
|
|
14
14
|
@attribute_name = attribute_name
|
|
15
15
|
@arel_attribute = model.arel_table[attribute_name]
|
|
16
|
+
@converter = converter
|
|
16
17
|
end
|
|
17
18
|
end
|
|
18
19
|
end
|
|
@@ -9,11 +9,13 @@ module Filterameter
|
|
|
9
9
|
include Filterameter::Errors
|
|
10
10
|
include AttributeValidator
|
|
11
11
|
|
|
12
|
-
def initialize(attribute_name)
|
|
12
|
+
def initialize(attribute_name, &converter)
|
|
13
13
|
@attribute_name = attribute_name
|
|
14
|
+
@converter = converter
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def apply(query, value)
|
|
18
|
+
value = @converter.call(value) if @converter
|
|
17
19
|
query.where(@attribute_name => value)
|
|
18
20
|
end
|
|
19
21
|
end
|
|
@@ -8,11 +8,13 @@ module Filterameter
|
|
|
8
8
|
class ConditionalScopeFilter
|
|
9
9
|
include Filterameter::Errors
|
|
10
10
|
|
|
11
|
-
def initialize(scope_name)
|
|
11
|
+
def initialize(scope_name, &converter)
|
|
12
12
|
@scope_name = scope_name
|
|
13
|
+
@converter = converter
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
def apply(query, value)
|
|
17
|
+
value = @converter.call(value) if @converter
|
|
16
18
|
return query unless ActiveModel::Type::Boolean.new.cast(value)
|
|
17
19
|
|
|
18
20
|
query.public_send(@scope_name)
|
|
@@ -9,14 +9,16 @@ module Filterameter
|
|
|
9
9
|
include Filterameter::Errors
|
|
10
10
|
include Filterameter::Filters::AttributeValidator
|
|
11
11
|
|
|
12
|
-
def initialize(attribute_name, options)
|
|
12
|
+
def initialize(attribute_name, options, &converter)
|
|
13
13
|
@attribute_name = attribute_name
|
|
14
14
|
@prefix = options.match_anywhere? ? '%' : nil
|
|
15
15
|
@suffix = options.match_anywhere? || options.match_from_start? ? '%' : nil
|
|
16
16
|
@case_sensitive = options.case_sensitive?
|
|
17
|
+
@converter = converter
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
def apply(query, value)
|
|
21
|
+
value = @converter.call(value) if @converter
|
|
20
22
|
arel = query.arel_table[@attribute_name].matches("#{@prefix}#{value}#{@suffix}", false, @case_sensitive)
|
|
21
23
|
query.where(arel)
|
|
22
24
|
end
|
|
@@ -7,6 +7,7 @@ module Filterameter
|
|
|
7
7
|
# Class MaximumFilter adds criteria for all values greater than or equal to a maximum.
|
|
8
8
|
class MaximumFilter < ArelFilter
|
|
9
9
|
def apply(query, value)
|
|
10
|
+
value = @converter.call(value) if @converter
|
|
10
11
|
query.where(@arel_attribute.lteq(value))
|
|
11
12
|
end
|
|
12
13
|
end
|
|
@@ -7,6 +7,7 @@ module Filterameter
|
|
|
7
7
|
# Class MinimumFilter adds criteria for all values greater than or equal to a minimum.
|
|
8
8
|
class MinimumFilter < ArelFilter
|
|
9
9
|
def apply(query, value)
|
|
10
|
+
value = @converter.call(value) if @converter
|
|
10
11
|
query.where(@arel_attribute.gteq(value))
|
|
11
12
|
end
|
|
12
13
|
end
|
|
@@ -8,11 +8,13 @@ module Filterameter
|
|
|
8
8
|
class ScopeFilter
|
|
9
9
|
include Filterameter::Errors
|
|
10
10
|
|
|
11
|
-
def initialize(scope_name)
|
|
11
|
+
def initialize(scope_name, &converter)
|
|
12
12
|
@scope_name = scope_name
|
|
13
|
+
@converter = converter
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
def apply(query, value)
|
|
17
|
+
value = @converter.call(value) if @converter
|
|
16
18
|
query.public_send(@scope_name, value)
|
|
17
19
|
end
|
|
18
20
|
|
data/lib/filterameter/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: filterameter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Todd Kummer
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-06-19 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: rails
|
|
@@ -196,7 +196,8 @@ files:
|
|
|
196
196
|
homepage: https://github.com/RockSolt/filterameter
|
|
197
197
|
licenses:
|
|
198
198
|
- MIT
|
|
199
|
-
metadata:
|
|
199
|
+
metadata:
|
|
200
|
+
rubygems_mfa_required: 'true'
|
|
200
201
|
rdoc_options: []
|
|
201
202
|
require_paths:
|
|
202
203
|
- lib
|