diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index c9059d4b..0478f11d 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -23,7 +23,7 @@ jobs: bundler: - latest ruby: - - "3.3" + - "3.4" runs-on: ubuntu-latest env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/style.gemfile diff --git a/.rubocop_thread_safety.yml b/.rubocop_thread_safety.yml index 93f386ff..8cf726fa 100644 --- a/.rubocop_thread_safety.yml +++ b/.rubocop_thread_safety.yml @@ -1,6 +1,6 @@ # It would be good to make the gem more thread safe, but at the moment it is not entirely. # TODO: Comment out the following to see code needing to be refactored for thread safety! -ThreadSafety/ClassAndModuleAttributes: - Enabled: false ThreadSafety/ClassInstanceVariable: Enabled: false +ThreadSafety/ClassAndModuleAttributes: + Enabled: false diff --git a/lib/dynamoid/dumping.rb b/lib/dynamoid/dumping.rb index 36e12bd5..50619e1b 100644 --- a/lib/dynamoid/dumping.rb +++ b/lib/dynamoid/dumping.rb @@ -323,10 +323,10 @@ class CustomTypeDumper < Base def process(value) field_class = @options[:type] - if value.respond_to?(:dynamoid_dump) - value.dynamoid_dump - elsif field_class.respond_to?(:dynamoid_dump) + if field_class.respond_to?(:dynamoid_dump) field_class.dynamoid_dump(value) + elsif value.respond_to?(:dynamoid_dump) + value.dynamoid_dump else raise ArgumentError, "Neither #{field_class} nor #{value} supports serialization for Dynamoid." end diff --git a/spec/dynamoid/dumping_spec.rb b/spec/dynamoid/dumping_spec.rb index 579c49da..2b238e7d 100644 --- a/spec/dynamoid/dumping_spec.rb +++ b/spec/dynamoid/dumping_spec.rb @@ -1449,6 +1449,21 @@ def self.load(str) end end + context 'Custom type with adapter interface provided' do + let(:klass) do + new_class do |_options| + field :user, DumpingSpecs::UserWithAdapterInterface + end + end + + it "prefers adapter's .dynamoid_dump method over #dynamoid_dump" do + user = DumpingSpecs::UserWithAdapterInterface.new('John') + obj = klass.create(user: user) + + expect(raw_attributes(obj)[:user]).to eql('John (dumped with .dynamoid_dump)') + end + end + context 'DynamoDB type specified' do let(:klass) do new_class do diff --git a/spec/fixtures/dumping.rb b/spec/fixtures/dumping.rb index df95a9c4..5cb41325 100644 --- a/spec/fixtures/dumping.rb +++ b/spec/fixtures/dumping.rb @@ -25,6 +25,35 @@ def self.dynamoid_load(string) end end + # implements both #dynamoid_dump and .dynamoid_dump methods + class UserWithAdapterInterface + attr_accessor :name + + def initialize(name) + self.name = name + end + + def dynamoid_dump + "#{name} (dumped with #dynamoid_dump)" + end + + def eql?(other) + name == other.name + end + + def hash + name.hash + end + + def self.dynamoid_dump(user) + "#{user.name} (dumped with .dynamoid_dump)" + end + + def self.dynamoid_load(string) + new(string.to_s) + end + end + # doesn't implement #dynamoid_dump/#dynamoid_load methods so requires an adapter class UserValue attr_accessor :name @@ -48,7 +77,7 @@ def self.dynamoid_dump(user) end def self.dynamoid_load(string) - User.new(string.to_s) + UserValue.new(string.to_s) end end @@ -58,8 +87,8 @@ def self.dynamoid_dump(user) end def self.dynamoid_load(array) - array = array.name.split if array.is_a?(User) - User.new(array.join(' ')) + array = array.name.split if array.is_a?(UserValue) + UserValue.new(array.join(' ')) end def self.dynamoid_field_type