diff --git a/lib/jsonapi/renderer/resources_processor.rb b/lib/jsonapi/renderer/resources_processor.rb index dfd5264..e164018 100644 --- a/lib/jsonapi/renderer/resources_processor.rb +++ b/lib/jsonapi/renderer/resources_processor.rb @@ -50,12 +50,42 @@ def traverse_resource(res, include_keys, primary) if @include_rels.include?(ri) @include_rels[ri].merge!(keys_hash) + + include_duplicate_resource(res) unless primary else @include_rels[ri] = keys_hash (primary ? @primary : @included) << res end end + def include_duplicate_resource(res) + duplicate_index = find_included_duplicate_resource(res) + + return unless duplicate_index + + duplicate = @included.delete_at(duplicate_index) + + if duplicate.is_a?(Array) + duplicate << res + else + duplicate = [duplicate, res] + end + + @included << duplicate + end + + def find_included_duplicate_resource(res) + @included.find_index do |included| + if included.is_a?(Array) + unless included.empty? + included.first.jsonapi_type == res.jsonapi_type && included.first.jsonapi_id == res.jsonapi_id + end + else + included.jsonapi_type == res.jsonapi_type && included.jsonapi_id == res.jsonapi_id + end + end + end + def enqueue_related_resources(res, prefix, include_dir) res.jsonapi_related(include_dir.keys).each do |key, data| child_prefix = "#{prefix}.#{key}".freeze diff --git a/lib/jsonapi/renderer/simple_resources_processor.rb b/lib/jsonapi/renderer/simple_resources_processor.rb index 1249e6d..13b3b27 100644 --- a/lib/jsonapi/renderer/simple_resources_processor.rb +++ b/lib/jsonapi/renderer/simple_resources_processor.rb @@ -7,13 +7,52 @@ class SimpleResourcesProcessor < ResourcesProcessor def process_resources [@primary, @included].each do |resources| resources.map! do |res| - ri = [res.jsonapi_type, res.jsonapi_id] - include_dir = @include_rels[ri].keys - fields = @fields[res.jsonapi_type.to_sym] - res.as_jsonapi(include: include_dir, fields: fields) + # Duplicates array + if res.is_a?(Array) + process_duplicates(res) + # Regular resource case + else + process_resource(res) + end end end end + + def process_resource(resource) + ri = [resource.jsonapi_type, resource.jsonapi_id] + include_dir = @include_rels[ri].keys + fields = @fields[resource.jsonapi_type.to_sym] + resource.as_jsonapi(include: include_dir, fields: fields) + end + + def process_duplicates(duplicates) + return unless duplicates.is_a?(Array) && duplicates.any? + + duplicates.inject({}) do |result, duplicate| + if result.empty? + result = process_resource(duplicate) if result.empty? + else + duplicate_result = process_resource(duplicate) + result = deep_merge_duplicate_hashes(result, duplicate_result) + end + end + end + + def deep_merge_duplicate_hashes(hash1, hash2) + merger = proc do |_, v1, v2| + if v1.is_a?(Hash) && v2.is_a?(Hash) + v1.merge(v2, &merger) + elsif v1.is_a?(Array) && v2.is_a?(Array) + v1 | v2 + elsif [:undefined, nil, :nil].include?(v2) + v1 + else + v2 + end + end + + hash1.merge(hash2, &merger) + end end end end