Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: allow multiple resource relation retrieval methods #1425

Merged
merged 4 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/jsonapi-resources.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'jsonapi/resources/railtie'
require 'jsonapi/naive_cache'
require 'jsonapi/compiled_json'
require 'jsonapi/relation_retrieval'
require 'jsonapi/active_relation_retrieval'
require 'jsonapi/active_relation_retrieval_v09'
require 'jsonapi/active_relation_retrieval_v10'
Expand Down
2 changes: 2 additions & 0 deletions lib/jsonapi/active_relation_retrieval.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

module JSONAPI
module ActiveRelationRetrieval
include ::JSONAPI::RelationRetrieval

def find_related_ids(relationship, options = {})
self.class.find_related_fragments(self, relationship, options).keys.collect { |rid| rid.id }
end
Expand Down
2 changes: 2 additions & 0 deletions lib/jsonapi/active_relation_retrieval_v09.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

module JSONAPI
module ActiveRelationRetrievalV09
include ::JSONAPI::RelationRetrieval

def find_related_ids(relationship, options = {})
self.class.find_related_fragments(self.fragment, relationship, options).keys.collect { |rid| rid.id }
end
Expand Down
2 changes: 2 additions & 0 deletions lib/jsonapi/active_relation_retrieval_v10.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

module JSONAPI
module ActiveRelationRetrievalV10
include ::JSONAPI::RelationRetrieval

def find_related_ids(relationship, options = {})
self.class.find_related_fragments(self, relationship, options).keys.collect { |rid| rid.id }
end
Expand Down
7 changes: 7 additions & 0 deletions lib/jsonapi/relation_retrieval.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

module JSONAPI
module RelationRetrieval
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally, I think, this defines the required abstract interface, I think, required for a valid strategy

end
end

21 changes: 13 additions & 8 deletions lib/jsonapi/resource_common.rb
Original file line number Diff line number Diff line change
Expand Up @@ -431,19 +431,24 @@ def find_related_ids(relationship, options = {})

module ClassMethods
def resource_retrieval_strategy(module_name = JSONAPI.configuration.default_resource_retrieval_strategy)
if @_resource_retrieval_strategy_loaded
warn "Resource retrieval strategy #{@_resource_retrieval_strategy_loaded} already loaded for #{self.name}"
return
end

module_name = module_name.to_s

return if module_name.blank? || module_name == 'self' || module_name == 'none'

class_eval do
resource_retrieval_module = module_name.safe_constantize
raise "Unable to find resource_retrieval_strategy #{module_name}" unless resource_retrieval_module
resource_retrieval_module = module_name.safe_constantize

raise "Unable to find resource_retrieval_strategy #{module_name}" unless resource_retrieval_module

if included_modules.include?(::JSONAPI::RelationRetrieval)
if _resource_retrieval_strategy_loaded.nil? || module_name == _resource_retrieval_strategy_loaded
warn "Resource retrieval strategy #{module_name} already loaded for #{self.name}"
return
else
fail ArgumentError.new("Resource retrieval strategy #{_resource_retrieval_strategy_loaded} already loaded for #{self.name}. Cannot load #{module_name}")
end
end

class_eval do
include resource_retrieval_module
extend "#{module_name}::ClassMethods".safe_constantize
@_resource_retrieval_strategy_loaded = module_name
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
require File.expand_path('../../../test_helper', __FILE__)

module VX
end

class MultipleActiveRelationResourceTest < ActiveSupport::TestCase
def setup
end

def teardown
teardown_test_constant(::VX, :BaseResource)
teardown_test_constant(::VX, :DuplicateSubBaseResource)
teardown_test_constant(::VX, :InvalidSubBaseResource)
teardown_test_constant(::VX, :ValidCustomBaseResource)
end

def teardown_test_constant(namespace, constant_name)
return unless namespace.const_defined?(constant_name)
namespace.send(:remove_const, constant_name)
rescue NameError
end

def test_correct_resource_retrieval_strategy
expected = 'JSONAPI::ActiveRelationRetrieval'
default = JSONAPI.configuration.default_resource_retrieval_strategy
assert_equal expected, default
assert_nil JSONAPI::Resource._resource_retrieval_strategy_loaded

expected = 'JSONAPI::ActiveRelationRetrieval'
assert_silent do
::VX.module_eval <<~MODULE
class BaseResource < JSONAPI::Resource
abstract
end
MODULE
end
assert_equal expected, VX::BaseResource._resource_retrieval_strategy_loaded

strategy = 'JSONAPI::ActiveRelationRetrieval'
expected = 'JSONAPI::ActiveRelationRetrieval'
assert_output nil, "Resource retrieval strategy #{expected} already loaded for VX::DuplicateSubBaseResource\n" do
::VX.module_eval <<~MODULE
class DuplicateSubBaseResource < JSONAPI::Resource
resource_retrieval_strategy '#{strategy}'
abstract
end
MODULE
end
assert_equal expected, VX::DuplicateSubBaseResource._resource_retrieval_strategy_loaded

strategy = 'JSONAPI::ActiveRelationRetrievalV10'
expected = "Resource retrieval strategy #{default} already loaded for VX::InvalidSubBaseResource. Cannot load #{strategy}"
ex = assert_raises ArgumentError do
::VX.module_eval <<~MODULE
class InvalidSubBaseResource < JSONAPI::Resource
resource_retrieval_strategy '#{strategy}'
abstract
end
MODULE
end
assert_equal expected, ex.message

strategy = 'JSONAPI::ActiveRelationRetrievalV10'
expected = 'JSONAPI::ActiveRelationRetrievalV10'
assert_silent do
::VX.module_eval <<~MODULE
class ValidCustomBaseResource
include JSONAPI::ResourceCommon
root_resource
abstract
immutable
resource_retrieval_strategy '#{strategy}'
end
MODULE
end
assert_equal expected, VX::ValidCustomBaseResource._resource_retrieval_strategy_loaded
end
end