graphiti 1.2.28 → 1.2.29

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: 62001af4fe0f26688b07d4f9e0565b2f2cd1e875fa299c982ef5986e9db66836
4
- data.tar.gz: 28ba11c786c4e7eb7be0612c2bd678434156e667110623046438d6e1a1c9b67d
3
+ metadata.gz: 4a1198667bd97f2aed53ee9652bf58e778c9423541e85c40122fcca1e504af6a
4
+ data.tar.gz: 58b4a16c2344147408b8f6bae93ba0f7268f45db8e1fdb0782f2eb452257f6af
5
5
  SHA512:
6
- metadata.gz: f5ed46d521816170aec5448ee816a5ea336faf791034c63c19a8bce64982d42ed9e19420b3d9e4f4782a78b20f8ba475636d920574b360d947991201eeb50bc8
7
- data.tar.gz: f8578aa1f893d531146204cc43c142ddc58b4cc98a272e08c33ab13fd308530f04d4bdd273ef638ff88017f88051c44a9c76b0e1335a47c80ec9eee6b412d87b
6
+ metadata.gz: 4000d1e9f172c3cb1b973d8545dc02d6771951ed16efac8e21ce948de2a7ebb457115128d375dfda7f0d05bc334ab2851f6d69b0de8c23530bae8c47702d12f4
7
+ data.tar.gz: a10bfea53ddbd2af821d9467204fd4550a288fe6a5f57b02e63915e7d14230b00924ec20a0f3e350c1282bf9aeaf75a043ce5309ca83bf892c900f5add59f776
@@ -19,7 +19,13 @@ env:
19
19
  - COMMAND="standardrb --no-fix --format progress"
20
20
  - COMMAND=rspec
21
21
  - COMMAND=rspec APPRAISAL_INITIALIZED=true
22
- matrix:
22
+ jobs:
23
+ allow_failures:
24
+ - rvm: ruby-head
25
+ include:
26
+ - env: COMMAND=rspec
27
+ gemfile: Gemfile
28
+ rvm: ruby-head
23
29
  exclude:
24
30
  # Don't run the appraisal version of the specs for the base gemfile
25
31
  - env: COMMAND=rspec APPRAISAL_INITIALIZED=true
