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 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