jsonapi-resources 0.10.7 → 0.11.0.beta2

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/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 -17
  28. data/lib/jsonapi/path.rb +2 -0
  29. data/lib/jsonapi/path_segment.rb +4 -2
  30. data/lib/jsonapi/processor.rb +100 -153
  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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JSONAPI
2
4
  class Processor
3
5
  include Callbacks
@@ -49,7 +51,7 @@ module JSONAPI
49
51
 
50
52
  verified_filters = resource_klass.verify_filters(filters, context)
51
53
 
52
- find_options = {
54
+ options = {
53
55
  context: context,
54
56
  sort_criteria: sort_criteria,
55
57
  paginator: paginator,
@@ -58,20 +60,18 @@ module JSONAPI
58
60
  include_directives: include_directives
59
61
  }
60
62
 
61
- resource_set = find_resource_set(resource_klass,
62
- include_directives,
63
- find_options)
63
+ resource_set = find_resource_set(include_directives, options)
64
64
 
65
- resource_set.populate!(serializer, context, find_options)
65
+ resource_set.populate!(serializer, context, options)
66
66
 
67
67
  page_options = result_options
68
- if (top_level_meta_include_record_count || (paginator && paginator.requires_record_count))
68
+ if (JSONAPI.configuration.top_level_meta_include_record_count || (paginator && paginator.class.requires_record_count))
69
69
  page_options[:record_count] = resource_klass.count(verified_filters,
70
70
  context: context,
71
71
  include_directives: include_directives)
72
72
  end
73
73
 
74
- if (top_level_meta_include_page_count && paginator && page_options[:record_count])
74
+ if (JSONAPI.configuration.top_level_meta_include_page_count && paginator && page_options[:record_count])
75
75
  page_options[:page_count] = paginator ? paginator.calculate_page_count(page_options[:record_count]) : 1
76
76
  end
77
77
 
@@ -79,7 +79,7 @@ module JSONAPI
79
79
  page_options[:pagination_params] = paginator.links_page_params(page_options.merge(fetched_resources: resource_set))
80
80
  end
81
81
 
82
- return JSONAPI::ResourcesSetOperationResult.new(:ok, resource_set, page_options)
82
+ JSONAPI::ResourcesSetOperationResult.new(:ok, resource_set, page_options)
83
83
  end
84
84
 
85
85
  def show
@@ -90,26 +90,25 @@ module JSONAPI
90
90
 
91
91
  key = resource_klass.verify_key(id, context)
92
92
 
93
- find_options = {
93
+ options = {
94
94
  context: context,
95
95
  fields: fields,
96
96
  filters: { resource_klass._primary_key => key },
97
97
  include_directives: include_directives
98
98
  }
99
99
 
100
- resource_set = find_resource_set(resource_klass,
101
- include_directives,
102
- find_options)
100
+ resource_set = find_resource_set(include_directives, options)
103
101
 
104
102
  fail JSONAPI::Exceptions::RecordNotFound.new(id) if resource_set.resource_klasses.empty?
105
- resource_set.populate!(serializer, context, find_options)
103
+ resource_set.populate!(serializer, context, options)
106
104
 
107
- return JSONAPI::ResourceSetOperationResult.new(:ok, resource_set, result_options)
105
+ JSONAPI::ResourceSetOperationResult.new(:ok, resource_set, result_options)
108
106
  end
109
107
 
110
108
  def show_relationship
111
109
  parent_key = params[:parent_key]
112
110
  relationship_type = params[:relationship_type].to_sym
111
+ relationship = resource_klass._relationship(relationship_type)
113
112
  paginator = params[:paginator]
114
113
  sort_criteria = params[:sort_criteria]
115
114
  include_directives = params[:include_directives]
@@ -117,25 +116,26 @@ module JSONAPI
117
116
 
118
117
  parent_resource = resource_klass.find_by_key(parent_key, context: context)
119
118
 
120
- find_options = {
121
- context: context,
122
- sort_criteria: sort_criteria,
123
- paginator: paginator,
124
- fields: fields,
125
- include_directives: include_directives
119
+ options = {
120
+ context: context,
121
+ sort_criteria: sort_criteria,
122
+ paginator: paginator,
123
+ fields: fields,
124
+ include_directives: include_directives
126
125
  }
127
126
 
128
- resource_id_tree = find_related_resource_id_tree(resource_klass,
129
- JSONAPI::ResourceIdentity.new(resource_klass, parent_key),
130
- relationship_type,
131
- find_options,
132
- nil)
133
-
134
- return JSONAPI::RelationshipOperationResult.new(:ok,
135
- parent_resource,
136
- resource_klass._relationship(relationship_type),
137
- resource_id_tree.fragments.keys,
138
- result_options)
127
+ resource_tree = find_related_resource_tree(
128
+ parent_resource,
129
+ relationship,
130
+ options,
131
+ nil
132
+ )
133
+
134
+ JSONAPI::RelationshipOperationResult.new(:ok,
135
+ parent_resource,
136
+ relationship,
137
+ resource_tree.fragments.keys,
138
+ result_options)
139
139
  end
140
140
 
141
141
  def show_related_resource
@@ -146,11 +146,11 @@ module JSONAPI
146
146
  serializer = params[:serializer]
147
147
  fields = params[:fields]
148
148
 
149
- find_options = {
150
- context: context,
151
- fields: fields,
152
- filters: {},
153
- include_directives: include_directives
149
+ options = {
150
+ context: context,
151
+ fields: fields,
152
+ filters: {},
153
+ include_directives: include_directives
154
154
  }
155
155
 
156
156
  source_resource = source_klass.find_by_key(source_id, context: context, fields: fields)
@@ -158,11 +158,11 @@ module JSONAPI
158
158
  resource_set = find_related_resource_set(source_resource,
159
159
  relationship_type,
160
160
  include_directives,
161
- find_options)
161
+ options)
162
162
 
163
- resource_set.populate!(serializer, context, find_options)
163
+ resource_set.populate!(serializer, context, options)
164
164
 
165
- return JSONAPI::ResourceSetOperationResult.new(:ok, resource_set, result_options)
165
+ JSONAPI::ResourceSetOperationResult.new(:ok, resource_set, result_options)
166
166
  end
167
167
 
168
168
  def show_related_resources
@@ -178,8 +178,8 @@ module JSONAPI
178
178
 
179
179
  verified_filters = resource_klass.verify_filters(filters, context)
180
180
 
181
- find_options = {
182
- filters: verified_filters,
181
+ options = {
182
+ filters: verified_filters,
183
183
  sort_criteria: sort_criteria,
184
184
  paginator: paginator,
185
185
  fields: fields,
@@ -192,38 +192,40 @@ module JSONAPI
192
192
  resource_set = find_related_resource_set(source_resource,
193
193
  relationship_type,
194
194
  include_directives,
195
- find_options)
195
+ options)
196
196
 
197
- resource_set.populate!(serializer, context, find_options)
197
+ resource_set.populate!(serializer, context, options)
198
198
 
199
199
  opts = result_options
200
- if ((top_level_meta_include_record_count) ||
201
- (paginator && paginator.requires_record_count) ||
202
- (top_level_meta_include_page_count))
200
+ if ((JSONAPI.configuration.top_level_meta_include_record_count) ||
201
+ (paginator && paginator.class.requires_record_count) ||
202
+ (JSONAPI.configuration.top_level_meta_include_page_count))
203
+
204
+ relationship = source_resource.class._relationship(relationship_type)
203
205
 
204
206
  opts[:record_count] = source_resource.class.count_related(
205
- source_resource.identity,
206
- relationship_type,
207
- find_options)
207
+ source_resource,
208
+ relationship,
209
+ options)
208
210
  end
209
211
 
210
- if (top_level_meta_include_page_count && opts[:record_count])
212
+ if (JSONAPI.configuration.top_level_meta_include_page_count && opts[:record_count])
211
213
  opts[:page_count] = paginator.calculate_page_count(opts[:record_count])
212
214
  end
213
215
 
214
216
  opts[:pagination_params] = if paginator && JSONAPI.configuration.top_level_links_include_pagination
215
217
  page_options = {}
216
- page_options[:record_count] = opts[:record_count] if paginator.requires_record_count
218
+ page_options[:record_count] = opts[:record_count] if paginator.class.requires_record_count
217
219
  paginator.links_page_params(page_options.merge(fetched_resources: resource_set))
218
220
  else
219
221
  {}
220
222
  end
221
223
 
222
- return JSONAPI::RelatedResourcesSetOperationResult.new(:ok,
223
- source_resource,
224
- relationship_type,
225
- resource_set,
226
- opts)
224
+ JSONAPI::RelatedResourcesSetOperationResult.new(:ok,
225
+ source_resource,
226
+ relationship_type,
227
+ resource_set,
228
+ opts)
227
229
  end
228
230
 
229
231
  def create_resource
@@ -235,20 +237,18 @@ module JSONAPI
235
237
  resource = resource_klass.create(context)
236
238
  result = resource.replace_fields(data)
237
239
 
238
- find_options = {
239
- context: context,
240
- fields: fields,
241
- filters: { resource_klass._primary_key => resource.id },
242
- include_directives: include_directives
240
+ options = {
241
+ context: context,
242
+ fields: fields,
243
+ filters: { resource_klass._primary_key => resource.id },
244
+ include_directives: include_directives
243
245
  }
244
246
 
245
- resource_set = find_resource_set(resource_klass,
246
- include_directives,
247
- find_options)
247
+ resource_set = find_resource_set(include_directives, options)
248
248
 
249
- resource_set.populate!(serializer, context, find_options)
249
+ resource_set.populate!(serializer, context, options)
250
250
 
251
- return JSONAPI::ResourceSetOperationResult.new((result == :completed ? :created : :accepted), resource_set, result_options)
251
+ JSONAPI::ResourceSetOperationResult.new((result == :completed ? :created : :accepted), resource_set, result_options)
252
252
  end
253
253
 
254
254
  def remove_resource
@@ -257,7 +257,7 @@ module JSONAPI
257
257
  resource = resource_klass.find_by_key(resource_id, context: context)
258
258
  result = resource.remove
259
259
 
260
- return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
260
+ JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
261
261
  end
262
262
 
263
263
  def replace_fields
@@ -272,20 +272,18 @@ module JSONAPI
272
272
 
273
273
  result = resource.replace_fields(data)
274
274
 
275
- find_options = {
276
- context: context,
277
- fields: fields,
278
- filters: { resource_klass._primary_key => resource.id },
279
- include_directives: include_directives
275
+ options = {
276
+ context: context,
277
+ fields: fields,
278
+ filters: { resource_klass._primary_key => resource.id },
279
+ include_directives: include_directives
280
280
  }
281
281
 
282
- resource_set = find_resource_set(resource_klass,
283
- include_directives,
284
- find_options)
282
+ resource_set = find_resource_set(include_directives, options)
285
283
 
286
- resource_set.populate!(serializer, context, find_options)
284
+ resource_set.populate!(serializer, context, options)
287
285
 
288
- return JSONAPI::ResourceSetOperationResult.new((result == :completed ? :ok : :accepted), resource_set, result_options)
286
+ JSONAPI::ResourceSetOperationResult.new((result == :completed ? :ok : :accepted), resource_set, result_options)
289
287
  end
290
288
 
291
289
  def replace_to_one_relationship
@@ -296,7 +294,7 @@ module JSONAPI
296
294
  resource = resource_klass.find_by_key(resource_id, context: context)
297
295
  result = resource.replace_to_one_link(relationship_type, key_value)
298
296
 
299
- return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
297
+ JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
300
298
  end
301
299
 
302
300
  def replace_polymorphic_to_one_relationship
@@ -308,7 +306,7 @@ module JSONAPI
308
306
  resource = resource_klass.find_by_key(resource_id, context: context)
309
307
  result = resource.replace_polymorphic_to_one_link(relationship_type, key_value, key_type)
310
308
 
311
- return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
309
+ JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
312
310
  end
313
311
 
314
312
  def create_to_many_relationships
@@ -319,7 +317,7 @@ module JSONAPI
319
317
  resource = resource_klass.find_by_key(resource_id, context: context)
320
318
  result = resource.create_to_many_links(relationship_type, data)
321
319
 
322
- return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
320
+ JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
323
321
  end
324
322
 
325
323
  def replace_to_many_relationships
@@ -330,7 +328,7 @@ module JSONAPI
330
328
  resource = resource_klass.find_by_key(resource_id, context: context)
331
329
  result = resource.replace_to_many_links(relationship_type, data)
332
330
 
333
- return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
331
+ JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
334
332
  end
335
333
 
336
334
  def remove_to_many_relationships
@@ -347,7 +345,7 @@ module JSONAPI
347
345
  complete = false
348
346
  end
349
347
  end
350
- return JSONAPI::OperationResult.new(complete ? :no_content : :accepted, result_options)
348
+ JSONAPI::OperationResult.new(complete ? :no_content : :accepted, result_options)
351
349
  end
352
350
 
353
351
  def remove_to_one_relationship
@@ -357,7 +355,7 @@ module JSONAPI
357
355
  resource = resource_klass.find_by_key(resource_id, context: context)
358
356
  result = resource.remove_to_one_link(relationship_type)
359
357
 
360
- return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
358
+ JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
361
359
  end
362
360
 
363
361
  def result_options
@@ -366,99 +364,48 @@ module JSONAPI
366
364
  options
367
365
  end
368
366
 
369
- def find_resource_set(resource_klass, include_directives, options)
370
- include_related = include_directives.include_directives[:include_related] if include_directives
367
+ def find_resource_set(include_directives, options)
368
+ include_related = include_directives[:include_related] if include_directives
371
369
 
372
- resource_id_tree = find_resource_id_tree(resource_klass, options, include_related)
370
+ resource_tree = find_resource_tree(options, include_related)
373
371
 
374
- JSONAPI::ResourceSet.new(resource_id_tree)
372
+ JSONAPI::ResourceSet.new(resource_tree)
375
373
  end
376
374
 
377
375
  def find_related_resource_set(resource, relationship_name, include_directives, options)
378
- include_related = include_directives.include_directives[:include_related] if include_directives
379
-
380
- resource_id_tree = find_resource_id_tree_from_resource_relationship(resource, relationship_name, options, include_related)
376
+ include_related = include_directives[:include_related] if include_directives
381
377
 
382
- JSONAPI::ResourceSet.new(resource_id_tree)
383
- end
384
-
385
- def top_level_meta_include_record_count
386
- JSONAPI.configuration.top_level_meta_include_record_count
387
- end
378
+ resource_tree = find_resource_tree_from_relationship(resource, relationship_name, options, include_related)
388
379
 
389
- def top_level_meta_include_page_count
390
- JSONAPI.configuration.top_level_meta_include_page_count
380
+ JSONAPI::ResourceSet.new(resource_tree)
391
381
  end
392
382
 
393
- private
394
- def find_related_resource_id_tree(resource_klass, source_id, relationship_name, find_options, include_related)
395
- options = find_options.except(:include_directives)
383
+ def find_resource_tree(options, include_related)
396
384
  options[:cache] = resource_klass.caching?
397
385
 
398
- fragments = resource_klass.find_included_fragments([source_id], relationship_name, options)
399
-
400
- primary_resource_id_tree = PrimaryResourceIdTree.new
401
- primary_resource_id_tree.add_resource_fragments(fragments, include_related)
402
-
403
- load_included(resource_klass, primary_resource_id_tree, include_related, options)
404
-
405
- primary_resource_id_tree
386
+ fragments = resource_klass.find_fragments(options[:filters], options)
387
+ PrimaryResourceTree.new(fragments: fragments, include_related: include_related, options: options)
406
388
  end
407
389
 
408
- def find_resource_id_tree(resource_klass, find_options, include_related)
409
- options = find_options
390
+ def find_related_resource_tree(parent_resource, relationship, options, include_related)
391
+ options = options.except(:include_directives)
410
392
  options[:cache] = resource_klass.caching?
411
393
 
412
- fragments = resource_klass.find_fragments(find_options[:filters], options)
413
-
414
- primary_resource_id_tree = PrimaryResourceIdTree.new
415
- primary_resource_id_tree.add_resource_fragments(fragments, include_related)
394
+ parent_resource_fragment = parent_resource.fragment(primary: true)
416
395
 
417
- load_included(resource_klass, primary_resource_id_tree, include_related, options)
418
-
419
- primary_resource_id_tree
396
+ fragments = resource_klass.find_related_fragments(parent_resource_fragment, relationship, options)
397
+ PrimaryResourceTree.new(fragments: fragments, include_related: include_related, options: options)
420
398
  end
421
399
 
422
- def find_resource_id_tree_from_resource_relationship(resource, relationship_name, find_options, include_related)
400
+ def find_resource_tree_from_relationship(resource, relationship_name, options, include_related)
423
401
  relationship = resource.class._relationship(relationship_name)
424
402
 
425
- options = find_options.except(:include_directives)
403
+ options = options.except(:include_directives)
426
404
  options[:cache] = relationship.resource_klass.caching?
427
405
 
428
- fragments = resource.class.find_related_fragments([resource.identity], relationship_name, options)
429
-
430
- primary_resource_id_tree = PrimaryResourceIdTree.new
431
- primary_resource_id_tree.add_resource_fragments(fragments, include_related)
406
+ fragments = resource.class.find_related_fragments(resource.fragment, relationship, options)
432
407
 
433
- load_included(resource_klass, primary_resource_id_tree, include_related, options)
434
-
435
- primary_resource_id_tree
436
- end
437
-
438
- def load_included(resource_klass, source_resource_id_tree, include_related, options)
439
- source_rids = source_resource_id_tree.fragments.keys
440
-
441
- include_related.try(:each_key) do |key|
442
- relationship = resource_klass._relationship(key)
443
- relationship_name = relationship.name.to_sym
444
-
445
- find_related_resource_options = options.except(:filters, :sort_criteria, :paginator)
446
- find_related_resource_options[:sort_criteria] = relationship.resource_klass.default_sort
447
- find_related_resource_options[:cache] = resource_klass.caching?
448
-
449
- related_fragments = resource_klass.find_included_fragments(
450
- source_rids, relationship_name, find_related_resource_options
451
- )
452
-
453
- related_resource_id_tree = source_resource_id_tree.fetch_related_resource_id_tree(relationship)
454
- related_resource_id_tree.add_resource_fragments(related_fragments, include_related[key][include_related])
455
-
456
- # Now recursively get the related resources for the currently found resources
457
- load_included(relationship.resource_klass,
458
- related_resource_id_tree,
459
- include_related[relationship_name][:include_related],
460
- options)
461
- end
408
+ PrimaryResourceTree.new(fragments: fragments, include_related: include_related, options: options)
462
409
  end
463
410
  end
464
411
  end