@@ -8,6 +8,9 @@ Features:
8
8
  - [157](https://github.com/graphiti-api/graphiti/pull/157) Using attribute option schema: false.
9
9
  This option is default true and is not effected by only and except options. (@zeisler)
10
10
 
11
+ Fixes:
12
+ - [282] Support model names including "Resource"
13
+
11
14
  ## 1.1.0
12
15
 
13
16
  Features:
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.bindir = "exe"
17
17
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
18
  spec.require_paths = ["lib"]
19
- spec.required_ruby_version = "~> 2.3"
19
+ spec.required_ruby_version = [">= 2.3", "< 3.1"]
20
20
 
21
21
  spec.add_dependency "jsonapi-serializable", "~> 0.3.0"
22
22
  spec.add_dependency "jsonapi-renderer", "~> 0.2", ">= 0.2.2"
@@ -1,6 +1,9 @@
1
1
  module Graphiti
2
2
  module Adapters
3
3
  class Abstract
4
+ require "graphiti/adapters/persistence/associations.rb"
5
+ include Graphiti::Adapters::Persistence::Associations
6
+
4
7
  attr_reader :resource
5
8
 
6
9
  def initialize(resource)
@@ -400,6 +403,13 @@ module Graphiti
400
403
  raise "you must override #destroy in an adapter subclass"
401
404
  end
402
405
 
406
+ def close
407
+ end
408
+
409
+ def persistence_attributes(persistance, attributes)
410
+ attributes
411
+ end
412
+
403
413
  def self.numerical_operators
404
414
  [:eq, :not_eq, :gt, :gte, :lt, :lte].freeze
405
415
  end
@@ -191,7 +191,7 @@ module Graphiti
191
191
  # (see Adapters::Abstract#count)
192
192
  def count(scope, attr)
193
193
  if attr.to_sym == :total
194
- scope.distinct.count
194
+ scope.distinct.count(:all)
195
195
  else
196
196
  scope.distinct.count(attr)
197
197
  end
@@ -297,6 +297,10 @@ module Graphiti
297
297
  model_instance
298
298
  end
299
299
 
300
+ def close
301
+ ActiveRecord::Base.clear_active_connections!
302
+ end
303
+
300
304
  private
301
305
 
302
306
  def column_for(scope, name)
@@ -0,0 +1,72 @@
1
+ module Graphiti
2
+ module Adapters
3
+ module Persistence
4
+ module Associations
5
+ def process_belongs_to(persistence, attributes)
6
+ parents = [].tap do |processed|
7
+ persistence.iterate(only: [:polymorphic_belongs_to, :belongs_to]) do |x|
8
+ begin
9
+ id = x.dig(:attributes, :id)
10
+ x[:object] = x[:resource]
11
+ .persist_with_relationships(x[:meta], x[:attributes], x[:relationships])
12
+ processed << x
13
+ rescue Graphiti::Errors::RecordNotFound
14
+ path = "relationships/#{x.dig(:meta, :jsonapi_type)}"
15
+ raise Graphiti::Errors::RecordNotFound.new(x[:sideload].name, id, path)
16
+ end
17
+ end
18
+ end
19
+
20
+ update_foreign_key_for_parents(parents, attributes)
21
+ parents
22
+ end
23
+
24
+ def process_has_many(persistence, caller_model)
25
+ [].tap do |processed|
26
+ persistence.iterate(except: [:polymorphic_belongs_to, :belongs_to]) do |x|
27
+ update_foreign_key(caller_model, x[:attributes], x)
28
+
29
+ x[:object] = x[:resource]
30
+ .persist_with_relationships(x[:meta], x[:attributes], x[:relationships], caller_model, x[:foreign_key])
31
+
32
+ processed << x
33
+ end
34
+ end
35
+ end
36
+
37
+ def update_foreign_key_for_parents(parents, attributes)
38
+ parents.each do |x|
39
+ update_foreign_key(x[:object], attributes, x)
40
+ end
41
+ end
42
+
43
+ # The child's attributes should be modified to nil-out the
44
+ # foreign_key when the parent is being destroyed or disassociated
45
+ #
46
+ # This is not the case for HABTM, whose "foreign key" is a join table
47
+ def update_foreign_key(parent_object, attrs, x)
48
+ return if x[:sideload].type == :many_to_many
49
+
50
+ if [:destroy, :disassociate].include?(x[:meta][:method])
51
+ if x[:sideload].polymorphic_has_one? || x[:sideload].polymorphic_has_many?
52
+ attrs[:"#{x[:sideload].polymorphic_as}_type"] = nil
53
+ end
54
+ attrs[x[:foreign_key]] = nil
55
+ update_foreign_type(attrs, x, null: true) if x[:is_polymorphic]
56
+ else
57
+ if x[:sideload].polymorphic_has_one? || x[:sideload].polymorphic_has_many?
58
+ attrs[:"#{x[:sideload].polymorphic_as}_type"] = parent_object.class.name
59
+ end
60
+ attrs[x[:foreign_key]] = parent_object.send(x[:primary_key])
61
+ update_foreign_type(attrs, x) if x[:is_polymorphic]
62
+ end
63
+ end
64
+
65
+ def update_foreign_type(attrs, x, null: false)
66
+ grouping_field = x[:sideload].parent.grouper.field_name
67
+ attrs[grouping_field] = null ? nil : x[:sideload].group_name
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -6,7 +6,7 @@ module Graphiti
6
6
  end
7
7
 
8
8
  def links?
9
- @proxy.query.pagination_links?
9
+ @proxy.query.pagination_links? && @proxy.data.present?
10
10
  end
11
11
 
12
12
  def links
@@ -53,7 +53,7 @@ module Graphiti
53
53
  def item_count
54
54
  begin
55
55
  return @item_count if @item_count
56
- @item_count = @proxy.resource.stat(:total, :count).call(@proxy.scope.unpaginated_object, :total)
56
+ @item_count = item_count_from_proxy || item_count_from_stats
57
57
  unless @item_count.is_a?(Numeric)
58
58
  raise TypeError, "#{@proxy.resource}.stat(:total, :count) returned an invalid value #{@item_count}"
59
59
  end
@@ -68,6 +68,15 @@ module Graphiti
68
68
  @item_count
69
69
  end
70
70
 
71
+ def item_count_from_proxy
72
+ @proxy.stats.dig(:total, :count)
73
+ end
74
+
75
+ def item_count_from_stats
76
+ stats = Stats::Payload.new(@proxy.resource, @proxy.query, @proxy.scope.unpaginated_object, @proxy.data)
77
+ stats.calculate_stat(:total, @proxy.resource.stat(:total, :count))
78
+ end
79
+
71
80
  def current_page
72
81
  @current_page ||= (page_param[:number] || 1).to_i
73
82
  end
@@ -45,10 +45,10 @@ module Graphiti
45
45
  {}.tap do |hash|
46
46
  hash[:data] = if serializers.is_a?(Array)
47
47
  serializers.map do |s|
48
- s.to_hash(opts)
48
+ s.to_hash(**opts)
49
49
  end
50
50
  else
51
- serializers.to_hash(opts)
51
+ serializers.to_hash(**opts)
52
52
  end
53
53
  end
54
54
  end
@@ -51,7 +51,7 @@ module Graphiti
51
51
  relationships: relationships
52
52
  }
