lib/dynamoid/persistence/save.rb in dynamoid-3.8.0 vs lib/dynamoid/persistence/save.rb in dynamoid-3.9.0

- old
+ new

@@ -2,29 +2,49 @@ module Dynamoid module Persistence # @private class Save - def self.call(model) - new(model).call + def self.call(model, **options) + new(model, **options).call end - def initialize(model) + def initialize(model, touch: nil) @model = model + @touch = touch # touch=false means explicit disabling of updating the `updated_at` attribute end def call @model.hash_key = SecureRandom.uuid if @model.hash_key.blank? + return true unless @model.changed? + + @model.created_at ||= DateTime.now.in_time_zone(Time.zone) if @model.class.timestamps_enabled? + + if @model.class.timestamps_enabled? && !@model.updated_at_changed? && !(@touch == false && @model.persisted?) + @model.updated_at = DateTime.now.in_time_zone(Time.zone) + end + # Add an optimistic locking check if the lock_version column exists if @model.class.attributes[:lock_version] @model.lock_version = (@model.lock_version || 0) + 1 end - attributes_dumped = Dumping.dump_attributes(@model.attributes, @model.class.attributes) - Dynamoid.adapter.write(@model.class.table_name, attributes_dumped, conditions_for_write) + if @model.new_record? + attributes_dumped = Dumping.dump_attributes(@model.attributes, @model.class.attributes) + Dynamoid.adapter.write(@model.class.table_name, attributes_dumped, conditions_for_write) + else + attributes_to_persist = @model.attributes.slice(*@model.changed.map(&:to_sym)) + Dynamoid.adapter.update_item(@model.class.table_name, @model.hash_key, options_to_update_item) do |t| + attributes_to_persist.each do |name, value| + value_dumped = Dumping.dump_field(value, @model.class.attributes[name]) + t.set(name => value_dumped) + end + end + end + @model.new_record = false true rescue Dynamoid::Errors::ConditionalCheckFailedException => e if @model.new_record? raise Dynamoid::Errors::RecordNotUnique.new(e, @model) @@ -56,9 +76,36 @@ conditions[:if][:lock_version] = @model.changes[:lock_version][0] end end conditions + end + + def options_to_update_item + options = {} + + if @model.class.range_key + value_dumped = Dumping.dump_field(@model.range_value, @model.class.attributes[@model.class.range_key]) + options[:range_key] = value_dumped + end + + conditions = {} + conditions[:if_exists] ||= {} + conditions[:if_exists][@model.class.hash_key] = @model.hash_key + + # Add an optimistic locking check if the lock_version column exists + if @model.class.attributes[:lock_version] + # Uses the original lock_version value from Dirty API + # in case user changed 'lock_version' manually + if @model.changes[:lock_version][0] + conditions[:if] ||= {} + conditions[:if][:lock_version] = @model.changes[:lock_version][0] + end + end + + options[:conditions] = conditions + + options end end end end