procore-sift 0.15.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 96191da518ce07229dd35fe0375a2b52a4da4ee69b7f506835a236c7e87c77a1
4
- data.tar.gz: 994eff7f0ed3417b0a9272e554d4ece07b73fdf99769b89497bbf56cf4259c00
3
+ metadata.gz: 1594b92ce7a641195d2c67b981f3f138648566196d8e56d80d0089689dd7a7b3
4
+ data.tar.gz: 97efc53749c62bdaad7b5888c5108c52ccf0c091af730a7ab12a9c7bee3d5f3a
5
5
  SHA512:
6
- metadata.gz: c6633d0d1260108f39ea161f001980c66102f908ca1b310aab9eefeec9b41dae02bd678dafad461e5f6c4d841b4ac61446f79136b27dd3e159c1b67bb84c5967
7
- data.tar.gz: 0d5ce661231cd9caaf98c145be89765e269755619838b60f9ba088d8f4456110794b154e6871887c05d42661dba2e7733e3178449ef474a0be78830a3ae14832
6
+ metadata.gz: 302c1147b6c5402449a4999492f176aceedf6648180673b5710fb21b522501e8de58945868dd487e286e0de7a403e8c6669431cbcf9565fa42c0b54041da5ffd
7
+ data.tar.gz: 0d050ee3c4fbeb0a270cb5994efcdd71f926901f3c2db1b79b38d241a17ebe14428b386de10f8b128885c331b334d20b5fedd4b3d153d047bf7a6f17bd9774bf
data/README.md CHANGED
@@ -5,6 +5,7 @@
5
5
  A tool to build your own filters and sorts with Rails and Active Record!
6
6
 
7
7
  ## Developer Usage
8
+
8
9
  Include Sift in your controllers, and define some filters.
9
10
 
10
11
  ```ruby
@@ -27,7 +28,7 @@ Sift will also handle rendering errors using the standard rails errors structure
27
28
  before_action :render_filter_errors, unless: :filters_valid?
28
29
 
29
30
  def render_filter_errors
30
- render json: { errors: filter_errors } and return
31
+ render json: { errors: filter_errors }, status: :bad_request && return
31
32
  end
32
33
  ```
33
34
 
@@ -36,19 +37,22 @@ to your controller.
36
37
  These errors are based on the type that you told sift your param was.
37
38
 
38
39
  ### Filter Types
40
+
39
41
  Every filter must have a type, so that Sift knows what to do with it. The current valid filter types are:
40
- * int - Filter on an integer column
41
- * decimal - Filter on a decimal column
42
- * boolean - Filter on a boolean column
43
- * string - Filter on a string column
44
- * text - Filter on a text column
45
- * date - Filter on a date column
46
- * time - Filter on a time column
47
- * datetime - Filter on a datetime column
48
- * scope - Filter on an ActiveRecord scope
49
- * jsonb - Filter on a jsonb column (supported only in PostgreSQL)
42
+
43
+ - int - Filter on an integer column
44
+ - decimal - Filter on a decimal column
45
+ - boolean - Filter on a boolean column
46
+ - string - Filter on a string column
47
+ - text - Filter on a text column
48
+ - date - Filter on a date column
49
+ - time - Filter on a time column
50
+ - datetime - Filter on a datetime column
51
+ - scope - Filter on an ActiveRecord scope
52
+ - jsonb - Filter on a jsonb column (supported only in PostgreSQL)
50
53
 
51
54
  ### Filter on Scopes
55
+
52
56
  Just as your filter values are used to scope queries on a column, values you
53
57
  pass to a scope filter will be used as arguments to that scope. For example:
54
58
 
@@ -75,7 +79,7 @@ Scopes that accept no arguments are currently not supported.
75
79
 
76
80
  #### Accessing Params with Filter Scopes
77
81
 
78
- Filters with `type: :scope` have access to the params hash by passing in the desired keys to the `scope_params`. The keys passed in will be returned as a hash with their associated values, and should always appear as the last argument in your scope.
82
+ Filters with `type: :scope` have access to the params hash by passing in the desired keys to the `scope_params`. The keys passed in will be returned as a hash with their associated values.
79
83
 
80
84
  ```ruby
81
85
  class Post < ActiveRecord::Base
@@ -94,6 +98,7 @@ class UsersController < ApplicationController
94
98
  end
95
99
  end
96
100
  ```
101
+
97
102
  Passing `?filters[user_posts_on_date]=10/12/20` will call the `user_posts_on_date` scope with
98
103
  `10/12/20` as the the first argument, and will grab the `user_id` and `blog_id` out of the params and pass them as a hash, as the second argument.
99
104
 
