lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb
# frozen_string_literal: true
module Dynamoid
# @private
module AdapterPlugin
class AwsSdkV3
# Mimics behavior of the yielded object on DynamoDB's update_item API (high level).
class ItemUpdater
ADD = 'ADD'
DELETE = 'DELETE'
PUT = 'PUT'
attr_reader :table, :key, :range_key
def initialize(table, key, range_key = nil)
@table = table
@key = key
@range_key = range_key
@additions = {}
@deletions = {}
@updates = {}
end
#
# Adds the given values to the values already stored in the corresponding columns.
# The column must contain a Set or a number.
#
# @param [Hash] values keys of the hash are the columns to update, values
# are the values to add. values must be a Set, Array, or Numeric
#
def add(values)
@additions.merge!(sanitize_attributes(values))
end
#
# Removes values from the sets of the given columns
#
# @param [Hash|Symbol|String] values keys of the hash are the columns, values are Arrays/Sets of items
# to remove
#
def delete(values)
if values.is_a?(Hash)
@deletions.merge!(sanitize_attributes(values))
else
@deletions.merge!(values.to_s => nil)
end
end
#
# Replaces the values of one or more attributes
#
def set(values)
values_sanitized = sanitize_attributes(values)
if Dynamoid.config.store_attribute_with_nil_value
@updates.merge!(values_sanitized)
else
# delete explicitly attributes if assigned nil value and configured
# to not store nil values
values_to_update = values_sanitized.reject { |_, v| v.nil? }
values_to_delete = values_sanitized.select { |_, v| v.nil? }
@updates.merge!(values_to_update)
@deletions.merge!(values_to_delete)
end
end
#
# Returns an AttributeUpdates hash suitable for passing to the V2 Client API
#
def attribute_updates
result = {}
@additions.each do |k, v|
result[k] = {
action: ADD,
value: v
}
end
@deletions.each do |k, v|
result[k] = {
action: DELETE
}
result[k][:value] = v unless v.nil?
end
@updates.each do |k, v|
result[k] = {
action: PUT,
value: v
}
end
result
end
private
# Keep in sync with AwsSdkV3.sanitize_item.
#
# The only difference is that to update item we need to track whether
# attribute value is nil or not.
def sanitize_attributes(attributes)
# rubocop:disable Lint/DuplicateBranch
attributes.transform_values do |v|
if v.is_a?(Hash)
v.stringify_keys
elsif v.is_a?(Set) && v.empty?
nil
elsif v.is_a?(String) && v.empty?
nil
else
v
end
end
# rubocop:enable Lint/DuplicateBranch
end
end
end
end
end