procore-sift 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +31 -0
- data/lib/procore-sift.rb +1 -0
- data/lib/sift/parameter.rb +7 -2
- data/lib/sift/type_validator.rb +5 -1
- data/lib/sift/validators/valid_json_validator.rb +14 -0
- data/lib/sift/value_parser.rb +19 -5
- data/lib/sift/version.rb +1 -1
- data/lib/sift/where_handler.rb +22 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3faa95a328bd7cb7f4252ed830e08bb0032a367526b223f3b24857b955912c2d
|
4
|
+
data.tar.gz: ef52247a7f9fd757d18fa662f7b7d7e4f9ab49e45b80de9ae68e18690fba80d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa7c02c0b73fcefc709b7030b636611ec6a821f14df32080fb21c4e4ddf0a50288ad298775bd8919196b47e30652e4d02a1303d1189d9e7703aadc435d7be54e
|
7
|
+
data.tar.gz: 4d1dfefa31e8b1537d9605d8724fa2fceb16739ed62300da2e38ec8a8ba4f567a47712b8b7fd82f52dc229495a14524896d7eab9dbbcfcde665fc9113dfe3ea6
|
data/README.md
CHANGED
@@ -46,6 +46,7 @@ Every filter must have a type, so that Sift knows what to do with it. The curren
|
|
46
46
|
* time - Filter on a time column
|
47
47
|
* datetime - Filter on a datetime column
|
48
48
|
* scope - Filter on an ActiveRecord scope
|
49
|
+
* jsonb - Filter on a jsonb column (supported only in PostgreSQL)
|
49
50
|
|
50
51
|
### Filter on Scopes
|
51
52
|
Just as your filter values are used to scope queries on a column, values you
|
@@ -122,6 +123,36 @@ The following types support ranges
|
|
122
123
|
* time
|
123
124
|
* datetime
|
124
125
|
|
126
|
+
### Filter on jsonb column
|
127
|
+
|
128
|
+
Usually JSONB columns stores values as an Array or an Object (key-value), in both cases the parameter needs to be sent in a JSON format
|
129
|
+
|
130
|
+
**Array**
|
131
|
+
|
132
|
+
It should be sent an array in the URL Query parameters
|
133
|
+
* `?filters[metadata]=[1,2]`
|
134
|
+
|
135
|
+
**key-value**
|
136
|
+
|
137
|
+
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]"}`
|
140
|
+
|
141
|
+
When the value is an array, it will filter records with those values or more, for example:
|
142
|
+
|
143
|
+
* `?filters[metadata]={"data_2":"[1,2]"}`
|
144
|
+
|
145
|
+
Will return records with next values stored in the JSONB column `metadata`:
|
146
|
+
```ruby
|
147
|
+
{ data_2: 1 }
|
148
|
+
{ data_2: 2 }
|
149
|
+
{ data_2: [1] }
|
150
|
+
{ data_2: [2] }
|
151
|
+
{ data_2: [1,2] }
|
152
|
+
{ data_2: [1,2,3] }
|
153
|
+
```
|
154
|
+
|
155
|
+
|
125
156
|
### Filter on JSON Array
|
126
157
|
`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`.
|
127
158
|
|
data/lib/procore-sift.rb
CHANGED
@@ -10,6 +10,7 @@ require "sift/scope_handler"
|
|
10
10
|
require "sift/where_handler"
|
11
11
|
require "sift/validators/valid_int_validator"
|
12
12
|
require "sift/validators/valid_date_range_validator"
|
13
|
+
require "sift/validators/valid_json_validator"
|
13
14
|
|
14
15
|
module Sift
|
15
16
|
extend ActiveSupport::Concern
|
data/lib/sift/parameter.rb
CHANGED
@@ -13,7 +13,8 @@ module Sift
|
|
13
13
|
{
|
14
14
|
supports_boolean: supports_boolean?,
|
15
15
|
supports_ranges: supports_ranges?,
|
16
|
-
supports_json: supports_json
|
16
|
+
supports_json: supports_json?,
|
17
|
+
supports_json_object: supports_json_object?
|
17
18
|
}
|
18
19
|
end
|
19
20
|
|
@@ -32,7 +33,11 @@ module Sift
|
|
32
33
|
end
|
33
34
|
|
34
35
|
def supports_json?
|
35
|
-
|
36
|
+
[:int, :jsonb].include?(type)
|
37
|
+
end
|
38
|
+
|
39
|
+
def supports_json_object?
|
40
|
+
type == :jsonb
|
36
41
|
end
|
37
42
|
|
38
43
|
def supports_boolean?
|
data/lib/sift/type_validator.rb
CHANGED
@@ -4,6 +4,7 @@ module Sift
|
|
4
4
|
DATETIME_RANGE_PATTERN = { format: { with: /\A.+(?:[^.]\.\.\.[^.]).+\z/, message: "must be a range" }, valid_date_range: true }.freeze
|
5
5
|
DECIMAL_PATTERN = { numericality: true, allow_nil: true }.freeze
|
6
6
|
BOOLEAN_PATTERN = { inclusion: { in: [true, false] }, allow_nil: true }.freeze
|
7
|
+
JSON_PATTERN = { valid_json: true }.freeze
|
7
8
|
|
8
9
|
WHITELIST_TYPES = [:int,
|
9
10
|
:decimal,
|
@@ -13,7 +14,8 @@ module Sift
|
|
13
14
|
:date,
|
14
15
|
:time,
|
15
16
|
:datetime,
|
16
|
-
:scope
|
17
|
+
:scope,
|
18
|
+
:jsonb].freeze
|
17
19
|
|
18
20
|
def initialize(param, type)
|
19
21
|
@param = param
|
@@ -32,6 +34,8 @@ module Sift
|
|
32
34
|
DECIMAL_PATTERN
|
33
35
|
when :boolean
|
34
36
|
BOOLEAN_PATTERN
|
37
|
+
when :jsonb
|
38
|
+
JSON_PATTERN
|
35
39
|
end
|
36
40
|
end
|
37
41
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class ValidJsonValidator < ActiveModel::EachValidator
|
2
|
+
def validate_each(record, attribute, value)
|
3
|
+
record.errors.add attribute, "must be a valid JSON" unless valid_json?(value)
|
4
|
+
end
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def valid_json?(value)
|
9
|
+
value = value.strip if value.is_a?(String)
|
10
|
+
JSON.parse(value)
|
11
|
+
rescue JSON::ParserError
|
12
|
+
false
|
13
|
+
end
|
14
|
+
end
|
data/lib/sift/value_parser.rb
CHANGED
@@ -5,6 +5,7 @@ module Sift
|
|
5
5
|
@supports_boolean = options.fetch(:supports_boolean, false)
|
6
6
|
@supports_ranges = options.fetch(:supports_ranges, false)
|
7
7
|
@supports_json = options.fetch(:supports_json, false)
|
8
|
+
@supports_json_object = options.fetch(:supports_json_object, false)
|
8
9
|
@value = normalized_value(value, type)
|
9
10
|
end
|
10
11
|
|
@@ -15,26 +16,39 @@ module Sift
|
|
15
16
|
elsif parse_as_boolean?
|
16
17
|
boolean_value
|
17
18
|
elsif parse_as_json?
|
18
|
-
array_from_json
|
19
|
+
supports_json_object ? parse_json_and_values : array_from_json
|
19
20
|
else
|
20
21
|
value
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
25
|
+
def parse_json(string)
|
26
|
+
JSON.parse(string)
|
27
|
+
rescue JSON::ParserError
|
28
|
+
string
|
29
|
+
end
|
30
|
+
|
31
|
+
def parse_json_and_values
|
32
|
+
parsed_jsonb = parse_json(value)
|
33
|
+
return parsed_jsonb if parsed_jsonb.is_a?(Array) || parsed_jsonb.is_a?(String)
|
34
|
+
|
35
|
+
parsed_jsonb.each_with_object({}) do |key_value, hash|
|
36
|
+
hash[key_value.first] = parse_json(key_value.last.to_s)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
24
40
|
def array_from_json
|
25
|
-
result =
|
41
|
+
result = parse_json(value)
|
26
42
|
if result.is_a?(Array)
|
27
43
|
result
|
28
44
|
else
|
29
45
|
value
|
30
46
|
end
|
31
|
-
rescue JSON::ParserError
|
32
|
-
value
|
33
47
|
end
|
34
48
|
|
35
49
|
private
|
36
50
|
|
37
|
-
attr_reader :value, :type, :supports_boolean, :supports_json, :supports_ranges
|
51
|
+
attr_reader :value, :type, :supports_boolean, :supports_json, :supports_json_object, :supports_ranges
|
38
52
|
|
39
53
|
def parse_as_range?(raw_value=value)
|
40
54
|
supports_ranges && raw_value.to_s.include?("...")
|
data/lib/sift/version.rb
CHANGED
data/lib/sift/where_handler.rb
CHANGED
@@ -5,7 +5,28 @@ module Sift
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def call(collection, value, _params, _scope_params)
|
8
|
-
|
8
|
+
if @param.type == :jsonb
|
9
|
+
apply_jsonb_conditions(collection, value)
|
10
|
+
else
|
11
|
+
collection.where(@param.internal_name => value)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def apply_jsonb_conditions(collection, value)
|
18
|
+
return collection.where("#{@param.internal_name} @> ?", val.to_s) if value.is_a?(Array)
|
19
|
+
|
20
|
+
value.each do |key, val|
|
21
|
+
condition = if val.is_a?(Array)
|
22
|
+
"('{' || TRANSLATE(#{@param.internal_name}->>'#{key}', '[]','') || '}')::int[] && ARRAY[?]"
|
23
|
+
else # Single Value
|
24
|
+
val = val.to_s
|
25
|
+
"#{@param.internal_name}->>'#{key}' = ?"
|
26
|
+
end
|
27
|
+
collection = collection.where(condition, val)
|
28
|
+
end
|
29
|
+
collection
|
9
30
|
end
|
10
31
|
end
|
11
32
|
end
|
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.14.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: 2020-
|
11
|
+
date: 2020-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -115,6 +115,7 @@ files:
|
|
115
115
|
- lib/sift/type_validator.rb
|
116
116
|
- lib/sift/validators/valid_date_range_validator.rb
|
117
117
|
- lib/sift/validators/valid_int_validator.rb
|
118
|
+
- lib/sift/validators/valid_json_validator.rb
|
118
119
|
- lib/sift/value_parser.rb
|
119
120
|
- lib/sift/version.rb
|
120
121
|
- lib/sift/where_handler.rb
|
@@ -138,8 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
139
|
- !ruby/object:Gem::Version
|
139
140
|
version: '0'
|
140
141
|
requirements: []
|
141
|
-
|
142
|
-
rubygems_version: 2.6.14
|
142
|
+
rubygems_version: 3.1.3
|
143
143
|
signing_key:
|
144
144
|
specification_version: 4
|
145
145
|
summary: Summary of Sift.
|