Class: DataMapper::Transaction

Inherits:
Object
  • Object
show all
Extended by:
Chainable
Defined in:
lib/dm-transactions.rb,
lib/dm-transactions/adapters/dm-do-adapter.rb,
lib/dm-transactions/adapters/dm-mysql-adapter.rb,
lib/dm-transactions/adapters/dm-oracle-adapter.rb,
lib/dm-transactions/adapters/dm-sqlite-adapter.rb,
lib/dm-transactions/adapters/dm-postgres-adapter.rb,
lib/dm-transactions/adapters/dm-sqlserver-adapter.rb

Defined Under Namespace

Modules: DataObjectsAdapter, Model, MysqlAdapter, OracleAdapter, PostgresAdapter, Repository, Resource, SqliteAdapter, SqlserverAdapter

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*things) ⇒ Transaction

Create a new Transaction

In fact, it just calls #link with the given arguments at the end of the constructor.

See Also:



38
39
40
41
42
43
44
45
46
47
# File 'lib/dm-transactions.rb', line 38

def initialize(*things)
  @transaction_primitives = {}
  self.state = :none
  @adapters = {}
  link(*things)
  if block_given?
    warn "Passing block to #{self.class.name}.new is deprecated (#{caller[0]})"
    commit { |*block_args| yield(*block_args) }
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/dm-transactions.rb', line 204

def method_missing(method, *args, &block)
  first_arg = args.first

  return super unless args.size == 1 && first_arg.kind_of?(Adapters::AbstractAdapter)
  return super unless match = method.to_s.match(/\A(.*)_(if|unless)_(none|begin|rollback|commit)\z/)

  action, condition, expected_state = match.captures
  return super unless respond_to?(action, true)

  state   = state_for(first_arg).to_s
  execute = (condition == 'if') == (state == expected_state)

  send(action, first_arg) if execute
end

Instance Attribute Details

#stateObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



8
9
10
# File 'lib/dm-transactions.rb', line 8

def state
  @state
end

Instance Method Details

#beginObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Begin the transaction

Before #begin is called, the transaction is not valid and can not be used.



103
104
105
106
107
108
109
110
111
# File 'lib/dm-transactions.rb', line 103

def begin
  unless none?
    raise "Illegal state for begin: #{state}"
  end

  each_adapter(:connect_adapter, [:log_fatal_transaction_breakage])
  each_adapter(:begin_adapter, [:rollback_and_close_adapter_if_begin, :close_adapter_if_none])
  self.state = :begin
end

#begin?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


16
17
18
# File 'lib/dm-transactions.rb', line 16

def begin?
  state == :begin
end

#commitObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Commit the transaction

If no block is given, it will simply commit any changes made since the
Transaction did #begin.

Parameters:

  • block (Block)

    a block (taking the one argument, the Transaction) to execute within this transaction. The transaction will begin and commit around the block, and roll back if an exception is raised.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/dm-transactions.rb', line 123

def commit
  if block_given?
    unless none?
      raise "Illegal state for commit with block: #{state}"
    end

    begin
      self.begin
      rval = within { |*block_args| yield(*block_args) }
    rescue Exception => exception
      if begin?
        rollback
      end
      raise exception
    ensure
      unless exception
        if begin?
          commit
        end
        return rval
      end
    end
  else
    unless begin?
      raise "Illegal state for commit without block: #{state}"
    end
    each_adapter(:commit_adapter, [:log_fatal_transaction_breakage])
    each_adapter(:close_adapter, [:log_fatal_transaction_breakage])
    self.state = :commit
  end
end

#commit?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


26
27
28
# File 'lib/dm-transactions.rb', line 26

def commit?
  state == :commit
end

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Associate this Transaction with some things.

Parameters:

  • things (Object)

    the things you want this Transaction associated with:

    Adapters::AbstractAdapter subclasses will be added as

    adapters as is.
    

    Arrays will have their elements added. Repository will have it’s own @adapters added. Resource subclasses will have all the repositories of all

    their properties added.
    

    Resource instances will have all repositories of all their

    properties added.
    
  • block (Proc)

    a block (taking one argument, the Transaction) to execute within this transaction. The transaction will begin and commit around the block, and rollback if an exception is raised.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/dm-transactions.rb', line 69

def link(*things)
  unless none?
    raise "Illegal state for link: #{state}"
  end

  things.each do |thing|
    case thing
      when DataMapper::Adapters::AbstractAdapter
        @adapters[thing] = :none
      when DataMapper::Repository
        link(thing.adapter)
      when DataMapper::Model
        link(*thing.repositories)
      when DataMapper::Resource
        link(thing.model)
      when Array
        link(*thing)
      else
        raise "Unknown argument to #{self.class}#link: #{thing.inspect} (#{thing.class})"
    end
  end

  if block_given?
    commit { |*block_args| yield(*block_args) }
  else
    self
  end
end

#none?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


11
12
13
# File 'lib/dm-transactions.rb', line 11

def none?
  state == :none
end

#primitive_for(adapter) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



220
221
222
223
224
225
226
227
228
229
230
# File 'lib/dm-transactions.rb', line 220

def primitive_for(adapter)
  unless @adapters.include?(adapter)
    raise "Unknown adapter #{adapter}"
  end

  unless @transaction_primitives.include?(adapter)
    raise "No primitive for #{adapter}"
  end

  @transaction_primitives[adapter]
end

#rollbackObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Rollback the transaction

Will undo all changes made during the transaction.



160
161
162
163
164
165
166
167
# File 'lib/dm-transactions.rb', line 160

def rollback
  unless begin?
    raise "Illegal state for rollback: #{state}"
  end
  each_adapter(:rollback_adapter_if_begin, [:rollback_and_close_adapter_if_begin, :close_adapter_if_none])
  each_adapter(:close_adapter_if_open, [:log_fatal_transaction_breakage])
  self.state = :rollback
end

#rollback?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


21
22
23
# File 'lib/dm-transactions.rb', line 21

def rollback?
  state == :rollback
end

#withinObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Execute a block within this Transaction.

No #begin, #commit or #rollback is performed in #within, but this Transaction will pushed on the per thread stack of transactions for each adapter it is associated with, and it will ensures that it will pop the Transaction away again after the block is finished.

Parameters:

  • block (Block)

    the block of code to execute.



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/dm-transactions.rb', line 179

def within
  unless block_given?
    raise 'No block provided'
  end

  unless begin?
    raise "Illegal state for within: #{state}"
  end

  adapters = @adapters

  adapters.each_key do |adapter|
    adapter.push_transaction(self)
  end

  begin
    yield self
  ensure
    adapters.each_key do |adapter|
      adapter.pop_transaction
    end
  end
end