graphiti 1.2.16 → 1.2.17

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +43 -14
  3. data/Appraisals +37 -5
  4. data/Guardfile +4 -4
  5. data/deprecated_generators/graphiti/resource_generator.rb +1 -1
  6. data/gemfiles/rails_5_0.gemfile +18 -0
  7. data/gemfiles/rails_5_0_graphiti_rails.gemfile +20 -0
  8. data/gemfiles/rails_5_1.gemfile +18 -0
  9. data/gemfiles/rails_5_1_graphiti_rails.gemfile +20 -0
  10. data/gemfiles/{rails_5.gemfile → rails_5_2.gemfile} +0 -0
  11. data/gemfiles/{rails_5_graphiti_rails.gemfile → rails_5_2_graphiti_rails.gemfile} +0 -0
  12. data/gemfiles/rails_6.gemfile +1 -1
  13. data/gemfiles/rails_6_graphiti_rails.gemfile +1 -1
  14. data/graphiti.gemspec +10 -10
  15. data/lib/graphiti.rb +3 -3
  16. data/lib/graphiti/adapters/abstract.rb +3 -3
  17. data/lib/graphiti/adapters/active_record.rb +64 -35
  18. data/lib/graphiti/configuration.rb +1 -1
  19. data/lib/graphiti/debugger.rb +4 -4
  20. data/lib/graphiti/delegates/pagination.rb +3 -3
  21. data/lib/graphiti/deserializer.rb +3 -3
  22. data/lib/graphiti/errors.rb +24 -4
  23. data/lib/graphiti/query.rb +4 -4
  24. data/lib/graphiti/railtie.rb +1 -1
  25. data/lib/graphiti/request_validator.rb +4 -4
  26. data/lib/graphiti/request_validators/update_validator.rb +1 -2
  27. data/lib/graphiti/request_validators/validator.rb +2 -2
  28. data/lib/graphiti/resource/configuration.rb +6 -4
  29. data/lib/graphiti/resource/dsl.rb +5 -4
  30. data/lib/graphiti/resource/links.rb +3 -3
  31. data/lib/graphiti/resource/persistence.rb +2 -1
  32. data/lib/graphiti/resource/polymorphism.rb +2 -1
  33. data/lib/graphiti/resource/remote.rb +1 -1
  34. data/lib/graphiti/runner.rb +1 -1
  35. data/lib/graphiti/schema.rb +6 -6
  36. data/lib/graphiti/scope.rb +5 -5
  37. data/lib/graphiti/scoping/base.rb +3 -3
  38. data/lib/graphiti/scoping/filter.rb +17 -7
  39. data/lib/graphiti/scoping/sort.rb +1 -1
  40. data/lib/graphiti/sideload.rb +26 -22
  41. data/lib/graphiti/sideload/belongs_to.rb +1 -1
  42. data/lib/graphiti/stats/payload.rb +4 -4
  43. data/lib/graphiti/types.rb +15 -15
  44. data/lib/graphiti/util/link.rb +5 -1
  45. data/lib/graphiti/util/persistence.rb +16 -10
  46. data/lib/graphiti/util/relationship_payload.rb +4 -4
  47. data/lib/graphiti/util/simple_errors.rb +1 -1
  48. data/lib/graphiti/util/transaction_hooks_recorder.rb +1 -1
  49. data/lib/graphiti/version.rb +1 -1
  50. metadata +8 -4
@@ -43,7 +43,7 @@ module Graphiti
43
43
  end
44
44
 
45
45
  if (logger = ::Rails.logger)
46
- self.debug = logger.level.zero? && self.debug
46
+ self.debug = logger.level.zero? && debug
47
47
  Graphiti.logger = logger
48
48
  end
49
49
  end
@@ -59,10 +59,10 @@ module Graphiti
59
59
  add_chunk(payload[:resource], payload[:parent]) do |logs, json|
60
60
  logs << [" \\_ #{sideload.name}", :yellow, true]
61
61
  json[:name] = sideload.name