@@ -111,17 +116,38 @@ end
111
116
  ```
112
117
 
113
118
  ### Filter on Ranges
119
+
114
120
  Some parameter types support ranges. Ranges are expected to be a string with the bounding values separated by `...`
115
121
 
116
122
  For example `?filters[price]=3...50` would return records with a price between 3 and 50.
117
123
 
118
124
  The following types support ranges
119
- * int
120
- * decimal
121
- * boolean
122
- * date
123
- * time
124
- * datetime
125
+
126
+ - int
127
+ - decimal
128
+ - boolean
129
+ - date
130
+ - time
131
+ - datetime
132
+
133
+ ### Mutating Filters
134
+
135
+ Filters can be mutated before the filter is applied using the `tap` argument. This is useful, for example, if you need to adjust the time zone of a `datetime` range filter.
136
+
137
+ ```ruby
138
+
139
+ class PostsController < ApplicationController
140
+ include Sift
141
+
142
+ filter_on :expiration, type: :datetime, tap: ->(value, params) {
143
+ value.split("...").
144
+ map do |str|
145
+ str.to_date.in_time_zone(LOCAL_TIME_ZONE)
146
+ end.
147
+ join("...")
148
+ }
149
+ end
150
+ ```
125
151
 
126
152
  ### Filter on jsonb column
127
153
 
@@ -130,19 +156,22 @@ Usually JSONB columns stores values as an Array or an Object (key-value), in bot
130
156
  **Array**
131
157
 
132
158
  It should be sent an array in the URL Query parameters
133
- * `?filters[metadata]=[1,2]`
159
+
160
+ - `?filters[metadata]=[1,2]`
134
161
 
135
162
  **key-value**
136
163
 
137
164
  It can be passed one or more Key values:
138
- * `?filters[metadata]={"data_1":"test"}`
139
- * `?filters[metadata]={"data_1":"test","data_2":"[1,2]"}`
165
+
166
+ - `?filters[metadata]={"data_1":"test"}`
167
+ - `?filters[metadata]={"data_1":"test","data_2":"[1,2]"}`
140
168
 
141
169
  When the value is an array, it will filter records with those values or more, for example:
142
170
 
143
- * `?filters[metadata]={"data_2":"[1,2]"}`
171
+ - `?filters[metadata]={"data_2":"[1,2]"}`
144
172
 
145
173
  Will return records with next values stored in the JSONB column `metadata`:
174
+
146
175
  ```ruby
147
176
  { data_2: 1 }
148
177
  { data_2: 2 }
@@ -154,9 +183,10 @@ Will return records with next values stored in the JSONB column `metadata`:
154
183
 
155
184
  When the `null` value is included in the array, it will return also all the records without any value in that property, for example:
156
185
 
157
- * `?filters[metadata]={"data_2":"[false,null]"}`
186
+ - `?filters[metadata]={"data_2":"[false,null]"}`
158
187
 
159
188
  Will return records with next values stored in the JSONB column `metadata`:
189
+
160
190
  ```ruby
161
191
  { data_2: null }
162
192
  { data_2: false }
@@ -165,9 +195,11 @@ Will return records with next values stored in the JSONB column `metadata`:
165
195
  ```
166
196
 
167
197
  ### Filter on JSON Array
198
+
168
199
  `int` type filters support sending the values as an array in the URL Query parameters. For example `?filters[id]=[1,2]`. This is a way to keep payloads smaller for GET requests. When URI encoded this will become `filters%5Bid%5D=%5B1,2%5D` which is much smaller the standard format of `filters%5Bid%5D%5B%5D=1&&filters%5Bid%5D%5B%5D=2`.
169
200
 
170
201
  On the server side, the params will be received as:
202
+
171
203
  ```ruby
172
204
  # JSON array encoded result
173
205
  "filters"=>{"id"=>"[1,2]"}
@@ -177,34 +209,41 @@ On the server side, the params will be received as:
177
209
  ```
178
210
 
179
211
  Note that this feature cannot currently be wrapped in an array and should not be used in combination with sending array parameters individually.
180
- * `?filters[id][]=[1,2]` => invalid
181
- * `?filters[id][]=[1,2]&filters[id][]=3` => invalid
182
- * `?filters[id]=[1,2]&filters[id]=3` => valid but only 3 is passed through to the server
183
- * `?filters[id]=[1,2]` => valid
212
+
213
+ - `?filters[id][]=[1,2]` => invalid
214
+ - `?filters[id][]=[1,2]&filters[id][]=3` => invalid
215
+ - `?filters[id]=[1,2]&filters[id]=3` => valid but only 3 is passed through to the server
216
+ - `?filters[id]=[1,2]` => valid
184
217
 
185
218
  #### A note on encoding for JSON Array feature
