transaction_isolation_level 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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