62
- if sideload.class.scope_proc
63
- query = "#{payload[:resource].class.name}: Manual sideload via .scope"
62
+ query = if sideload.class.scope_proc
63
+ "#{payload[:resource].class.name}: Manual sideload via .scope"
64
64
  else
65
- query = "#{payload[:resource].class.name}.all(#{params.inspect})"
65
+ "#{payload[:resource].class.name}.all(#{params.inspect})"
66
66
  end
67
67
  logs << [" #{query}", :cyan, true]
68
68
  json[:query] = query
@@ -148,7 +148,7 @@ module Graphiti
148
148
  parent: parent,
149
149
  logs: logs,
150
150
  json: json,
151
- children: [],
151
+ children: []
152
152
  }
153
153
  end
154
154
 
@@ -15,7 +15,7 @@ module Graphiti
15
15
  links[:last] = pagination_link(last_page)
16
16
  links[:prev] = pagination_link(current_page - 1) unless current_page == 1
17
17
  links[:next] = pagination_link(current_page + 1) unless current_page == last_page
18
- end.select {|k, v| !v.nil? }
18
+ end.select { |k, v| !v.nil? }
19
19
  end
20
20
 
21
21
  private
@@ -29,8 +29,8 @@ module Graphiti
29
29
  uri.query = @proxy.query.hash.merge({
30
30
  page: {
31
31
  number: page,
32
- size: page_size,
33
- },
32
+ size: page_size
33
+ }
34
34
  }).to_query
35
35
  uri.to_s
36
36
  end
@@ -87,7 +87,7 @@ class Graphiti::Deserializer
87
87
  type: data[:type],
88
88
  temp_id: data[:'temp-id'],
89
89
  method: action,
90
- payload_path: ["data"],
90
+ payload_path: ["data"]
91
91
  }
92
92
  end
93
93
 
@@ -185,10 +185,10 @@ class Graphiti::Deserializer
185
185
  jsonapi_type: datum[:type],
186
186
  temp_id: temp_id,
187
187
  method: method,
188
- payload_path: ["included", included_idx],
188
+ payload_path: ["included", included_idx]
189
189
  },
190
190
  attributes: attributes,
191
- relationships: relationships,
191
+ relationships: relationships
192
192
  }
193
193
  end
194
194
 
@@ -143,8 +143,13 @@ module Graphiti
143
143
  def message
144
144
  allow = @filter.values[0][:allow]
145
145
  deny = @filter.values[0][:deny]
146
+ value_string = if @value == "(empty)"
147
+ "empty value"
148
+ else
149
+ "value #{@value.inspect}"
150
+ end
146
151
  msg = <<-MSG
147
- #{@resource.class.name}: tried to filter on #{@filter.keys[0].inspect}, but passed invalid value #{@value.inspect}.
152
+ #{@resource.class.name}: tried to filter on #{@filter.keys[0].inspect}, but passed invalid #{value_string}.
148
153
  MSG
149
154
  msg << "\nAllowlist: #{allow.inspect}" if allow
150
155
  msg << "\nDenylist: #{deny.inspect}" if deny
@@ -189,7 +194,7 @@ module Graphiti
189
194
 
190
195
  Make sure the endpoint "#{@sideload.resource.endpoint[:full_path]}" exists with action #{@action.inspect}, or customize the endpoint for #{@sideload.resource.class.name}.
191
196
 
192
- If you do not wish to generate a link, pass link: false or set self.relationship_links_by_default = false.
197
+ If you do not wish to generate a link, pass link: false or set self.autolink = false.
193
198
  MSG
194
199
  end
195
200
  end
@@ -316,14 +321,14 @@ module Graphiti
316
321
  sortable: "sort on",
317
322
  filterable: "filter on",
318
323
  readable: "read",
319
- writable: "write",
324
+ writable: "write"
320
325
  }[@flag]
321
326
  else
322
327
  {
323
328
  sortable: "add sort",
324
329
  filterable: "add filter",
325
330
  readable: "read",
326
- writable: "write",
331
+ writable: "write"
327
332
  }[@flag]
328
333
  end
329
334
  end
@@ -722,6 +727,21 @@ module Graphiti
722
727
  end
723
728
 