219
+
186
220
  JSON arrays contain the reserved characters "`,`" and "`[`" and "`]`". When encoding a JSON array in the URL there are two different ways to handle the encoding. Both ways are supported by Rails.
187
221
  For example, lets look at the following filter with a JSON array `?filters[id]=[1,2]`:
188
- * `?filters%5Bid%5D=%5B1,2%5D`
189
- * `?filters%5Bid%5D%3D%5B1%2C2%5D`
222
+
223
+ - `?filters%5Bid%5D=%5B1,2%5D`
224
+ - `?filters%5Bid%5D%3D%5B1%2C2%5D`
190
225
 
191
226
  In both cases Rails will correctly decode to the expected result of
227
+
192
228
  ```ruby
193
229
  { "filters" => { "id" => "[1,2]" } }
194
230
  ```
195
231
 
196
232
  ### Sort Types
233
+
197
234
  Every sort must have a type, so that Sift knows what to do with it. The current valid sort types are:
198
- * int - Sort on an integer column
199
- * decimal - Sort on a decimal column
200
- * string - Sort on a string column
201
- * text - Sort on a text column
202
- * date - Sort on a date column
203
- * time - Sort on a time column
204
- * datetime - Sort on a datetime column
205
- * scope - Sort on an ActiveRecord scope
235
+
236
+ - int - Sort on an integer column
237
+ - decimal - Sort on a decimal column
238
+ - string - Sort on a string column
239
+ - text - Sort on a text column
240
+ - date - Sort on a date column
241
+ - time - Sort on a time column
242
+ - datetime - Sort on a datetime column
243
+ - scope - Sort on an ActiveRecord scope
206
244
 
207
245
  ### Sort on Scopes
246
+
208
247
  Just as your sort values are used to scope queries on a column, values you
209
248
  pass to a scope sort will be used as arguments to that scope. For example:
210
249
 
@@ -240,7 +279,6 @@ Scopes that accept no arguments are currently supported, but you should note tha
240
279
 
241
280
  `scope_params` can also accept symbols that are keys in the `params` hash. The value will be fetched and passed on as an argument to the scope.
242
281
 
243
-
244
282
  ## Consumer Usage
245
283
 
246
284
  Filter:
@@ -255,6 +293,7 @@ Sort is translated to Active Record `order` The sorts are applied in the order t
255
293
  the `-` symbol means to sort in `desc` order. By default, keys are sorted in `asc` order.
256
294
 
257
295
  ## Installation
296
+
258
297
  Add this line to your application's Gemfile:
259
298
 
260
299
  ```ruby
@@ -262,11 +301,13 @@ gem 'procore-sift'
262
301
  ```
263
302
 
264
303
  And then execute:
304
+
265
305
  ```bash
266
306
  $ bundle
267
307
  ```
268
308
 
269
309
  Or install it yourself as:
310
+
270
311
  ```bash
271
312
  $ gem install procore-sift
272
313
  ```
@@ -277,9 +318,16 @@ We have some future plans to remove the rails dependency so that other framework
277
318
 
278
319
  ## Contributing
279
320
 
321
+ Installing gems before running tests:
322
+
323
+ ```bash
324
+ $ bundle exec appraisal install
325
+ ```
326
+
280
327
  Running tests:
328
+
281
329
  ```bash
282
- $ bundle exec rake test
330
+ $ bundle exec appraisal rake test
283
331
  ```
284
332
 
285
333
  ## Publishing
@@ -290,6 +338,7 @@ When a bump is desired, the gemspec should have the version number bumped and me
290
338
 
291
339
  Step 1: build the new version
292
340
  `gem build sift.gemspec`
341
+
293
342
  ```
294
343
  Successfully built RubyGem
295
344
  Name: procore-sift
@@ -299,6 +348,7 @@ Step 1: build the new version
299
348
 
300
349
  Step2: Push the updated build
301
350
  `gem push procore-sift-0.14.0.gem`
351
+
302
352
  ```
303
353
  Pushing gem to https://rubygems.org...
304
354
  Successfully registered gem: procore-sift (0.14.0)
data/lib/procore-sift.rb CHANGED
@@ -66,8 +66,8 @@ module Sift
66
66
  end
67
67
 
68
68
  class_methods do
69
- def filter_on(parameter, type:, internal_name: parameter, default: nil, validate: nil, scope_params: [])
70
- filters << Filter.new(parameter, type, internal_name, default, validate, scope_params)
69
+ def filter_on(parameter, type:, internal_name: parameter, default: nil, validate: nil, scope_params: [], tap: nil)
70
+ filters << Filter.new(parameter, type, internal_name, default, validate, scope_params, tap)
71
71
  end
72
72
 
73
73
  def filters
data/lib/sift/filter.rb CHANGED
@@ -4,11 +4,12 @@ module Sift
4
4
  class Filter
