graphiti 1.2.28 → 1.2.29

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: 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
  - - ">="