724
729
  class RecordNotFound < Base
730
+ def initialize(resource = nil, id = nil, path = nil)
731
+ @resource = resource
732
+ @id = id
733
+ @path = path
734
+ end
735
+
736
+ def message
737
+ if !@resource.nil? && !@id.nil?
738
+ "The referenced resource '#{@resource}' with id '#{@id}' could not be found.".tap do |msg|
739
+ msg << " Referenced at '#{@path}'" unless @path.nil?
740
+ end
741
+ else
742
+ "Specified Record Not Found"
743
+ end
744
+ end
725
745
  end
726
746
 
727
747
  class RequiredFilter < Base
@@ -232,7 +232,7 @@ module Graphiti
232
232
  return true if @resource.remote?
233
233
 
234
234
  if (att = @resource.get_attr(name, flag, request: true))
235
- return att
235
+ att
236
236
  else
237
237
  not_associated_name = !@resource.class.association_names.include?(name)
238
238
  not_associated_type = !@resource.class.association_types.include?(name)
@@ -262,8 +262,8 @@ module Graphiti
262
262
  def parse_fieldset(fieldset)
263
263
  {}.tap do |hash|
264
264
  fieldset.each_pair do |type, fields|
265
- type = type.to_sym
266
- fields = fields.split(",") unless fields.is_a?(Array)
265
+ type = type.to_sym
266
+ fields = fields.split(",") unless fields.is_a?(Array)
267
267
  hash[type] = fields.map(&:to_sym)
268
268
  end
269
269
  end
@@ -282,7 +282,7 @@ module Graphiti
282
282
 
283
283
  def sort_hash(attr)
284
284
  value = attr[0] == "-" ? :desc : :asc
285
- key = attr.sub("-", "").to_sym
285
+ key = attr.sub("-", "").to_sym
286
286
 
287
287
  {key => value}
288
288
  end
@@ -6,7 +6,7 @@ module Graphiti
6
6
  end
7
7
 
8
8
  generators do
9
- Dir[File.expand_path("../../deprecated_generators/**/*.rb", __dir__)].each do |f|
9
+ Dir[File.expand_path("../../deprecated_generators/**/*.rb", __dir__)].sort.each do |f|
10
10
  require f
11
11
  end
12
12
  end
@@ -1,10 +1,10 @@
1
1
  module Graphiti
2
2
  class RequestValidator
3
3
  delegate :validate,
4
- :validate!,
5
- :errors,
6
- :deserialized_payload,
7
- to: :@validator
4
+ :validate!,
5
+ :errors,
6
+ :deserialized_payload,
7
+ to: :@validator
8
8
 
9
9
  def initialize(root_resource, raw_params)
10
10
  @validator = ValidatorFactory.create(root_resource, raw_params)
@@ -5,7 +5,7 @@ module Graphiti
5
5
  if required_payload? && payload_matches_endpoint?
6
6
  super
7
7
  else
8
- return false
8
+ false
9
9
  end
10
10
  end
11
11
 
@@ -36,7 +36,6 @@ module Graphiti
36
36
  attribute_mismatch([:data, :id])
37
37
  end
38
38
 
39
-
40
39
  meta_type = @raw_params.dig(:data, :type)
41
40
 
42
41
  # NOTE: calling #to_s and comparing 2 strings is slower than
@@ -25,7 +25,7 @@ module Graphiti
25
25
 
26
26
  def validate!
27
27
  unless validate
28
- raise @error_class || Graphiti::Errors::InvalidRequest, self.errors
28
+ raise @error_class || Graphiti::Errors::InvalidRequest, errors
29
29
  end
30
30
 
31
31
  true
@@ -47,7 +47,7 @@ module Graphiti
47
47
  def process_relationships(resource, relationships, payload_path)
48
48
  opts = {
49
49
  resource: resource,
50
- relationships: relationships,
50
+ relationships: relationships
51
51
  }
52
52
 
53
53
  Graphiti::Util::RelationshipPayload.iterate(opts) do |x|
@@ -22,7 +22,7 @@ module Graphiti
22
22
  end
23
23
 
24
24
  def type=(val)
