Skip to content

Commit

Permalink
Replace #update(class, attributes) with #update_fields(class, hash_ke…
Browse files Browse the repository at this point in the history
…y, attributes)
  • Loading branch information
andrykonchin committed Oct 28, 2024
1 parent 6f932a6 commit b63bfad
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 94 deletions.
11 changes: 6 additions & 5 deletions lib/dynamoid/transaction_write.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
require 'dynamoid/transaction_write/create'
require 'dynamoid/transaction_write/delete'
require 'dynamoid/transaction_write/destroy'
require 'dynamoid/transaction_write/update'
require 'dynamoid/transaction_write/update_fields'
require 'dynamoid/transaction_write/update_attributes'
require 'dynamoid/transaction_write/upsert'

Expand Down Expand Up @@ -52,12 +52,13 @@ def upsert(model_or_model_class, attributes = {}, options = {}, &block)
add_action_and_validate Dynamoid::TransactionWrite::Upsert.new(model_or_model_class, attributes, options, &block)
end

def update!(model_or_model_class, attributes = {}, options = {}, &block)
update(model_or_model_class, attributes, options.reverse_merge(raise_validation_error: true), &block)
def update_fields!(klass, hash_key, range_key = nil, attributes = {}, options = {}, &block)
update_fields(klass, hash_key, range_key, attributes, options.reverse_merge(raise_validation_error: true), &block)
end

def update(model_or_model_class, attributes = {}, options = {}, &block)
add_action_and_validate Dynamoid::TransactionWrite::Update.new(model_or_model_class, attributes, options, &block)
def update_fields(klass, hash_key, range_key = nil, attributes = {}, options = {}, &block)
add_action_and_validate Dynamoid::TransactionWrite::UpdateFields.new(klass, hash_key, range_key, attributes, options, &block)
end

def update_attributes(model, attributes = {}, options = {}, &block)
add_action_and_validate Dynamoid::TransactionWrite::UpdateAttributes.new(model, attributes, options, &block)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,36 @@

module Dynamoid
class TransactionWrite
class Update < Action
class UpdateFields < Action
# model is found if not otherwise specified so callbacks can be run
def initialize(model_or_model_class, attributes, options = {})
model = if model_or_model_class.is_a?(Dynamoid::Document)
model_or_model_class
else
find_from_attributes(model_or_model_class, attributes)
end
super(model, attributes, options)
write_attributes_to_model
end
def initialize(klass, hash_key, range_key, attributes, options = {})
optional_params = [range_key, attributes, options].compact

def run_callbacks
unless model
yield if block_given?
return
end
model.run_callbacks(:save) do
model.run_callbacks(:update) do
model.run_callbacks(:validate) do
yield if block_given?
end
end
if optional_params.first.is_a?(Hash)
range_key = nil
attributes, options = optional_params[0..1]
else
range_key = optional_params.first
attributes, options = optional_params[1..2]
end

@hash_key = hash_key
@range_key = range_key

super(klass, attributes, options)
end

def to_h
if model
# model.hash_key = SecureRandom.uuid if model.hash_key.blank?
touch_model_timestamps(skip_created_at: true)
changes = model.changes.map { |k, v| [k.to_sym, v[1]] }.to_h # hash of dirty attributes
else
changes = attributes.clone || {}
# changes[model_class.hash_key] = SecureRandom.uuid
changes = add_timestamps(changes, skip_created_at: true)
end
changes = attributes.clone || {}
# changes[model_class.hash_key] = SecureRandom.uuid
changes = add_timestamps(changes, skip_created_at: true)
changes.delete(model_class.hash_key) # can't update id!
changes.delete(model_class.range_key) if model_class.range_key?
item = Dynamoid::Dumping.dump_attributes(changes, model_class.attributes)

# set 'key' that is used to look up record for updating
key = { model_class.hash_key => hash_key }
key[model_class.range_key] = range_key if model_class.range_key?
key = { model_class.hash_key => @hash_key }
key[model_class.range_key] = @range_key if model_class.range_key?

# e.g. "SET #updated_at = :updated_at ADD record_count :i"
item_keys = item.keys
Expand Down Expand Up @@ -83,6 +70,10 @@ def to_h
result
end

def skip_validation?
true
end

private

# adds all of the ADD statements to the update_expression and returns it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require 'spec_helper'

describe Dynamoid::TransactionWrite, '.update(class, attributes)' do # => .update_fields
describe Dynamoid::TransactionWrite, '#update_fields' do
let(:klass) do
new_class do
field :name
Expand All @@ -20,7 +20,7 @@
obj = klass.create!(name: 'Alex')

described_class.execute do |txn|
txn.update klass, id: obj.id, name: 'Alex [Updated]'
txn.update_fields klass, obj.id, name: 'Alex [Updated]'
end

obj_loaded = klass.find(obj.id)
Expand All @@ -34,7 +34,7 @@

