graphiti 1.2.2 → 1.2.3
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/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
|