jsonapi-resources 0.10.6 → 0.11.0.beta2

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/LICENSE.txt +1 -1
  3. data/README.md +39 -2
  4. data/lib/generators/jsonapi/controller_generator.rb +2 -0
  5. data/lib/generators/jsonapi/resource_generator.rb +2 -0
  6. data/lib/jsonapi/active_relation/adapters/join_left_active_record_adapter.rb +3 -2
  7. data/lib/jsonapi/active_relation/join_manager.rb +30 -18
  8. data/lib/jsonapi/active_relation/join_manager_v10.rb +305 -0
  9. data/lib/jsonapi/active_relation_retrieval.rb +885 -0
  10. data/lib/jsonapi/active_relation_retrieval_v09.rb +715 -0
  11. data/lib/jsonapi/{active_relation_resource.rb → active_relation_retrieval_v10.rb} +113 -135
  12. data/lib/jsonapi/acts_as_resource_controller.rb +49 -49
  13. data/lib/jsonapi/cached_response_fragment.rb +4 -2
  14. data/lib/jsonapi/callbacks.rb +2 -0
  15. data/lib/jsonapi/compiled_json.rb +2 -0
  16. data/lib/jsonapi/configuration.rb +35 -15
  17. data/lib/jsonapi/error.rb +2 -0
  18. data/lib/jsonapi/error_codes.rb +2 -0
  19. data/lib/jsonapi/exceptions.rb +2 -0
  20. data/lib/jsonapi/formatter.rb +2 -0
  21. data/lib/jsonapi/include_directives.rb +77 -19
  22. data/lib/jsonapi/link_builder.rb +2 -0
  23. data/lib/jsonapi/mime_types.rb +6 -10
  24. data/lib/jsonapi/naive_cache.rb +2 -0
  25. data/lib/jsonapi/operation.rb +2 -0
  26. data/lib/jsonapi/operation_result.rb +2 -0
  27. data/lib/jsonapi/paginator.rb +2 -0
  28. data/lib/jsonapi/path.rb +2 -0
  29. data/lib/jsonapi/path_segment.rb +4 -2
  30. data/lib/jsonapi/processor.rb +95 -140
  31. data/lib/jsonapi/relationship.rb +89 -35
  32. data/lib/jsonapi/{request_parser.rb → request.rb} +157 -164
  33. data/lib/jsonapi/resource.rb +7 -2
  34. data/lib/jsonapi/{basic_resource.rb → resource_common.rb} +187 -88
  35. data/lib/jsonapi/resource_controller.rb +2 -0
  36. data/lib/jsonapi/resource_controller_metal.rb +2 -0
  37. data/lib/jsonapi/resource_fragment.rb +17 -15
  38. data/lib/jsonapi/resource_identity.rb +6 -0
  39. data/lib/jsonapi/resource_serializer.rb +20 -4
  40. data/lib/jsonapi/resource_set.rb +36 -16
  41. data/lib/jsonapi/resource_tree.rb +191 -0
  42. data/lib/jsonapi/resources/railtie.rb +3 -1
  43. data/lib/jsonapi/resources/version.rb +3 -1
  44. data/lib/jsonapi/response_document.rb +4 -2
  45. data/lib/jsonapi/routing_ext.rb +4 -2
  46. data/lib/jsonapi/simple_resource.rb +13 -0
  47. data/lib/jsonapi-resources.rb +10 -4
  48. data/lib/tasks/check_upgrade.rake +3 -1
  49. metadata +47 -15
  50. data/lib/jsonapi/resource_id_tree.rb +0 -112
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JSONAPI
2
- class RequestParser
4
+ class Request
3
5
  attr_accessor :fields, :include, :filters, :sort_criteria, :errors, :controller_module_path,
4
6
  :context, :paginator, :source_klass, :source_id,
5
- :include_directives, :params, :warnings, :server_error_callbacks
7
+ :include_directives, :params, :warnings, :server_error_callbacks, :operations
6
8
 
7
9
  def initialize(params = nil, options = {})
8
10
  @params = params
@@ -18,33 +20,25 @@ module JSONAPI
18
20
  @errors = []
19
21
  @warnings = []
20
22
  @server_error_callbacks = options.fetch(:server_error_callbacks, [])
23
+ @operations = []
24
+
25
+ setup_operations(params)
21
26
  end
22
27
 
23
28
  def error_object_overrides
24
29
  {}
25
30
  end
26
31
 