53
53
 
54
- Graphiti::Util::RelationshipPayload.iterate(opts) do |x|
54
+ Graphiti::Util::RelationshipPayload.iterate(**opts) do |x|
55
55
  sideload_def = x[:sideload]
56
56
 
57
57
  unless sideload_def.writable?
@@ -129,7 +129,7 @@ module Graphiti
129
129
  def get_attr(name, flag, opts = {})
130
130
  defaults = {request: false}
131
131
  opts = defaults.merge(opts)
132
- new.get_attr(name, flag, opts)
132
+ new.get_attr(name, flag, **opts)
133
133
  end
134
134
 
135
135
  def abstract_class?
@@ -149,14 +149,14 @@ module Graphiti
149
149
 
150
150
  def infer_type
151
151
  if name.present?
152
- name.demodulize.gsub("Resource", "").underscore.pluralize.to_sym
152
+ name.demodulize.sub(/.*\KResource/, "").underscore.pluralize.to_sym
153
153
  else
154
154
  :undefined_jsonapi_type
155
155
  end
156
156
  end
157
157
 
158
158
  def infer_model
159
- name&.gsub("Resource", "")&.safe_constantize
159
+ name&.sub(/.*\KResource/, "")&.safe_constantize
160
160
  end
161
161
 
162
162
  # @api private
@@ -247,7 +247,7 @@ module Graphiti
247
247
 
248
248
  def get_attr!(name, flag, options = {})
249
249
  options[:raise_error] = true
250
- get_attr(name, flag, options)
250
+ get_attr(name, flag, **options)
251
251
  end
252
252
 
253
253
  def get_attr(name, flag, request: false, raise_error: false)
@@ -45,9 +45,7 @@ module Graphiti
45
45
  resolve_sideload = -> {
46
46
  Graphiti.context = graphiti_context
47
47
  sideload.resolve(results, q, parent_resource)
48
- if concurrent && defined?(ActiveRecord)
49
- ActiveRecord::Base.clear_active_connections!
50
- end
48
+ @resource.adapter.close if concurrent
51
49
  }
52
50
  if concurrent
53
51
  promises << Concurrent::Promise.execute(&resolve_sideload)
@@ -22,8 +22,8 @@ module Graphiti
22
22
  end
23
23
  end
24
24
 
25
- def as_jsonapi(*)
26
- super.tap do |hash|
25
+ def as_jsonapi(kwargs = {})
26
+ super(**kwargs).tap do |hash|
27
27
  strip_relationships!(hash) if strip_relationships?
28
28
  add_links!(hash)
29
29
  end
@@ -31,16 +31,19 @@ module Graphiti
31
31
  stats[name] = {}
32
32
 
33
33
  each_calculation(name, calculation) do |calc, function|
34
- args = [@scope, name]
35
- args << @resource.context if function.arity >= 3
36
- args << @data if function.arity == 4
37
-
38
- stats[name][calc] = function.call(*args)
34
+ stats[name][calc] = calculate_stat(name, function)
39
35
  end
40
36
  end
41
37
  end
42
38
  end
43
39
 
