From e5f82d9e709a56a90e0b1ef75d7304610a258a93 Mon Sep 17 00:00:00 2001 From: Denis Talakevich Date: Wed, 3 Oct 2018 12:37:04 +0300 Subject: [PATCH] #299 optional get relationship from dataset --- CHANGELOG.md | 2 + lib/json_api_client/included_data.rb | 19 ++--- lib/json_api_client/resource.rb | 2 + test/unit/association_test.rb | 104 +++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ecb38b1..e8fbab43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ - [#316](https://github.com/JsonApiClient/json_api_client/pull/316) - Allow custom error messages +- [#305](https://github.com/JsonApiClient/json_api_client/pull/305) - optional search relationship data in result set + ## 1.7.0 - [#320](https://github.com/JsonApiClient/json_api_client/pull/320) - fix passing relationships on create diff --git a/lib/json_api_client/included_data.rb b/lib/json_api_client/included_data.rb index 2ae26591..c62e1f73 100644 --- a/lib/json_api_client/included_data.rb +++ b/lib/json_api_client/included_data.rb @@ -4,15 +4,18 @@ class IncludedData def initialize(result_set, data) record_class = result_set.record_class - grouped_data = data.group_by{|datum| datum["type"]} - @data = grouped_data.inject({}) do |h, (type, records)| + included_set = data.map do |datum| + type = datum["type"] klass = Utils.compute_type(record_class, record_class.key_formatter.unformat(type).singularize.classify) - h[type] = records.map do |datum| - params = klass.parser.parameters_from_resource(datum) - resource = klass.load(params) - resource.last_result_set = result_set - resource - end.index_by(&:id) + params = klass.parser.parameters_from_resource(datum) + resource = klass.load(params) + resource.last_result_set = result_set + resource + end + + included_set.concat(result_set) if record_class.search_included_in_result_set + @data = included_set.group_by(&:type).inject({}) do |h, (type, resources)| + h[type] = resources.index_by(&:id) h end end diff --git a/lib/json_api_client/resource.rb b/lib/json_api_client/resource.rb index 0c44f9d4..56991b2b 100644 --- a/lib/json_api_client/resource.rb +++ b/lib/json_api_client/resource.rb @@ -34,6 +34,7 @@ class Resource :route_format, :request_params_class, :keep_request_params, + :search_included_in_result_set, instance_accessor: false class_attribute :add_defaults_to_changes, instance_writer: false @@ -50,6 +51,7 @@ class Resource self.request_params_class = RequestParams self.keep_request_params = false self.add_defaults_to_changes = false + self.search_included_in_result_set = false #:underscored_key, :camelized_key, :dasherized_key, or custom self.json_key_format = :underscored_key diff --git a/test/unit/association_test.rb b/test/unit/association_test.rb index 6031f226..89624d0b 100644 --- a/test/unit/association_test.rb +++ b/test/unit/association_test.rb @@ -74,6 +74,10 @@ class UserAccount < TestResource property :balance end +class Employee < TestResource + has_one :chief, klass: 'Employee' +end + class AssociationTest < MiniTest::Test def test_default_properties_no_changes @@ -765,4 +769,104 @@ def test_nested_create_from_scope Specified.where(foo_id: 1).create end + def test_load_include_from_dataset + stub_request(:get, 'http://example.com/employees?include=chief&page[per_page]=2') + .to_return( + headers: { + content_type: 'application/vnd.api+json' + }, body: { + data: [ + { + id: '1', + type: 'employees', + attributes: { + name: 'John Doe' + }, + relationships: { + chief: { + data: {id: '2', type: 'employees'} + } + } + }, + { + id: '2', + attributes: { + name: 'Jane Doe' + }, + relationships: { + chief: { + data: {id: '3', type: 'employees'} + } + } + } + ], + included: [ + { + id: '3', + type: 'employees', + attributes: { + name: 'Richard Reed' + } + } + ] + }.to_json) + Employee.search_included_in_result_set = true + records = Employee.includes(:chief).per(2).to_a + assert_equal(2, records.size) + assert_equal('1', records.first.id) + assert_equal('2', records.second.id) + assert_equal('3', records.second.chief.id) + assert_equal('2', records.first.chief.id) + end + + def test_does_not_load_include_from_dataset + stub_request(:get, 'http://example.com/employees?include=chief&page[per_page]=2') + .to_return( + headers: { + content_type: 'application/vnd.api+json' + }, body: { + data: [ + { + id: '1', + type: 'employees', + attributes: { + name: 'John Doe' + }, + relationships: { + chief: { + data: {id: '2', type: 'employees'} + } + } + }, + { + id: '2', + attributes: { + name: 'Jane Doe' + }, + relationships: { + chief: { + data: {id: '3', type: 'employees'} + } + } + } + ], + included: [ + { + id: '3', + type: 'employees', + attributes: { + name: 'Richard Reed' + } + } + ] + }.to_json) + Employee.search_included_in_result_set = false + records = Employee.includes(:chief).per(2).to_a + assert_equal(2, records.size) + assert_equal('1', records.first.id) + assert_equal('2', records.second.id) + assert_equal('3', records.second.chief.id) + assert_nil(records.first.chief) + end + end