27
- def each(_response_document)
28
- operation = setup_base_op(params)
29
- if @errors.any?
30
- fail JSONAPI::Exceptions::Errors.new(@errors)
31
- else
32
- yield operation
33
- end
34
- rescue ActionController::ParameterMissing => e
35
- fail JSONAPI::Exceptions::ParameterMissing.new(e.param, error_object_overrides)
36
- end
37
-
38
32
  def transactional?
39
33
  case params[:action]
40
- when 'index', 'show_related_resource', 'index_related_resources', 'show', 'show_relationship'
41
- return false
42
- else
43
- return true
34
+ when 'index', 'show_related_resource', 'index_related_resources', 'show', 'show_relationship'
35
+ false
36
+ else
37
+ true
44
38
  end
45
39
  end
46
40
 
47
- def setup_base_op(params)
41
+ def setup_operations(params)
48
42
  return if params.nil?
49
43
 
50
44
  resource_klass = Resource.resource_klass_for(params[:controller]) if params[:controller]
@@ -68,15 +62,15 @@ module JSONAPI
68
62
  sort_criteria = parse_sort_criteria(resource_klass, params[:sort])
69
63
  paginator = parse_pagination(resource_klass, params[:page])
70
64
 
71
- JSONAPI::Operation.new(
72
- :find,
73
- resource_klass,
74
- context: context,
75
- filters: filters,
76
- include_directives: include_directives,
77
- sort_criteria: sort_criteria,
78
- paginator: paginator,
79
- fields: fields
65
+ @operations << JSONAPI::Operation.new(
66
+ :find,
67
+ resource_klass,
68
+ context: context,
69
+ filters: filters,
70
+ include_directives: include_directives,
71
+ sort_criteria: sort_criteria,
72
+ paginator: paginator,
73
+ fields: fields
80
74
  )
81
75
  end
82
76
 
@@ -90,15 +84,15 @@ module JSONAPI
90
84
 
91
85
  relationship_type = params[:relationship].to_sym
92
86
 
93
- JSONAPI::Operation.new(
94
- :show_related_resource,
95
- resource_klass,
96
- context: @context,
97
- relationship_type: relationship_type,
98
- source_klass: source_klass,
99
- source_id: source_id,
100
- fields: fields,
101
- include_directives: include_directives
87
+ @operations << JSONAPI::Operation.new(
88
+ :show_related_resource,
89
+ resource_klass,
90
+ context: @context,
91
+ relationship_type: relationship_type,
92
+ source_klass: source_klass,
93
+ source_id: source_id,
94
+ fields: fields,
95
+ include_directives: include_directives
102
96
  )
103
97
  end
104
98
 
@@ -114,18 +108,18 @@ module JSONAPI
114
108
  paginator = parse_pagination(resource_klass, params[:page])
115
109
  relationship_type = params[:relationship]
116
110
 
117
- JSONAPI::Operation.new(
118
- :show_related_resources,
119
- resource_klass,
120
- context: @context,
121
- relationship_type: relationship_type,
122
- source_klass: source_klass,
123
- source_id: source_id,
124
- filters: filters,
125
- sort_criteria: sort_criteria,
126
- paginator: paginator,
127
- fields: fields,
128
- include_directives: include_directives
111
+ @operations << JSONAPI::Operation.new(
112
+ :show_related_resources,
113
+ resource_klass,
114
+ context: @context,
115
+ relationship_type: relationship_type,
116
+ source_klass: source_klass,
117
+ source_id: source_id,
118
+ filters: filters,
119
+ sort_criteria: sort_criteria,
120
+ paginator: paginator,
121
+ fields: fields,
122
+ include_directives: include_directives
129
123
  )
130
124
  end
131
125
 
@@ -135,14 +129,14 @@ module JSONAPI
135
129
  include_directives = parse_include_directives(resource_klass, params[:include])
136
130
  id = params[:id]
137
131
 
138
- JSONAPI::Operation.new(
139
- :show,
140
- resource_klass,
141
- context: @context,
142
- id: id,
143
- include_directives: include_directives,
144
- fields: fields,
145
- allowed_resources: params[:allowed_resources]
132
+ @operations << JSONAPI::Operation.new(
133
+ :show,
134
+ resource_klass,
135
+ context: @context,
136
+ id: id,
137
+ include_directives: include_directives,
138
+ fields: fields,
139
+ allowed_resources: params[:allowed_resources]
146
140
  )
147
141
  end
148
142
 
@@ -155,17 +149,17 @@ module JSONAPI
155
149
  sort_criteria = parse_sort_criteria(resource_klass, params[:sort])
156
150
  paginator = parse_pagination(resource_klass, params[:page])
157
151
 
158
- JSONAPI::Operation.new(
159
- :show_relationship,
160
- resource_klass,
161
- context: @context,
162
- relationship_type: relationship_type,
163
- parent_key: resource_klass.verify_key(parent_key),
164
- filters: filters,
165
- sort_criteria: sort_criteria,
166
- paginator: paginator,
167
- fields: fields,
168
- include_directives: include_directives
152
+ @operations << JSONAPI::Operation.new(
153
+ :show_relationship,
154
+ resource_klass,
155
+ context: @context,
156
+ relationship_type: relationship_type,
157
+ parent_key: resource_klass.verify_key(parent_key),
158
+ filters: filters,
159
+ sort_criteria: sort_criteria,
160
+ paginator: paginator,
161
+ fields: fields,
162
+ include_directives: include_directives
169
163
  )
170
164
  end
171
165
 
@@ -183,14 +177,14 @@ module JSONAPI
183
177
 
184
178
  data = parse_params(resource_klass, data, resource_klass.creatable_fields(@context))
185
179
 
186
- JSONAPI::Operation.new(
187
- :create_resource,
188
- resource_klass,
189
- context: @context,
190
- data: data,
191
- fields: fields,
192
- include_directives: include_directives,
193
- warnings: @warnings
180
+ @operations << JSONAPI::Operation.new(
181
+ :create_resource,
182
+ resource_klass,
183
+ context: @context,
184
+ data: data,
185
+ fields: fields,
186
+ include_directives: include_directives,
187
+ warnings: @warnings
194
188
  )
195
189
  end
196
190
 
@@ -225,25 +219,25 @@ module JSONAPI
225
219
 
226
220
  verify_type(data[:type], resource_klass)
227
221
 
228
- JSONAPI::Operation.new(
229
- :replace_fields,
230
- resource_klass,
231
- context: @context,
232
- resource_id: resource_id,
233
- data: parse_params(resource_klass, data, resource_klass.updatable_fields(@context)),
234
- fields: fields,
235
- include_directives: include_directives,
236
- warnings: @warnings
222
+ @operations << JSONAPI::Operation.new(
223
+ :replace_fields,
224
+ resource_klass,
225
+ context: @context,
226
+ resource_id: resource_id,
227
+ data: parse_params(resource_klass, data, resource_klass.updatable_fields(@context)),
228
+ fields: fields,
229
+ include_directives: include_directives,
230
+ warnings: @warnings
237
231
  )
238
232
  end
239
233
 
240
234
  def setup_destroy_action(params, resource_klass)
241
235
  resolve_singleton_id(params, resource_klass)
242
- JSONAPI::Operation.new(
243
- :remove_resource,
244
- resource_klass,
245
- context: @context,
246
- resource_id: resource_klass.verify_key(params.require(:id), @context))
236
+ @operations << JSONAPI::Operation.new(
237
+ :remove_resource,
238
+ resource_klass,
239
+ context: @context,
240
+ resource_id: resource_klass.verify_key(params.require(:id), @context))
247
241
  end
248
242
 
249
243
  def setup_destroy_relationship_action(params, resource_klass)
@@ -349,7 +343,6 @@ module JSONAPI
349
343
  else
350
344
  fail JSONAPI::Exceptions::InvalidInclude.new(format_key(resource_klass._type), include_parts.first)
351
345
  end
352
- true
353
346
  end
354
347
 
355
348
  def parse_include_directives(resource_klass, raw_include)
@@ -458,19 +451,19 @@ module JSONAPI
458
451
  def parse_to_one_links_object(raw)
459
452
  if raw.nil?
460
453
  return {
461
- type: nil,
462
- id: nil
454
+ type: nil,
455
+ id: nil
463
456
  }
464
457
  end
465
458
 
466
459
  if !(raw.is_a?(Hash) || raw.is_a?(ActionController::Parameters)) ||
467
- raw.keys.length != 2 || !(raw.key?('type') && raw.key?('id'))
460
+ raw.keys.length != 2 || !(raw.key?('type') && raw.key?('id'))
468
461
  fail JSONAPI::Exceptions::InvalidLinksObject.new(error_object_overrides)
469
462
  end
470
463
 
471
464
  {
472
- type: unformat_key(raw['type']).to_s,
473
- id: raw['id']
465
+ type: unformat_key(raw['type']).to_s,
466
+ id: raw['id']
474
467
  }
475
468
  end
476
469
 
@@ -499,33 +492,33 @@ module JSONAPI
499
492
 
500
493
  params.each do |key, value|
501
494
  case key.to_s
502
- when 'relationships'
503
- value.each do |link_key, link_value|
504
- param = unformat_key(link_key)
505
- relationship = resource_klass._relationship(param)
506
-
507
- if relationship.is_a?(JSONAPI::Relationship::ToOne)
508
- checked_to_one_relationships[param] = parse_to_one_relationship(resource_klass, link_value, relationship)
509
- elsif relationship.is_a?(JSONAPI::Relationship::ToMany)
510
- parse_to_many_relationship(resource_klass, link_value, relationship) do |result_val|
511
- checked_to_many_relationships[param] = result_val
512
- end
495
+ when 'relationships'
496
+ value.each do |link_key, link_value|
497
+ param = unformat_key(link_key)
498
+ relationship = resource_klass._relationship(param)
499
+
500
+ if relationship.is_a?(JSONAPI::Relationship::ToOne)
501
+ checked_to_one_relationships[param] = parse_to_one_relationship(resource_klass, link_value, relationship)
502
+ elsif relationship.is_a?(JSONAPI::Relationship::ToMany)
503
+ parse_to_many_relationship(resource_klass, link_value, relationship) do |result_val|
504
+ checked_to_many_relationships[param] = result_val
513
505
  end
514
506
  end
515
- when 'id'
516
- checked_attributes['id'] = unformat_value(resource_klass, :id, value)
517
- when 'attributes'
518
- value.each do |key, value|
519
- param = unformat_key(key)
520
- checked_attributes[param] = unformat_value(resource_klass, param, value)
521
- end
507
+ end
508
+ when 'id'
509
+ checked_attributes['id'] = unformat_value(resource_klass, :id, value)
510
+ when 'attributes'
511
+ value.each do |key, value|
512
+ param = unformat_key(key)
513
+ checked_attributes[param] = unformat_value(resource_klass, param, value)
514
+ end
522
515
  end
523
516
  end
524
517
 
525
- return {
526
- 'attributes' => checked_attributes,
527
- 'to_one' => checked_to_one_relationships,
528
- 'to_many' => checked_to_many_relationships
518
+ {
519
+ 'attributes' => checked_attributes,
520
+ 'to_one' => checked_to_one_relationships,
521
+ 'to_many' => checked_to_many_relationships
529
522
  }.deep_transform_keys { |key| unformat_key(key) }
530
523
  end
531
524
 
@@ -584,7 +577,7 @@ module JSONAPI
584
577
  end
585
578
 
586
579
  relationship_ids = relationship_resource_klass.verify_keys(keys, @context)
587
- polymorphic_results << { type: type, ids: relationship_ids }
580
+ polymorphic_results << { type: type, ids: relationship_ids }
588
581
  end
589
582
 
590
583
  add_result.call polymorphic_results
@@ -612,45 +605,45 @@ module JSONAPI
612
605
 
613
606
  params.each do |key, value|
614
607
  case key.to_s
615
- when 'relationships'
616
- value.keys.each do |links_key|
617
- unless formatted_allowed_fields.include?(links_key.to_sym)
618
- if JSONAPI.configuration.raise_if_parameters_not_allowed
619
- fail JSONAPI::Exceptions::ParameterNotAllowed.new(links_key, error_object_overrides)
620
- else
621
- params_not_allowed.push(links_key)
622
- value.delete links_key
623
- end
624
- end
625
- end
626
- when 'attributes'
627
- value.each do |attr_key, _attr_value|
628
- unless formatted_allowed_fields.include?(attr_key.to_sym)
629
- if JSONAPI.configuration.raise_if_parameters_not_allowed
630
- fail JSONAPI::Exceptions::ParameterNotAllowed.new(attr_key, error_object_overrides)
631
- else
632
- params_not_allowed.push(attr_key)
633
- value.delete attr_key
634
- end
608
+ when 'relationships'
609
+ value.keys.each do |links_key|
610
+ unless formatted_allowed_fields.include?(links_key.to_sym)
611
+ if JSONAPI.configuration.raise_if_parameters_not_allowed
612
+ fail JSONAPI::Exceptions::ParameterNotAllowed.new(links_key, error_object_overrides)
613
+ else
614
+ params_not_allowed.push(links_key)
615
+ value.delete links_key
635
616
  end
636
617
  end
637
- when 'type'
638
- when 'id'
639
- unless formatted_allowed_fields.include?(:id)
618
+ end
619
+ when 'attributes'
620
+ value.each do |attr_key, _attr_value|
621
+ unless formatted_allowed_fields.include?(attr_key.to_sym)
640
622
  if JSONAPI.configuration.raise_if_parameters_not_allowed
641
- fail JSONAPI::Exceptions::ParameterNotAllowed.new(:id, error_object_overrides)
623
+ fail JSONAPI::Exceptions::ParameterNotAllowed.new(attr_key, error_object_overrides)
642
624
  else
643
- params_not_allowed.push(:id)
644
- params.delete :id
625
+ params_not_allowed.push(attr_key)
626
+ value.delete attr_key
645
627
  end
646
628
  end
647
- else
629
+ end
630
+ when 'type'
631
+ when 'id'
632
+ unless formatted_allowed_fields.include?(:id)
648
633
  if JSONAPI.configuration.raise_if_parameters_not_allowed
649
- fail JSONAPI::Exceptions::ParameterNotAllowed.new(key, error_object_overrides)
634
+ fail JSONAPI::Exceptions::ParameterNotAllowed.new(:id, error_object_overrides)
650
635
  else
651
- params_not_allowed.push(key)
652
- params.delete key
636
+ params_not_allowed.push(:id)
637
+ params.delete :id
653
638
  end
639
+ end
640
+ else
641
+ if JSONAPI.configuration.raise_if_parameters_not_allowed
642
+ fail JSONAPI::Exceptions::ParameterNotAllowed.new(key, error_object_overrides)
643
+ else
644
+ params_not_allowed.push(key)
645
+ params.delete key
646
+ end
654
647
  end
655
648
  end
656
649
 
@@ -666,22 +659,22 @@ module JSONAPI
666
659
 
667
660
  def parse_add_relationship_operation(resource_klass, verified_params, relationship, parent_key)
668
661
  if relationship.is_a?(JSONAPI::Relationship::ToMany)
669
- return JSONAPI::Operation.new(
670
- :create_to_many_relationships,
671
- resource_klass,
672
- context: @context,
673
- resource_id: parent_key,
674
- relationship_type: relationship.name,
675
- data: verified_params[:to_many].values[0]
662
+ @operations << JSONAPI::Operation.new(
663
+ :create_to_many_relationships,
664
+ resource_klass,
665
+ context: @context,
666
+ resource_id: parent_key,
667
+ relationship_type: relationship.name,
668
+ data: verified_params[:to_many].values[0]
676
669
  )
677
670
  end
678
671
  end
679
672
 
680
673
  def parse_update_relationship_operation(resource_klass, verified_params, relationship, parent_key)
681
674
  options = {
682
- context: @context,
683
- resource_id: parent_key,
684
- relationship_type: relationship.name
675
+ context: @context,
676
+ resource_id: parent_key,
677
+ relationship_type: relationship.name
685
678
  }
686
679
 
687
680
  if relationship.is_a?(JSONAPI::Relationship::ToOne)
@@ -702,23 +695,23 @@ module JSONAPI
702
695
  operation_type = :replace_to_many_relationships
703
696
  end
704
697
 
705
- JSONAPI::Operation.new(operation_type, resource_klass, options)
698
+ @operations << JSONAPI::Operation.new(operation_type, resource_klass, options)
706
699
  end
707
700
 
708
701
  def parse_remove_relationship_operation(resource_klass, params, relationship, parent_key)
709
702
  operation_base_args = [resource_klass].push(
710
- context: @context,
711
- resource_id: parent_key,
712
- relationship_type: relationship.name
703
+ context: @context,
704
+ resource_id: parent_key,
705
+ relationship_type: relationship.name
713
706
  )
714
707
 
715
708
  if relationship.is_a?(JSONAPI::Relationship::ToMany)
716
709
  operation_args = operation_base_args.dup
717
710
  keys = params[:to_many].values[0]
718
711
  operation_args[1] = operation_args[1].merge(associated_keys: keys)
719
- JSONAPI::Operation.new(:remove_to_many_relationships, *operation_args)
712
+ @operations << JSONAPI::Operation.new(:remove_to_many_relationships, *operation_args)
720
713
  else
721
- JSONAPI::Operation.new(:remove_to_one_relationship, *operation_base_args)
714
+ @operations << JSONAPI::Operation.new(:remove_to_one_relationship, *operation_base_args)
722
715
  end
723
716
  end
724
717
 
@@ -1,5 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JSONAPI
2
- class Resource < ActiveRelationResource
4
+ class Resource
5
+ include ResourceCommon
3
6
  root_resource
7
+ abstract
8
+ immutable
4
9
  end
5
- end
10
+ end