40
+ def calculate_stat(name, function)
41
+ args = [@scope, name]
42
+ args << @resource.context if function.arity >= 3
43
+ args << @data if function.arity == 4
44
+ function.call(*args)
45
+ end
46
+
44
47
  private
45
48
 
46
49
  def each_calculation(name, calculations)
@@ -44,7 +44,7 @@ module Graphiti
44
44
  Graphiti::Errors::UnknownAttribute
45
45
 
46
46
  if raise_error?(opts[:exists])
47
- raise error_class.new(resource, name, flag, opts)
47
+ raise error_class.new(resource, name, flag, **opts)
48
48
  else
49
49
  false
50
50
  end
@@ -14,6 +14,7 @@ class Graphiti::Util::Persistence
14
14
  @relationships = relationships
15
15
  @caller_model = caller_model
16
16
  @foreign_key = foreign_key
17
+ @adapter = @resource.adapter
17
18
 
18
19
  # Find the correct child resource for a given jsonapi type
19
20
  if (meta_type = @meta[:type].try(:to_sym))
@@ -43,18 +44,16 @@ class Graphiti::Util::Persistence
43
44
  #
44
45
  # @return a model instance
45
46
  def run
46
- parents = process_belongs_to(@relationships)
47
- update_foreign_key_for_parents(parents)
47
+ attributes = @adapter.persistence_attributes(self, @attributes)
48
48
 
49
- persisted = persist_object(@meta[:method], @attributes)
49
+ parents = @adapter.process_belongs_to(self, attributes)
50
+ persisted = persist_object(@meta[:method], attributes)
50
51
  @resource.decorate_record(persisted)
51
52
  assign_temp_id(persisted, @meta[:temp_id])
52
53
 
53
54
  associate_parents(persisted, parents)
54
55
 
55
- children = process_has_many(@relationships, persisted) { |x|
56
- update_foreign_key(persisted, x[:attributes], x)
57
- }
56
+ children = @adapter.process_has_many(self, persisted)
58
57
 
59
58
  associate_children(persisted, children) unless @meta[:method] == :destroy
60
59
 
@@ -69,43 +68,21 @@ class Graphiti::Util::Persistence
69
68
  persisted
70
69
  end
71
70
 
72
- private
73
-
74
- def add_hook(prc, lifecycle_event)
75
- ::Graphiti::Util::TransactionHooksRecorder.add(prc, lifecycle_event)
76
- end
77
-
78
- # The child's attributes should be modified to nil-out the
79
- # foreign_key when the parent is being destroyed or disassociated
80
- #
81
- # This is not the case for HABTM, whose "foreign key" is a join table
82
- def update_foreign_key(parent_object, attrs, x)
83
- return if x[:sideload].type == :many_to_many
71
+ def iterate(only: [], except: [])
72
+ opts = {
73
+ resource: @resource,
74
+ relationships: @relationships
75
+ }.merge(only: only, except: except)
84
76
 
85
- if [:destroy, :disassociate].include?(x[:meta][:method])
86
- if x[:sideload].polymorphic_has_one? || x[:sideload].polymorphic_has_many?
87
- attrs[:"#{x[:sideload].polymorphic_as}_type"] = nil
88
- end
89
- attrs[x[:foreign_key]] = nil
90
- update_foreign_type(attrs, x, null: true) if x[:is_polymorphic]
91
- else
92
- if x[:sideload].polymorphic_has_one? || x[:sideload].polymorphic_has_many?
93
- attrs[:"#{x[:sideload].polymorphic_as}_type"] = parent_object.class.name
94
- end
95
- attrs[x[:foreign_key]] = parent_object.send(x[:primary_key])
96
- update_foreign_type(attrs, x) if x[:is_polymorphic]
77
+ Graphiti::Util::RelationshipPayload.iterate(**opts) do |x|
78
+ yield x
97
79
  end
98
80
  end
99
81
 
100
- def update_foreign_type(attrs, x, null: false)
101
- grouping_field = x[:sideload].parent.grouper.field_name
102
- attrs[grouping_field] = null ? nil : x[:sideload].group_name
103
- end
82
+ private
104
83
 
