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.
- checksums.yaml +4 -4
 - data/LICENSE.txt +1 -1
 - data/README.md +39 -2
 - data/lib/generators/jsonapi/controller_generator.rb +2 -0
 - data/lib/generators/jsonapi/resource_generator.rb +2 -0
 - data/lib/jsonapi/active_relation/adapters/join_left_active_record_adapter.rb +3 -2
 - data/lib/jsonapi/active_relation/join_manager.rb +30 -18
 - data/lib/jsonapi/active_relation/join_manager_v10.rb +305 -0
 - data/lib/jsonapi/active_relation_retrieval.rb +885 -0
 - data/lib/jsonapi/active_relation_retrieval_v09.rb +715 -0
 - data/lib/jsonapi/{active_relation_resource.rb → active_relation_retrieval_v10.rb} +113 -135
 - data/lib/jsonapi/acts_as_resource_controller.rb +49 -49
 - data/lib/jsonapi/cached_response_fragment.rb +4 -2
 - data/lib/jsonapi/callbacks.rb +2 -0
 - data/lib/jsonapi/compiled_json.rb +2 -0
 - data/lib/jsonapi/configuration.rb +35 -15
 - data/lib/jsonapi/error.rb +2 -0
 - data/lib/jsonapi/error_codes.rb +2 -0
 - data/lib/jsonapi/exceptions.rb +2 -0
 - data/lib/jsonapi/formatter.rb +2 -0
 - data/lib/jsonapi/include_directives.rb +77 -19
 - data/lib/jsonapi/link_builder.rb +2 -0
 - data/lib/jsonapi/mime_types.rb +6 -10
 - data/lib/jsonapi/naive_cache.rb +2 -0
 - data/lib/jsonapi/operation.rb +2 -0
 - data/lib/jsonapi/operation_result.rb +2 -0
 - data/lib/jsonapi/paginator.rb +2 -0
 - data/lib/jsonapi/path.rb +2 -0
 - data/lib/jsonapi/path_segment.rb +4 -2
 - data/lib/jsonapi/processor.rb +95 -140
 - data/lib/jsonapi/relationship.rb +89 -35
 - data/lib/jsonapi/{request_parser.rb → request.rb} +157 -164
 - data/lib/jsonapi/resource.rb +7 -2
 - data/lib/jsonapi/{basic_resource.rb → resource_common.rb} +187 -88
 - data/lib/jsonapi/resource_controller.rb +2 -0
 - data/lib/jsonapi/resource_controller_metal.rb +2 -0
 - data/lib/jsonapi/resource_fragment.rb +17 -15
 - data/lib/jsonapi/resource_identity.rb +6 -0
 - data/lib/jsonapi/resource_serializer.rb +20 -4
 - data/lib/jsonapi/resource_set.rb +36 -16
 - data/lib/jsonapi/resource_tree.rb +191 -0
 - data/lib/jsonapi/resources/railtie.rb +3 -1
 - data/lib/jsonapi/resources/version.rb +3 -1
 - data/lib/jsonapi/response_document.rb +4 -2
 - data/lib/jsonapi/routing_ext.rb +4 -2
 - data/lib/jsonapi/simple_resource.rb +13 -0
 - data/lib/jsonapi-resources.rb +10 -4
 - data/lib/tasks/check_upgrade.rake +3 -1
 - metadata +47 -15
 - data/lib/jsonapi/resource_id_tree.rb +0 -112
 
| 
         @@ -1,28 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            require 'jsonapi/callbacks'
         
     | 
| 
       2 
4 
     | 
    
         
             
            require 'jsonapi/configuration'
         
     | 
| 
       3 
5 
     | 
    
         | 
| 
       4 
6 
     | 
    
         
             
            module JSONAPI
         
     | 
| 
       5 
     | 
    
         
            -
               
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
      
 7 
     | 
    
         
            +
              module ResourceCommon
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def self.included(base)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  base.extend ClassMethods
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  base.include Callbacks
         
     | 
| 
      
 13 
     | 
    
         
            +
                  base.define_jsonapi_resources_callbacks :create,
         
     | 
| 
      
 14 
     | 
    
         
            +
                                                     :update,
         
     | 
| 
      
 15 
     | 
    
         
            +
                                                     :remove,
         
     | 
| 
      
 16 
     | 
    
         
            +
                                                     :save,
         
     | 
| 
      
 17 
     | 
    
         
            +
                                                     :create_to_many_link,
         
     | 
| 
      
 18 
     | 
    
         
            +
                                                     :replace_to_many_links,
         
     | 
| 
      
 19 
     | 
    
         
            +
                                                     :create_to_one_link,
         
     | 
| 
      
 20 
     | 
    
         
            +
                                                     :replace_to_one_link,
         
     | 
| 
      
 21 
     | 
    
         
            +
                                                     :replace_polymorphic_to_one_link,
         
     | 
| 
      
 22 
     | 
    
         
            +
                                                     :remove_to_many_link,
         
     | 
| 
      
 23 
     | 
    
         
            +
                                                     :remove_to_one_link,
         
     | 
| 
      
 24 
     | 
    
         
            +
                                                     :replace_fields
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  base.attr_reader :context
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
       26 
28 
     | 
    
         | 
| 
       27 
29 
     | 
    
         
             
                def initialize(model, context)
         
     | 
| 
       28 
30 
     | 
    
         
             
                  @model = model
         
     | 
| 
         @@ -44,8 +46,16 @@ module JSONAPI 
     | 
|
| 
       44 
46 
     | 
    
         
             
                  JSONAPI::ResourceIdentity.new(self.class, id)
         
     | 
| 
       45 
47 
     | 
    
         
             
                end
         
     | 
| 
       46 
48 
     | 
    
         | 
| 
      
 49 
     | 
    
         
            +
                def fragment(cache: nil, primary: false)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  @fragment ||= JSONAPI::ResourceFragment.new(identity, resource: self, cache: cache, primary: primary)
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                def cache_field_value
         
     | 
| 
      
 54 
     | 
    
         
            +
                  _model.public_send(self.class._cache_field)
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
       47 
57 
     | 
    
         
             
                def cache_id
         
     | 
