rack-reducer 0.1.0 → 0.1.1

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +170 -104
  3. data/lib/rack/reducer/middleware.rb +24 -0
  4. data/lib/rack/reducer/reduction.rb +5 -17
  5. data/lib/rack/reducer.rb +7 -7
  6. data/spec/_hanami_example/apps/web/application.rb +326 -0
  7. data/spec/_hanami_example/apps/web/config/routes.rb +4 -0
  8. data/spec/_hanami_example/apps/web/controllers/artists/index.rb +12 -0
  9. data/spec/_hanami_example/apps/web/views/application_layout.rb +7 -0
  10. data/spec/_hanami_example/config/boot.rb +2 -0
  11. data/spec/_hanami_example/config/environment.rb +29 -0
  12. data/spec/_hanami_example/lib/hanami_example/entities/artist.rb +2 -0
  13. data/spec/_hanami_example/lib/hanami_example/repositories/artist_repository.rb +9 -0
  14. data/spec/_hanami_example/lib/hanami_example.rb +5 -0
  15. data/spec/{rails_example → _rails_example}/app/channels/application_cable/channel.rb +0 -0
  16. data/spec/{rails_example → _rails_example}/app/channels/application_cable/connection.rb +0 -0
  17. data/spec/{rails_example → _rails_example}/app/controllers/application_controller.rb +0 -0
  18. data/spec/_rails_example/app/controllers/artists_controller.rb +8 -0
  19. data/spec/{rails_example → _rails_example}/app/jobs/application_job.rb +0 -0
  20. data/spec/{rails_example → _rails_example}/app/mailers/application_mailer.rb +0 -0
  21. data/spec/{rails_example → _rails_example}/app/models/application_record.rb +0 -0
  22. data/spec/_rails_example/app/models/rails_example/artist.rb +20 -0
  23. data/spec/{rails_example → _rails_example}/config/application.rb +0 -0
  24. data/spec/{rails_example → _rails_example}/config/boot.rb +0 -0
  25. data/spec/{rails_example → _rails_example}/config/environment.rb +0 -0
  26. data/spec/{rails_example → _rails_example}/config/environments/development.rb +0 -0
  27. data/spec/{rails_example → _rails_example}/config/environments/production.rb +0 -0
  28. data/spec/{rails_example → _rails_example}/config/environments/test.rb +0 -0
  29. data/spec/{rails_example → _rails_example}/config/initializers/application_controller_renderer.rb +0 -0
  30. data/spec/{rails_example → _rails_example}/config/initializers/backtrace_silencers.rb +0 -0
  31. data/spec/{rails_example → _rails_example}/config/initializers/cors.rb +0 -0
  32. data/spec/{rails_example → _rails_example}/config/initializers/filter_parameter_logging.rb +0 -0
  33. data/spec/{rails_example → _rails_example}/config/initializers/inflections.rb +0 -0
  34. data/spec/{rails_example → _rails_example}/config/initializers/mime_types.rb +0 -0
  35. data/spec/{rails_example → _rails_example}/config/initializers/wrap_parameters.rb +0 -0
  36. data/spec/{rails_example → _rails_example}/config/puma.rb +0 -0
  37. data/spec/{rails_example → _rails_example}/config/routes.rb +0 -0
  38. data/spec/{rails_example → _rails_example}/db/seeds.rb +0 -0
  39. data/spec/behavior.rb +2 -2
  40. data/spec/hanami_spec.rb +6 -0
  41. data/spec/middleware_spec.rb +16 -8
  42. data/spec/rails_spec.rb +1 -2
  43. data/spec/roda_spec.rb +15 -0
  44. data/spec/sinatra_functional_spec.rb +3 -9
  45. data/spec/sinatra_mixin_spec.rb +0 -2
  46. data/spec/spec_helper.rb +12 -1
  47. metadata +121 -62
  48. data/spec/fixtures.rb +0 -19
  49. data/spec/rails_example/app/controllers/artists_controller.rb +0 -53
  50. data/spec/rails_example/app/models/artist.rb +0 -18
  51. data/spec/rails_example/config/initializers/schema.rb +0 -13
  52. data/spec/rails_example/test/test_helper.rb +0 -10