25
- val = val && val.to_sym
25
+ val = val&.to_sym
26
26
  if (val = super)
27
27
  serializer.type(val)
28
28
  end
@@ -42,7 +42,7 @@ module Graphiti
42
42
  path: val,
43
43
  full_path: val,
44
44
  url: val,
45
- actions: [:index, :show],
45
+ actions: [:index, :show]
46
46
  }
47
47
  end
48
48
 
@@ -82,7 +82,8 @@ module Graphiti
82
82
  :attributes_schema_by_default,
83
83
  :relationships_readable_by_default,
84
84
  :relationships_writable_by_default,
85
- :filters_accept_nil_by_default
85
+ :filters_accept_nil_by_default,
86
+ :filters_deny_empty_by_default
86
87
 
87
88
  class << self
88
89
  prepend Overrides
@@ -104,6 +105,7 @@ module Graphiti
104
105
  default(klass, :relationships_readable_by_default, true)
105
106
  default(klass, :relationships_writable_by_default, true)
106
107
  default(klass, :filters_accept_nil_by_default, false)
108
+ default(klass, :filters_deny_empty_by_default, false)
107
109
 
108
110
  unless klass.config[:attributes][:id]
109
111
  klass.attribute :id, :integer_id
@@ -197,7 +199,7 @@ module Graphiti
197
199
  attributes: {},
198
200
  extra_attributes: {},
199
201
  sideloads: {},
200
- callbacks: {},
202
+ callbacks: {}
201
203
  }
202
204
  end
203
205
 
@@ -32,7 +32,8 @@ 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
+ allow_nil: opts.fetch(:allow_nil, filters_accept_nil_by_default),
36
+ deny_empty: opts.fetch(:deny_empty, filters_deny_empty_by_default)
36
37
  }
37
38
  elsif (type = args[0])
38
39
  attribute name, type, only: [:filterable], allow: opts[:allow]
@@ -55,7 +56,7 @@ module Graphiti
55
56
 
56
57
  if get_attr(name, :sortable, raise_error: :only_unsupported)
57
58
  config[:sorts][name] = {
58
- proc: blk,
59
+ proc: blk
59
60
  }.merge(opts.slice(:only))
60
61
  elsif (type = args[0])
61
62
  attribute name, type, only: [:sortable]
@@ -78,7 +79,7 @@ module Graphiti
78
79
  def default_filter(name = nil, &blk)
79
80
  name ||= :__default
80
81
  config[:default_filters][name.to_sym] = {
81
- filter: blk,
82
+ filter: blk
82
83
  }
83
84
  end
84
85
 
@@ -131,7 +132,7 @@ module Graphiti
131
132
  readable: true,
132
133
  writable: false,
133
134
  sortable: false,
134
- filterable: false,
135
+ filterable: false
135
136
  }
136
137
  options = defaults.merge(options)
137
138
  config[:extra_attributes][name] = options
@@ -39,7 +39,7 @@ module Graphiti
39
39
  path: path,
40
40
  full_path: full_path_for(path),
41
41
  url: url_for(path),
42
- actions: DEFAULT_ACTIONS.dup,
42
+ actions: DEFAULT_ACTIONS.dup
43
43
  }
44
44
  end
45
45
 
@@ -49,7 +49,7 @@ module Graphiti
49
49
  path: path,
50
50
  full_path: full_path_for(path),
51
51
  url: url_for(path),
52
- actions: actions,
52
+ actions: actions
53
53
  }
54
54
  end
55
55
 
@@ -60,7 +60,7 @@ module Graphiti
60
60
  path: path,
61
61
  full_path: full_path_for(path),
62
62
  url: url_for(path),
63
- actions: actions,
63
+ actions: actions
64
64
  }]
65
65
  end
66
66
 
@@ -89,7 +89,8 @@ module Graphiti
89
89
 
90
90
  def update(update_params, meta = nil)
91
91
  model_instance = nil
92
- id = update_params.delete(:id)
92
+ id = update_params[:id]
93
+ update_params = update_params.except(:id)
93
94
 
94
95
  run_callbacks :persistence, :update, update_params, meta do
