transaction_isolation_continued 1.0.5 → 1.1.1
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.
- checksums.yaml +4 -4
- data/.dockerignore +1 -0
- data/.github/workflows/main.yml +35 -20
- data/.github/workflows/rubygem.yml +28 -0
- data/.gitignore +3 -0
- data/{Gemfile.local → Gemfile.old.local} +9 -0
- data/README.md +77 -56
- data/docker/ruby-2.5/Dockerfile +6 -0
- data/docker/ruby-2.7/Dockerfile +6 -0
- data/docker/ruby-3.0/Dockerfile +6 -0
- data/docker/ruby-3.1/Dockerfile +6 -0
- data/docker/test-ruby-2.5.sh +26 -0
- data/docker/test-ruby-2.7.sh +29 -0
- data/docker/test-ruby-3.0.sh +26 -0
- data/docker/test-ruby-3.1.sh +26 -0
- data/docker/test-ruby.sh +8 -0
- data/docker-compose.yml +60 -0
- data/gemfiles/Gemfile.base +4 -0
- data/gemfiles/activerecord-5.2/Gemfile.sqlite3 +1 -1
- data/gemfiles/activerecord-6.0/Gemfile.sqlite3 +1 -1
- data/gemfiles/activerecord-6.1/Gemfile.sqlite3 +1 -1
- data/gemfiles/activerecord-7.0/Gemfile.sqlite3 +1 -1
- data/lib/transaction_isolation/active_record/base.rb +5 -3
- data/lib/transaction_isolation/active_record/connection_adapters/abstract_adapter.rb +10 -9
- data/lib/transaction_isolation/active_record/connection_adapters/mysql2_adapter.rb +29 -27
- data/lib/transaction_isolation/active_record/connection_adapters/postgresql_adapter.rb +26 -24
- data/lib/transaction_isolation/active_record/connection_adapters/sqlite3_adapter.rb +24 -21
- data/lib/transaction_isolation/active_record/errors.rb +2 -0
- data/lib/transaction_isolation/configuration.rb +6 -4
- data/lib/transaction_isolation/version.rb +3 -1
- data/lib/transaction_isolation.rb +16 -11
- data/lib/transaction_isolation_continued.rb +1 -0
- data/spec/gem_template_spec.rb +11 -0
- data/spec/spec_helper.rb +15 -0
- data/test/db/all.rb +2 -0
- data/test/db/db.rb +15 -15
- data/test/db/migrations.rb +6 -7
- data/test/db/queued_job.rb +2 -0
- data/test/integration/active_record/base/isolation_level_test.rb +3 -9
- data/test/integration/active_record/connection_adapters/any_adapter/current_isolation_level_test.rb +8 -16
- data/test/integration/active_record/connection_adapters/any_adapter/current_vendor_isolation_level_test.rb +8 -16
- data/test/integration/active_record/connection_adapters/any_adapter/isolation_level_test.rb +18 -29
- data/test/integration/active_record/connection_adapters/any_adapter/supports_isolation_levels_test.rb +2 -10
- data/test/integration/active_record/connection_adapters/any_adapter/translate_exception_test.rb +20 -26
- data/test/library_setup.rb +11 -9
- data/test/test_helper.rb +9 -6
- data/test/test_runner.rb +3 -2
- data/transaction_isolation_continued.gemspec +15 -15
- metadata +33 -20
- data/d +0 -1
- data/test/test_console.rb +0 -11
@@ -1,69 +1,58 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'test_helper'
|
4
4
|
|
5
5
|
class ActiveRecordTest < Minitest::Test
|
6
|
-
|
7
6
|
class ConnectionAdaptersTest < Minitest::Test
|
8
|
-
|
9
7
|
class AnyAdapterTest < Minitest::Test
|
10
|
-
|
11
8
|
class IsolationLevelTest < Minitest::Test
|
12
|
-
|
13
9
|
def test_without_a_block
|
14
10
|
original_isolation_level = ActiveRecord::Base.connection.current_isolation_level
|
15
11
|
|
16
|
-
ActiveRecord::Base.connection.isolation_level(
|
17
|
-
assert_equal(
|
12
|
+
ActiveRecord::Base.connection.isolation_level(:read_uncommitted)
|
13
|
+
assert_equal(:read_uncommitted, ActiveRecord::Base.connection.current_isolation_level)
|
18
14
|
|
19
|
-
ActiveRecord::Base.connection.isolation_level(
|
20
|
-
assert_equal(
|
15
|
+
ActiveRecord::Base.connection.isolation_level(original_isolation_level)
|
16
|
+
assert_equal(original_isolation_level, ActiveRecord::Base.connection.current_isolation_level)
|
21
17
|
end
|
22
18
|
|
23
19
|
def test_with_a_block
|
24
20
|
original_isolation_level = ActiveRecord::Base.connection.current_isolation_level
|
25
|
-
refute_equal(
|
21
|
+
refute_equal(:read_uncommitted, original_isolation_level)
|
26
22
|
|
27
|
-
ActiveRecord::Base.connection.isolation_level(
|
28
|
-
assert_equal(
|
23
|
+
ActiveRecord::Base.connection.isolation_level(:read_uncommitted) do
|
24
|
+
assert_equal(:read_uncommitted, ActiveRecord::Base.connection.current_isolation_level)
|
29
25
|
ActiveRecord::Base.transaction do
|
30
|
-
assert_equal(
|
26
|
+
assert_equal(:read_uncommitted, ActiveRecord::Base.connection.current_isolation_level)
|
31
27
|
QueuedJob.count
|
32
28
|
QueuedJob.first
|
33
|
-
assert_equal(
|
29
|
+
assert_equal(:read_uncommitted, ActiveRecord::Base.connection.current_isolation_level)
|
34
30
|
end
|
35
|
-
assert_equal(
|
31
|
+
assert_equal(:read_uncommitted, ActiveRecord::Base.connection.current_isolation_level)
|
36
32
|
end
|
37
33
|
|
38
|
-
assert_equal(
|
34
|
+
assert_equal(original_isolation_level, ActiveRecord::Base.connection.current_isolation_level)
|
39
35
|
end
|
40
36
|
|
41
37
|
def test_with_all_possible_ansi_levels
|
42
|
-
[
|
43
|
-
|
44
|
-
QueuedJob.isolation_level( ansi_level ) do
|
45
|
-
|
38
|
+
%i[read_uncommitted read_committed repeatable_read serializable].each do |ansi_level|
|
39
|
+
QueuedJob.isolation_level(ansi_level) do
|
46
40
|
# Some typical usage
|
47
41
|
QueuedJob.transaction do
|
48
|
-
QueuedJob.create!(
|
49
|
-
assert_equal(
|
42
|
+
QueuedJob.create!(job: 'is fun')
|
43
|
+
assert_equal(1, QueuedJob.count)
|
50
44
|
raise ActiveRecord::Rollback
|
51
45
|
end
|
52
|
-
|
53
46
|
end
|
54
47
|
end
|
55
48
|
end
|
56
49
|
|
57
50
|
def test_with_invalid_isolation_level
|
58
|
-
assert_raises(
|
59
|
-
QueuedJob.isolation_level(
|
51
|
+
assert_raises(ArgumentError) do
|
52
|
+
QueuedJob.isolation_level(:dupa)
|
60
53
|
end
|
61
54
|
end
|
62
|
-
|
63
55
|
end
|
64
|
-
|
65
56
|
end
|
66
|
-
|
67
57
|
end
|
68
|
-
|
69
58
|
end
|
@@ -1,23 +1,15 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'test_helper'
|
4
4
|
|
5
5
|
class ActiveRecordTest < Minitest::Test
|
6
|
-
|
7
6
|
class ConnectionAdaptersTest < Minitest::Test
|
8
|
-
|
9
7
|
class AnyAdapterTest < Minitest::Test
|
10
|
-
|
11
8
|
class SupportsIsolationLevelsTest < Minitest::Test
|
12
|
-
|
13
9
|
def test_returns_true
|
14
|
-
assert(
|
10
|
+
assert(ActiveRecord::Base.connection.supports_isolation_levels?)
|
15
11
|
end
|
16
|
-
|
17
12
|
end
|
18
|
-
|
19
13
|
end
|
20
|
-
|
21
14
|
end
|
22
|
-
|
23
15
|
end
|
data/test/integration/active_record/connection_adapters/any_adapter/translate_exception_test.rb
CHANGED
@@ -1,46 +1,40 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'test_helper'
|
4
4
|
|
5
5
|
class ActiveRecordTest < Minitest::Test
|
6
|
-
|
7
6
|
class ConnectionAdaptersTest < Minitest::Test
|
8
|
-
|
9
7
|
class AnyAdapterTest < Minitest::Test
|
10
|
-
|
11
8
|
class TranslateExceptionTest < Minitest::Test
|
12
|
-
|
13
9
|
def test_does_not_break_existing_translation
|
14
|
-
assert_raises(
|
15
|
-
ActiveRecord::Base.connection.execute(
|
10
|
+
assert_raises(ActiveRecord::StatementInvalid) do
|
11
|
+
ActiveRecord::Base.connection.execute('WE LIVE IN THE MOST EXCITING TIMES EVER')
|
16
12
|
end
|
17
13
|
end
|
18
14
|
|
19
15
|
def test_translates_low_level_exceptions_to_transaction_isolation_level
|
20
|
-
if defined?(
|
21
|
-
message =
|
22
|
-
translated_exception = ActiveRecord::Base.connection.send(
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
if defined?( ActiveRecord::ConnectionAdapters::PostgreSQLAdapter )
|
27
|
-
message = "deadlock detected"
|
28
|
-
translated_exception = ActiveRecord::Base.connection.send( :translate_exception, PG::Error.new( message ), message: message, sql: nil, binds: nil )
|
29
|
-
assert_equal( ActiveRecord::TransactionIsolationConflict, translated_exception.class )
|
16
|
+
if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
|
17
|
+
message = 'Deadlock found when trying to get lock'
|
18
|
+
translated_exception = ActiveRecord::Base.connection.send(:translate_exception,
|
19
|
+
Mysql2::Error.new(message), message: message, sql: nil, binds: nil)
|
20
|
+
assert_equal(ActiveRecord::TransactionIsolationConflict, translated_exception.class)
|
30
21
|
end
|
31
|
-
|
32
|
-
if defined?(
|
33
|
-
message =
|
34
|
-
translated_exception = ActiveRecord::Base.connection.send(
|
35
|
-
|
22
|
+
|
23
|
+
if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
24
|
+
message = 'deadlock detected'
|
25
|
+
translated_exception = ActiveRecord::Base.connection.send(:translate_exception, PG::Error.new(message),
|
26
|
+
message: message, sql: nil, binds: nil)
|
27
|
+
assert_equal(ActiveRecord::TransactionIsolationConflict, translated_exception.class)
|
36
28
|
end
|
37
29
|
|
38
|
-
|
30
|
+
return unless defined?(ActiveRecord::ConnectionAdapters::SQLite3Adapter)
|
39
31
|
|
32
|
+
message = 'The database file is locked'
|
33
|
+
translated_exception = ActiveRecord::Base.connection.send(:translate_exception,
|
34
|
+
StandardError.new(message), message: message, sql: nil, binds: nil)
|
35
|
+
assert_equal(ActiveRecord::TransactionIsolationConflict, translated_exception.class)
|
36
|
+
end
|
40
37
|
end
|
41
|
-
|
42
38
|
end
|
43
|
-
|
44
39
|
end
|
45
|
-
|
46
40
|
end
|
data/test/library_setup.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Prepares application to be tested (requires files, connects to db, resets schema and data, applies patches, etc.)
|
2
4
|
|
3
5
|
# Initialize database
|
4
6
|
require 'db/all'
|
5
7
|
|
6
8
|
case ENV['db']
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
when 'mysql2'
|
10
|
+
TransactionIsolation::Test::Db.connect_to_mysql2
|
11
|
+
when 'postgresql'
|
12
|
+
TransactionIsolation::Test::Db.connect_to_postgresql
|
13
|
+
when 'sqlite3'
|
14
|
+
TransactionIsolation::Test::Db.connect_to_sqlite3
|
15
|
+
else
|
16
|
+
TransactionIsolation::Test::Db.connect_to_sqlite3
|
15
17
|
end
|
16
18
|
|
17
19
|
TransactionIsolation::Test::Migrations.run!
|
@@ -20,6 +22,6 @@ TransactionIsolation::Test::Migrations.run!
|
|
20
22
|
require 'transaction_isolation'
|
21
23
|
|
22
24
|
require 'logger'
|
23
|
-
ActiveRecord::Base.logger = Logger.new(
|
25
|
+
ActiveRecord::Base.logger = Logger.new(File.expand_path("#{File.dirname(__FILE__)}/log/test.log"))
|
24
26
|
|
25
27
|
TransactionIsolation.apply_activerecord_patch
|
data/test/test_helper.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'simplecov'
|
4
|
+
require 'simplecov_json_formatter'
|
5
|
+
SimpleCov.formatter = SimpleCov::Formatter::JSONFormatter
|
6
|
+
|
7
|
+
SimpleCov.start do
|
8
|
+
add_filter '/test/'
|
9
|
+
end
|
7
10
|
|
8
11
|
# Load and initialize the application to be tested
|
9
12
|
require 'library_setup'
|
data/test/test_runner.rb
CHANGED
@@ -1,25 +1,25 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
4
|
+
require 'transaction_isolation/version'
|
4
5
|
|
5
6
|
Gem::Specification.new do |s|
|
6
|
-
s.name =
|
7
|
+
s.name = 'transaction_isolation_continued'
|
7
8
|
s.version = TransactionIsolation::VERSION
|
8
|
-
s.authors = [
|
9
|
-
s.
|
10
|
-
s.
|
11
|
-
s.
|
12
|
-
s.description = %q{Set transaction isolation level in the ActiveRecord in a database agnostic way.
|
9
|
+
s.authors = ['Iago Pimenta']
|
10
|
+
s.homepage = 'https://github.com/iagopiimenta/transaction_isolation_continued'
|
11
|
+
s.summary = 'Set transaction isolation level in the ActiveRecord in a database agnostic way.'
|
12
|
+
s.description = 'Set transaction isolation level in the ActiveRecord in a database agnostic way.
|
13
13
|
Works with MySQL, PostgreSQL and SQLite as long as you are using new adapters mysql2, pg or sqlite3.
|
14
|
-
Supports all ANSI SQL isolation levels: :serializable, :repeatable_read, :read_committed, :read_uncommitted.
|
15
|
-
s.required_ruby_version = '>=
|
14
|
+
Supports all ANSI SQL isolation levels: :serializable, :repeatable_read, :read_committed, :read_uncommitted.'
|
15
|
+
s.required_ruby_version = '>= 2.3'
|
16
16
|
|
17
17
|
s.files = `git ls-files`.split("\n")
|
18
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
-
s.require_paths = [
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
20
|
+
s.require_paths = ['lib']
|
21
21
|
|
22
|
-
s.add_development_dependency 'rake', '~> 13.0'
|
23
22
|
s.add_development_dependency 'minitest', '5.3.4'
|
24
|
-
s.
|
23
|
+
s.add_development_dependency 'rake', '~> 13.0'
|
24
|
+
s.add_runtime_dependency 'activerecord', '>= 5.2'
|
25
25
|
end
|
metadata
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: transaction_isolation_continued
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Iago Pimenta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: minitest
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 5.3.4
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 5.3.4
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: '13.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: '13.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: activerecord
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -57,19 +57,29 @@ description: |-
|
|
57
57
|
Works with MySQL, PostgreSQL and SQLite as long as you are using new adapters mysql2, pg or sqlite3.
|
58
58
|
Supports all ANSI SQL isolation levels: :serializable, :repeatable_read, :read_committed, :read_uncommitted.
|
59
59
|
email:
|
60
|
-
- qertoip@gmail.com
|
61
60
|
executables: []
|
62
61
|
extensions: []
|
63
62
|
extra_rdoc_files: []
|
64
63
|
files:
|
64
|
+
- ".dockerignore"
|
65
65
|
- ".github/workflows/main.yml"
|
66
|
+
- ".github/workflows/rubygem.yml"
|
66
67
|
- ".gitignore"
|
67
68
|
- Gemfile
|
68
|
-
- Gemfile.local
|
69
|
+
- Gemfile.old.local
|
69
70
|
- LICENSE
|
70
71
|
- README.md
|
71
72
|
- Rakefile
|
72
|
-
-
|
73
|
+
- docker-compose.yml
|
74
|
+
- docker/ruby-2.5/Dockerfile
|
75
|
+
- docker/ruby-2.7/Dockerfile
|
76
|
+
- docker/ruby-3.0/Dockerfile
|
77
|
+
- docker/ruby-3.1/Dockerfile
|
78
|
+
- docker/test-ruby-2.5.sh
|
79
|
+
- docker/test-ruby-2.7.sh
|
80
|
+
- docker/test-ruby-3.0.sh
|
81
|
+
- docker/test-ruby-3.1.sh
|
82
|
+
- docker/test-ruby.sh
|
73
83
|
- gemfiles/Gemfile.base
|
74
84
|
- gemfiles/activerecord-5.2/Gemfile.base
|
75
85
|
- gemfiles/activerecord-5.2/Gemfile.mysql2
|
@@ -96,6 +106,9 @@ files:
|
|
96
106
|
- lib/transaction_isolation/active_record/errors.rb
|
97
107
|
- lib/transaction_isolation/configuration.rb
|
98
108
|
- lib/transaction_isolation/version.rb
|
109
|
+
- lib/transaction_isolation_continued.rb
|
110
|
+
- spec/gem_template_spec.rb
|
111
|
+
- spec/spec_helper.rb
|
99
112
|
- test/db/all.rb
|
100
113
|
- test/db/db.rb
|
101
114
|
- test/db/migrations.rb
|
@@ -108,12 +121,11 @@ files:
|
|
108
121
|
- test/integration/active_record/connection_adapters/any_adapter/translate_exception_test.rb
|
109
122
|
- test/library_setup.rb
|
110
123
|
- test/log/.gitkeep
|
111
|
-
- test/test_console.rb
|
112
124
|
- test/test_helper.rb
|
113
125
|
- test/test_runner.rb
|
114
126
|
- tests
|
115
127
|
- transaction_isolation_continued.gemspec
|
116
|
-
homepage: https://github.com/
|
128
|
+
homepage: https://github.com/iagopiimenta/transaction_isolation_continued
|
117
129
|
licenses: []
|
118
130
|
metadata: {}
|
119
131
|
post_install_message:
|
@@ -124,7 +136,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
124
136
|
requirements:
|
125
137
|
- - ">="
|
126
138
|
- !ruby/object:Gem::Version
|
127
|
-
version:
|
139
|
+
version: '2.3'
|
128
140
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
141
|
requirements:
|
130
142
|
- - ">="
|
@@ -137,6 +149,8 @@ specification_version: 4
|
|
137
149
|
summary: Set transaction isolation level in the ActiveRecord in a database agnostic
|
138
150
|
way.
|
139
151
|
test_files:
|
152
|
+
- spec/gem_template_spec.rb
|
153
|
+
- spec/spec_helper.rb
|
140
154
|
- test/db/all.rb
|
141
155
|
- test/db/db.rb
|
142
156
|
- test/db/migrations.rb
|
@@ -149,6 +163,5 @@ test_files:
|
|
149
163
|
- test/integration/active_record/connection_adapters/any_adapter/translate_exception_test.rb
|
150
164
|
- test/library_setup.rb
|
151
165
|
- test/log/.gitkeep
|
152
|
-
- test/test_console.rb
|
153
166
|
- test/test_helper.rb
|
154
167
|
- test/test_runner.rb
|
data/test/test_console.rb
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
# Ensure that LOAD_PATH is the same as when running "rake test"; normally rake takes care of that
|
2
|
-
$LOAD_PATH << File.expand_path( ".", File.dirname( __FILE__ ) )
|
3
|
-
$LOAD_PATH << File.expand_path( "./lib", File.dirname( __FILE__ ) )
|
4
|
-
$LOAD_PATH << File.expand_path( "./test", File.dirname( __FILE__ ) )
|
5
|
-
|
6
|
-
# Boot the app
|
7
|
-
require_relative 'library_setup'
|
8
|
-
|
9
|
-
# Fire the console
|
10
|
-
require 'pry'
|
11
|
-
binding.pry
|