ClassyFilter

ClassyFilter is a customizeable class-based filtering library. Currently it's only build for Sequel, but there are plans to expand!

Installation

Add this line to your application's Gemfile:

gem 'classy_filter'

And then execute:

$ bundle

Or install it yourself as:

$ gem install classy_filter

Usage

Writing a filter

To begin using this gem, you must first define your filter class, deriving it from ClassyFilter::Base. In this class, you'd specify your filter fields, extra predicates and coercions (should you need those).

Let's begin with an example. Assuming you have a table named people with this structure:

name type
first_name varchar(1023)
last_name varchar(1023)
date_of_birth date
trust_level integer

You could write a filter like this:

class MyFilter < ClassyFilter::Base
  filter_field :first_name # (1)
  filter_field :last_name_prefix, attribute: :last_name, predicate: :starts_with_i # (2)
  filter_field :dob_after, attribute: :date_of_birth, predicate: :gteq, coercion: :integer # (3)
  filter_field :rough_trust, attribute: :trust_level, predicate: :gt_10x, coercion: :integer # (4)

  predicate :gt_10x, ->(dataset, attr, input) { dataset.where { |r| Sequel[attr] > input } } # (5)
end

Let's walk through this filter line by line.

Line (1) shows us how to define a very basic filter. This definition lets our filter accept the first_name parameter and perform simple filtering by equality or inclusion.

Line (2) shows us how to define a filter with a custom predicate and parameter name. Our filter will accept the last_name_prefix parameter and filter by the last_name column, using ILIKE to do it.

Line (3) shows us how to define a filter not just with a custom predicate, but also with a coercion. Before performing the filtering, our filter will attempt to coerce the dob_after parameter into an Integer.

Line (5) shows us a custom predicate (that's used on the line (4)). A predicate is defined using the ClassyFilter::Base.predicate method that accepts the predicate name and a proc that receives the dataset, the attribute name and the parameter value.

You can see all existing predicates here and all existing coercions here.

Performing the filtering

This one is actually quite easy. Assuming we have a database named DB and receive a hash named params from somewhere (say, the URL query string), we can use our filter as follows:

ds = DB[:people]
MyFilter.new(params).call(ds)

Development

After checking out the repo, run bundle install to install dependencies. Then, run rake spec to run the tests. You can also run pry -rclassy_filter for an interactive prompt that will allow you to experiment.

TODO

❗ Add collection (array/hash) coercions
❗ Move the Sequel implementation out of the gem
⬜ Try to find out a way to simplify predicates definitions
⬜ More tests. Never enough tests.
❓ Add a better coercion library. Dry-rb? Or maybe Hashie?

Contributing

Bug reports and pull requests are welcome on GitLab at https://gitlab.com/art-solopov/classy_filter.