Skip to content

Commit 9f1a9d3

Browse files
committed
Sync specs for transactional save/save! and update_attributes/update_attributes!
1 parent 9acf05c commit 9f1a9d3

File tree

2 files changed

+159
-2
lines changed

2 files changed

+159
-2
lines changed

spec/dynamoid/transaction_write/save_spec.rb

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,9 @@ def around_update_callback
12111211
end
12121212

12131213
describe Dynamoid::TransactionWrite, '.save!' do
1214+
# The only difference in specs structure between #save and #save! is missing
1215+
# a section for callbacks here
1216+
12141217
let(:klass) do
12151218
new_class do
12161219
field :name
@@ -1469,6 +1472,51 @@ def around_update_callback
14691472
expect(obj_to_create).to be_changed
14701473
end
14711474

1475+
it 'does not roll back the transaction when a model to update does not exist' do
1476+
obj_deleted = klass.create!(name: 'one')
1477+
klass.find(obj_deleted.id).delete
1478+
obj_deleted.name = 'one [updated]'
1479+
obj_to_create = nil
1480+
1481+
expect {
1482+
described_class.execute do |txn|
1483+
txn.save! obj_deleted
1484+
obj_to_create = txn.create klass, name: 'two'
1485+
end
1486+
}.to change(klass, :count).by(2)
1487+
1488+
expect(obj_to_create).to be_persisted
1489+
expect(obj_to_create).not_to be_changed
1490+
end
1491+
1492+
it 'is marked as not persisted and is marked as changed at creation when the transaction rolled back' do
1493+
obj = klass.new(name: 'Alex')
1494+
1495+
expect {
1496+
described_class.execute do |txn|
1497+
txn.save! obj
1498+
raise 'trigger rollback'
1499+
end
1500+
}.to raise_error('trigger rollback')
1501+
1502+
expect(obj).not_to be_persisted
1503+
expect(obj).to be_changed
1504+
end
1505+
1506+
it 'is marked as changed at updating when the transaction rolled back' do
1507+
obj = klass.create!(name: 'Alex')
1508+
obj.name = 'Alex [Updated]'
1509+
1510+
expect {
1511+
described_class.execute do |txn|
1512+
txn.save! obj
1513+
raise 'trigger rollback'
1514+
end
1515+
}.to raise_error('trigger rollback')
1516+
1517+
expect(obj).to be_changed
1518+
end
1519+
14721520
context 'primary key is of non-native DynamoDB type' do
14731521
context 'a new model' do
14741522
it 'uses dumped value of partition key to update item' do

spec/dynamoid/transaction_write/update_attributes_spec.rb

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def around_save_callback
5252
end
5353
end
5454

55-
it 'persists changes' do
55+
it 'persists changes in already presisted model' do
5656
obj = klass.create!(name: 'Alex')
5757

5858
described_class.execute do |txn|
@@ -316,7 +316,7 @@ def around_save_callback
316316
expect(klass.find(obj_deleted.id).name).to eql 'Alex [Updated]'
317317
end
318318

319-
it 'is marked as changed when the transaction rolled back' do
319+
it 'keeps a model as changed when the transaction rolled back' do
320320
obj = klass.create!(name: 'Alex')
321321

322322
expect {
@@ -545,6 +545,10 @@ def around_update_callback
545545
end
546546

547547
describe Dynamoid::TransactionWrite, '#update_attributes!' do
548+
# The only difference in specs structure between
549+
# #update_attributes and #update_attributes! is missing a section
550+
# for callbacks here
551+
548552
let(:klass) do
549553
new_class do
550554
field :name
@@ -603,6 +607,98 @@ def around_update_callback
603607
end
604608
end
605609

610+
describe 'primary key validation' do
611+
context 'simple primary key' do
612+
it 'requires partition key to be specified' do
613+
obj = klass.create!(name: 'Alex')
614+
obj.id = nil
615+
616+
expect {
617+
described_class.execute do |txn|
618+
txn.update_attributes! obj, name: 'Alex [Updated]'
619+
end
620+
}.to raise_exception(Dynamoid::Errors::MissingHashKey)
621+
end
622+
end
623+
624+
context 'composite key' do
625+
it 'requires partition key to be specified' do
626+
obj = klass_with_composite_key.create!(name: 'Alex', age: 3)
627+
obj.id = nil
628+
629+
expect {
630+
described_class.execute do |txn|
631+
txn.update_attributes! obj, name: 'Alex [Updated]'
632+
end
633+
}.to raise_exception(Dynamoid::Errors::MissingHashKey)
634+
end
635+
636+
it 'requires sort key to be specified' do
637+
obj = klass_with_composite_key.create!(name: 'Alex', age: 3)
638+
obj.age = nil
639+
640+
expect {
641+
described_class.execute do |txn|
642+
txn.update_attributes! obj, name: 'Alex [Updated]'
643+
end
644+
}.to raise_exception(Dynamoid::Errors::MissingRangeKey)
645+
end
646+
end
647+
end
648+
649+
describe 'timestamps' do
650+
it 'sets updated_at if Config.timestamps=true', config: { timestamps: true } do
651+
obj = klass.create!
652+
653+
travel 1.hour do
654+
time_now = Time.now
655+
656+
described_class.execute do |txn|
657+
txn.update_attributes! obj, name: 'Alex [Updated]'
658+
end
659+
660+
obj.reload
661+
expect(obj.updated_at.to_i).to eql time_now.to_i
662+
end
663+
end
664+
665+
it 'uses provided values of created_at and updated_at if Config.timestamps=true', config: { timestamps: true } do
666+
obj = klass.create!
667+
668+
travel 1.hour do
669+
created_at = updated_at = Time.now
670+
671+
described_class.execute do |txn|
672+
txn.update_attributes! obj, created_at: created_at, updated_at: updated_at
673+
end
674+
675+
obj.reload
676+
expect(obj.created_at.to_i).to eql created_at.to_i
677+
expect(obj.updated_at.to_i).to eql updated_at.to_i
678+
end
679+
end
680+
681+
it 'does not raise error if Config.timestamps=false', config: { timestamps: false } do
682+
obj = klass.create!
683+
684+
expect {
685+
described_class.execute do |txn|
686+
txn.update_attributes! obj, name: 'Alex [Updated]'
687+
end
688+
}.not_to raise_error
689+
end
690+
691+
it 'does not raise error if no changes and Config.timestamps=false', config: { timestamps: false } do
692+
obj = klass.create!
693+
694+
expect {
695+
described_class.execute do |txn|
696+
txn.update_attributes! obj, {}
697+
end
698+
}.not_to raise_error
699+
end
700+
end
701+
606702
describe 'validation' do
607703
before do
608704
klass_with_validation.create_table
@@ -710,6 +806,19 @@ def around_update_callback
710806
expect(klass.find(obj_deleted.id).name).to eql 'Alex [Updated]'
711807
end
712808

809+
it 'keeps a model as changed when the transaction rolled back' do
810+
obj = klass.create!(name: 'Alex')
811+
812+
expect {
813+
described_class.execute do |txn|
814+
txn.update_attributes! obj, name: 'Alex [Updated]'
815+
raise 'trigger rollback'
816+
end
817+
}.to raise_error('trigger rollback')
818+
819+
expect(obj).to be_changed
820+
end
821+
713822
it 'uses dumped value of partition key to update item' do
714823
klass = new_class(partition_key: { name: :published_on, type: :date }) do
715824
field :name

0 commit comments

Comments
 (0)