Skip to content

Commit c974218

Browse files
author
Ivan Tyurin
committed
Add dataset filter methods
1 parent fc76152 commit c974218

4 files changed

Lines changed: 199 additions & 20 deletions

File tree

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,34 @@ item.created? # => true
106106
item.selected? # => false
107107
```
108108

109+
### Filter methods
110+
111+
Plugin can define dataset methods for all enum values:
112+
113+
```ruby
114+
Item.plugin :enum_values, filter_methods: true # default is `false`
115+
116+
Item.dataset.type_first # => #<Sequel::Dataset: "SELECT * FROM \"items\" WHERE (\"type\" = 'first')">
117+
Item.dataset.type_second # => #<Sequel::Dataset: "SELECT * FROM \"items\" WHERE (\"type\" = 'second')">
118+
119+
Item.status_created # => #<Sequel::Dataset: "SELECT * FROM \"items\" WHERE (\"status\" = 'created')">
120+
Item.status_selected # => #<Sequel::Dataset: "SELECT * FROM \"items\" WHERE (\"status\" = 'selected')">
121+
```
122+
123+
Or just for specific fields:
124+
125+
```ruby
126+
Item.plugin :enum_values, filter_methods: %i[status]
127+
# or just `:status` for single value
128+
129+
item = Item.new(type: 'first', status: 'created')
130+
131+
Item.dataset.type_first # => NoMethodError
132+
133+
Item.status_created # => #<Sequel::Dataset: "SELECT * FROM \"items\" WHERE (\"status\" = 'created')">
134+
Item.status_selected # => #<Sequel::Dataset: "SELECT * FROM \"items\" WHERE (\"status\" = 'selected')">
135+
```
136+
109137
## Development
110138

111139
After checking out the repo, run `bundle install` to install dependencies.

lib/sequel/plugins/enum_values.rb

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ def self.apply(model, _options = {})
2323
## @option options [Boolean, Symbol, Array<Symbol>]
2424
## predicate_methods (false)
2525
## enum fields for which predicate methods will be defined
26+
## @option options [Boolean, Symbol, Array<Symbol>]
27+
## filter_methods (false)
28+
## enum fields for which dataset filter methods will be defined
2629
## @example Disable caching
2730
## Item.plugin :enum_values, caching: false
2831
## @example Define predicate methods for all enum fields
@@ -31,18 +34,18 @@ def self.apply(model, _options = {})
3134
## Item.plugin :enum_values, predicate_methods: %[status type]
3235
## @example Define predicate methods for specific enum field
3336
## Item.plugin :enum_values, predicate_methods: :status
37+
## @example Define filter methods for all enum fields
38+
## Item.plugin :enum_values, filter_methods: true
39+
## @example Define filter methods for specific enum field
40+
## Item.plugin :enum_values, filter_methods: :status
41+
## @example Define filter methods for specific enum fields
42+
## Item.plugin :enum_values, filter_methods: %[status type]
3443
def self.configure(model, options = {})
3544
model.instance_exec do
45+
@enum_values_options = options
3646
@enum_values_caching = options.fetch(:caching, @enum_values_caching)
3747

38-
predicate_methods = options.fetch(:predicate_methods, false)
39-
40-
transform_predicate_methods_to_enum_fields(predicate_methods)
41-
.each do |field|
42-
all_enum_fields[field][:enum_values].each do |enum_value|
43-
define_predicate_method field, enum_value
44-
end
45-
end
48+
process_enum_values_options
4649
end
4750
end
4851

@@ -68,20 +71,24 @@ def enum_values(field)
6871

6972
private
7073

71-
def transform_predicate_methods_to_enum_fields(predicate_methods)
72-
case predicate_methods
73-
when TrueClass
74-
all_enum_fields.keys
75-
when FalseClass
76-
[]
77-
else
78-
Array(predicate_methods)
74+
def process_enum_values_options
75+
process_enum_values_option(:filter_methods) do |field, value|
76+
dataset_module { where "#{field}_#{value}", field => value }
77+
end
78+
79+
process_enum_values_option(:predicate_methods) do |field, value|
80+
define_method("#{value}?", -> { public_send(field) == value })
7981
end
8082
end
8183

82-
def define_predicate_method(field, enum_value)
83-
define_method "#{enum_value}?" do
84-
public_send(field) == enum_value
84+
def process_enum_values_option(key)
85+
return unless block_given? && (option = @enum_values_options[key])
86+
87+
enum_fields = all_enum_fields
88+
enum_fields = enum_fields.slice(*Array(option)) unless option == true
89+
90+
enum_fields.each do |field, field_schema|
91+
field_schema[:enum_values].each { |value| yield field, value }
8592
end
8693
end
8794

sequel-enum_values.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ Gem::Specification.new do |spec|
4545
spec.add_development_dependency 'rspec', '~> 3.9'
4646
spec.add_development_dependency 'simplecov', '~> 0.18.0'
4747

48-
spec.add_development_dependency 'rubocop', '~> 0.88.0'
48+
spec.add_development_dependency 'rubocop', '~> 0.89.0'
4949
spec.add_development_dependency 'rubocop-performance', '~> 1.0'
5050
spec.add_development_dependency 'rubocop-rspec', '~> 1.0'
5151
end

spec/sequel/plugins/enum_values_spec.rb

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,150 @@
227227
-> { expect { subject }.to raise_error(NoMethodError) }
228228
end
229229
end
230+
231+
shared_context('with filter_methods environment') do
232+
subject(:enum_filter) { item_class.public_send(enum_value) }
233+
234+
def filter_sql(column, value)
235+
"SELECT * FROM \"items\" WHERE (\"#{column}\" = '#{value}')"
236+
end
237+
end
238+
239+
shared_context('with filter_methods option') do |value|
240+
before do
241+
item_class.plugin :enum_values, filter_methods: value
242+
end
243+
end
244+
245+
describe 'filter_methods default option' do
246+
before { item_class.plugin :enum_values }
247+
248+
include_context('with filter_methods environment')
249+
250+
type_enum_values.each do |filter_method_name|
251+
describe filter_method_name do
252+
let(:enum_value) { "type_#{filter_method_name}" }
253+
254+
it { expect { enum_filter }.to raise_error(NoMethodError) }
255+
end
256+
end
257+
258+
status_enum_values.each do |filter_method_name|
259+
describe filter_method_name do
260+
let(:enum_value) { "status_#{filter_method_name}" }
261+
262+
it { expect { enum_filter }.to raise_error(NoMethodError) }
263+
end
264+
end
265+
end
266+
267+
describe 'filter_methods true option' do
268+
include_context('with filter_methods environment')
269+
include_context('with filter_methods option', true)
270+
271+
type_enum_values.each do |filter_method_name|
272+
describe filter_method_name do
273+
let(:enum_value) { "type_#{filter_method_name}" }
274+
275+
it { expect(enum_filter).to be_kind_of(Sequel::Dataset) }
276+
277+
it do
278+
expect(enum_filter.sql).to(
279+
eq filter_sql(:type, filter_method_name)
280+
)
281+
end
282+
end
283+
end
284+
285+
status_enum_values.each do |filter_method_name|
286+
describe filter_method_name do
287+
let(:enum_value) { "status_#{filter_method_name}" }
288+
289+
it { expect(enum_filter).to be_kind_of(Sequel::Dataset) }
290+
291+
it do
292+
expect(enum_filter.sql).to(
293+
eq filter_sql(:status, filter_method_name)
294+
)
295+
end
296+
end
297+
end
298+
end
299+
300+
describe 'filter_methods false option' do
301+
include_context('with filter_methods environment')
302+
include_context('with filter_methods option', false)
303+
304+
type_enum_values.each do |filter_method_name|
305+
describe filter_method_name do
306+
let(:enum_value) { "type_#{filter_method_name}" }
307+
308+
it { expect { enum_filter }.to raise_error(NoMethodError) }
309+
end
310+
end
311+
312+
status_enum_values.each do |filter_method_name|
313+
describe filter_method_name do
314+
let(:enum_value) { "status_#{filter_method_name}" }
315+
316+
it { expect { enum_filter }.to raise_error(NoMethodError) }
317+
end
318+
end
319+
end
320+
321+
describe 'filter_methods Array option' do
322+
include_context('with filter_methods environment')
323+
include_context('with filter_methods option', %i[status])
324+
325+
status_enum_values.each do |filter_method_name|
326+
describe filter_method_name do
327+
let(:enum_value) { "status_#{filter_method_name}" }
328+
329+
it { expect(enum_filter).to be_kind_of(Sequel::Dataset) }
330+
331+
it do
332+
expect(enum_filter.sql).to(
333+
eq filter_sql(:status, filter_method_name)
334+
)
335+
end
336+
end
337+
end
338+
339+
type_enum_values.each do |filter_method_name|
340+
describe filter_method_name do
341+
let(:enum_value) { "type_#{filter_method_name}" }
342+
343+
it { expect { enum_filter }.to raise_error(NoMethodError) }
344+
end
345+
end
346+
end
347+
348+
describe 'filter_methods Symbol option' do
349+
include_context('with filter_methods environment')
350+
include_context('with filter_methods option', :status)
351+
352+
status_enum_values.each do |filter_method_name|
353+
describe filter_method_name do
354+
let(:enum_value) { "status_#{filter_method_name}" }
355+
356+
it { expect(enum_filter).to be_kind_of(Sequel::Dataset) }
357+
358+
it do
359+
expect(enum_filter.sql).to(
360+
eq filter_sql(:status, filter_method_name)
361+
)
362+
end
363+
end
364+
end
365+
366+
type_enum_values.each do |filter_method_name|
367+
describe filter_method_name do
368+
let(:enum_value) { "type_#{filter_method_name}" }
369+
370+
it { expect { enum_filter }.to raise_error(NoMethodError) }
371+
end
372+
end
373+
end
230374
end
231375
end
232376
end

0 commit comments

Comments
 (0)