5
5
  attr_reader :parameter, :default, :custom_validate, :scope_params
6
6
 
7
- def initialize(param, type, internal_name, default, custom_validate = nil, scope_params = [])
7
+ def initialize(param, type, internal_name, default, custom_validate = nil, scope_params = [], tap = ->(value, _params) { value })
8
8
  @parameter = Parameter.new(param, type, internal_name)
9
9
  @default = default
10
10
  @custom_validate = custom_validate
11
11
  @scope_params = scope_params
12
+ @tap = tap
12
13
  raise ArgumentError, "scope_params must be an array of symbols" unless valid_scope_params?(scope_params)
13
14
  raise "unknown filter type: #{type}" unless type_validator.valid_type?
14
15
  end
@@ -24,7 +25,9 @@ module Sift
24
25
  elsif should_apply_default?(value)
25
26
  default.call(collection)
26
27
  else
27
- handler.call(collection, parameterize(value), params, scope_params)
28
+ parameterized_values = parameterize(value)
29
+ processed_values = @tap.present? ? @tap.call(parameterized_values, params) : parameterized_values
30
+ handler.call(collection, processed_values, params, scope_params)
28
31
  end
29
32
  end
30
33
  # rubocop:enable Lint/UnusedMethodArgument
@@ -52,11 +52,7 @@ module Sift
52
52
 
53
53
  def to_type(filter)
54
54
  if filter.type == :boolean
55
- if Rails.version.starts_with?('5') || Rails.version.starts_with?('6')
56
- ActiveRecord::Type::Boolean.new.cast(filter_params[filter.param])
57
- else
58
- ActiveRecord::Type::Boolean.new.type_cast_from_user(filter_params[filter.param])
59
- end
55
+ ActiveRecord::Type::Boolean.new.cast(filter_params[filter.param])
60
56
  elsif filter.validation_field == :sort
61
57
  sort_params
62
58
  else
data/lib/sift/sort.rb CHANGED
@@ -17,6 +17,7 @@ module Sift
17
17
  def initialize(param, type, internal_name = param, scope_params = [])
18
18
  raise "unknown filter type: #{type}" unless WHITELIST_TYPES.include?(type)
19
19
  raise "scope params must be an array" unless scope_params.is_a?(Array)
20
+
20
21
  @parameter = Parameter.new(param, type, internal_name)
21
22
  @scope_params = scope_params
22
23
  end
@@ -5,6 +5,8 @@ module Sift
5
5
  end
6
6
 
7
7
  def include?(other)
8
+ other = [other] unless other.is_a?(Array)
9
+
8
10
  @array.to_set >= other.to_set
9
11
  end
10
12
  end
@@ -69,11 +69,7 @@ module Sift
69
69
  end
70
70
 
71
71
  def boolean_value
72
- if Rails.version.to_i >= 5
73
- ActiveRecord::Type::Boolean.new.cast(value)
74
- else
75
- ActiveRecord::Type::Boolean.new.type_cast_from_user(value)
76
- end
72
+ ActiveRecord::Type::Boolean.new.cast(value)
77
73
  end
78
74
 
79
75
  def normalized_value(raw_value, type)
data/lib/sift/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Sift
2
- VERSION = "0.15.0".freeze
2
+ VERSION = "1.0.0".freeze
3
3
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: procore-sift
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Procore Technologies
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-03 00:00:00.000000000 Z
11
+ date: 2023-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: activerecord
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.2.0
19
+ version: '6.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 4.2.0
26
+ version: '6.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pry
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '5.1'
47
+ version: '6.1'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '5.1'
54
+ version: '6.1'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: appraisal
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
97
111
  description: Easily write arbitrary filters
98
112
  email:
99
113
  - dev@procore.com
@@ -124,7 +138,7 @@ homepage: https://github.com/procore/sift
124
138
  licenses:
125
139
  - MIT
126
140
  metadata: {}
127
- post_install_message:
141
+ post_install_message:
128
142
  rdoc_options: []
129
143
  require_paths:
130
144
  - lib
@@ -132,15 +146,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
132
146
  requirements:
133
147
  - - ">="
134
148
  - !ruby/object:Gem::Version
135
- version: 2.3.0
149
+ version: 2.7.0
136
150
  required_rubygems_version: !ruby/object:Gem::Requirement
137
151
  requirements:
138
152
  - - ">="
139
153
  - !ruby/object:Gem::Version
140
154
  version: '0'
141
155
  requirements: []
142
- rubygems_version: 3.1.3
143
- signing_key:
156
+ rubygems_version: 3.4.8
157
+ signing_key:
144
158
  specification_version: 4
145
159
  summary: Summary of Sift.
146
160
  test_files: []