graphiti 1.2.20 → 1.2.28

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: db3bae18176af83f5ac1b88c50546cefcf57f38245e69a5fcbb45f3028ca2273
4
- data.tar.gz: 6ee077531421990da7d4fe80bedfada136b299420d7b82566e9261b7f1a2800a
3
+ metadata.gz: 62001af4fe0f26688b07d4f9e0565b2f2cd1e875fa299c982ef5986e9db66836
4
+ data.tar.gz: 28ba11c786c4e7eb7be0612c2bd678434156e667110623046438d6e1a1c9b67d
5
5
  SHA512:
6
- metadata.gz: 0ceeabdfe64a03c4d709353a763a49224a14eb068633dcbd67c4ef2ee370dbdcd47781b0a4c15f19fe02956712aaca3dda42a17eb514bf44b821725261dc7ddf
7
- data.tar.gz: d329a82610a68dec935625edbd502e85c39907a64261f170d342f632c82dc211c0fab440edbb16210483eb2154f44d403a2f13d5f3b9b7e41d4aafe68c66bf4a
6
+ metadata.gz: f5ed46d521816170aec5448ee816a5ea336faf791034c63c19a8bce64982d42ed9e19420b3d9e4f4782a78b20f8ba475636d920574b360d947991201eeb50bc8
7
+ data.tar.gz: f8578aa1f893d531146204cc43c142ddc58b4cc98a272e08c33ab13fd308530f04d4bdd273ef638ff88017f88051c44a9c76b0e1335a47c80ec9eee6b412d87b
data/Gemfile CHANGED
@@ -3,8 +3,6 @@ source "https://rubygems.org"
3
3
  # Specify your gem's dependencies in graphiti.gemspec
4
4
  gemspec
5
5
 
6
- gem "standard", "0.4.7"
7
-
8
6
  group :test do
9
7
  gem "pry"
10
8
  gem "pry-byebug", platform: [:mri]
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 4.1"
5
+ gem "rails", "~> 4.2"
6
6
  gem "rspec-rails"
7
7
  gem "sqlite3", "~> 1.3.6"
8
8
  gem "database_cleaner"
@@ -29,6 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.add_development_dependency "kaminari", "~> 0.17"
30
30
  spec.add_development_dependency "bundler"
31
31
  spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_development_dependency "standard", "0.4.7"
32
33
  spec.add_development_dependency "activemodel", ">= 4.1"
33
34
  spec.add_development_dependency "graphiti_spec_helpers", "1.0.beta.4"
34
35
  end
@@ -1,7 +1,7 @@
1
1
  module Graphiti
2
2
  module Adapters
3
3
  class ActiveRecord < ::Graphiti::Adapters::Abstract
4
- require "graphiti/adapters/active_record/inferrence"
4
+ require "graphiti/adapters/active_record/inference"
5
5
  require "graphiti/adapters/active_record/has_many_sideload"
6
6
  require "graphiti/adapters/active_record/belongs_to_sideload"
7
7
  require "graphiti/adapters/active_record/has_one_sideload"
@@ -1,5 +1,5 @@
1
1
  class Graphiti::Adapters::ActiveRecord::BelongsToSideload < Graphiti::Sideload::BelongsTo
2
- include Graphiti::Adapters::ActiveRecord::Inferrence
2
+ include Graphiti::Adapters::ActiveRecord::Inference
3
3
 
4
4
  def default_base_scope
5
5
  resource_class.model.all
@@ -1,5 +1,5 @@
1
1
  class Graphiti::Adapters::ActiveRecord::HasManySideload < Graphiti::Sideload::HasMany
2
- include Graphiti::Adapters::ActiveRecord::Inferrence
2
+ include Graphiti::Adapters::ActiveRecord::Inference
3
3
 
4
4
  def default_base_scope
5
5
  resource_class.model.all
@@ -1,5 +1,5 @@
1
1
  class Graphiti::Adapters::ActiveRecord::HasOneSideload < Graphiti::Sideload::HasOne
2
- include Graphiti::Adapters::ActiveRecord::Inferrence
2
+ include Graphiti::Adapters::ActiveRecord::Inference
3
3
 
4
4
  def default_base_scope
5
5
  resource_class.model.all
