graphiti 1.2.2 → 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/graphiti.gemspec +1 -1
- data/lib/graphiti/resource.rb +7 -0
- data/lib/graphiti/resource/configuration.rb +6 -1
- data/lib/graphiti/resource/dsl.rb +12 -3
- data/lib/graphiti/resource_proxy.rb +2 -0
- data/lib/graphiti/schema.rb +5 -1
- data/lib/graphiti/scoping/filter.rb +14 -5
- data/lib/graphiti/types.rb +5 -4
- data/lib/graphiti/util/persistence.rb +2 -0
- data/lib/graphiti/util/transaction_hooks_recorder.rb +5 -0
- data/lib/graphiti/version.rb +1 -1
- metadata +13 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d55ad609644e718abecd160c32841a49fd66123c901a17c809279df9edc47e01
|
4
|
+
data.tar.gz: eb67647f916696ee9664619076335eaa5e19407b63b2a504b582e9fee9cf6e17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 92c82864cf79cc8e2bed3d87b1add842a5ac5f70aaf2fe130f2e03e9c44bc7a78e473121564f4bb7c7dca1617aba1df90b529d5724df4d61378ee27848bd4047
|
7
|
+
data.tar.gz: eb049661cd88e8636c658566d3c4fc882e13bbe6de33aa50744c4561404d4aef937bcbad66406886940d8dec388655b674fcab0efac9ac01fecbe35bc4d08cd1
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## Unreleased
|
2
|
+
|
3
|
+
Features:
|
4
|
+
|
5
|
+
- [158](https://github.com/graphiti-api/graphiti/pull/158) Filters options `allow_nil: true`
|
6
|
+
Option can be set at the resource level `Resource.filters_accept_nil_by_default = true`.
|
7
|
+
By default this is set to false. (@zeisler)
|
8
|
+
- [157](https://github.com/graphiti-api/graphiti/pull/157) Using attribute option schema: false.
|
9
|
+
This option is default true and is not effected by only and except options. (@zeisler)
|
10
|
+
|
1
11
|
## 1.1.0
|
2
12
|
|
3
13
|
Features:
|
@@ -36,6 +46,11 @@ Fixes:
|
|
36
46
|
|
37
47
|
### master (unreleased)
|
38
48
|
|
49
|
+
Features:
|
50
|
+
|
51
|
+
- [#153](https://github.com/graphiti-api/graphiti/pull/153) Add after_graph_persist hook.
|
52
|
+
This hook fires after the graph of resources is persisted and before validation. (@A-Boudi)
|
53
|
+
|
39
54
|
<!-- ### [version (YYYY-MM-DD)](diff_link) -->
|
40
55
|
<!-- Breaking changes:-->
|
41
56
|
<!-- Features:-->
|
data/graphiti.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_dependency "jsonapi-serializable", "~> 0.3.0"
|
22
22
|
spec.add_dependency "jsonapi-renderer", "0.2.0"
|
23
|
-
spec.add_dependency "dry-types", "
|
23
|
+
spec.add_dependency "dry-types", ">= 0.15.0", "< 2.0"
|
24
24
|
spec.add_dependency "graphiti_errors", "~> 1.1.0"
|
25
25
|
spec.add_dependency "concurrent-ruby", "~> 1.0"
|
26
26
|
spec.add_dependency "activesupport", ">= 4.1"
|
data/lib/graphiti/resource.rb
CHANGED
@@ -112,6 +112,13 @@ module Graphiti
|
|
112
112
|
adapter.resolve(scope)
|
113
113
|
end
|
114
114
|
|
115
|
+
def after_graph_persist(model, metadata)
|
116
|
+
hooks = self.class.config[:after_graph_persist][metadata[:method]] || []
|
117
|
+
hooks.each do |hook|
|
118
|
+
instance_exec(model, metadata, &hook)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
115
122
|
def before_commit(model, metadata)
|
116
123
|
hooks = self.class.config[:before_commit][metadata[:method]] || []
|
117
124
|
hooks.each do |hook|
|
@@ -78,8 +78,10 @@ module Graphiti
|
|
78
78
|
:attributes_writable_by_default,
|
79
79
|
:attributes_sortable_by_default,
|
80
80
|
:attributes_filterable_by_default,
|
81
|
+
:attributes_schema_by_default,
|
81
82
|
:relationships_readable_by_default,
|
82
|
-
:relationships_writable_by_default
|
83
|
+
:relationships_writable_by_default,
|
84
|
+
:filters_accept_nil_by_default
|
83
85
|
|
84
86
|
class << self
|
85
87
|
prepend Overrides
|
@@ -97,8 +99,10 @@ module Graphiti
|
|
97
99
|
default(klass, :attributes_writable_by_default, true)
|
98
100
|
default(klass, :attributes_sortable_by_default, true)
|
99
101
|
default(klass, :attributes_filterable_by_default, true)
|
102
|
+
default(klass, :attributes_schema_by_default, true)
|
100
103
|
default(klass, :relationships_readable_by_default, true)
|
101
104
|
default(klass, :relationships_writable_by_default, true)
|
105
|
+
default(klass, :filters_accept_nil_by_default, false)
|
102
106
|
|
103
107
|
unless klass.config[:attributes][:id]
|
104
108
|
klass.attribute :id, :integer_id
|
@@ -186,6 +190,7 @@ module Graphiti
|
|
186
190
|
sort_all: nil,
|
187
191
|
sorts: {},
|
188
192
|
pagination: nil,
|
193
|
+
after_graph_persist: {},
|
189
194
|
before_commit: {},
|
190
195
|
after_commit: {},
|
191
196
|
attributes: {},
|
@@ -32,6 +32,7 @@ module Graphiti
|
|
32
32
|
dependencies: opts[:dependent],
|
33
33
|
required: required,
|
34
34
|
operators: operators.to_hash,
|
35
|
+
allow_nil: opts.fetch(:allow_nil, filters_accept_nil_by_default)
|
35
36
|
}
|
36
37
|
elsif (type = args[0])
|
37
38
|
attribute name, type, only: [:filterable], allow: opts[:allow]
|
@@ -81,6 +82,13 @@ module Graphiti
|
|
81
82
|
}
|
82
83
|
end
|
83
84
|
|
85
|
+
def after_graph_persist(only: [:create, :update, :destroy], &blk)
|
86
|
+
Array(only).each do |verb|
|
87
|
+
config[:after_graph_persist][verb] ||= []
|
88
|
+
config[:after_graph_persist][verb] << blk
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
84
92
|
def before_commit(only: [:create, :update, :destroy], &blk)
|
85
93
|
Array(only).each do |verb|
|
86
94
|
config[:before_commit][verb] ||= []
|
@@ -101,6 +109,7 @@ module Graphiti
|
|
101
109
|
attribute_option(options, :writable)
|
102
110
|
attribute_option(options, :sortable)
|
103
111
|
attribute_option(options, :filterable)
|
112
|
+
attribute_option(options, :schema, true)
|
104
113
|
options[:type] = type
|
105
114
|
options[:proc] = blk
|
106
115
|
config[:attributes][name] = options
|
@@ -151,11 +160,11 @@ module Graphiti
|
|
151
160
|
Util::SerializerAttributes.new(self, extra_attributes, true).apply
|
152
161
|
end
|
153
162
|
|
154
|
-
def attribute_option(options, name)
|
163
|
+
def attribute_option(options, name, exclusive = false)
|
155
164
|
if options[name] != false
|
156
|
-
default = if (only = options[:only])
|
165
|
+
default = if (only = options[:only]) && !exclusive
|
157
166
|
Array(only).include?(name) ? true : false
|
158
|
-
elsif (except = options[:except])
|
167
|
+
elsif (except = options[:except]) && !exclusive
|
159
168
|
Array(except).include?(name) ? false : true
|
160
169
|
else
|
161
170
|
send(:"attributes_#{name}_by_default")
|
@@ -121,6 +121,7 @@ module Graphiti
|
|
121
121
|
metadata = {method: :destroy}
|
122
122
|
model = @resource.destroy(@query.filters[:id], metadata)
|
123
123
|
model.instance_variable_set(:@__serializer_klass, @resource.serializer)
|
124
|
+
@resource.after_graph_persist(model, metadata)
|
124
125
|
validator = ::Graphiti::Util::ValidationResponse.new \
|
125
126
|
model, @payload
|
126
127
|
validator.validate!
|
@@ -161,6 +162,7 @@ module Graphiti
|
|
161
162
|
transaction_response = @resource.transaction do
|
162
163
|
::Graphiti::Util::TransactionHooksRecorder.record do
|
163
164
|
model = yield
|
165
|
+
::Graphiti::Util::TransactionHooksRecorder.run_graph_persist_hooks
|
164
166
|
validator = ::Graphiti::Util::ValidationResponse.new \
|
165
167
|
model, @payload
|
166
168
|
validator.validate!
|
data/lib/graphiti/schema.rb
CHANGED
@@ -131,7 +131,7 @@ module Graphiti
|
|
131
131
|
def attributes(resource)
|
132
132
|
{}.tap do |attrs|
|
133
133
|
resource.attributes.each_pair do |name, config|
|
134
|
-
if config.values_at(:readable, :writable).any?
|
134
|
+
if config.values_at(:readable, :writable).any? && config[:schema]
|
135
135
|
attrs[name] = {
|
136
136
|
type: config[:type].to_s,
|
137
137
|
readable: flag(config[:readable]),
|
@@ -166,6 +166,8 @@ module Graphiti
|
|
166
166
|
def sorts(resource)
|
167
167
|
{}.tap do |s|
|
168
168
|
resource.sorts.each_pair do |name, sort|
|
169
|
+
next unless resource.attributes[name][:schema]
|
170
|
+
|
169
171
|
config = {}
|
170
172
|
config[:only] = sort[:only] if sort[:only]
|
171
173
|
attr = resource.attributes[name]
|
@@ -180,6 +182,8 @@ module Graphiti
|
|
180
182
|
def filters(resource)
|
181
183
|
{}.tap do |f|
|
182
184
|
resource.filters.each_pair do |name, filter|
|
185
|
+
next unless resource.attributes[name][:schema]
|
186
|
+
|
183
187
|
config = {
|
184
188
|
type: filter[:type].to_s,
|
185
189
|
operators: filter[:operators].keys.map(&:to_s),
|
@@ -54,6 +54,7 @@ module Graphiti
|
|
54
54
|
unless type[:canonical_name] == :hash || !value.is_a?(String)
|
55
55
|
value = parse_string_value(filter.values[0], value)
|
56
56
|
end
|
57
|
+
value = parse_string_null(filter.values[0], value)
|
57
58
|
validate_singular(resource, filter, value)
|
58
59
|
value = coerce_types(filter.values[0], param_name.to_sym, value)
|
59
60
|
validate_allowlist(resource, filter, value)
|
@@ -150,8 +151,6 @@ module Graphiti
|
|
150
151
|
# JSON of
|
151
152
|
# {{{ "id": 1 }}} becomes { 'id' => 1 }
|
152
153
|
def parse_string_value(filter, value)
|
153
|
-
return value if !!filter[:single]
|
154
|
-
|
155
154
|
type = Graphiti::Types[filter[:type]]
|
156
155
|
array_or_string = [:string, :array].include?(type[:canonical_name])
|
157
156
|
if (arr = value.scan(/\[.*?\]/)).present? && array_or_string
|
@@ -164,12 +163,12 @@ module Graphiti
|
|
164
163
|
}
|
165
164
|
value = value[0] if value.length == 1
|
166
165
|
else
|
167
|
-
value = parse_string_arrays(value)
|
166
|
+
value = parse_string_arrays(value, !!filter[:single])
|
168
167
|
end
|
169
168
|
value
|
170
169
|
end
|
171
170
|
|
172
|
-
def parse_string_arrays(value)
|
171
|
+
def parse_string_arrays(value, singular_filter)
|
173
172
|
# Find the quoted strings
|
174
173
|
quotes = value.scan(/{{.*?}}/)
|
175
174
|
# remove them from the rest
|
@@ -177,11 +176,21 @@ module Graphiti
|
|
177
176
|
# remove the quote characters from the quoted strings
|
178
177
|
quotes.each { |q| q.gsub!("{{", "").gsub!("}}", "") }
|
179
178
|
# merge everything back together into an array
|
180
|
-
|
179
|
+
if singular_filter
|
180
|
+
value = Array(value) + quotes
|
181
|
+
else
|
182
|
+
value = Array(value.split(",")) + quotes
|
183
|
+
end
|
181
184
|
# remove any blanks that are left
|
182
185
|
value.reject! { |v| v.length.zero? }
|
183
186
|
value = value[0] if value.length == 1
|
184
187
|
value
|
185
188
|
end
|
189
|
+
|
190
|
+
def parse_string_null(filter, value)
|
191
|
+
return if value == "null" && filter[:allow_nil]
|
192
|
+
|
193
|
+
value
|
194
|
+
end
|
186
195
|
end
|
187
196
|
end
|
data/lib/graphiti/types.rb
CHANGED
@@ -13,7 +13,7 @@ module Graphiti
|
|
13
13
|
::DateTime.parse(input.to_s)
|
14
14
|
end
|
15
15
|
end
|
16
|
-
input = Dry::Types["json.date_time"][input]
|
16
|
+
input = Dry::Types["json.date_time"][input] if input.is_a?(::String)
|
17
17
|
Dry::Types["strict.date_time"][input] if input
|
18
18
|
}
|
19
19
|
|
@@ -25,7 +25,8 @@ module Graphiti
|
|
25
25
|
::DateTime.parse(input.to_s)
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
|
+
input = Dry::Types["json.date_time"][input] if input.is_a?(::String)
|
29
30
|
Dry::Types["strict.date_time"][input].iso8601 if input
|
30
31
|
}
|
31
32
|
|
@@ -36,13 +37,13 @@ module Graphiti
|
|
36
37
|
|
37
38
|
Date = create(::Date) { |input|
|
38
39
|
input = ::Date.parse(input.to_s) if input.is_a?(::Time)
|
39
|
-
input = Dry::Types["json.date"][input]
|
40
|
+
input = Dry::Types["json.date"][input] if input.is_a?(::String)
|
40
41
|
Dry::Types["strict.date"][input] if input
|
41
42
|
}
|
42
43
|
|
43
44
|
PresentDate = create(::Date) { |input|
|
44
45
|
input = ::Date.parse(input.to_s) if input.is_a?(::Time)
|
45
|
-
input = Dry::Types["json.date"][input]
|
46
|
+
input = Dry::Types["json.date"][input] if input.is_a?(::String)
|
46
47
|
Dry::Types["strict.date"][input]
|
47
48
|
}
|
48
49
|
|
@@ -60,6 +60,8 @@ class Graphiti::Util::Persistence
|
|
60
60
|
|
61
61
|
post_process(persisted, parents)
|
62
62
|
post_process(persisted, children)
|
63
|
+
after_graph_persist = -> { @resource.after_graph_persist(persisted, metadata) }
|
64
|
+
add_hook(after_graph_persist, :after_graph_persist)
|
63
65
|
before_commit = -> { @resource.before_commit(persisted, metadata) }
|
64
66
|
add_hook(before_commit, :before_commit)
|
65
67
|
after_commit = -> { @resource.after_commit(persisted, metadata) }
|
@@ -41,6 +41,10 @@ module Graphiti
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
def run_graph_persist_hooks
|
45
|
+
run(:after_graph_persist)
|
46
|
+
end
|
47
|
+
|
44
48
|
# Because hooks will be added from the outer edges of
|
45
49
|
# the graph, working inwards
|
46
50
|
def add(prc, lifecycle_event)
|
@@ -59,6 +63,7 @@ module Graphiti
|
|
59
63
|
|
60
64
|
def reset_hooks
|
61
65
|
Thread.current[:_graphiti_hooks] = {
|
66
|
+
after_graph_persist: [],
|
62
67
|
before_commit: [],
|
63
68
|
after_commit: [],
|
64
69
|
}
|
data/lib/graphiti/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphiti
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lee Richmond
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jsonapi-serializable
|
@@ -42,16 +42,22 @@ dependencies:
|
|
42
42
|
name: dry-types
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 0.15.0
|
48
|
+
- - "<"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '2.0'
|
48
51
|
type: :runtime
|
49
52
|
prerelease: false
|
50
53
|
version_requirements: !ruby/object:Gem::Requirement
|
51
54
|
requirements:
|
52
|
-
- - "
|
55
|
+
- - ">="
|
53
56
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
57
|
+
version: 0.15.0
|
58
|
+
- - "<"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '2.0'
|
55
61
|
- !ruby/object:Gem::Dependency
|
56
62
|
name: graphiti_errors
|
57
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -338,8 +344,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
338
344
|
- !ruby/object:Gem::Version
|
339
345
|
version: '0'
|
340
346
|
requirements: []
|
341
|
-
|
342
|
-
rubygems_version: 2.7.6
|
347
|
+
rubygems_version: 3.0.1
|
343
348
|
signing_key:
|
344
349
|
specification_version: 4
|
345
350
|
summary: Easily build jsonapi.org-compatible APIs
|