transaction_isolation_level 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ transaction-isolation-level-*.gem
3
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Declare your gem's dependencies in transaction_isolation_level.gemspec.
4
+ # Bundler will treat runtime dependencies like base dependencies, and
5
+ # development dependencies will be added by default to the :development group.
6
+ gemspec
7
+
8
+ # Declare any dependencies that are still in development here instead of in
9
+ # your gemspec. These might include edge Rails or gems from your path or
10
+ # Git. Remember to move these dependencies to your gemspec before releasing
11
+ # your gem to rubygems.org.
12
+
13
+ # To use debugger
14
+ # gem 'ruby-debug19', :require => 'ruby-debug'
15
+ # gem 'ruby-debug'
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Will Bryant, Sekuda Ltd
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake'
5
+ require 'rake/testtask'
6
+
7
+ desc 'Default: run unit tests.'
8
+ task :default => :test
9
+
10
+ desc 'Test the transaction_isolation_level plugin.'
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << 'lib'
13
+ t.libs << 'test'
14
+ t.pattern = 'test/*_test.rb'
15
+ t.verbose = true
16
+ end
@@ -0,0 +1,24 @@
1
+ require 'active_record'
2
+ require 'active_record/connection_adapters/abstract/connection_pool'
3
+
4
+ module ActiveRecord
5
+ class IncompatibleTransactionIsolationLevel < StandardError; end
6
+
7
+ module ConnectionAdapters
8
+ class ConnectionHandler
9
+ # ActiveRecord only loads the adapters actually used for connections, so we can't patch their
10
+ # classes until we know which one will be loaded. however, the adapter classes are not statically
11
+ # required; they are only loaded when ActiveRecord::Base#establish_connection retrieves them from
12
+ # the connection spec. that has several code paths to handle different arguments but eventually
13
+ # uses the ConnectionHandler#establish_connection method we override here to load our patches once
14
+ # ActiveRecord::Base#establish_connection has loaded the class to patch.
15
+ def establish_connection_with_isolation_level_adapter_patches(*args)
16
+ require 'transaction_isolation_level/adapter_patches'
17
+ establish_connection_without_isolation_level_adapter_patches(*args)
18
+ end
19
+
20
+ alias_method :establish_connection_without_isolation_level_adapter_patches, :establish_connection
21
+ alias_method :establish_connection, :establish_connection_with_isolation_level_adapter_patches
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,113 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module DatabaseStatements
4
+ ORDER_OF_TRANSACTION_ISOLATION_LEVELS = [:read_uncommitted, :read_committed, :repeatable_read, :serializable]
5
+
6
+ def transaction_isolation_level_sql(value)
7
+ case value
8
+ when :read_uncommitted then 'ISOLATION LEVEL READ UNCOMMITTED'
9
+ when :read_committed then 'ISOLATION LEVEL READ COMMITTED'
10
+ when :repeatable_read then 'ISOLATION LEVEL REPEATABLE READ'
11
+ when :serializable then 'ISOLATION LEVEL SERIALIZABLE'
12
+ when nil then nil
13
+ else raise "Unknown transaction isolation level: #{value.inspect}"
14
+ end
15
+ end
16
+
17
+ def transaction_isolation_level_from_sql(value)
18
+ case value.gsub('-', ' ').upcase
19
+ when 'READ UNCOMMITTED' then :read_uncommitted
20
+ when 'READ COMMITTED' then :read_committed
21
+ when 'REPEATABLE READ' then :repeatable_read
22
+ when 'SERIALIZABLE' then :serializable
23
+ else raise "Unknown transaction isolation level: #{value.inspect}"
24
+ end
25
+ end
26
+
27
+ def transaction_with_isolation_level(options = {})
28
+ isolation_level = options.delete(:isolation_level)
29
+ minimum_isolation_level = options.delete(:minimum_isolation_level)
30
+
31
+ raise ArgumentError, "#{isolation_level.inspect} is not a known transaction isolation level" unless isolation_level.nil? || ORDER_OF_TRANSACTION_ISOLATION_LEVELS.include?(isolation_level)
32
+ raise ArgumentError, "#{minimum_isolation_level.inspect} is not a known transaction isolation level" unless minimum_isolation_level.nil? || ORDER_OF_TRANSACTION_ISOLATION_LEVELS.include?(minimum_isolation_level)
33
+
34
+ if open_transactions == 0
35
+ @transaction_isolation_level = isolation_level || minimum_isolation_level
36
+ elsif isolation_level && isolation_level != (@transaction_isolation_level || default_transaction_isolation_level)
37
+ raise IncompatibleTransactionIsolationLevel, "Asked to use transaction isolation level #{isolation_level}, but the transaction has already begun with isolation level #{@transaction_isolation_level || default_transaction_isolation_level}"
38
+ end
39
+ if minimum_isolation_level && ORDER_OF_TRANSACTION_ISOLATION_LEVELS.index(minimum_isolation_level) > ORDER_OF_TRANSACTION_ISOLATION_LEVELS.index(@transaction_isolation_level || default_transaction_isolation_level)
40
+ raise IncompatibleTransactionIsolationLevel, "Asked to use transaction isolation level at least #{minimum_isolation_level}, but the transaction has already begun with isolation level #{@transaction_isolation_level || default_transaction_isolation_level}"
41
+ end
42
+
43
+ transaction_without_isolation_level(options) { yield }
44
+ end
45
+
46
+ alias_method_chain :transaction, :isolation_level
47
+ end
48
+
49
+ class AbstractAdapter
50
+ attr_reader :default_transaction_isolation_level, :transaction_isolation_level
51
+
52
+ def commit_db_transaction #:nodoc:
53
+ super
54
+ ensure
55
+ @transaction_isolation_level = nil
56
+ end
57
+
58
+ def rollback_db_transaction #:nodoc:
59
+ super
60
+ ensure
61
+ @transaction_isolation_level = nil
62
+ end
63
+ end
64
+
65
+ PostgreSQLAdapter.class_eval do
66
+ def begin_db_transaction
67
+ execute "BEGIN TRANSACTION #{transaction_isolation_level_sql(@transaction_isolation_level)}"
68
+ end
69
+
70
+ def configure_connection_with_isolation_level
71
+ configure_connection_without_isolation_level
72
+ if @config[:transaction_isolation_level]
73
+ @default_transaction_isolation_level = @config[:transaction_isolation_level].to_sym
74
+ execute "SET SESSION CHARACTERISTICS AS TRANSACTION #{transaction_isolation_level_sql default_transaction_isolation_level}"
75
+ else
76
+ @default_transaction_isolation_level = transaction_isolation_level_from_sql(select_value("SELECT current_setting('default_transaction_isolation')"))
77
+ end
78
+ end
79
+
80
+ alias_method_chain :configure_connection, :isolation_level
81
+ end if const_defined?(:PostgreSQLAdapter)
82
+
83
+ module MysqlAdapterPatches
84
+ def self.included(base)
85
+ base.alias_method_chain :begin_db_transaction, :isolation_level
86
+ base.alias_method_chain :configure_connection, :isolation_level
87
+ end
88
+
89
+ def begin_db_transaction_with_isolation_level
90
+ execute "SET TRANSACTION #{transaction_isolation_level_sql(@transaction_isolation_level)}" if @transaction_isolation_level # applies only to the next transaction
91
+ begin_db_transaction_without_isolation_level
92
+ end
93
+
94
+ def configure_connection_with_isolation_level
95
+ configure_connection_without_isolation_level
96
+ if @config[:transaction_isolation_level]
97
+ @default_transaction_isolation_level = @config[:transaction_isolation_level].to_sym
98
+ execute "SET SESSION TRANSACTION #{transaction_isolation_level_sql default_transaction_isolation_level}"
99
+ else
100
+ @default_transaction_isolation_level = transaction_isolation_level_from_sql(select_value("SELECT @@session.tx_isolation"))
101
+ end
102
+ end
103
+ end
104
+
105
+ MysqlAdapter.class_eval do
106
+ include MysqlAdapterPatches
107
+ end if const_defined?(:MysqlAdapter)
108
+
109
+ Mysql2Adapter.class_eval do
110
+ include MysqlAdapterPatches
111
+ end if const_defined?(:Mysql2Adapter)
112
+ end
113
+ end
@@ -0,0 +1,3 @@
1
+ module TransactionIsolationLevel
2
+ VERSION = '0.1.0'
3
+ end
data/test/database.yml ADDED
@@ -0,0 +1,11 @@
1
+ postgresql:
2
+ adapter: postgresql
3
+ database: transaction_isolation_level_test
4
+ postgresql_set_to_serializable:
5
+ adapter: postgresql
6
+ database: transaction_isolation_level_test
7
+ transaction_isolation_level: serializable
8
+ postgresql_set_to_read_committed:
9
+ adapter: postgresql
10
+ database: transaction_isolation_level_test
11
+ transaction_isolation_level: read_committed
@@ -0,0 +1,9 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ Bundler.require(:default, :development)
5
+
6
+ RAILS_ENV = ENV['RAILS_ENV'] || 'postgresql'
7
+
8
+ database_config = YAML::load(IO.read(File.join(File.dirname(__FILE__), '/database.yml')))
9
+ ActiveRecord::Base.establish_connection(database_config[RAILS_ENV])
@@ -0,0 +1,186 @@
1
+ require 'test_helper'
2
+
3
+ class TransactionIsolationLevelTest < ActiveSupport::TestCase
4
+ def current_isolation_level(connection = ActiveRecord::Base.connection)
5
+ # we can't implement this for mysql as it does not expose the value set for the transaction (as opposed to the session) -
6
+ # see http://bugs.mysql.com/bug.php?id=53341. so currently we can only run tests on postgresql.
7
+ connection.transaction_isolation_level_from_sql(connection.select_value("SELECT current_setting('transaction_isolation')"))
8
+ end
9
+
10
+ test "it does nothing to queries by default" do
11
+ default_level = current_isolation_level
12
+ ActiveRecord::Base.transaction do
13
+ assert_equal default_level, current_isolation_level
14
+ end
15
+ end
16
+
17
+ test "it allows the isolation level to be set for the transaction, and it is reset after the transaction" do
18
+ default_level = current_isolation_level
19
+ ActiveRecord::Base.transaction(:isolation_level => :read_uncommitted) do
20
+ assert_equal :read_uncommitted, current_isolation_level
21
+ end
22
+ assert_equal default_level, current_isolation_level
23
+ ActiveRecord::Base.transaction(:isolation_level => :read_committed) do
24
+ assert_equal :read_committed, current_isolation_level
25
+ end
26
+ assert_equal default_level, current_isolation_level
27
+ ActiveRecord::Base.transaction(:isolation_level => :repeatable_read) do
28
+ assert_equal :repeatable_read, current_isolation_level
29
+ end
30
+ assert_equal default_level, current_isolation_level
31
+ ActiveRecord::Base.transaction(:isolation_level => :serializable) do
32
+ assert_equal :serializable, current_isolation_level
33
+ end
34
+ assert_equal default_level, current_isolation_level
35
+ end
36
+
37
+ test "raises an error if the requested transaction isolation level is not known" do
38
+ assert_raises(ArgumentError) do
39
+ ActiveRecord::Base.transaction(:isolation_level => :serialisable) {}
40
+ end
41
+ assert_raises(ArgumentError) do
42
+ ActiveRecord::Base.transaction(:minimum_isolation_level => :serialisable) {}
43
+ end
44
+ end
45
+
46
+ test "raises an error if a transaction is already open and the requested transaction isolation level is different to the current level" do
47
+ ActiveRecord::Base.transaction(:isolation_level => :repeatable_read) do
48
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
49
+ ActiveRecord::Base.transaction(:isolation_level => :read_uncommitted) {}
50
+ end
51
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
52
+ ActiveRecord::Base.transaction(:isolation_level => :read_committed) {}
53
+ end
54
+ assert_nothing_raised do
55
+ ActiveRecord::Base.transaction(:isolation_level => :repeatable_read) {}
56
+ end
57
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
58
+ ActiveRecord::Base.transaction(:isolation_level => :serializable) {}
59
+ end
60
+ end
61
+
62
+ ActiveRecord::Base.transaction(:isolation_level => :read_committed) do
63
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
64
+ ActiveRecord::Base.transaction(:isolation_level => :read_uncommitted) {}
65
+ end
66
+ assert_nothing_raised do
67
+ ActiveRecord::Base.transaction(:isolation_level => :read_committed) {}
68
+ end
69
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
70
+ ActiveRecord::Base.transaction(:isolation_level => :repeatable_read) {}
71
+ end
72
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
73
+ ActiveRecord::Base.transaction(:isolation_level => :serializable) {}
74
+ end
75
+ end
76
+
77
+ default = current_isolation_level
78
+ ActiveRecord::Base.transaction do
79
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
80
+ ActiveRecord::Base.transaction(:isolation_level => ([:read_committed, :repeatable_read] - [default]).first) {}
81
+ end
82
+ assert_nothing_raised do
83
+ ActiveRecord::Base.transaction(:isolation_level => current_isolation_level) {}
84
+ end
85
+ end
86
+ end
87
+
88
+ test "supports requesting a minimum transaction isolation level, in which case an error is raised only if requested transaction isolation level is higher than the actual transaction isolation" do
89
+ ActiveRecord::Base.transaction(:isolation_level => :repeatable_read) do
90
+ assert_nothing_raised do
91
+ ActiveRecord::Base.transaction(:minimum_isolation_level => :read_uncommitted) {}
92
+ ActiveRecord::Base.transaction(:minimum_isolation_level => :read_committed) {}
93
+ ActiveRecord::Base.transaction(:minimum_isolation_level => :repeatable_read) {}
94
+ end
95
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
96
+ ActiveRecord::Base.transaction(:minimum_isolation_level => :serializable) {}
97
+ end
98
+ end
99
+
100
+ ActiveRecord::Base.transaction(:isolation_level => :read_committed) do
101
+ assert_nothing_raised do
102
+ ActiveRecord::Base.transaction(:minimum_isolation_level => :read_uncommitted) {}
103
+ ActiveRecord::Base.transaction(:minimum_isolation_level => :read_committed) {}
104
+ end
105
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
106
+ ActiveRecord::Base.transaction(:minimum_isolation_level => :repeatable_read) {}
107
+ ActiveRecord::Base.transaction(:minimum_isolation_level => :serializable) {}
108
+ end
109
+ end
110
+ end
111
+
112
+ class ModelWithConnectionForSerializable < ActiveRecord::Base
113
+ abstract_class
114
+ end
115
+
116
+ class ModelWithConnectionForReadCommitted < ActiveRecord::Base
117
+ abstract_class
118
+ end
119
+
120
+ test "it supports setting the transaction_isolation in database.yml" do
121
+ database_config = YAML::load(IO.read(File.join(File.dirname(__FILE__), '/database.yml')))
122
+
123
+ ModelWithConnectionForSerializable.establish_connection(database_config["#{RAILS_ENV}_set_to_serializable"])
124
+ assert_equal :serializable, current_isolation_level(ModelWithConnectionForSerializable.connection)
125
+
126
+ ModelWithConnectionForReadCommitted.establish_connection(database_config["#{RAILS_ENV}_set_to_read_committed"])
127
+ assert_equal :read_committed, current_isolation_level(ModelWithConnectionForReadCommitted.connection)
128
+
129
+ ModelWithConnectionForSerializable.transaction do # will use default isolation level
130
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
131
+ ModelWithConnectionForSerializable.transaction(:isolation_level => :read_uncommitted) {}
132
+ end
133
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
134
+ ModelWithConnectionForSerializable.transaction(:isolation_level => :read_committed) {}
135
+ end
136
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
137
+ ModelWithConnectionForSerializable.transaction(:isolation_level => :repeatable_read) {}
138
+ end
139
+ assert_nothing_raised do
140
+ ModelWithConnectionForSerializable.transaction(:isolation_level => :serializable) {}
141
+ assert_equal :serializable, current_isolation_level(ModelWithConnectionForSerializable.connection)
142
+ end
143
+ end
144
+
145
+ ModelWithConnectionForReadCommitted.transaction do
146
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
147
+ ModelWithConnectionForReadCommitted.transaction(:isolation_level => :read_uncommitted) {}
148
+ end
149
+ assert_nothing_raised do
150
+ ModelWithConnectionForReadCommitted.transaction(:isolation_level => :read_committed) {}
151
+ assert_equal :read_committed, current_isolation_level(ModelWithConnectionForReadCommitted.connection)
152
+ end
153
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
154
+ ModelWithConnectionForReadCommitted.transaction(:isolation_level => :repeatable_read) {}
155
+ end
156
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
157
+ ModelWithConnectionForReadCommitted.transaction(:isolation_level => :serializable) {}
158
+ end
159
+ end
160
+
161
+ ModelWithConnectionForSerializable.transaction(:isolation_level => :read_committed) do
162
+ assert_equal :read_committed, current_isolation_level(ModelWithConnectionForSerializable.connection)
163
+ assert_nothing_raised do
164
+ ModelWithConnectionForSerializable.transaction(:isolation_level => :read_committed) {}
165
+ end
166
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
167
+ ModelWithConnectionForSerializable.transaction(:isolation_level => :repeatable_read) {}
168
+ end
169
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
170
+ ModelWithConnectionForSerializable.transaction(:isolation_level => :serializable) {}
171
+ end
172
+ end
173
+ ModelWithConnectionForReadCommitted.transaction(:isolation_level => :repeatable_read) do
174
+ assert_equal :repeatable_read, current_isolation_level(ModelWithConnectionForReadCommitted.connection)
175
+ assert_nothing_raised do
176
+ ModelWithConnectionForReadCommitted.transaction(:isolation_level => :repeatable_read) {}
177
+ end
178
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
179
+ ModelWithConnectionForReadCommitted.transaction(:isolation_level => :read_committed) {}
180
+ end
181
+ assert_raises(ActiveRecord::IncompatibleTransactionIsolationLevel) do
182
+ ModelWithConnectionForReadCommitted.transaction(:isolation_level => :serializable) {}
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/transaction_isolation_level/version', __FILE__)
3
+
4
+ spec = Gem::Specification.new do |gem|
5
+ gem.name = 'transaction_isolation_level'
6
+ gem.version = TransactionIsolationLevel::VERSION
7
+ gem.summary = "Adds :isolation_level option to ActiveRecord #transaction calls"
8
+ gem.description = "Adds :isolation_level option to ActiveRecord #transaction calls, as well as :minimum_isolation_level. Supports mysql and postgresql."
9
+ gem.has_rdoc = false
10
+ gem.author = "Will Bryant"
11
+ gem.email = "will.bryant@gmail.com"
12
+ gem.homepage = "http://github.com/willbryant/transaction_isolation_level"
13
+
14
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
+ gem.files = `git ls-files`.split("\n")
16
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ gem.require_path = "lib"
18
+
19
+ gem.add_dependency "activerecord"
20
+ gem.add_development_dependency "rake"
21
+ gem.add_development_dependency "pg"
22
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: transaction_isolation_level
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Will Bryant
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-02-26 00:00:00 +13:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activerecord
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rake
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: pg
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :development
62
+ version_requirements: *id003
63
+ description: "Adds :isolation_level option to ActiveRecord #transaction calls, as well as :minimum_isolation_level. Supports mysql and postgresql."
64
+ email: will.bryant@gmail.com
65
+ executables: []
66
+
67
+ extensions: []
68
+
69
+ extra_rdoc_files: []
70
+
71
+ files:
72
+ - .gitignore
73
+ - Gemfile
74
+ - MIT-LICENSE
75
+ - Rakefile
76
+ - lib/transaction_isolation_level.rb
77
+ - lib/transaction_isolation_level/adapter_patches.rb
78
+ - lib/transaction_isolation_level/version.rb
79
+ - test/database.yml
80
+ - test/test_helper.rb
81
+ - test/transaction_isolation_level_test.rb
82
+ - transaction_isolation_level.gemspec
83
+ has_rdoc: false
84
+ homepage: http://github.com/willbryant/transaction_isolation_level
85
+ licenses: []
86
+
87
+ post_install_message:
88
+ rdoc_options: []
89
+
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ hash: 3
98
+ segments:
99
+ - 0
100
+ version: "0"
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ hash: 3
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ requirements: []
111
+
112
+ rubyforge_project:
113
+ rubygems_version: 1.5.3
114
+ signing_key:
115
+ specification_version: 3
116
+ summary: "Adds :isolation_level option to ActiveRecord #transaction calls"
117
+ test_files:
118
+ - test/database.yml
119
+ - test/test_helper.rb
120
+ - test/transaction_isolation_level_test.rb