@@ -0,0 +1,326 @@
1
+ require 'hanami/helpers'
2
+ require 'hanami/assets'
3
+
4
+ module Web
5
+ class Application < Hanami::Application
6
+ configure do
7
+ ##
8
+ # BASIC
9
+ #
10
+
11
+ # Define the root path of this application.
12
+ # All paths specified in this configuration are relative to path below.
13
+ #
14
+ root __dir__
15
+
16
+ # Relative load paths where this application will recursively load the
17
+ # code.
18
+ #
19
+ # When you add new directories, remember to add them here.
20
+ #
21
+ load_paths << [
22
+ 'controllers',
23
+ 'views'
24
+ ]
25
+
26
+ # Handle exceptions with HTTP statuses (true) or don't catch them (false).
27
+ # Defaults to true.
28
+ # See: http://www.rubydoc.info/gems/hanami-controller/#Exceptions_management
29
+ #
30
+ # handle_exceptions true
31
+
32
+ ##
33
+ # HTTP
34
+ #
35
+
36
+ # Routes definitions for this application
37
+ # See: http://www.rubydoc.info/gems/hanami-router#Usage
38
+ #
39
+ routes 'config/routes'
40
+
41
+ # URI scheme used by the routing system to generate absolute URLs
42
+ # Defaults to "http"
43
+ #
44
+ # scheme 'https'
45
+
46
+ # URI host used by the routing system to generate absolute URLs
47
+ # Defaults to "localhost"
48
+ #
49
+ # host 'example.org'
50
+
51
+ # URI port used by the routing system to generate absolute URLs
52
+ # Argument: An object coercible to integer, defaults to 80 if the scheme
53
+ # is http and 443 if it's https
54
+ #
55
+ # This should only be configured if app listens to non-standard ports
56
+ #
57
+ # port 443
58
+
59
+ # Enable cookies
60
+ # Argument: boolean to toggle the feature
61
+ # A Hash with options
62
+ #
63
+ # Options:
64
+ # :domain - The domain (String - nil by default, not required)
65
+ # :path - Restrict cookies to a relative URI
66
+ # (String - nil by default)
67
+ # :max_age - Cookies expiration expressed in seconds
68
+ # (Integer - nil by default)
69
+ # :secure - Restrict cookies to secure connections
70
+ # (Boolean - Automatically true when using HTTPS)
71
+ # See #scheme and #ssl?
72
+ # :httponly - Prevent JavaScript access (Boolean - true by default)
73
+ #
74
+ # cookies true
75
+ # or
76
+ # cookies max_age: 300
77
+
78
+ # Enable sessions
79
+ # Argument: Symbol the Rack session adapter
80
+ # A Hash with options
81
+ #
82
+ # See: http://www.rubydoc.info/gems/rack/Rack/Session/Cookie
83
+ #
84
+ # sessions :cookie, secret: ENV['WEB_SESSIONS_SECRET']
85
+
86
+ # Configure Rack middleware for this application
87
+ #
88
+ # middleware.use Rack::Protection
89
+
90
+ # Default format for the requests that don't specify an HTTP_ACCEPT header
91
+ # Argument: A symbol representation of a mime type, defaults to :html
92
+ #
93
+ default_request_format :json
94
+
95
+ # Default format for responses that don't consider the request format
96
+ # Argument: A symbol representation of a mime type, defaults to :html
97
+ #
98
+ default_response_format :json
99
+
100
+ # HTTP Body parsers
101
+ # Parse non GET responses body for a specific mime type
102
+ # Argument: Symbol, which represent the format of the mime type
103
+ # (only `:json` is supported)
104
+ # Object, the parser
105
+ #
106
+ # body_parsers :json
107
+
108
+ # When it's true and the router receives a non-encrypted request (http),
109
+ # it redirects to the secure equivalent (https). Disabled by default.
110
+ #
111
+ # force_ssl true
112
+
113
+ ##
114
+ # TEMPLATES
115
+ #
116
+
117
+ # The layout to be used by all views
118
+ #
119
+ layout :application # It will load Web::Views::ApplicationLayout
120
+
121
+ # The relative path to templates
122
+ #
123
+ templates 'templates'
124
+
125
+ ##
126
+ # ASSETS
127
+ #
128
+ assets do
129
+ # JavaScript compressor
130
+ #
131
+ # Supported engines:
132
+ #
133
+ # * :builtin
134
+ # * :uglifier
135
+ # * :yui
136
+ # * :closure
137
+ #
138
+ # See: http://hanamirb.org/guides/assets/compressors
139
+ #
140
+ # In order to skip JavaScript compression comment the following line
141
+ javascript_compressor :builtin
142
+
143
+ # Stylesheet compressor
144
+ #
145
+ # Supported engines:
146
+ #
147
+ # * :builtin
148
+ # * :yui
149
+ # * :sass
150
+ #
151
+ # See: http://hanamirb.org/guides/assets/compressors
152
+ #
153
+ # In order to skip stylesheet compression comment the following line
154
+ stylesheet_compressor :builtin
155
+
156
+ # Specify sources for assets
157
+ #
158
+ sources << [
159
+ 'assets'
160
+ ]
161
+ end
162
+
163
+ ##
164
+ # SECURITY
165
+ #
166
+
167
+ # X-Frame-Options is a HTTP header supported by modern browsers.
168
+ # It determines if a web page can or cannot be included via <frame> and
169
+ # <iframe> tags by untrusted domains.
170
+ #
171
+ # Web applications can send this header to prevent Clickjacking attacks.
172
+ #
173
+ # Read more at:
174
+ #
175
+ # * https://developer.mozilla.org/en-US/docs/Web/HTTP/X-Frame-Options
176
+ # * https://www.owasp.org/index.php/Clickjacking
177
+ #
178
+ security.x_frame_options 'DENY'
179
+
180
+ # X-Content-Type-Options prevents browsers from interpreting files as
181
+ # something else than declared by the content type in the HTTP headers.
182
+ #
183
+ # Read more at:
184
+ #
185
+ # * https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#X-Content-Type-Options
186
+ # * https://msdn.microsoft.com/en-us/library/gg622941%28v=vs.85%29.aspx
187
+ # * https://blogs.msdn.microsoft.com/ie/2008/09/02/ie8-security-part-vi-beta-2-update
188
+ #
189
+ security.x_content_type_options 'nosniff'
190
+
191
+ # X-XSS-Protection is a HTTP header to determine the behavior of the
192
+ # browser in case an XSS attack is detected.
193
+ #
194
+ # Read more at:
195
+ #
196
+ # * https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)
197
+ # * https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#X-XSS-Protection
198
+ #
199
+ security.x_xss_protection '1; mode=block'
200
+
201
+ # Content-Security-Policy (CSP) is a HTTP header supported by modern
202
+ # browsers. It determines trusted sources of execution for dynamic
203
+ # contents (JavaScript) or other web related assets: stylesheets, images,
204
+ # fonts, plugins, etc.
205
+ #
206
+ # Web applications can send this header to mitigate Cross Site Scripting
207
+ # (XSS) attacks.
208
+ #
209
+ # The default value allows images, scripts, AJAX, fonts and CSS from the
210
+ # same origin, and does not allow any other resources to load (eg object,
211
+ # frame, media, etc).
212
+ #
213
+ # Inline JavaScript is NOT allowed. To enable it, please use:
214
+ # "script-src 'unsafe-inline'".
215
+ #
216
+ # Content Security Policy introduction:
217
+ #
218
+ # * http://www.html5rocks.com/en/tutorials/security/content-security-policy/
219
+ # * https://www.owasp.org/index.php/Content_Security_Policy
220
+ # * https://www.owasp.org/index.php/Cross-site_Scripting_%28XSS%29
221
+ #
222
+ # Inline and eval JavaScript risks:
223
+ #
224
+ # * http://www.html5rocks.com/en/tutorials/security/content-security-policy/#inline-code-considered-harmful
225
+ # * http://www.html5rocks.com/en/tutorials/security/content-security-policy/#eval-too
226
+ #
227
+ # Content Security Policy usage:
228
+ #
229
+ # * http://content-security-policy.com/
230
+ # * https://developer.mozilla.org/en-US/docs/Web/Security/CSP/Using_Content_Security_Policy
231
+ #
232
+ # Content Security Policy references:
233
+ #
234
+ # * https://developer.mozilla.org/en-US/docs/Web/Security/CSP/CSP_policy_directives
235
+ #
236
+ security.content_security_policy %{
237
+ form-action 'self';
238
+ frame-ancestors 'self';
239
+ base-uri 'self';
240
+ default-src 'none';
241
+ script-src 'self';
242
+ connect-src 'self';
243
+ img-src 'self' https: data:;
244
+ style-src 'self' 'unsafe-inline' https:;
245
+ font-src 'self';
246
+ object-src 'none';
247
+ plugin-types application/pdf;
248
+ child-src 'self';
249
+ frame-src 'self';
250
+ media-src 'self'
251
+ }
252
+
253
+ ##
254
+ # FRAMEWORKS
255
+ #
256
+
257
+ # Configure the code that will yield each time Web::Action is included
258
+ # This is useful for sharing common functionality
259
+ #
260
+ # See: http://www.rubydoc.info/gems/hanami-controller#Configuration
261
+ controller.prepare do
262
+ # include MyAuthentication # included in all the actions
263
+ # before :authenticate! # run an authentication before callback
264
+ end
265
+
266
+ # Configure the code that will yield each time Web::View is included
267
+ # This is useful for sharing common functionality
268
+ #
269
+ # See: http://www.rubydoc.info/gems/hanami-view#Configuration
270
+ view.prepare do
271
+ include Hanami::Helpers
272
+ include Web::Assets::Helpers
273
+ end
274
+ end
275
+
276
+ ##
277
+ # DEVELOPMENT
278
+ #
279
+ configure :development do
280
+ # Don't handle exceptions, render the stack trace
281
+ handle_exceptions false
282
+ end
283
+
284
+ ##
285
+ # TEST
286
+ #
287
+ configure :test do
288
+ # Don't handle exceptions, render the stack trace
289
+ handle_exceptions false
290
+ end
291
+
292
+ ##
293
+ # PRODUCTION
294
+ #
295
+ configure :production do
296
+ # scheme 'https'
297
+ # host 'example.org'
298
+ # port 443
299
+
300
+ assets do
301
+ # Don't compile static assets in production mode (eg. Sass, ES6)
302
+ #
303
+ # See: http://www.rubydoc.info/gems/hanami-assets#Configuration
304
+ compile false
305
+
306
+ # Use fingerprint file name for asset paths
307
+ #
308
+ # See: http://hanamirb.org/guides/assets/overview
309
+ fingerprint true
310
+
311
+ # Content Delivery Network (CDN)
312
+ #
313
+ # See: http://hanamirb.org/guides/assets/content-delivery-network
314
+ #
315
+ # scheme 'https'
316
+ # host 'cdn.example.org'
317
+ # port 443
318
+
319
+ # Subresource Integrity
320
+ #
321
+ # See: http://hanamirb.org/guides/assets/content-delivery-network/#subresource-integrity
322
+ subresource_integrity :sha256
323
+ end
324
+ end
325
+ end
326
+ end
@@ -0,0 +1,4 @@
1
+ # Configure your routes here
2
+ # See: http://hanamirb.org/guides/routing/overview/
3
+ #
4
+ get '/artists', to: 'artists#index'
@@ -0,0 +1,12 @@
1
+ require_relative '../../../../lib/hanami_example'
2
+
3
+ module Web::Controllers::Artists
4
+ class Index
5
+ include Web::Action
6
+
7
+ def call(params)
8
+ @artists = ArtistRepository.new.reduce(params).to_a
9
+ self.body = @artists.to_json
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ module Web
2
+ module Views
3
+ class ApplicationLayout
4
+ include Web::Layout
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,2 @@
1
+ require_relative './environment'
2
+ Hanami.boot
@@ -0,0 +1,29 @@
1
+ require 'bundler/setup'
2
+ require 'hanami/setup'
3
+ require 'hanami/model'
4
+ require_relative '../lib/hanami_example'
5
+ require_relative '../apps/web/application'
6
+
7
+ Hanami.configure do
8
+ mount Web::Application, at: '/'
9
+
10
+ model do
11
+ ##
12
+ # Database adapter
13
+ #
14
+ # Available options:
15
+ #
16
+ # * SQL adapter
17
+ # adapter :sql, 'sqlite://db/hanami_example_development.sqlite3'
18
+ # adapter :sql, 'postgresql://localhost/hanami_example_development'
19
+ # adapter :sql, 'mysql://localhost/hanami_example_development'
20
+ #
21
+ adapter :sql, "sqlite://#{__dir__}/../../fixtures.sqlite"
22
+
23
+ ##
24
+ # Migrations
25
+ #
26
+ migrations 'db/migrations'
27
+ schema 'db/schema.sql'
28
+ end
29
+ end
@@ -0,0 +1,2 @@
1
+ class Artist < Hanami::Entity
2
+ end
@@ -0,0 +1,9 @@
1
+ class ArtistRepository < Hanami::Repository
2
+ def query
3
+ { dataset: artists.dataset, filters: SEQUEL_QUERY[:filters] }
4
+ end
5
+
6
+ def reduce(params)
7
+ Rack::Reducer.call(params, query)
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ require_relative 'hanami_example/entities/artist'
2
+ require_relative 'hanami_example/repositories/artist_repository'
3
+
4
+ module HanamiExample
5
+ end
@@ -0,0 +1,8 @@
1
+ class ArtistsController < ApplicationController
2
+ # GET /artists
3
+ def index
4
+ @artists = RailsExample::Artist.reduce(params)
5
+
6
+ render json: @artists
7
+ end
8
+ end
@@ -0,0 +1,20 @@
1
+ module RailsExample
2
+ class Artist < ApplicationRecord
3
+ scope :by_name, lambda { |name|
4
+ where('lower(name) like ?', "%#{name.downcase}%")
5
+ }
6
+ def self.search_genre(genre)
7
+ where('lower(genre) like ?', "%#{genre.downcase}%")
8
+ end
9
+
10
+ extend Rack::Reducer
11
+ reduces all, filters: [
12
+ # filters can call class methods...
13
+ ->(genre:) { search_genre(genre) },
14
+ # or scopes...
15
+ ->(name:) { by_name(name) },
16
+ # or inline ActiveRecord queries
17
+ ->(order:) { order(order.to_sym) }
18
+ ]
19
+ end
20
+ end
File without changes
data/spec/behavior.rb CHANGED
@@ -3,7 +3,7 @@ shared_examples_for Rack::Reducer do
3
3
 
