procore-sift 0.15.0 → 0.16.0
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.
- checksums.yaml +4 -4
- data/README.md +82 -38
- data/lib/procore-sift.rb +2 -2
- data/lib/sift/filter.rb +5 -2
- data/lib/sift/sort.rb +1 -0
- data/lib/sift/subset_comparator.rb +2 -0
- data/lib/sift/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf5b2ef9c9c924ef031b2626d1acc7a89fe5fce882410c01ff0d0b784640e9be
|
4
|
+
data.tar.gz: 5adf8202ac47b3cfeea5244480de98a27737fad342a8c138d3338b0dd7eb27f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1b0e77176f7c0648832374c63f60087695519ba1878e4ad325bd13453d9c77c584cb25d975d2ec129fb42b20ce8abc1afd1fc33e0e1ed0dc92af4108d96adf05
|
7
|
+
data.tar.gz: e633d786d9dbafd79f551e8c41dd6e1031658a4c299c2b6d11a4821561fde62b98b47696c0820f7800d464c0e69cd53a240880d7959bde837981e83ea00598f2
|
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 }
|
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
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
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
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
-
|
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
|
-
|
139
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
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
|
-
|
189
|
-
|
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
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
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
|
```
|
@@ -278,6 +319,7 @@ We have some future plans to remove the rails dependency so that other framework
|
|
278
319
|
## Contributing
|
279
320
|
|
280
321
|
Running tests:
|
322
|
+
|
281
323
|
```bash
|
282
324
|
$ bundle exec rake test
|
283
325
|
```
|
@@ -290,6 +332,7 @@ When a bump is desired, the gemspec should have the version number bumped and me
|
|
290
332
|
|
291
333
|
Step 1: build the new version
|
292
334
|
`gem build sift.gemspec`
|
335
|
+
|
293
336
|
```
|
294
337
|
Successfully built RubyGem
|
295
338
|
Name: procore-sift
|
@@ -299,6 +342,7 @@ Step 1: build the new version
|
|
299
342
|
|
300
343
|
Step2: Push the updated build
|
301
344
|
`gem push procore-sift-0.14.0.gem`
|
345
|
+
|
302
346
|
```
|
303
347
|
Pushing gem to https://rubygems.org...
|
304
348
|
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
|
-
|
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
|
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
|
data/lib/sift/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: procore-sift
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Procore Technologies
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -139,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
139
|
- !ruby/object:Gem::Version
|
140
140
|
version: '0'
|
141
141
|
requirements: []
|
142
|
-
rubygems_version: 3.
|
142
|
+
rubygems_version: 3.0.3
|
143
143
|
signing_key:
|
144
144
|
specification_version: 4
|
145
145
|
summary: Summary of Sift.
|