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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c32e852f2ca9612b4aa23f76b56407c6630dfdedc3f92dd796e15371a328e07c
4
- data.tar.gz: ad997863f7a4f3ead3d184e3568a42743b2bdbb517f2f7b6f64969923d2b83c4
3
+ metadata.gz: d55ad609644e718abecd160c32841a49fd66123c901a17c809279df9edc47e01
4
+ data.tar.gz: eb67647f916696ee9664619076335eaa5e19407b63b2a504b582e9fee9cf6e17
5
5
  SHA512:
6
- metadata.gz: 17acf0e59cb4bbda082f8a977c6689fc24bb4889f96cb1978fd89954100cfdaf4143f6a38cb4c0ad16a74b42a40c81d2ce0e7e2d23337846dba178d3bc953059
7
- data.tar.gz: f3eaab52d8880e40c915f743ff65049416181dfd80e73a2d6c6b443b050dd4e92ba4d3a93f71c416e1a6901ecfcc16d035aad604449caad868819a0d43e70358
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", "~> 0.15"
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"
@@ -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!
@@ -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
- value = Array(value.split(",")) + quotes
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
@@ -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
- input = Dry::Types["json.date_time"][input]
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
  }
@@ -1,3 +1,3 @@
1
1
  module Graphiti
2
- VERSION = "1.2.2"
2
+ VERSION = "1.2.3"
3
3
  end
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.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-06-11 00:00:00.000000000 Z
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: '0.15'
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: '0.15'
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
- rubyforge_project:
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