# result = true
# described_class.execute do |txn|
# result = txn.update klass, id: obj.id, name: 'Alex [Updated]'
# result = txn.update_fields klass, obj.id, name: 'Alex [Updated]'
# end

# expect(result).to eql nil
Expand All @@ -47,7 +47,7 @@

expect {
described_class.execute do |txn|
txn.update klass, id: obj.id, name: 'Alex [Updated]'
txn.update_fields klass, obj.id, name: 'Alex [Updated]'
end
}.to change { klass.find(obj.id).name }.to('Alex [Updated]')
end
Expand All @@ -59,7 +59,7 @@

expect {
described_class.execute do |txn|
txn.update klass_with_composite_key, id: obj.id, age: obj.age, name: 'Alex [Updated]'
txn.update_fields klass_with_composite_key, obj.id, obj.age, name: 'Alex [Updated]'
end
}.to change { obj.reload.name }.to('Alex [Updated]')
end
Expand All @@ -74,7 +74,7 @@
time_now = Time.now

described_class.execute do |txn|
txn.update klass, id: obj.id, name: 'Alex [Updated]'
txn.update_fields klass, obj.id, name: 'Alex [Updated]'
end

obj.reload
Expand All @@ -89,7 +89,7 @@
created_at = updated_at = Time.now

described_class.execute do |txn|
txn.update klass, id: obj.id, created_at: created_at, updated_at: updated_at
txn.update_fields klass, obj.id, created_at: created_at, updated_at: updated_at
end

obj.reload
Expand All @@ -103,7 +103,7 @@

expect {
described_class.execute do |txn|
txn.update klass, id: obj.id, name: 'Alex [Updated]'
txn.update_fields klass, obj.id, name: 'Alex [Updated]'
end
}.not_to raise_error
end
Expand All @@ -118,7 +118,7 @@

# expect {
# described_class.execute do |txn|
# txn.update klass, {id: obj1.id, name: 'one [updated]' }
# txn.update_fields klass, obj1.id, { name: 'one [updated]' }
# txn.create obj2
# end
# }.to raise_error(Aws::DynamoDB::Errors::TransactionCanceledException)
Expand All @@ -131,53 +131,53 @@

describe 'callbacks' do
# FIXME
# it 'does not run any callback' do
# klass_with_callbacks = new_class do
# field :name

# before_validation { ScratchPad << 'run before_validation' }
# after_validation { ScratchPad << 'run after_validation' }

# before_create { ScratchPad << 'run before_create' }
# after_create { ScratchPad << 'run after_create' }
# around_create :around_create_callback

# before_save { ScratchPad << 'run before_save' }
# after_save { ScratchPad << 'run after_save' }
# around_save :around_save_callback

# before_destroy { ScratchPad << 'run before_destroy' }
# after_destroy { ScratchPad << 'run after_destroy' }
# around_destroy :around_destroy_callback

# def around_create_callback
# ScratchPad << 'start around_create'
# yield
# ScratchPad << 'finish around_create'
# end

# def around_save_callback
# ScratchPad << 'start around_save'
# yield
# ScratchPad << 'finish around_save'
# end

# def around_destroy_callback
# ScratchPad << 'start around_destroy'
# yield
# ScratchPad << 'finish around_destroy'
# end
# end

# ScratchPad.record []
# obj = klass_with_callbacks.create!(name: 'Alex')
# ScratchPad.clear

# described_class.execute do |txn|
# txn.update klass_with_callbacks, id: obj.id, name: 'Alex [Updated]'
# end

# expect(ScratchPad.recorded).to eql([])
# end
it 'does not run any callback' do
klass_with_callbacks = new_class do
field :name

before_validation { ScratchPad << 'run before_validation' }
after_validation { ScratchPad << 'run after_validation' }

before_create { ScratchPad << 'run before_create' }
after_create { ScratchPad << 'run after_create' }
around_create :around_create_callback

before_save { ScratchPad << 'run before_save' }
after_save { ScratchPad << 'run after_save' }
around_save :around_save_callback

before_destroy { ScratchPad << 'run before_destroy' }
after_destroy { ScratchPad << 'run after_destroy' }
around_destroy :around_destroy_callback

def around_create_callback
ScratchPad << 'start around_create'
yield
ScratchPad << 'finish around_create'
end

def around_save_callback
ScratchPad << 'start around_save'
yield
ScratchPad << 'finish around_save'
end

def around_destroy_callback
ScratchPad << 'start around_destroy'
yield
ScratchPad << 'finish around_destroy'
end
end

ScratchPad.record []
obj = klass_with_callbacks.create!(name: 'Alex')
ScratchPad.clear

described_class.execute do |txn|
txn.update_fields klass_with_callbacks, obj.id, name: 'Alex [Updated]'
end

expect(ScratchPad.recorded).to eql([])
end
end
end

0 comments on commit b63bfad

Please sign in to comment.