Navigation Menu

Skip to content

Commit

Permalink
Cleanup Transaction inheritance.
Browse files Browse the repository at this point in the history
Transaction class doesnt need to encapsulate the transaction state using
inheritance.
This removes all Transaction subclasses, and let the Transaction object
controls different actions based on its own state. Basically the only
actions would behave differently are `being`,`commit`,`rollback` as they
could act in a savepoint or in a real transaction.
  • Loading branch information
arthurnn committed Aug 5, 2014
1 parent c8317cd commit 8298d3a
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 72 deletions.
Expand Up @@ -30,49 +30,24 @@ def set_state(state)
end
end

class Transaction #:nodoc:
attr_reader :connection, :state

def initialize(connection)
@connection = connection
@state = TransactionState.new
end

def savepoint_name
nil
end
end

class NullTransaction < Transaction #:nodoc:
class NullTransaction #:nodoc:
def initialize; end
def closed?; true; end
def open?; false; end
def joinable?; false; end
# This is a noop when there are no open transactions
def add_record(record); end
end

class OpenTransaction < Transaction #:nodoc:
attr_reader :records
attr_writer :joinable

def initialize(connection, options = {})
super connection

@records = []
@joinable = options.fetch(:joinable, true)
end

def joinable?
@joinable
end
class Transaction #:nodoc:

def rollback
perform_rollback
end
attr_reader :connection, :state, :records, :savepoint_name
attr_writer :joinable

def commit
perform_commit
def initialize(connection, options)
@connection = connection
@state = TransactionState.new
@records = []
@joinable = options.fetch(:joinable, true)
end

def add_record(record)
Expand All @@ -83,19 +58,25 @@ def add_record(record)
end
end

def rollback_records
def rollback
@state.set_state(:rolledback)
end

def rollback_records
records.uniq.each do |record|
begin
record.rolledback!(self.is_a?(RealTransaction))
record.rolledback! full_rollback?
rescue => e
record.logger.error(e) if record.respond_to?(:logger) && record.logger
end
end
end

def commit_records
def commit
@state.set_state(:committed)
end

def commit_records
records.uniq.each do |record|
begin
record.committed!
Expand All @@ -105,57 +86,57 @@ def commit_records
end
end

def closed?
false
end

def open?
true
end
def full_rollback?; true; end
def joinable?; @joinable; end
def closed?; false; end
def open?; !closed?; end
end

class RealTransaction < OpenTransaction #:nodoc:
def initialize(connection, _, options = {})
super(connection, options)
class SavepointTransaction < Transaction

def initialize(connection, savepoint_name, options)
super(connection, options)
if options[:isolation]
connection.begin_isolated_db_transaction(options[:isolation])
else
connection.begin_db_transaction
raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
end
connection.create_savepoint(@savepoint_name = savepoint_name)
end

def perform_rollback
connection.rollback_db_transaction
def rollback
super
connection.rollback_to_savepoint(savepoint_name)
rollback_records
end

def perform_commit
connection.commit_db_transaction
commit_records
def commit
super
connection.release_savepoint(savepoint_name)
end

def full_rollback?; false; end
end

class SavepointTransaction < OpenTransaction #:nodoc:
attr_reader :savepoint_name
class RealTransaction < Transaction

def initialize(connection, savepoint_name, options = {})
def initialize(connection, options)
super
if options[:isolation]
raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
connection.begin_isolated_db_transaction(options[:isolation])
else
connection.begin_db_transaction
end

super(connection, options)
connection.create_savepoint(@savepoint_name = savepoint_name)
end

def perform_rollback
connection.rollback_to_savepoint(savepoint_name)
def rollback
super
connection.rollback_db_transaction
rollback_records
end

def perform_commit
@state.set_state(:committed)
connection.release_savepoint(savepoint_name)
def commit
super
connection.commit_db_transaction
commit_records
end
end

Expand All @@ -166,9 +147,12 @@ def initialize(connection)
end

def begin_transaction(options = {})
transaction_class = @stack.empty? ? RealTransaction : SavepointTransaction
transaction = transaction_class.new(@connection, "active_record_#{@stack.size}", options)

transaction =
if @stack.empty?
RealTransaction.new(@connection, options)
else
SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options)
end
@stack.push(transaction)
transaction
end
Expand Down
4 changes: 2 additions & 2 deletions activerecord/test/cases/transactions_test.rb
Expand Up @@ -552,7 +552,7 @@ def test_transactions_state_from_rollback
assert !transaction.state.rolledback?
assert !transaction.state.committed?

transaction.perform_rollback
transaction.rollback

assert transaction.state.rolledback?
assert !transaction.state.committed?
Expand All @@ -566,7 +566,7 @@ def test_transactions_state_from_commit
assert !transaction.state.rolledback?
assert !transaction.state.committed?

transaction.perform_commit
transaction.commit

assert !transaction.state.rolledback?
assert transaction.state.committed?
Expand Down

0 comments on commit 8298d3a

Please sign in to comment.