sequel-activerecord_connection 0.2.6 → 0.3.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.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4078a41f54331cbb97fc266abdbe24cf8c297be14bb7f92b3bf605bf9b549bd
|
4
|
+
data.tar.gz: af466cd9b062279a7781106136a05151f02339830469136cdf9b58d629397b98
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e28881de46188d6dc143952a473e00254b0742c497e7888e8d334ff33b627d3d90d9174675809cc3248b15cfcc800908bc83dda5a8da3fee93c4048c44282424
|
7
|
+
data.tar.gz: 7c0a46d18a45e76ca4a7af11d467b957035dd4b62adbdcaf64d8e9cafe1bfb406fa40c3d4feadff10c823d2535cab978111203ade32ea519f991e828ed1df033
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
This is an extension for [Sequel] that allows it to reuse an existing
|
4
4
|
ActiveRecord connection for database interaction. It works on ActiveRecord 4.2
|
5
5
|
or higher, and supports the built-in `postgresql`, `mysql2` and `sqlite3`
|
6
|
-
adapters.
|
6
|
+
adapters, as well as JDBC adapter for JRuby.
|
7
7
|
|
8
8
|
This can be useful if you're using a library that uses Sequel for database
|
9
9
|
interaction (e.g. [Rodauth]), but you want to avoid creating a separate
|
@@ -11,15 +11,15 @@ database connection. Or if you're transitioning from ActiveRecord to Sequel,
|
|
11
11
|
and want the database connection to be shared.
|
12
12
|
|
13
13
|
Note that this is a best-effort implementation, so some discrepancies are still
|
14
|
-
possible. That being said, this implementation passes
|
15
|
-
(for all adapters), which has fairly advanced Sequel usage.
|
14
|
+
possible. That being said, this implementation passes Rodauth's test suite
|
15
|
+
(for all adapters), which has some fairly advanced Sequel usage.
|
16
16
|
|
17
17
|
## Installation
|
18
18
|
|
19
19
|
Add this line to your application's Gemfile:
|
20
20
|
|
21
21
|
```ruby
|
22
|
-
gem "sequel-activerecord_connection"
|
22
|
+
gem "sequel-activerecord_connection", "~> 0.3"
|
23
23
|
```
|
24
24
|
|
25
25
|
And then execute:
|
@@ -80,65 +80,62 @@ DB = Sequel.postgres(test: false) # for "postgresql" adapter
|
|
80
80
|
DB = Sequel.mysql2(test: false) # for "mysql2" adapter
|
81
81
|
# or
|
82
82
|
DB = Sequel.sqlite(test: false) # for "sqlite3" adapter
|
83
|
+
# or
|
84
|
+
DB = Sequel.jdbc(test: false) # for JDBC adapter
|
83
85
|
```
|
84
86
|
|
85
87
|
### Transactions
|
86
88
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
work correctly.
|
89
|
+
This database extension keeps the transaction state of Sequel and ActiveRecord
|
90
|
+
in sync, allowing you to use Sequel and ActiveRecord transactions
|
91
|
+
interchangeably (including nesting them), and have things like ActiveRecord's
|
92
|
+
and Sequel's transactional callbacks still work correctly.
|
91
93
|
|
92
94
|
```rb
|
93
|
-
|
94
|
-
|
95
|
-
# this all works
|
96
|
-
end
|
95
|
+
ActiveRecord::Base.transaction do
|
96
|
+
DB.in_transaction? #=> true
|
97
97
|
end
|
98
98
|
```
|
99
99
|
|
100
|
-
|
101
|
-
|
102
|
-
* `:savepoint`
|
103
|
-
* `:auto_savepoint`
|
104
|
-
* `:rollback`
|
100
|
+
Sequel's transaction API is fully supported:
|
105
101
|
|
106
102
|
```rb
|
107
|
-
|
108
|
-
DB.
|
109
|
-
|
110
|
-
|
111
|
-
end
|
103
|
+
DB.transaction(isolation: :serializable) do
|
104
|
+
DB.after_commit { ... } # call block after transaction commits
|
105
|
+
DB.transaction(savepoint: true) do # creates a savepoint
|
106
|
+
# ...
|
112
107
|
end
|
113
108
|
end
|
114
109
|
```
|
115
110
|
|
116
|
-
|
111
|
+
One caveat to keep in mind is that Sequel's transaction hooks
|
112
|
+
(`after_commit`, `after_rollback`) will *not* run if ActiveRecord holds the
|
113
|
+
outer transaction:
|
117
114
|
|
118
115
|
```rb
|
119
|
-
|
120
|
-
DB.
|
116
|
+
DB.transaction do
|
117
|
+
DB.after_commit { ... } # will get executed
|
121
118
|
end
|
122
|
-
```
|
123
119
|
|
124
|
-
|
125
|
-
|
126
|
-
|
120
|
+
ActiveRecord::Base.transaction do
|
121
|
+
DB.after_commit { ... } # won't get executed
|
122
|
+
end
|
127
123
|
|
128
|
-
|
124
|
+
ActiveRecord::Base.transaction do
|
125
|
+
DB.transaction do
|
126
|
+
DB.after_commit { ... } # won't get executed
|
127
|
+
end
|
128
|
+
end
|
129
|
+
```
|
129
130
|
|
130
|
-
|
131
|
-
will be translated into Sequel exceptions:
|
131
|
+
Savepoint hooks should still work, though:
|
132
132
|
|
133
133
|
```rb
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
DB[:posts].insert(author_id: 123)
|
141
|
-
#~> Sequel::ForeignKeyConstraintViolation
|
134
|
+
ActiveRecord::Base.transaction do
|
135
|
+
DB.transaction(savepoint: true) do
|
136
|
+
DB.after_commit { ... } # will get executed after savepoint is released
|
137
|
+
end
|
138
|
+
end
|
142
139
|
```
|
143
140
|
|
144
141
|
### Model
|
@@ -2,6 +2,13 @@ module Sequel
|
|
2
2
|
module ActiveRecordConnection
|
3
3
|
Error = Class.new(Sequel::Error)
|
4
4
|
|
5
|
+
TRANSACTION_ISOLATION_MAP = {
|
6
|
+
uncommitted: :read_uncommitted,
|
7
|
+
committed: :read_committed,
|
8
|
+
repeatable: :repeatable_read,
|
9
|
+
serializable: :serializable,
|
10
|
+
}
|
11
|
+
|
5
12
|
def self.extended(db)
|
6
13
|
db.activerecord_model = ActiveRecord::Base
|
7
14
|
db.timezone = ActiveRecord::Base.default_timezone
|
@@ -21,36 +28,6 @@ module Sequel
|
|
21
28
|
raise Error, "creating a Sequel connection is not allowed"
|
22
29
|
end
|
23
30
|
|
24
|
-
def transaction(options = {})
|
25
|
-
%i[isolation num_retries before_retry prepare retry_on].each do |key|
|
26
|
-
fail Error, "#{key.inspect} transaction option is currently not supported" if options.key?(key)
|
27
|
-
end
|
28
|
-
|
29
|
-
activerecord_model.transaction(requires_new: !in_transaction? || options[:savepoint] || Thread.current[:sequel_activerecord_auto_savepoint]) do
|
30
|
-
begin
|
31
|
-
Thread.current[:sequel_activerecord_auto_savepoint] = true if options[:auto_savepoint]
|
32
|
-
result = yield
|
33
|
-
raise ActiveRecord::Rollback if options[:rollback] == :always
|
34
|
-
result
|
35
|
-
rescue Sequel::Rollback => exception
|
36
|
-
raise if options[:rollback] == :reraise
|
37
|
-
raise ActiveRecord::Rollback, exception.message, exception.backtrace
|
38
|
-
ensure
|
39
|
-
Thread.current[:sequel_activerecord_auto_savepoint] = nil if options[:auto_savepoint]
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def in_transaction?(*)
|
45
|
-
activerecord_connection.transaction_open?
|
46
|
-
end
|
47
|
-
|
48
|
-
%i[after_commit after_rollback rollback_on_exit rollback_checker].each do |meth|
|
49
|
-
define_method(meth) do |*|
|
50
|
-
fail Error, "Database##{meth} is currently not supported"
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
31
|
# Avoid calling Sequel's connection pool, instead use ActiveRecord.
|
55
32
|
def synchronize(*)
|
56
33
|
if ActiveRecord.version >= Gem::Version.new("5.1.0")
|
@@ -64,6 +41,53 @@ module Sequel
|
|
64
41
|
|
65
42
|
private
|
66
43
|
|
44
|
+
# Backfills any ActiveRecord transactions/savepoints that have been opened
|
45
|
+
# directly via ActiveRecord::Base.transaction. Sequel uses this information
|
46
|
+
# to know whether we're in a transaction, whether to create a savepoint,
|
47
|
+
# when to run transaction/savepoint hooks etc.
|
48
|
+
def _trans(conn)
|
49
|
+
Sequel.synchronize do
|
50
|
+
result = @transactions[conn]
|
51
|
+
|
52
|
+
if activerecord_connection.transaction_open?
|
53
|
+
result ||= { savepoints: [] }
|
54
|
+
while result[:savepoints].length < activerecord_connection.open_transactions
|
55
|
+
result[:savepoints].unshift({ activerecord: true })
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
@transactions[conn] = result if result
|
60
|
+
result
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# First delete any transactions/savepoints opened directly via
|
65
|
+
# ActiveRecord::Base.transaction, so that Sequel can detect when the last
|
66
|
+
# Sequel transaction has been closed and clear transaction information.
|
67
|
+
def transaction_finished?(conn)
|
68
|
+
_trans(conn)[:savepoints].shift while _trans(conn)[:savepoints].first[:activerecord]
|
69
|
+
super
|
70
|
+
end
|
71
|
+
|
72
|
+
def begin_transaction(conn, opts = {})
|
73
|
+
isolation = TRANSACTION_ISOLATION_MAP.fetch(opts[:isolation]) if opts[:isolation]
|
74
|
+
|
75
|
+
activerecord_connection.begin_transaction(isolation: isolation)
|
76
|
+
end
|
77
|
+
|
78
|
+
def commit_transaction(conn, opts = {})
|
79
|
+
activerecord_connection.commit_transaction
|
80
|
+
end
|
81
|
+
|
82
|
+
def rollback_transaction(conn, opts = {})
|
83
|
+
activerecord_connection.rollback_transaction
|
84
|
+
activerecord_connection.transaction_manager.send(:after_failure_actions, activerecord_connection.current_transaction, $!) if activerecord_connection.transaction_manager.respond_to?(:after_failure_actions)
|
85
|
+
end
|
86
|
+
|
87
|
+
def savepoint_level(conn)
|
88
|
+
activerecord_connection.open_transactions
|
89
|
+
end
|
90
|
+
|
67
91
|
def activerecord_raw_connection
|
68
92
|
activerecord_connection.raw_connection
|
69
93
|
end
|
@@ -9,6 +9,8 @@ module Sequel
|
|
9
9
|
else
|
10
10
|
result.cmd_tuples
|
11
11
|
end
|
12
|
+
rescue ActiveRecord::PreparedStatementCacheExpired
|
13
|
+
raise # ActiveRecord's transaction manager needs to handle this exception
|
12
14
|
rescue ActiveRecord::StatementInvalid => exception
|
13
15
|
raise_error(exception.cause, classes: database_error_classes)
|
14
16
|
ensure
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel-activerecord_connection
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Janko Marohnić
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|