4
4
  it 'responds with unfiltered data when filter params are empty' do
5
5
  get('/artists') do |res|
6
- ARTISTS.each { |artist| expect(res.body).to include(artist[:name]) }
6
+ DB[:artists].each { |artist| expect(res.body).to include(artist[:name]) }
7
7
  end
8
8
  end
9
9
 
@@ -37,7 +37,7 @@ shared_examples_for Rack::Reducer do
37
37
 
38
38
  it 'can sort as well as filter' do
39
39
  get '/artists?order=genre' do |response|
40
- genre = JSON.parse(response.body).dig(0, 'genre')
40
+ genre = JSON.parse(response.body)[0]['genre']
41
41
  expect(genre).to eq('alt-soul')
42
42
  end
43
43
  end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require_relative '_hanami_example/config/boot'
3
+
4
+ describe Hanami.app do
5
+ it_behaves_like Rack::Reducer
6
+ end
@@ -1,18 +1,22 @@
1
1
  require 'spec_helper'
2
- require_relative 'fixtures'
3
2
  require 'json'
4
3
 
5
4
  # mount Rack::Reducer as middleware, let it filter data into env['rack.reduction'],
6
5
  # and respond with env['rack.reduction'].to_json
7
6
  module MiddlewareTest
8
- def self.app
7
+ DEFAULTS = {
8
+ dataset: DB[:artists].all,
9
+ filters: [
10
+ ->(genre:) { select { |item| item[:genre].match(/#{genre}/i) } },
11
+ ->(name:) { select { |item| item[:name].match(/#{name}/i) } },
12
+ ->(order:) { sort_by { |item| item[order.to_sym] } }
13
+ ]
14
+ }
15
+
16
+ def self.app(options = {}, key = options[:key] || 'rack.reduction')
9
17
  Rack::Builder.new do
10
- use Rack::Reducer, dataset: ARTISTS, filters: [
11
- ->(genre:) { select { |item| item[:genre].match(/#{genre}/i) } },
12
- ->(name:) { select { |item| item[:name].match(/#{name}/i) } },
13
- ->(order:) { sort_by { |item| item[order.to_sym] } }
14
- ]
15
- run ->(env) { [200, {}, [env['rack.reduction'].to_json]] }
18
+ use Rack::Reducer, DEFAULTS.merge(options)
19
+ run ->(env) { [200, {}, [env[key].to_json]] }
16
20
  end
17
21
  end
18
22
  end
@@ -20,3 +24,7 @@ end
20
24
  describe MiddlewareTest.app do
21
25
  it_behaves_like Rack::Reducer
22
26
  end
27
+
28
+ describe MiddlewareTest.app(key: 'some.custom.key') do
29
+ it_behaves_like Rack::Reducer
30
+ end
data/spec/rails_spec.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'spec_helper'
2
- ENV['RACK_ENV'] = ENV['RAILS_ENV'] = 'test'
3
- require_relative 'rails_example/config/environment'
2
+ require_relative '_rails_example/config/environment'
4
3
 
5
4
  describe Rails.application do
6
5
  it_behaves_like Rack::Reducer
data/spec/roda_spec.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+ require 'roda'
3
+
4
+ class RodaTest < Roda
5
+ plugin :json
6
+ route do |r|
7
+ r.on 'artists' do
8
+ r.get { Rack::Reducer.call(r.params, SEQUEL_QUERY).to_a }
9
+ end
10
+ end
11
+ end
12
+
13
+ describe RodaTest do
14
+ it_behaves_like Rack::Reducer
15
+ end
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require_relative 'fixtures'
3
2
  require 'sinatra/base'
4
3
  require 'json'
5
4
 
@@ -9,13 +8,8 @@ class SinatraFunctional < Sinatra::Base
9
8
  end
10
9
 
11
10
  get '/artists' do
12
- @artists = Rack::Reducer.call(params, dataset: Artist, filters: [
13
- ->(genre:) { grep(:genre, "%#{genre}%", case_insensitive: true) },
14
- ->(name:) { grep(:name, "%#{name}%", case_insensitive: true) },
15
- ->(order: 'genre') { order(order.to_sym) }
16
- ])
17
-
18
- @artists.all.to_json
11
+ @artists = Rack::Reducer.call(params, SEQUEL_QUERY).to_a
12
+ @artists.to_json
19
13
  end
20
14
  end
21
15
 
@@ -25,7 +19,7 @@ describe SinatraFunctional do
25
19
 
26
20
  it 'applies a default order' do
27
21
  get '/artists' do |response|
28
- genre = JSON.parse(response.body).dig(0, 'genre')
22
+ genre = JSON.parse(response.body)[0]['genre']
29
23
  expect(genre).to eq('alt-soul')
30
24
  end
31
25
  end
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require_relative 'fixtures'
3
2
  require 'sinatra/base'
4
3
  require 'json'
5
4
 
@@ -12,7 +11,6 @@ class SinatraMixin < Sinatra::Base
12
11
  ->(name:) { grep(:name, "%#{name}%", case_insensitive: true) },
13
12
  ->(order:) { order(order.to_sym) }
14
13
  ]
15
-
16
14
  end
17
15
 
18
16
  get '/artists' do
data/spec/spec_helper.rb CHANGED
@@ -3,8 +3,19 @@ Bundler.setup
3
3
  require 'pry'
4
4
  require 'rack/test'
5
5
  require 'rack/reducer'
6
- require_relative 'fixtures'
6
+ require 'sequel'
7
7
  require_relative 'behavior'
8
+ ENV['RACK_ENV'] = ENV['RAILS_ENV'] = 'test'
9
+ DB = Sequel.connect "sqlite://#{__dir__}/fixtures.sqlite"
10
+
11
+ SEQUEL_QUERY = {
12
+ dataset: DB[:artists],
13
+ filters: [
14
+ ->(genre:) { grep(:genre, "%#{genre}%", case_insensitive: true) },
15
+ ->(name:) { grep(:name, "%#{name}%", case_insensitive: true) },
16
+ ->(order: 'genre') { order(order.to_sym) }
17
+ ]
18
+ }.freeze
8
19
 
9
20
  RSpec.configure do |config|
10
21
  config.color = true