graphiti 1.2.16 → 1.2.17

Sign up to get free protection for your applications and to get access to all the features.
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
  }