Skip to content
Merged
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
25 changes: 25 additions & 0 deletions lib/switch_point/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,36 @@ def switch_point_proxy
end
end

def transaction_with(*models, &block)
unless can_transaction_with?(*models)
raise RuntimeError.new("switch_point's model names must be consistent")
end

with_writable do
self.transaction(&block)
end
end

private

def assert_existing_switch_point!(name)
SwitchPoint.config.fetch(name)
end

def can_transaction_with?(*models)
writable_switch_points = [self, *models].map do |model|
if model.instance_variable_defined?(:@switch_point_name)
SwitchPoint.config.model_name(
model.instance_variable_get(:@switch_point_name),
:writable
)
else
nil
end
end

writable_switch_points.uniq.size == 1
end
end
end
end
13 changes: 13 additions & 0 deletions spec/models.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
config.define_switch_point :main,
readonly: :main_readonly,
writable: :main_writable
config.define_switch_point :main2,
readonly: :main2_readonly,
writable: :main2_writable
config.define_switch_point :user,
readonly: :user,
writable: :user
Expand Down Expand Up @@ -31,6 +34,14 @@ def do_after_save
end
end

class Book2 < ActiveRecord::Base
use_switch_point :main
end

class Book3 < ActiveRecord::Base
use_switch_point :main2
end

class Publisher < ActiveRecord::Base
use_switch_point :main
end
Expand Down Expand Up @@ -66,6 +77,8 @@ class Nanika3 < ActiveRecord::Base
ActiveRecord::Base.configurations = {
'main_readonly' => base.merge(database: 'main_readonly.sqlite3'),
'main_writable' => base.merge(database: 'main_writable.sqlite3'),
'main2_readonly' => base.merge(database: 'main2_readonly.sqlite3'),
'main2_writable' => base.merge(database: 'main2_writable.sqlite3'),
'main_readonly_special' => base.merge(database: 'main_readonly_special.sqlite3'),
'user' => base.merge(database: 'user.sqlite3'),
'comment_readonly' => base.merge(database: 'comment_readonly.sqlite3'),
Expand Down
11 changes: 11 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,19 @@
Book.with_writable do
Book.connection.execute('CREATE TABLE books (id integer primary key autoincrement)')
end

Book2.with_writable do
Book2.connection.execute('CREATE TABLE book2s (id integer primary key autoincrement)')
end

FileUtils.cp('main_writable.sqlite3', 'main_readonly.sqlite3')

Book3.with_writable do
Book3.connection.execute('CREATE TABLE book3s (id integer primary key autoincrement)')
end

FileUtils.cp('main2_writable.sqlite3', 'main2_readonly.sqlite3')

Note.connection.execute('CREATE TABLE notes (id integer primary key autoincrement)')

Nanika3.connection.execute('CREATE TABLE nanika3s (id integer primary key)')
Expand Down
108 changes: 108 additions & 0 deletions spec/switch_point/model_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -261,4 +261,112 @@
end
end
end

describe '.transaction_with' do
context "when each model has a same writable" do
before do
@before_book_count = Book.count
@before_book2_count = Book2.count

Book.transaction_with(Book2) do
new_book = Book.create
new_book2 = Book2.create
end

@after_book_count = Book.with_writable do
Book.count
end
@after_book2_count = Book2.with_writable do
Book2.count
end
end

it 'should create a new record' do
expect(
Book.with_writable do
Book.count
end
).to be > @before_book_count

expect(
Book2.with_writable do
Book2.count
end
).to be > @before_book2_count
end
end

context "when each model has a other writable" do
it {
expect {
Book.transaction_with(Book3) do
new_book = Book.create
new_book3 = Book3.create
end
}.to raise_error RuntimeError
}
end

context "when raise exception in transaction that include some model, and models each have other writable" do
before do
@before_book_count = Book.count
@before_book3_count = Book3.count

Book.transaction_with(Book2) do
new_book = Book.create
new_book3 = Book3.with_writable do
Book3.create
end
raise ActiveRecord::Rollback
end
end

it 'Book should not create a new record (rollbacked)' do
expect(
Book.with_writable do
Book.count
end
).to eq @before_book_count
end

it 'Book3 should create a new record (not rollbacked)' do
expect(
Book3.with_writable do
Book3.count
end
).to be > @before_book3_count
end
end

context "when nested transaction_with then parent transaction rollbacked" do
before do
@before_book_count = Book.count
@before_book3_count = Book3.count

Book.transaction_with do
Book.create

Book3.transaction_with do
Book3.create
end

raise ActiveRecord::Rollback
end

it {
expect(
Book.with_writable do
Book.count
end
).to be = @before_book_count

expect(
Book3.with_writable do
Book3.count
end
).to be > @before_book3_count
}
end
end
end
end