| 
       48 
     | 
    
         
            -
                  [id, self.class.hash_cache_field( 
     | 
| 
      
 58 
     | 
    
         
            +
                  [id, self.class.hash_cache_field(cache_field_value)]
         
     | 
| 
       49 
59 
     | 
    
         
             
                end
         
     | 
| 
       50 
60 
     | 
    
         | 
| 
       51 
61 
     | 
    
         
             
                def is_new?
         
     | 
| 
         @@ -232,7 +242,7 @@ module JSONAPI 
     | 
|
| 
       232 
242 
     | 
    
         
             
                  return false if !relationship.reflect ||
         
     | 
| 
       233 
243 
     | 
    
         
             
                    (!JSONAPI.configuration.use_relationship_reflection || options[:reflected_source])
         
     | 
| 
       234 
244 
     | 
    
         | 
| 
       235 
     | 
    
         
            -
                  inverse_relationship = relationship.resource_klass. 
     | 
| 
      
 245 
     | 
    
         
            +
                  inverse_relationship = relationship.resource_klass._relationship(relationship.inverse_relationship)
         
     | 
| 
       236 
246 
     | 
    
         
             
                  if inverse_relationship.nil?
         
     | 
| 
       237 
247 
     | 
    
         
             
                    warn "Inverse relationship could not be found for #{self.class.name}.#{relationship.name}. Relationship reflection disabled."
         
     | 
| 
       238 
248 
     | 
    
         
             
                    return false
         
     | 
| 
         @@ -241,7 +251,7 @@ module JSONAPI 
     | 
|
| 
       241 
251 
     | 
    
         
             
                end
         
     | 
| 
       242 
252 
     | 
    
         | 
| 
       243 
253 
     | 
    
         
             
                def _create_to_many_links(relationship_type, relationship_key_values, options)
         
     | 
| 
       244 
     | 
    
         
            -
                  relationship = self.class. 
     | 
| 
      
 254 
     | 
    
         
            +
                  relationship = self.class._relationship(relationship_type)
         
     | 
| 
       245 
255 
     | 
    
         
             
                  relation_name = relationship.relation_name(context: @context)
         
     | 
| 
       246 
256 
     | 
    
         | 
| 
       247 
257 
     | 
    
         
             
                  if options[:reflected_source]
         
     | 
| 
         @@ -263,7 +273,7 @@ module JSONAPI 
     | 
|
| 
       263 
273 
     | 
    
         | 
| 
       264 
274 
     | 
    
         
             
                  related_resources.each do |related_resource|
         
     | 
| 
       265 
275 
     | 
    
         
             
                    if reflect
         
     | 
| 
       266 
     | 
    
         
            -
                      if related_resource.class. 
     | 
| 
      
 276 
     | 
    
         
            +
                      if related_resource.class._relationship(relationship.inverse_relationship).is_a?(JSONAPI::Relationship::ToMany)
         
     | 
| 
       267 
277 
     | 
    
         
             
                        related_resource.create_to_many_links(relationship.inverse_relationship, [id], reflected_source: self)
         
     | 
| 
       268 
278 
     | 
    
         
             
                      else
         
     | 
| 
       269 
279 
     | 
    
         
             
                        related_resource.replace_to_one_link(relationship.inverse_relationship, id, reflected_source: self)
         
     | 
| 
         @@ -285,9 +295,7 @@ module JSONAPI 
     | 
|
| 
       285 
295 
     | 
    
         
             
                  reflect = reflect_relationship?(relationship, options)
         
     | 
| 
       286 
296 
     | 
    
         | 
| 
       287 
297 
     | 
    
         
             
                  if reflect
         
     | 
| 
       288 
     | 
    
         
            -
                     
     | 
| 
       289 
     | 
    
         
            -
             
     | 
| 
       290 
     | 
    
         
            -
                    existing = existing_rids.keys.collect { |rid| rid.id }
         
     | 
| 
      
 298 
     | 
    
         
            +
                    existing = find_related_ids(relationship, options)
         
     | 
| 
       291 
299 
     | 
    
         | 
| 
       292 
300 
     | 
    
         
             
                    to_delete = existing - (relationship_key_values & existing)
         
     | 
| 
       293 
301 
     | 
    
         
             
                    to_delete.each do |key|
         
     | 
| 
         @@ -304,8 +312,8 @@ module JSONAPI 
     | 
|
| 
       304 
312 
     | 
    
         
             
                      ids = relationship_key_value[:ids]
         
     | 
| 
       305 
313 
     | 
    
         | 
| 
       306 
314 
     | 
    
         
             
                      related_records = relationship_resource_klass
         
     | 
| 
       307 
     | 
    
         
            -
             
     | 
| 
       308 
     | 
    
         
            -
             
     | 
| 
      
 315 
     | 
    
         
            +
                                          .records(options)
         
     | 
| 
      
 316 
     | 
    
         
            +
                                          .where({relationship_resource_klass._primary_key => ids})
         
     | 
| 
       309 
317 
     | 
    
         | 
| 
       310 
318 
     | 
    
         
             
                      missed_ids = ids - related_records.pluck(relationship_resource_klass._primary_key)
         
     | 
| 
       311 
319 
     | 
    
         | 
| 
         @@ -327,7 +335,7 @@ module JSONAPI 
     | 
|
| 
       327 
335 
     | 
    
         
             
                end
         
     | 
| 
       328 
336 
     | 
    
         | 
| 
       329 
337 
     | 
    
         
             
                def _replace_to_one_link(relationship_type, relationship_key_value, _options)
         
     | 
| 
       330 
     | 
    
         
            -
                  relationship = self.class. 
     | 
| 
      
 338 
     | 
    
         
            +
                  relationship = self.class._relationship(relationship_type)
         
     | 
| 
       331 
339 
     | 
    
         | 
| 
       332 
340 
     | 
    
         
             
                  send("#{relationship.foreign_key}=", relationship_key_value)
         
     | 
| 
       333 
341 
     | 
    
         
             
                  @save_needed = true
         
     | 
| 
         @@ -336,7 +344,7 @@ module JSONAPI 
     | 
|
| 
       336 
344 
     | 
    
         
             
                end
         
     | 
| 
       337 
345 
     | 
    
         | 
| 
       338 
346 
     | 
    
         
             
                def _replace_polymorphic_to_one_link(relationship_type, key_value, key_type, _options)
         
     | 
| 
       339 
     | 
    
         
            -
                  relationship = self.class. 
     | 
| 
      
 347 
     | 
    
         
            +
                  relationship = self.class._relationship(relationship_type.to_sym)
         
     | 
| 
       340 
348 
     | 
    
         | 
| 
       341 
349 
     | 
    
         
             
                  send("#{relationship.foreign_key}=", {type: key_type, id: key_value})
         
     | 
| 
       342 
350 
     | 
    
         
             
                  @save_needed = true
         
     | 
| 
         @@ -345,7 +353,7 @@ module JSONAPI 
     | 
|
| 
       345 
353 
     | 
    
         
             
                end
         
     | 
| 
       346 
354 
     | 
    
         | 
| 
       347 
355 
     | 
    
         
             
                def _remove_to_many_link(relationship_type, key, options)
         
     | 
| 
       348 
     | 
    
         
            -
                  relationship = self.class. 
     | 
| 
      
 356 
     | 
    
         
            +
                  relationship = self.class._relationship(relationship_type)
         
     | 
| 
       349 
357 
     | 
    
         | 
| 
       350 
358 
     | 
    
         
             
                  reflect = reflect_relationship?(relationship, options)
         
     | 
| 
       351 
359 
     | 
    
         | 
| 
         @@ -356,7 +364,7 @@ module JSONAPI 
     | 
|
| 
       356 
364 
     | 
    
         
             
                    if related_resource.nil?
         
     | 
| 
       357 
365 
     | 
    
         
             
                      fail JSONAPI::Exceptions::RecordNotFound.new(key)
         
     | 
| 
       358 
366 
     | 
    
         
             
                    else
         
     | 
| 
       359 
     | 
    
         
            -
                      if related_resource.class. 
     | 
| 
      
 367 
     | 
    
         
            +
                      if related_resource.class._relationship(relationship.inverse_relationship).is_a?(JSONAPI::Relationship::ToMany)
         
     | 
| 
       360 
368 
     | 
    
         
             
                        related_resource.remove_to_many_link(relationship.inverse_relationship, id, reflected_source: self)
         
     | 
| 
       361 
369 
     | 
    
         
             
                      else
         
     | 
| 
       362 
370 
     | 
    
         
             
                        related_resource.remove_to_one_link(relationship.inverse_relationship, reflected_source: self)
         
     | 
| 
         @@ -377,7 +385,7 @@ module JSONAPI 
     | 
|
| 
       377 
385 
     | 
    
         
             
                end
         
     | 
| 
       378 
386 
     | 
    
         | 
| 
       379 
387 
     | 
    
         
             
                def _remove_to_one_link(relationship_type, _options)
         
     | 
| 
       380 
     | 
    
         
            -
                  relationship = self.class. 
     | 
| 
      
 388 
     | 
    
         
            +
                  relationship = self.class._relationship(relationship_type)
         
     | 
| 
       381 
389 
     | 
    
         | 
| 
       382 
390 
     | 
    
         
             
                  send("#{relationship.foreign_key}=", nil)
         
     | 
| 
       383 
391 
     | 
    
         
             
                  @save_needed = true
         
     | 
| 
         @@ -417,8 +425,56 @@ module JSONAPI 
     | 
|
| 
       417 
425 
     | 
    
         
             
                  :completed
         
     | 
| 
       418 
426 
     | 
    
         
             
                end
         
     | 
| 
       419 
427 
     | 
    
         | 
| 
       420 
     | 
    
         
            -
                 
     | 
| 
      
 428 
     | 
    
         
            +
                def find_related_ids(relationship, options = {})
         
     | 
| 
      
 429 
     | 
    
         
            +
                  send(relationship.foreign_key)
         
     | 
| 
      
 430 
     | 
    
         
            +
                end
         
     | 
| 
      
 431 
     | 
    
         
            +
             
     | 
| 
      
 432 
     | 
    
         
            +
                module ClassMethods
         
     | 
| 
      
 433 
     | 
    
         
            +
                  def resource_retrieval_strategy(module_name = JSONAPI.configuration.default_resource_retrieval_strategy)
         
     | 
| 
      
 434 
     | 
    
         
            +
                    if @_resource_retrieval_strategy_loaded
         
     | 
| 
      
 435 
     | 
    
         
            +
                      warn "Resource retrieval strategy #{@_resource_retrieval_strategy_loaded} already loaded for #{self.name}"
         
     | 
| 
      
 436 
     | 
    
         
            +
                      return
         
     | 
| 
      
 437 
     | 
    
         
            +
                    end
         
     | 
| 
      
 438 
     | 
    
         
            +
             
     | 
| 
      
 439 
     | 
    
         
            +
                    module_name = module_name.to_s
         
     | 
| 
      
 440 
     | 
    
         
            +
             
     | 
| 
      
 441 
     | 
    
         
            +
                    return if module_name.blank? || module_name == 'self' || module_name == 'none'
         
     | 
| 
      
 442 
     | 
    
         
            +
             
     | 
| 
      
 443 
     | 
    
         
            +
                    class_eval do
         
     | 
| 
      
 444 
     | 
    
         
            +
                      resource_retrieval_module = module_name.safe_constantize
         
     | 
| 
      
 445 
     | 
    
         
            +
                      raise "Unable to find resource_retrieval_strategy #{module_name}" unless resource_retrieval_module
         
     | 
| 
      
 446 
     | 
    
         
            +
             
     | 
| 
      
 447 
     | 
    
         
            +
                      include resource_retrieval_module
         
     | 
| 
      
 448 
     | 
    
         
            +
                      extend "#{module_name}::ClassMethods".safe_constantize
         
     | 
| 
      
 449 
     | 
    
         
            +
                      @_resource_retrieval_strategy_loaded = module_name
         
     | 
| 
      
 450 
     | 
    
         
            +
                    end
         
     | 
| 
      
 451 
     | 
    
         
            +
                  end
         
     | 
| 
      
 452 
     | 
    
         
            +
             
     | 
| 
      
 453 
     | 
    
         
            +
                  def warn_about_missing_retrieval_methods
         
     | 
| 
      
 454 
     | 
    
         
            +
                    resource_retrieval_methods = %i[find count find_by_key find_by_keys find_to_populate_by_keys find_fragments
         
     | 
| 
      
 455 
     | 
    
         
            +
                                                    find_related_fragments find_included_fragments count_related]
         
     | 
| 
      
 456 
     | 
    
         
            +
             
     | 
| 
      
 457 
     | 
    
         
            +
                    resource_retrieval_methods.each do |method_name|
         
     | 
| 
      
 458 
     | 
    
         
            +
                      warn "#{self.name} has not defined standard method #{method_name}" unless self.respond_to?(method_name)
         
     | 
| 
      
 459 
     | 
    
         
            +
                    end
         
     | 
| 
      
 460 
     | 
    
         
            +
                  end
         
     | 
| 
      
 461 
     | 
    
         
            +
             
     | 
| 
       421 
462 
     | 
    
         
             
                  def inherited(subclass)
         
     | 
| 
      
 463 
     | 
    
         
            +
                    super
         
     | 
| 
      
 464 
     | 
    
         
            +
             
     | 
| 
      
 465 
     | 
    
         
            +
                    # Defer loading the resource retrieval strategy module until the class has been fully read to allow setting
         
     | 
| 
      
 466 
     | 
    
         
            +
                    # a custom resource_retrieval_strategy in the class definition
         
     | 
| 
      
 467 
     | 
    
         
            +
                    trace_point = TracePoint.new(:end) do |tp|
         
     | 
| 
      
 468 
     | 
    
         
            +
                      if subclass == tp.self
         
     | 
| 
      
 469 
     | 
    
         
            +
                        unless subclass._abstract
         
     | 
| 
      
 470 
     | 
    
         
            +
                          subclass.warn_about_missing_retrieval_methods
         
     | 
| 
      
 471 
     | 
    
         
            +
                          subclass.warn_about_unused_methods if subclass.methods.include?(:warn_about_unused_methods)
         
     | 
| 
      
 472 
     | 
    
         
            +
                        end
         
     | 
| 
      
 473 
     | 
    
         
            +
                        tp.disable
         
     | 
| 
      
 474 
     | 
    
         
            +
                      end
         
     | 
| 
      
 475 
     | 
    
         
            +
                    end
         
     | 
| 
      
 476 
     | 
    
         
            +
                    trace_point.enable
         
     | 
| 
      
 477 
     | 
    
         
            +
             
     | 
| 
       422 
478 
     | 
    
         
             
                    subclass.abstract(false)
         
     | 
| 
       423 
479 
     | 
    
         
             
                    subclass.immutable(false)
         
     | 
| 
       424 
480 
     | 
    
         
             
                    subclass.caching(_caching)
         
     | 
| 
         @@ -456,6 +512,9 @@ module JSONAPI 
     | 
|
| 
       456 
512 
     | 
    
         | 
| 
       457 
513 
     | 
    
         
             
                    subclass._clear_cached_attribute_options
         
     | 
| 
       458 
514 
     | 
    
         
             
                    subclass._clear_fields_cache
         
     | 
| 
      
 515 
     | 
    
         
            +
             
     | 
| 
      
 516 
     | 
    
         
            +
                    subclass._resource_retrieval_strategy_loaded = @_resource_retrieval_strategy_loaded
         
     | 
| 
      
 517 
     | 
    
         
            +
                    subclass.resource_retrieval_strategy unless subclass._resource_retrieval_strategy_loaded
         
     | 
| 
       459 
518 
     | 
    
         
             
                  end
         
     | 
| 
       460 
519 
     | 
    
         | 
| 
       461 
520 
     | 
    
         
             
                  def rebuild_relationships(relationships)
         
     | 
| 
         @@ -467,7 +526,7 @@ module JSONAPI 
     | 
|
| 
       467 
526 
     | 
    
         
             
                      original_relationships.each_value do |relationship|
         
     | 
| 
       468 
527 
     | 
    
         
             
                        options = relationship.options.dup
         
     | 
| 
       469 
528 
     | 
    
         
             
                        options[:parent_resource] = self
         
     | 
| 
       470 
     | 
    
         
            -
                        options[:inverse_relationship] = relationship.inverse_relationship
         
     | 
| 
      
 529 
     | 
    
         
            +
                        options[:inverse_relationship] = relationship.options[:inverse_relationship]
         
     | 
| 
       471 
530 
     | 
    
         
             
                        _add_relationship(relationship.class, relationship.name, options)
         
     | 
| 
       472 
531 
     | 
    
         
             
                      end
         
     | 
| 
       473 
532 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -502,7 +561,8 @@ module JSONAPI 
     | 
|
| 
       502 
561 
     | 
    
         
             
                    end
         
     | 
| 
       503 
562 
     | 
    
         
             
                  end
         
     | 
| 
       504 
563 
     | 
    
         | 
| 
       505 
     | 
    
         
            -
                  attr_accessor :_attributes, :_relationships, :_type, :_model_hints, :_routed, :_warned_missing_route
         
     | 
| 
      
 564 
     | 
    
         
            +
                  attr_accessor :_attributes, :_relationships, :_type, :_model_hints, :_routed, :_warned_missing_route,
         
     | 
| 
      
 565 
     | 
    
         
            +
                                :_resource_retrieval_strategy_loaded
         
     | 
| 
       506 
566 
     | 
    
         
             
                  attr_writer :_allowed_filters, :_paginator, :_allowed_sort
         
     | 
| 
       507 
567 
     | 
    
         | 
| 
       508 
568 
     | 
    
         
             
                  def create(context)
         
     | 
| 
         @@ -565,23 +625,15 @@ module JSONAPI 
     | 
|
| 
       565 
625 
     | 
    
         
             
                                   # Note: this will allow the returning of model attributes without a corresponding
         
     | 
| 
       566 
626 
     | 
    
         
             
                                   # resource attribute, for example a belongs_to id such as `author_id` or bypassing
         
     | 
| 
       567 
627 
     | 
    
         
             
                                   # the delegate.
         
     | 
| 
       568 
     | 
    
         
            -
                                   attr = @_attributes[attribute]
         
     | 
| 
      
 628 
     | 
    
         
            +
                                   attr = @_attributes[attribute.to_sym]
         
     | 
| 
       569 
629 
     | 
    
         
             
                                   attr && attr[:delegate] ? attr[:delegate].to_sym : attribute
         
     | 
| 
       570 
630 
     | 
    
         
             
                                 end
         
     | 
| 
       571 
     | 
    
         
            -
             
     | 
| 
       572 
     | 
    
         
            -
             
     | 
| 
       573 
     | 
    
         
            -
                    else
         
     | 
| 
       574 
     | 
    
         
            -
                      attribute_type = _model_class.column_types[field_name.to_s]
         
     | 
| 
       575 
     | 
    
         
            -
                    end
         
     | 
| 
       576 
     | 
    
         
            -
                    { name: field_name, type: attribute_type}
         
     | 
| 
      
 631 
     | 
    
         
            +
             
     | 
| 
      
 632 
     | 
    
         
            +
                    { name: field_name, type: _model_class.attribute_types[field_name.to_s]}
         
     | 
| 
       577 
633 
     | 
    
         
             
                  end
         
     | 
| 
       578 
634 
     | 
    
         | 
| 
       579 
635 
     | 
    
         
             
                  def cast_to_attribute_type(value, type)
         
     | 
| 
       580 
     | 
    
         
            -
                     
     | 
| 
       581 
     | 
    
         
            -
                      return type.cast(value)
         
     | 
| 
       582 
     | 
    
         
            -
                    else
         
     | 
| 
       583 
     | 
    
         
            -
                      return type.type_cast_from_database(value)
         
     | 
| 
       584 
     | 
    
         
            -
                    end
         
     | 
| 
      
 636 
     | 
    
         
            +
                    type.cast(value)
         
     | 
| 
       585 
637 
     | 
    
         
             
                  end
         
     | 
| 
       586 
638 
     | 
    
         | 
| 
       587 
639 
     | 
    
         
             
                  def default_attribute_options
         
     | 
| 
         @@ -591,14 +643,14 @@ module JSONAPI 
     | 
|
| 
       591 
643 
     | 
    
         
             
                  def relationship(*attrs)
         
     | 
| 
       592 
644 
     | 
    
         
             
                    options = attrs.extract_options!
         
     | 
| 
       593 
645 
     | 
    
         
             
                    klass = case options[:to]
         
     | 
| 
       594 
     | 
    
         
            -
             
     | 
| 
       595 
     | 
    
         
            -
             
     | 
| 
       596 
     | 
    
         
            -
             
     | 
| 
       597 
     | 
    
         
            -
             
     | 
| 
       598 
     | 
    
         
            -
             
     | 
| 
       599 
     | 
    
         
            -
             
     | 
| 
       600 
     | 
    
         
            -
             
     | 
| 
       601 
     | 
    
         
            -
             
     | 
| 
      
 646 
     | 
    
         
            +
                            when :one
         
     | 
| 
      
 647 
     | 
    
         
            +
                              Relationship::ToOne
         
     | 
| 
      
 648 
     | 
    
         
            +
                            when :many
         
     | 
| 
      
 649 
     | 
    
         
            +
                              Relationship::ToMany
         
     | 
| 
      
 650 
     | 
    
         
            +
                            else
         
     | 
| 
      
 651 
     | 
    
         
            +
                              #:nocov:#
         
     | 
| 
      
 652 
     | 
    
         
            +
                              fail ArgumentError.new('to: must be either :one or :many')
         
     | 
| 
      
 653 
     | 
    
         
            +
                              #:nocov:#
         
     | 
| 
       602 
654 
     | 
    
         
             
                            end
         
     | 
| 
       603 
655 
     | 
    
         
             
                    _add_relationship(klass, *attrs, options.except(:to))
         
     | 
| 
       604 
656 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -609,10 +661,10 @@ module JSONAPI 
     | 
|
| 
       609 
661 
     | 
    
         | 
| 
       610 
662 
     | 
    
         
             
                  def belongs_to(*attrs)
         
     | 
| 
       611 
663 
     | 
    
         
             
                    ActiveSupport::Deprecation.warn "In #{name} you exposed a `has_one` relationship "\
         
     | 
| 
       612 
     | 
    
         
            -
             
     | 
| 
       613 
     | 
    
         
            -
             
     | 
| 
       614 
     | 
    
         
            -
             
     | 
| 
       615 
     | 
    
         
            -
             
     | 
| 
      
 664 
     | 
    
         
            +
                                                  " using the `belongs_to` class method. We think `has_one`" \
         
     | 
| 
      
 665 
     | 
    
         
            +
                                                  " is more appropriate. If you know what you're doing," \
         
     | 
| 
      
 666 
     | 
    
         
            +
                                                  " and don't want to see this warning again, override the" \
         
     | 
| 
      
 667 
     | 
    
         
            +
                                                  " `belongs_to` class method on your resource."
         
     | 
| 
       616 
668 
     | 
    
         
             
                    _add_relationship(Relationship::ToOne, *attrs)
         
     | 
| 
       617 
669 
     | 
    
         
             
                  end
         
     | 
| 
       618 
670 
     | 
    
         | 
| 
         @@ -636,7 +688,7 @@ module JSONAPI 
     | 
|
| 
       636 
688 
     | 
    
         
             
                  end
         
     | 
| 
       637 
689 
     | 
    
         | 
| 
       638 
690 
     | 
    
         
             
                  def model_hint(model: _model_name, resource: _type)
         
     | 
| 
       639 
     | 
    
         
            -
                    resource_type = ((resource.is_a?(Class)) && ( 
     | 
| 
      
 691 
     | 
    
         
            +
                    resource_type = ((resource.is_a?(Class)) && resource.include?(JSONAPI::ResourceCommon)) ? resource._type : resource.to_s
         
     | 
| 
       640 
692 
     | 
    
         | 
| 
       641 
693 
     | 
    
         
             
                    _model_hints[model.to_s.gsub('::', '/').underscore] = resource_type.to_s
         
     | 
| 
       642 
694 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -699,7 +751,22 @@ module JSONAPI 
     | 
|
| 
       699 
751 
     | 
    
         
             
                  end
         
     | 
| 
       700 
752 
     | 
    
         | 
| 
       701 
753 
     | 
    
         
             
                  def fields
         
     | 
| 
       702 
     | 
    
         
            -
                    @_fields_cache ||= _relationships.keys | _attributes.keys
         
     | 
| 
      
 754 
     | 
    
         
            +
                    @_fields_cache ||= _relationships.select { |k,v| !v.hidden? }.keys | _attributes.keys
         
     | 
| 
      
 755 
     | 
    
         
            +
                  end
         
     | 
| 
      
 756 
     | 
    
         
            +
             
     | 
| 
      
 757 
     | 
    
         
            +
                  def to_one_relationships_including_optional_linkage_data
         
     | 
| 
      
 758 
     | 
    
         
            +
                    # ToDo: can we only calculate this once?
         
     | 
| 
      
 759 
     | 
    
         
            +
                    @to_one_relationships_including_optional_linkage_data =
         
     | 
| 
      
 760 
     | 
    
         
            +
                      _relationships.select do |_name, relationship|
         
     | 
| 
      
 761 
     | 
    
         
            +
                        relationship.is_a?(JSONAPI::Relationship::ToOne) && relationship.include_optional_linkage_data?
         
     | 
| 
      
 762 
     | 
    
         
            +
                      end
         
     | 
| 
      
 763 
     | 
    
         
            +
                  end
         
     | 
| 
      
 764 
     | 
    
         
            +
             
     | 
| 
      
 765 
     | 
    
         
            +
                  def to_one_relationships_for_linkage(include_related)
         
     | 
| 
      
 766 
     | 
    
         
            +
                    # exclude the relationships that are already included in the include_related param
         
     | 
| 
      
 767 
     | 
    
         
            +
                    include_related_names = include_related.present? ? include_related.keys : []
         
     | 
| 
      
 768 
     | 
    
         
            +
                    relationship_names = to_one_relationships_including_optional_linkage_data.keys - include_related_names
         
     | 
| 
      
 769 
     | 
    
         
            +
                    _relationships.fetch_values(*relationship_names)
         
     | 
| 
       703 
770 
     | 
    
         
             
                  end
         
     | 
| 
       704 
771 
     | 
    
         | 
| 
       705 
772 
     | 
    
         
             
                  def resources_for(records, context)
         
     | 
| 
         @@ -709,10 +776,14 @@ module JSONAPI 
     | 
|
| 
       709 
776 
     | 
    
         
             
                  end
         
     | 
| 
       710 
777 
     | 
    
         | 
| 
       711 
778 
     | 
    
         
             
                  def resource_for(model_record, context)
         
     | 
| 
       712 
     | 
    
         
            -
                    resource_klass =  
     | 
| 
      
 779 
     | 
    
         
            +
                    resource_klass = resource_klass_for_model(model_record)
         
     | 
| 
       713 
780 
     | 
    
         
             
                    resource_klass.new(model_record, context)
         
     | 
| 
       714 
781 
     | 
    
         
             
                  end
         
     | 
| 
       715 
782 
     | 
    
         | 
| 
      
 783 
     | 
    
         
            +
                  def resource_for_model(model, context)
         
     | 
| 
      
 784 
     | 
    
         
            +
                    resource_for(resource_type_for(model), context)
         
     | 
| 
      
 785 
     | 
    
         
            +
                  end
         
     | 
| 
      
 786 
     | 
    
         
            +
             
     | 
| 
       716 
787 
     | 
    
         
             
                  def verify_filters(filters, context = nil)
         
     | 
| 
       717 
788 
     | 
    
         
             
                    verified_filters = {}
         
     | 
| 
       718 
789 
     | 
    
         
             
                    filters.each do |filter, raw_value|
         
     | 
| 
         @@ -773,12 +844,12 @@ module JSONAPI 
     | 
|
| 
       773 
844 
     | 
    
         
             
                    if @_singleton_options && @_singleton_options[:singleton_key]
         
     | 
| 
       774 
845 
     | 
    
         
             
                      strategy = @_singleton_options[:singleton_key]
         
     | 
| 
       775 
846 
     | 
    
         
             
                      case strategy
         
     | 
| 
       776 
     | 
    
         
            -
             
     | 
| 
       777 
     | 
    
         
            -
             
     | 
| 
       778 
     | 
    
         
            -
             
     | 
| 
       779 
     | 
    
         
            -
             
     | 
| 
       780 
     | 
    
         
            -
             
     | 
| 
       781 
     | 
    
         
            -
             
     | 
| 
      
 847 
     | 
    
         
            +
                      when Proc
         
     | 
| 
      
 848 
     | 
    
         
            +
                        key = strategy.call(context)
         
     | 
| 
      
 849 
     | 
    
         
            +
                      when Symbol, String
         
     | 
| 
      
 850 
     | 
    
         
            +
                        key = send(strategy, context)
         
     | 
| 
      
 851 
     | 
    
         
            +
                      else
         
     | 
| 
      
 852 
     | 
    
         
            +
                        raise "singleton_key must be a proc or function name"
         
     | 
| 
       782 
853 
     | 
    
         
             
                      end
         
     | 
| 
       783 
854 
     | 
    
         
             
                    end
         
     | 
| 
       784 
855 
     | 
    
         
             
                    key
         
     | 
| 
         @@ -853,13 +924,12 @@ module JSONAPI 
     | 
|
| 
       853 
924 
     | 
    
         | 
| 
       854 
925 
     | 
    
         
             
                  def _relationship(type)
         
     | 
| 
       855 
926 
     | 
    
         
             
                    return nil unless type
         
     | 
| 
       856 
     | 
    
         
            -
                    type 
     | 
| 
       857 
     | 
    
         
            -
                    @_relationships[type]
         
     | 
| 
      
 927 
     | 
    
         
            +
                    @_relationships[type.to_sym]
         
     | 
| 
       858 
928 
     | 
    
         
             
                  end
         
     | 
| 
       859 
929 
     | 
    
         | 
| 
       860 
930 
     | 
    
         
             
                  def _model_name
         
     | 
| 
       861 
931 
     | 
    
         
             
                    if _abstract
         
     | 
| 
       862 
     | 
    
         
            -
             
     | 
| 
      
 932 
     | 
    
         
            +
                      ''
         
     | 
| 
       863 
933 
     | 
    
         
             
                    else
         
     | 
| 
       864 
934 
     | 
    
         
             
                      return @_model_name.to_s if defined?(@_model_name)
         
     | 
| 
       865 
935 
     | 
    
         
             
                      class_name = self.name
         
     | 
| 
         @@ -882,7 +952,7 @@ module JSONAPI 
     | 
|
| 
       882 
952 
     | 
    
         
             
                  end
         
     | 
| 
       883 
953 
     | 
    
         | 
| 
       884 
954 
     | 
    
         
             
                  def _default_primary_key
         
     | 
| 
       885 
     | 
    
         
            -
                    @_default_primary_key ||=_model_class.respond_to?(:primary_key) ? _model_class.primary_key : :id
         
     | 
| 
      
 955 
     | 
    
         
            +
                    @_default_primary_key ||= _model_class.respond_to?(:primary_key) ? _model_class.primary_key : :id
         
     | 
| 
       886 
956 
     | 
    
         
             
                  end
         
     | 
| 
       887 
957 
     | 
    
         | 
| 
       888 
958 
     | 
    
         
             
                  def _cache_field
         
     | 
| 
         @@ -973,14 +1043,14 @@ module JSONAPI 
     | 
|
| 
       973 
1043 
     | 
    
         | 
| 
       974 
1044 
     | 
    
         
             
                  def parse_exclude_links(exclude)
         
     | 
| 
       975 
1045 
     | 
    
         
             
                    case exclude
         
     | 
| 
       976 
     | 
    
         
            -
             
     | 
| 
       977 
     | 
    
         
            -
             
     | 
| 
       978 
     | 
    
         
            -
             
     | 
| 
       979 
     | 
    
         
            -
             
     | 
| 
       980 
     | 
    
         
            -
             
     | 
| 
       981 
     | 
    
         
            -
             
     | 
| 
       982 
     | 
    
         
            -
             
     | 
| 
       983 
     | 
    
         
            -
             
     | 
| 
      
 1046 
     | 
    
         
            +
                    when :default, "default"
         
     | 
| 
      
 1047 
     | 
    
         
            +
                      [:self]
         
     | 
| 
      
 1048 
     | 
    
         
            +
                    when :none, "none"
         
     | 
| 
      
 1049 
     | 
    
         
            +
                      []
         
     | 
| 
      
 1050 
     | 
    
         
            +
                    when Array
         
     | 
| 
      
 1051 
     | 
    
         
            +
                      exclude.collect {|link| link.to_sym}
         
     | 
| 
      
 1052 
     | 
    
         
            +
                    else
         
     | 
| 
      
 1053 
     | 
    
         
            +
                      fail "Invalid exclude_links"
         
     | 
| 
       984 
1054 
     | 
    
         
             
                    end
         
     | 
| 
       985 
1055 
     | 
    
         
             
                  end
         
     | 
| 
       986 
1056 
     | 
    
         | 
| 
         @@ -1016,6 +1086,22 @@ module JSONAPI 
     | 
|
| 
       1016 
1086 
     | 
    
         
             
                    nil
         
     | 
| 
       1017 
1087 
     | 
    
         
             
                  end
         
     | 
| 
       1018 
1088 
     | 
    
         | 
| 
      
 1089 
     | 
    
         
            +
                  def _included_strategy
         
     | 
| 
      
 1090 
     | 
    
         
            +
                    @_included_strategy || JSONAPI.configuration.default_included_strategy
         
     | 
| 
      
 1091 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1092 
     | 
    
         
            +
             
     | 
| 
      
 1093 
     | 
    
         
            +
                  def included_strategy(included_strategy)
         
     | 
| 
      
 1094 
     | 
    
         
            +
                    @_included_strategy = included_strategy
         
     | 
| 
      
 1095 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1096 
     | 
    
         
            +
             
     | 
| 
      
 1097 
     | 
    
         
            +
                  def _related_strategy
         
     | 
| 
      
 1098 
     | 
    
         
            +
                    @_related_strategy || JSONAPI.configuration.default_related_strategy
         
     | 
| 
      
 1099 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1100 
     | 
    
         
            +
             
     | 
| 
      
 1101 
     | 
    
         
            +
                  def related_strategy(related_strategy)
         
     | 
| 
      
 1102 
     | 
    
         
            +
                    @_related_strategy = related_strategy
         
     | 
| 
      
 1103 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1104 
     | 
    
         
            +
             
     | 
| 
       1019 
1105 
     | 
    
         
             
                  # Generate a hashcode from the value to be used as part of the cache lookup
         
     | 
| 
       1020 
1106 
     | 
    
         
             
                  def hash_cache_field(value)
         
     | 
| 
       1021 
1107 
     | 
    
         
             
                    value.hash
         
     | 
| 
         @@ -1054,7 +1140,7 @@ module JSONAPI 
     | 
|
| 
       1054 
1140 
     | 
    
         
             
                  end
         
     | 
| 
       1055 
1141 
     | 
    
         | 
| 
       1056 
1142 
     | 
    
         
             
                  def default_sort
         
     | 
| 
       1057 
     | 
    
         
            -
                    [{field:  
     | 
| 
      
 1143 
     | 
    
         
            +
                    [{field: _primary_key, direction: :asc}]
         
     | 
| 
       1058 
1144 
     | 
    
         
             
                  end
         
     | 
| 
       1059 
1145 
     | 
    
         | 
| 
       1060 
1146 
     | 
    
         
             
                  def construct_order_options(sort_params)
         
     | 
| 
         @@ -1083,11 +1169,23 @@ module JSONAPI 
     | 
|
| 
       1083 
1169 
     | 
    
         
             
                    end
         
     | 
| 
       1084 
1170 
     | 
    
         
             
                  end
         
     | 
| 
       1085 
1171 
     | 
    
         | 
| 
       1086 
     | 
    
         
            -
                   
     | 
| 
      
 1172 
     | 
    
         
            +
                  def _setup_relationship(klass, *attrs)
         
     | 
| 
      
 1173 
     | 
    
         
            +
                    _clear_fields_cache
         
     | 
| 
      
 1174 
     | 
    
         
            +
             
     | 
| 
      
 1175 
     | 
    
         
            +
                    options = attrs.extract_options!
         
     | 
| 
      
 1176 
     | 
    
         
            +
                    options[:parent_resource] = self
         
     | 
| 
      
 1177 
     | 
    
         
            +
             
     | 
| 
      
 1178 
     | 
    
         
            +
                    relationship_name = attrs[0].to_sym
         
     | 
| 
      
 1179 
     | 
    
         
            +
                    check_duplicate_relationship_name(relationship_name)
         
     | 
| 
      
 1180 
     | 
    
         
            +
             
     | 
| 
      
 1181 
     | 
    
         
            +
                    define_relationship_methods(relationship_name.to_sym, klass, options)
         
     | 
| 
      
 1182 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1183 
     | 
    
         
            +
             
     | 
| 
      
 1184 
     | 
    
         
            +
                  # ResourceBuilder methods
         
     | 
| 
       1087 
1185 
     | 
    
         
             
                  def define_relationship_methods(relationship_name, relationship_klass, options)
         
     | 
| 
       1088 
1186 
     | 
    
         
             
                    relationship = register_relationship(
         
     | 
| 
       1089 
     | 
    
         
            -
             
     | 
| 
       1090 
     | 
    
         
            -
             
     | 
| 
      
 1187 
     | 
    
         
            +
                      relationship_name,
         
     | 
| 
      
 1188 
     | 
    
         
            +
                      relationship_klass.new(relationship_name, options)
         
     | 
| 
       1091 
1189 
     | 
    
         
             
                    )
         
     | 
| 
       1092 
1190 
     | 
    
         | 
| 
       1093 
1191 
     | 
    
         
             
                    define_foreign_key_setter(relationship)
         
     | 
| 
         @@ -1104,10 +1202,11 @@ module JSONAPI 
     | 
|
| 
       1104 
1202 
     | 
    
         
             
                        _model.method("#{relationship.foreign_key}=").call(value)
         
     | 
| 
       1105 
1203 
     | 
    
         
             
                      end
         
     | 
| 
       1106 
1204 
     | 
    
         
             
                    end
         
     | 
| 
      
 1205 
     | 
    
         
            +
                    relationship.foreign_key
         
     | 
| 
       1107 
1206 
     | 
    
         
             
                  end
         
     | 
| 
       1108 
1207 
     | 
    
         | 
| 
       1109 
1208 
     | 
    
         
             
                  def define_on_resource(method_name, &block)
         
     | 
| 
       1110 
     | 
    
         
            -
                    return if method_defined?(method_name)
         
     | 
| 
      
 1209 
     | 
    
         
            +
                    return method_name if method_defined?(method_name)
         
     | 
| 
       1111 
1210 
     | 
    
         
             
                    define_method(method_name, block)
         
     | 
| 
       1112 
1211 
     | 
    
         
             
                  end
         
     | 
| 
       1113 
1212 
     | 
    
         | 
| 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module JSONAPI
         
     | 
| 
       2 
4 
     | 
    
         | 
| 
       3 
5 
     | 
    
         
             
              # A ResourceFragment holds a ResourceIdentity and associated partial resource data.
         
     | 
| 
         @@ -6,42 +8,42 @@ module JSONAPI 
     | 
|
| 
       6 
8 
     | 
    
         
             
              # cache - the value of the cache field for the resource instance
         
     | 
| 
       7 
9 
     | 
    
         
             
              # related - a hash of arrays of related resource identities, grouped by relationship name
         
     | 
| 
       8 
10 
     | 
    
         
             
              # related_from - a set of related resource identities that loaded the fragment
         
     | 
| 
      
 11 
     | 
    
         
            +
              # resource - a resource instance
         
     | 
| 
       9 
12 
     | 
    
         
             
              #
         
     | 
| 
       10 
     | 
    
         
            -
              # Todo: optionally use these for faster responses by bypassing model instantiation)
         
     | 
| 
       11 
     | 
    
         
            -
              # attributes - resource attributes
         
     | 
| 
       12 
13 
     | 
    
         | 
| 
       13 
14 
     | 
    
         
             
              class ResourceFragment
         
     | 
| 
       14 
     | 
    
         
            -
                attr_reader :identity, : 
     | 
| 
      
 15 
     | 
    
         
            +
                attr_reader :identity, :related_from, :related, :resource
         
     | 
| 
       15 
16 
     | 
    
         | 
| 
       16 
17 
     | 
    
         
             
                attr_accessor :primary, :cache
         
     | 
| 
       17 
18 
     | 
    
         | 
| 
       18 
19 
     | 
    
         
             
                alias :cache_field :cache #ToDo: Rename one or the other
         
     | 
| 
       19 
20 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
                def initialize(identity)
         
     | 
| 
      
 21 
     | 
    
         
            +
                def initialize(identity, resource: nil, cache: nil, primary: false)
         
     | 
| 
       21 
22 
     | 
    
         
             
                  @identity = identity
         
     | 
| 
       22 
     | 
    
         
            -
                  @cache =  
     | 
| 
       23 
     | 
    
         
            -
                  @ 
     | 
| 
      
 23 
     | 
    
         
            +
                  @cache = cache
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @resource = resource
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @primary = primary
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
       24 
27 
     | 
    
         
             
                  @related = {}
         
     | 
| 
       25 
     | 
    
         
            -
                  @ 
     | 
| 
       26 
     | 
    
         
            -
                  @related_from = Set.new
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @related_from = SortedSet.new
         
     | 
| 
       27 
29 
     | 
    
         
             
                end
         
     | 
| 
       28 
30 
     | 
    
         | 
| 
       29 
31 
     | 
    
         
             
                def initialize_related(relationship_name)
         
     | 
| 
       30 
     | 
    
         
            -
                  @related ||= {}
         
     | 
| 
       31 
32 
     | 
    
         
             
                  @related[relationship_name.to_sym] ||= Set.new
         
     | 
| 
       32 
33 
     | 
    
         
             
                end
         
     | 
| 
       33 
34 
     | 
    
         | 
| 
       34 
35 
     | 
    
         
             
                def add_related_identity(relationship_name, identity)
         
     | 
| 
       35 
36 
     | 
    
         
             
                  initialize_related(relationship_name)
         
     | 
| 
       36 
     | 
    
         
            -
                  @related[relationship_name.to_sym] << identity
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @related[relationship_name.to_sym] << identity if identity
         
     | 
| 
       37 
38 
     | 
    
         
             
                end
         
     | 
| 
       38 
39 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
                def  
     | 
| 
       40 
     | 
    
         
            -
                   
     | 
| 
      
 40 
     | 
    
         
            +
                def merge_related_identities(relationship_name, identities)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  initialize_related(relationship_name)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  @related[relationship_name.to_sym].merge(identities) if identities
         
     | 
| 
       41 
43 
     | 
    
         
             
                end
         
     | 
| 
       42 
44 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
                def  
     | 
| 
       44 
     | 
    
         
            -
                  @ 
     | 
| 
      
 45 
     | 
    
         
            +
                def add_related_from(identity)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  @related_from << identity
         
     | 
| 
       45 
47 
     | 
    
         
             
                end
         
     | 
| 
       46 
48 
     | 
    
         
             
              end
         
     | 
| 
       47 
     | 
    
         
            -
            end
         
     | 
| 
      
 49 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module JSONAPI
         
     | 
| 
       2 
4 
     | 
    
         | 
| 
       3 
5 
     | 
    
         
             
              # ResourceIdentity describes a unique identity of a resource in the system.
         
     | 
| 
         @@ -32,6 +34,10 @@ module JSONAPI 
     | 
|
| 
       32 
34 
     | 
    
         
             
                  [@resource_klass, @id].hash
         
     | 
| 
       33 
35 
     | 
    
         
             
                end
         
     | 
| 
       34 
36 
     | 
    
         | 
| 
      
 37 
     | 
    
         
            +
                def <=>(other_identity)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  self.id <=> other_identity.id
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
       35 
41 
     | 
    
         
             
                # Creates a string representation of the identifier.
         
     | 
| 
       36 
42 
     | 
    
         
             
                def to_s
         
     | 
| 
       37 
43 
     | 
    
         
             
                  # :nocov:
         
     | 
| 
         @@ -1,9 +1,11 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module JSONAPI
         
     | 
| 
       2 
4 
     | 
    
         
             
              class ResourceSerializer
         
     | 
| 
       3 
5 
     | 
    
         | 
| 
       4 
6 
     | 
    
         
             
                attr_reader :link_builder, :key_formatter, :serialization_options,
         
     | 
| 
       5 
7 
     | 
    
         
             
                            :fields, :include_directives, :always_include_to_one_linkage_data,
         
     | 
| 
       6 
     | 
    
         
            -
                            :always_include_to_many_linkage_data
         
     | 
| 
      
 8 
     | 
    
         
            +
                            :always_include_to_many_linkage_data, :options
         
     | 
| 
       7 
9 
     | 
    
         | 
| 
       8 
10 
     | 
    
         
             
                # initialize
         
     | 
| 
       9 
11 
     | 
    
         
             
                # Options can include
         
     | 
| 
         @@ -18,11 +20,12 @@ module JSONAPI 
     | 
|
| 
       18 
20 
     | 
    
         
             
                # serialization_options: additional options that will be passed to resource meta and links lambdas
         
     | 
| 
       19 
21 
     | 
    
         | 
| 
       20 
22 
     | 
    
         
             
                def initialize(primary_resource_klass, options = {})
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @options                = options
         
     | 
| 
       21 
24 
     | 
    
         
             
                  @primary_resource_klass = primary_resource_klass
         
     | 
| 
       22 
25 
     | 
    
         
             
                  @fields                 = options.fetch(:fields, {})
         
     | 
| 
       23 
26 
     | 
    
         
             
                  @include                = options.fetch(:include, [])
         
     | 
| 
       24 
     | 
    
         
            -
                  @include_directives     = options 
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
      
 27 
     | 
    
         
            +
                  @include_directives     = options.fetch(:include_directives,
         
     | 
| 
      
 28 
     | 
    
         
            +
                                                          JSONAPI::IncludeDirectives.new(@primary_resource_klass, @include))
         
     | 
| 
       26 
29 
     | 
    
         
             
                  @key_formatter          = options.fetch(:key_formatter, JSONAPI.configuration.key_formatter)
         
     | 
| 
       27 
30 
     | 
    
         
             
                  @id_formatter           = ValueFormatter.value_formatter_for(:id)
         
     | 
| 
       28 
31 
     | 
    
         
             
                  @link_builder           = generate_link_builder(primary_resource_klass, options)
         
     | 
| 
         @@ -41,6 +44,19 @@ module JSONAPI 
     | 
|
| 
       41 
44 
     | 
    
         
             
                  @_supplying_relationship_fields = {}
         
     | 
| 
       42 
45 
     | 
    
         
             
                end
         
     | 
| 
       43 
46 
     | 
    
         | 
| 
      
 47 
     | 
    
         
            +
                # Converts a single resource, or an array of resources to a hash, conforming to the JSONAPI structure
         
     | 
| 
      
 48 
     | 
    
         
            +
                def serialize_to_hash(source)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  include_related = include_directives[:include_related]
         
     | 
| 
      
 50 
     | 
    
         
            +
                  resource_set = JSONAPI::ResourceSet.new(source, include_related, options)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  resource_set.populate!(self, options[:context], options)
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                  if source.is_a?(Array)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    serialize_resource_set_to_hash_plural(resource_set)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  else
         
     | 
| 
      
 56 
     | 
    
         
            +
                    serialize_resource_set_to_hash_single(resource_set)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
       44 
60 
     | 
    
         
             
                # Converts a resource_set to a hash, conforming to the JSONAPI structure
         
     | 
| 
       45 
61 
     | 
    
         
             
                def serialize_resource_set_to_hash_single(resource_set)
         
     | 
| 
       46 
62 
     | 
    
         | 
| 
         @@ -291,7 +307,7 @@ module JSONAPI 
     | 
|
| 
       291 
307 
     | 
    
         
             
                    if field_set.include?(name)
         
     | 
| 
       292 
308 
     | 
    
         | 
| 
       293 
309 
     | 
    
         
             
                      relationship_name = unformat_key(name).to_sym
         
     | 
| 
       294 
     | 
    
         
            -
                      relationship_klass = source.resource_klass. 
     | 
| 
      
 310 
     | 
    
         
            +
                      relationship_klass = source.resource_klass._relationship(relationship_name)
         
     | 
| 
       295 
311 
     | 
    
         | 
| 
       296 
312 
     | 
    
         
             
                      if relationship_klass.is_a?(JSONAPI::Relationship::ToOne)
         
     | 
| 
       297 
313 
     | 
    
         
             
                        # include_linkage = @always_include_to_one_linkage_data | relationship_klass.always_include_linkage_data
         
     |