105
- def update_foreign_key_for_parents(parents)
106
- parents.each do |x|
107
- update_foreign_key(x[:object], @attributes, x)
108
- end
84
+ def add_hook(prc, lifecycle_event)
85
+ ::Graphiti::Util::TransactionHooksRecorder.add(prc, lifecycle_event)
109
86
  end
110
87
 
111
88
  def associate_parents(object, parents)
@@ -161,35 +138,6 @@ class Graphiti::Util::Persistence
161
138
  end
162
139
  end
163
140
 
164
- def process_has_many(relationships, caller_model)
165
- [].tap do |processed|
166
- iterate(except: [:polymorphic_belongs_to, :belongs_to]) do |x|
167
- yield x
168
-
169
- x[:object] = x[:resource]
170
- .persist_with_relationships(x[:meta], x[:attributes], x[:relationships], caller_model, x[:foreign_key])
171
-
172
- processed << x
173
- end
174
- end
175
- end
176
-
177
- def process_belongs_to(relationships)
178
- [].tap do |processed|
179
- iterate(only: [:polymorphic_belongs_to, :belongs_to]) do |x|
180
- begin
181
- id = x.dig(:attributes, :id)
182
- x[:object] = x[:resource]
183
- .persist_with_relationships(x[:meta], x[:attributes], x[:relationships])
184
- processed << x
185
- rescue Graphiti::Errors::RecordNotFound
186
- path = "relationships/#{x.dig(:meta, :jsonapi_type)}"
187
- raise Graphiti::Errors::RecordNotFound.new(x[:sideload].name, id, path)
188
- end
189
- end
190
- end
191
- end
192
-
193
141
  def post_process(caller_model, processed)
194
142
  groups = processed.group_by { |x| x[:meta][:method] }
195
143
  groups.each_pair do |method, group|
@@ -205,17 +153,6 @@ class Graphiti::Util::Persistence
205
153
  object.instance_variable_set(:@_jsonapi_temp_id, temp_id)
206
154
  end
207
155
 
208
- def iterate(only: [], except: [])
209
- opts = {
210
- resource: @resource,
211
- relationships: @relationships
212
- }.merge(only: only, except: except)
213
-
214
- Graphiti::Util::RelationshipPayload.iterate(opts) do |x|
215
- yield x
216
- end
217
- end
218
-
219
156
  def metadata
220
157
  {
221
158
  method: @meta[:method],
@@ -55,13 +55,16 @@ module Graphiti
55
55
  def guard
56
56
  method_name = @attr[:readable]
57
57
  instance = @resource.new
58
+ attribute = @name.to_s
58
59
 
59
60
  -> {
60
61
  method = instance.method(method_name)
61
62
  if method.arity.zero?
62
63
  instance.instance_eval(&method_name)
63
- else
64
+ elsif method.arity == 1
64
65
  instance.instance_exec(@object, &method)
66
+ else
67
+ instance.instance_exec(@object, attribute, &method)
65
68
  end
66
69
  }
67
70
  end
@@ -1,3 +1,3 @@
1
1
  module Graphiti
2
- VERSION = "1.2.28"
2
+ VERSION = "1.2.29"
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.28
4
+ version: 1.2.29
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Richmond
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-19 00:00:00.000000000 Z
11
+ date: 2020-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jsonapi-serializable
@@ -266,6 +266,7 @@ files:
266
266
  - lib/graphiti/adapters/active_record/many_to_many_sideload.rb
267
267
  - lib/graphiti/adapters/graphiti_api.rb
268
268
  - lib/graphiti/adapters/null.rb
269
+ - lib/graphiti/adapters/persistence/associations.rb
269
270
  - lib/graphiti/cli.rb
270
271
  - lib/graphiti/configuration.rb
271
272
  - lib/graphiti/context.rb
@@ -347,9 +348,12 @@ require_paths:
347
348
  - lib
348
349
  required_ruby_version: !ruby/object:Gem::Requirement
349
350
  requirements:
350
- - - "~>"
351
+ - - ">="
351
352
  - !ruby/object:Gem::Version
352
353
  version: '2.3'
354
+ - - "<"
355
+ - !ruby/object:Gem::Version
356
+ version: '3.1'
353
357
  required_rubygems_version: !ruby/object:Gem::Requirement
354
358
  requirements:
355
359
  - - ">="