Skip to content
Open
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
9 changes: 7 additions & 2 deletions lib/dynomite/item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,13 @@ def update_attribute(field, value)
end

def delete_attribute(field)
@attrs.delete(field.to_sym)
update(@attrs, {validate: false})
update_params = {
expression_attribute_names: { "#field_0" => field.to_s },
update_expression: "REMOVE #field_0",
key: self.primary_key,
table_name: self.class.table_name
}
self.class.client.update_item(update_params)
valid? # ActiveRecord does not have a delete_attribute. Follow update_attribute behavior.
end
alias :remove_attribute :delete_attribute
Expand Down
6 changes: 1 addition & 5 deletions lib/dynomite/item/indexes/finder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,7 @@ def find_primary_key_index
end

def primary_key_found?
if @source.composite_key?
query_fields.include?(@source.partition_key_field) && query_fields.include?(@source.sort_key_field)
else
query_fields.include?(@source.partition_key_field)
end
query_fields.include?(@source.partition_key_field)
end

# It's possible to have multiple indexes with the same partition and sort key.
Expand Down
2 changes: 1 addition & 1 deletion lib/dynomite/item/typecaster.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def dump(data, depth=0)
# The method also helps keep track of where we cast_to_type
# It's only a few spots this provides an easy to search for it.
# See: https://v5.docs.rubyonjets.com/docs/database/dynamodb/model/typecasting/
FALSEY = [false, 'false', 'FALSE', 0, '0', 'f', 'F', 'off', 'OFF']
FALSEY = [nil, false, 'false', 'FALSE', 0, '0', 'f', 'F', 'off', 'OFF']
def cast_to_type(type, value, on: :read)
case type
when :integer
Expand Down
26 changes: 14 additions & 12 deletions lib/dynomite/item/write/put_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def permitted_attrs
end

def handle_conditional_check_failed_exception(exception)
if @params[:condition_expression] == check_unique_condition
if @params[:condition_expression] == check_unique_params[:condition_expression]
raise Dynomite::Error::RecordNotUnique.new(not_unique_message)
else # currently only other case is locking
raise Dynomite::Error::StaleObject.new(exception.message)
Expand All @@ -62,24 +62,26 @@ def not_unique_message
"A #{@model.class.name} with the primary key #{primary_key_attrs} already exists"
end

# https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ConditionExpressions.html#Expressions.ConditionExpressions.PreventingOverwrites
# Examples:
# attribute_not_exists(id)
# attribute_not_exists(category) AND attribute_not_exists(sku)
def check_unique_params
if @model.new_record? && !@options[:put]
@params.merge!(condition_expression: check_unique_condition)
condition_expression = @model.primary_key_fields.map do |field|
"attribute_not_exists(##{field})"
end.join(" AND ")
expression_attribute_names = {}.tap do |attribute_names|
@model.primary_key_fields.each do |field|
attribute_names["##{field}"] = field
end
end
{ condition_expression: condition_expression, expression_attribute_names: expression_attribute_names }
else
{}
end
end

# https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ConditionExpressions.html#Expressions.ConditionExpressions.PreventingOverwrites
# Examples:
# attribute_not_exists(id)
# attribute_not_exists(category) AND attribute_not_exists(sku)
def check_unique_condition
condition_expression = @model.primary_key_fields.map do |field|
"attribute_not_exists(#{field})"
end.join(" AND ")
end

def locking_params
return {} if @params[:condition_expression] # already set from check_unique_params
return {} unless @model.class.locking_enabled?
Expand Down