@@ -1,6 +1,6 @@
1
- module Graphiti::Adapters::ActiveRecord::Inferrence
1
+ module Graphiti::Adapters::ActiveRecord::Inference
2
2
  # If going AR to AR, use AR introspection
3
- # If going AR to PORO, fall back to normal inferrence
3
+ # If going AR to PORO, fall back to normal inference
4
4
  def infer_foreign_key
5
5
  parent_model = parent_resource_class.model
6
6
  reflection = parent_model.reflections[association_name.to_s]
@@ -8,6 +8,18 @@ class Graphiti::Adapters::ActiveRecord::ManyToManySideload < Graphiti::Sideload:
8
8
  foreign_key.keys.first
9
9
  end
10
10
 
11
+ def inverse_filter
12
+ return @inverse_filter if @inverse_filter
13
+
14
+ inferred_name = infer_inverse_association
15
+
16
+ if inferred_name
17
+ "#{inferred_name.to_s.singularize}_id"
18
+ else
19
+ super
20
+ end
21
+ end
22
+
11
23
  def belongs_to_many_filter(scope, value)
12
24
  if polymorphic?
13
25
  clauses = value.group_by { |v| v["type"] }.map { |group|
@@ -36,8 +48,7 @@ class Graphiti::Adapters::ActiveRecord::ManyToManySideload < Graphiti::Sideload:
36
48
 
37
49
  def filter_for(scope, value, type = nil)
38
50
  scope
39
- .preload(through_relationship_name)
40
- .joins(through_relationship_name)
51
+ .includes(through_relationship_name)
41
52
  .where(belongs_to_many_clause(value, type))
42
53
  end
43
54
 
@@ -76,4 +87,11 @@ class Graphiti::Adapters::ActiveRecord::ManyToManySideload < Graphiti::Sideload:
76
87
  value = through_reflection.foreign_key.to_sym
77
88
  {key => value}
78
89
  end
90
+
91
+ def infer_inverse_association
92
+ through_class = through_reflection.klass
93
+
94
+ foreign_reflection = through_class.reflections[name.to_s.singularize]
95
+ foreign_reflection && foreign_reflection.options[:inverse_of]
96
+ end
79
97
  end
@@ -10,6 +10,8 @@ module Graphiti
10
10
 
11
11
  class << self
12
12
  def on_data(name, start, stop, id, payload)
13
+ return [] unless enabled
14
+
13
15
  took = ((stop - start) * 1000.0).round(2)
14
16
  params = scrub_params(payload[:params])
15
17
 
@@ -24,7 +26,7 @@ module Graphiti
24
26
  end
25
27
  end
26
28
 
27
- def on_data_exception(payload, params)
29
+ private def on_data_exception(payload, params)
28
30
  unless payload[:exception_object].instance_variable_get(:@__graphiti_debug)
29
31
  add_chunk do |logs, json|
30
32
  logs << ["\n=== Graphiti Debug ERROR", :red, true]
@@ -49,11 +51,11 @@ module Graphiti
49
51
  end
50
52
  end
51
53
 
52
- def results(raw_results)
54
+ private def results(raw_results)
53
55
  raw_results.map { |r| "[#{r.class.name}, #{r.id.inspect}]" }.join(", ")
54
56
  end
55
57
 
56
- def on_sideload_data(payload, params, took)
58
+ private def on_sideload_data(payload, params, took)
57
59
  sideload = payload[:sideload]
58
60
  results = results(payload[:results])
59
61
  add_chunk(payload[:resource], payload[:parent]) do |logs, json|
@@ -72,7 +74,7 @@ module Graphiti
72
74
  end
73
75
  end
74
76
 
75
- def on_primary_data(payload, params, took)
77
+ private def on_primary_data(payload, params, took)
76
78
  results = results(payload[:results])
77
79
  add_chunk(payload[:resource], payload[:parent]) do |logs, json|
78
80
  logs << [""]
@@ -90,6 +92,8 @@ module Graphiti
90
92
  end
91
93
 
92
94
  def on_render(name, start, stop, id, payload)
95
+ return [] unless enabled
96
+
93
97
  add_chunk do |logs|
94
98
  took = ((stop - start) * 1000.0).round(2)
95
99
  logs << [""]
@@ -366,6 +366,20 @@ module Graphiti
366
366
  end
367
367
  end
368
368
 
369
+ class UndefinedIDLookup < Base
370
+ def initialize(resource_class)
371
+ @resource_class = resource_class
372
+ end
373
+
374
+ def message
375
+ <<~MSG
376
+ Tried to resolve #{@resource_class} with an :id filter, but the filter was nil.
377
+ This can result in unscoping a query, which can cause incorrect values to be
378
+ returned which may or may not bypass standard access controls.
379
+ MSG
380
+ end
381
+ end
382
+
369
383
  class UnknownAttribute < AttributeError
370
384
  def message
371
385
  "#{super}, but could not find an attribute with that name."
@@ -6,18 +6,18 @@ module Graphiti
6
6
  :deserialized_payload,
7
7
  to: :@validator
8
8
 
9
- def initialize(root_resource, raw_params)
10
- @validator = ValidatorFactory.create(root_resource, raw_params)
9
+ def initialize(root_resource, raw_params, action)
10
+ @validator = ValidatorFactory.create(root_resource, raw_params, action)
11
11
  end
12
12
 
13
13
  class ValidatorFactory
14
- def self.create(root_resource, raw_params)
15
- case raw_params["action"]
16
- when "update" then
14
+ def self.create(root_resource, raw_params, action)
15
+ case action
16
+ when :update then
17
17
  RequestValidators::UpdateValidator
18
18
  else
19
19
  RequestValidators::Validator
20
- end.new(root_resource, raw_params)
20
+ end.new(root_resource, raw_params, action)
21
21
  end
22
22
  end
23
23
  end
@@ -3,10 +3,11 @@ module Graphiti
3
3
  class Validator
4
4
  attr_reader :errors
5
5
 
6
- def initialize(root_resource, raw_params)
6
+ def initialize(root_resource, raw_params, action)
7
7
  @root_resource = root_resource
8
8
  @raw_params = raw_params
9
9
  @errors = Graphiti::Util::SimpleErrors.new(raw_params)
10
+ @action = action
10
11
  end
11
12
 
12
13
  def validate
@@ -68,6 +69,11 @@ module Graphiti
68
69
 
69
70
  def typecast_attributes(resource, attributes, payload_path)
70
71
  attributes.each_pair do |key, value|
72
+ # Only validate id if create action, otherwise it's only used for lookup
73
+ next if @action != :create &&
74
+ key == :id &&
75
+ resource.class.config[:attributes][:id][:writable] == false
76
+
71
77
  begin
72
78
  attributes[key] = resource.typecast(key, value, :writable)
73
79
  rescue Graphiti::Errors::UnknownAttribute
@@ -5,6 +5,7 @@ module Graphiti
5
5
 
6
6
  class_methods do
7
7
  def filter(name, *args, &blk)
8
+ name = name.to_sym
8
9
  opts = args.extract_options!
9
10
  type_override = args[0]
10
11
 
@@ -23,6 +23,9 @@ module Graphiti
23
23
 
24
24
  # @api private
25
25
  def _find(params = {}, base_scope = nil)
26
+ guard_nil_id!(params[:data])
27
+ guard_nil_id!(params)
28
+
26
29
  id = params[:data].try(:[], :id) || params.delete(:id)
27
30
  params[:filter] ||= {}
28
31
  params[:filter][:id] = id if id
@@ -52,6 +55,13 @@ module Graphiti
52
55
  end
53
56
  end
54
57
  end
58
+
59
+ def guard_nil_id!(params)
60
+ return unless params
61
+ if params.key?(:id) && params[:id].nil?
62
+ raise Errors::UndefinedIDLookup.new(self)
63
+ end
64
+ end
55
65
  end
56
66
  end
57
67
  end
@@ -93,7 +93,7 @@ module Graphiti
93
93
  original = Graphiti.context[:namespace]
94
94
  begin
95
95
  Graphiti.context[:namespace] = action
96
- ::Graphiti::RequestValidator.new(@resource, @payload.params).validate!
96
+ ::Graphiti::RequestValidator.new(@resource, @payload.params, action).validate!
97
97
  validator = persist {
98
98
  @resource.persist_with_relationships \
99
99
  @payload.meta(action: action),
@@ -118,6 +118,7 @@ module Graphiti
118
118
  end
119
119
 
120
120
  def destroy
121
+ data
121
122
  transaction_response = @resource.transaction do
122
123
  metadata = {method: :destroy}
123
124
  model = @resource.destroy(@query.filters[:id], metadata)
@@ -135,6 +136,7 @@ module Graphiti
135
136
  end
136
137
 
137
138
  def update_attributes
139
+ data
138
140
  save(action: :update)
139
141
  end
140
142
 
@@ -9,8 +9,7 @@ module Graphiti
9
9
  @query = query
10
10
  @action = action
11
11
 
12
- validator = RequestValidator.new(jsonapi_resource, params)
13
-
12
+ validator = RequestValidator.new(jsonapi_resource, params, action)
14
13
  validator.validate!
15
14
 
16
15
  @deserialized_payload = validator.deserialized_payload
@@ -26,8 +26,8 @@ module Graphiti
26
26
  @foreign_key = opts[:foreign_key]
27
27
  @type = opts[:type]
28
28
  @base_scope = opts[:base_scope]
29
- @readable = evaluate_flag(opts[:readable])
30
- @writable = evaluate_flag(opts[:writable])
29
+ @readable = opts[:readable]
30
+ @writable = opts[:writable]
31
31
  @as = opts[:as]
32
32
  @link = opts[:link]
33
33
  @single = opts[:single]
@@ -426,6 +426,7 @@ module Graphiti
426
426
  Util::Class.namespace_for(klass)
427
427
  end
428
428
 
429
+ # TODO: call this at runtime to support procs
429
430
  def evaluate_flag(flag)
430
431
  return false if flag.blank?
431
432
 
@@ -1,3 +1,3 @@
1
1
  module Graphiti
2
- VERSION = "1.2.20"
2
+ VERSION = "1.2.28"
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.20
4
+ version: 1.2.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Richmond
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-07-17 00:00:00.000000000 Z
11
+ date: 2020-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jsonapi-serializable
@@ -162,6 +162,20 @@ dependencies:
162
162
  - - "~>"
163
163
  - !ruby/object:Gem::Version
164
164
  version: '10.0'
165
+ - !ruby/object:Gem::Dependency
166
+ name: standard
167
+ requirement: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - '='
170
+ - !ruby/object:Gem::Version
171
+ version: 0.4.7
172
+ type: :development
173
+ prerelease: false
174
+ version_requirements: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - '='
177
+ - !ruby/object:Gem::Version
178
+ version: 0.4.7
165
179
  - !ruby/object:Gem::Dependency
166
180
  name: activemodel
167
181
  requirement: !ruby/object:Gem::Requirement
@@ -190,7 +204,7 @@ dependencies:
190
204
  - - '='
191
205
  - !ruby/object:Gem::Version
192
206
  version: 1.0.beta.4
193
- description:
207
+ description:
194
208
  email:
195
209
  - richmolj@gmail.com
196
210
  executables:
@@ -248,7 +262,7 @@ files:
248
262
  - lib/graphiti/adapters/active_record/belongs_to_sideload.rb
249
263
  - lib/graphiti/adapters/active_record/has_many_sideload.rb
250
264
  - lib/graphiti/adapters/active_record/has_one_sideload.rb
251
- - lib/graphiti/adapters/active_record/inferrence.rb
265
+ - lib/graphiti/adapters/active_record/inference.rb
252
266
  - lib/graphiti/adapters/active_record/many_to_many_sideload.rb
253
267
  - lib/graphiti/adapters/graphiti_api.rb
254
268
  - lib/graphiti/adapters/null.rb
@@ -327,7 +341,7 @@ homepage: https://github.com/graphiti-api/graphiti
327
341
  licenses:
328
342
  - MIT
329
343
  metadata: {}
330
- post_install_message:
344
+ post_install_message:
331
345
  rdoc_options: []
332
346
  require_paths:
333
347
  - lib
@@ -343,7 +357,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
343
357
  version: '0'
344
358
  requirements: []
345
359
  rubygems_version: 3.0.6
346
- signing_key:
360
+ signing_key:
347
361
  specification_version: 4
348
362
  summary: Easily build jsonapi.org-compatible APIs
349
363
  test_files: []