95
96
  run_callbacks :attributes, :update, update_params, meta do |params|
@@ -67,7 +67,8 @@ module Graphiti
67
67
  end
68
68
 
69
69
  def resource_for_model(model)
70
- resource = children.find { |c| model.is_a?(c.model) }
70
+ resource = children.find { |c| model.class == c.model } ||
71
+ children.find { |c| model.is_a?(c.model) }
71
72
  if resource.nil?
72
73
  raise Errors::PolymorphicResourceChildNotFound.new(self, model: model)
73
74
  else
@@ -19,7 +19,7 @@ module Graphiti
19
19
  end
20
20
 
21
21
  def save(model, meta)
22
- if meta[:attributes] == {} && meta[:method] == :update
22
+ if meta[:attributes].except(:id) == {} && meta[:method] == :update
23
23
  model
24
24
  else
25
25
  raise Errors::RemoteWrite.new(self.class)
@@ -50,7 +50,7 @@ module Graphiti
50
50
  def jsonapi_render_options
51
51
  options = {}
52
52
  options.merge!(default_jsonapi_render_options)
53
- options[:meta] ||= {}
53
+ options[:meta] ||= {}
54
54
  options[:expose] ||= {}
55
55
  options[:expose][:context] = jsonapi_context
56
56
  options
@@ -33,7 +33,7 @@ module Graphiti
33
33
  {
34
34
  resources: generate_resources,
35
35
  endpoints: generate_endpoints,
36
- types: generate_types,
36
+ types: generate_types
37
37
  }
38
38
  end
39
39
 
@@ -94,7 +94,7 @@ module Graphiti
94
94
  extra_attributes: extra_attributes(r),
95
95
  sorts: sorts(r),
96
96
  filters: filters(r),
97
- relationships: relationships(r),
97
+ relationships: relationships(r)
98
98
  }
99
99
 
100
100
  if r.default_sort
@@ -121,7 +121,7 @@ module Graphiti
121
121
  name: r.name,
122
122
  description: r.description,
123
123
  remote: r.remote_url,
124
- relationships: relationships(r),
124
+ relationships: relationships(r)
125
125
  }
126
126
  }
127
127
 
@@ -136,7 +136,7 @@ module Graphiti
136
136
  type: config[:type].to_s,
137
137
  readable: flag(config[:readable]),
138
138
  writable: flag(config[:writable]),
139
- description: resource.attribute_description(name),
139
+ description: resource.attribute_description(name)
140
140
  }
141
141
  end
142
142
  end
@@ -149,7 +149,7 @@ module Graphiti
149
149
  attrs[name] = {
150
150
  type: config[:type].to_s,
151
151
  readable: flag(config[:readable]),
152
- description: resource.attribute_description(name),
152
+ description: resource.attribute_description(name)
153
153
  }
154
154
  end
155
155
  end
@@ -186,7 +186,7 @@ module Graphiti
186
186
 
187
187
  config = {
188
188
  type: filter[:type].to_s,
189
- operators: filter[:operators].keys.map(&:to_s),
189
+ operators: filter[:operators].keys.map(&:to_s)
190
190
  }
191
191
 
192
192
  config[:single] = true if filter[:single]
@@ -3,10 +3,10 @@ module Graphiti
3
3
  attr_accessor :object, :unpaginated_object
4
4
  attr_reader :pagination
5
5
  def initialize(object, resource, query, opts = {})
6
- @object = object
7
- @resource = resource
8
- @query = query
9
- @opts = opts
6
+ @object = object
7
+ @resource = resource
8
+ @query = query
9
+ @opts = opts
10
10
 
11
11
  @object = @resource.around_scoping(@object, @query.hash) { |scope|
12
12
  apply_scoping(scope, opts)
@@ -75,7 +75,7 @@ module Graphiti
75
75
  resource: @resource,
76
76
  params: @opts[:params],
77
77
  sideload: @opts[:sideload],
78
- parent: @opts[:parent],
78
+ parent: @opts[:parent]
79
79
  # Set once data is resolved within block
80
80
  # results: ...
81
81
  }