Class: Rack::Reducer

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/reducer.rb,
lib/rack/reducer/version.rb,
lib/rack/reducer/middleware.rb,
lib/rack/reducer/refinements.rb

Overview

Declaratively filter data via URL params, in any Rack app, with any ORM.

Defined Under Namespace

Classes: Middleware

Constant Summary collapse

VERSION =
'2.0.3'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dataset, *filters) ⇒ Reducer

Instantiate a Reducer that can filter ‘dataset` via `#apply`.

Examples:

Create a reducer and use it in a Sinatra app

DB = Sequel.connect(ENV['DATABASE_URL'])

MyReducer = Rack::Reducer.new(
  DB[:artists],
  lambda { |name:| where(name: name) },
  lambda { |genre:| where(genre: genre) },
)

get '/artists' do
  @artists = MyReducer.apply(params)
  @artists.to_json
end

Parameters:

  • dataset (Object)

    an ActiveRecord::Relation, Sequel::Dataset, or other class with chainable methods

  • filters (Array<Proc>)

    An array of lambdas whose keyword arguments name the URL params you will use as filters



39
40
41
42
43
44
45
# File 'lib/rack/reducer.rb', line 39

def initialize(dataset, *filters)
  @dataset = dataset
  @filters = filters
  @default_filters = filters.select do |filter|
    filter.required_argument_names.empty?
  end
end

Class Method Details

.call(params, dataset:, filters:) ⇒ Object

Call Rack::Reducer as a function instead of creating a named reducer



16
17
18
# File 'lib/rack/reducer.rb', line 16

def call(params, dataset:, filters:)
  new(dataset, *filters).apply(params)
end

Instance Method Details

#apply(url_params) ⇒ Object

Run ‘@filters` against `url_params`

Parameters:

  • url_params (Hash, ActionController::Parameters, nil)

    a Rack-compatible params hash

Returns:

  • ‘@dataset` with the matching filters applied



51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/rack/reducer.rb', line 51

def apply(url_params)
  if url_params.empty?
    # Return early with the unfiltered dataset if no default filters exist
    return fresh_dataset if @default_filters.empty?

    # Run only the default filters
    filters, params = @default_filters, EMPTY_PARAMS
  else
    # This request really does want filtering; run a full reduction
    filters, params = @filters, url_params.to_unsafe_h.deep_symbolize_keys
  end

  reduce(params, filters)
end