switch_point 0.4.2 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/README.md +5 -0
- data/lib/switch_point/model.rb +25 -0
- data/lib/switch_point/proxy.rb +12 -4
- data/lib/switch_point/version.rb +1 -1
- data/spec/models.rb +26 -1
- data/spec/spec_helper.rb +11 -0
- data/spec/switch_point/model_spec.rb +108 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e586669d11f096afeeb93a78957547b262583dd
|
4
|
+
data.tar.gz: 72070196c4ca9a4ace102c2e70e24924eac98859
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bcd62b44be847b7466f31083b10eb9662061e27f33855d75bc5867ba5c12b43ac6fd57e2fb539e5a3234755540e397b9c5a3c1b30a036cbb09b60ef63d6ed282
|
7
|
+
data.tar.gz: 56249e61ef7b33a5b170680a1fd9350e8fdc42a54d051790e2c6bbb53b2056661e93c9fed7a66d9cdc1a9b4b49ef6926073f12d5dc2ba7764e27a8fbbac4ef2c
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -40,6 +40,11 @@ Suppose `after_save` callback is set to User model. When `User.create` is called
|
|
40
40
|
- At this point, the connection is READONLY and in a transaction.
|
41
41
|
6. COMMIT TRANSACTION is sent to READONLY connection.
|
42
42
|
|
43
|
+
### connection-related methods of model
|
44
|
+
Model has several connection-related methods: `connection_handler`, `connection_pool`, `connected?` and so on.
|
45
|
+
Since only `connection` method is monkey-patched, other connection-related methods doesn't work properly.
|
46
|
+
If you'd like to use those methods, send it to `Model.switch_point_proxy.model_for_connection`.
|
47
|
+
|
43
48
|
## Internals
|
44
49
|
There's a proxy which holds two connections: readonly one and writable one.
|
45
50
|
A proxy has a thread-local state indicating the current mode: readonly or writable.
|
data/lib/switch_point/model.rb
CHANGED
@@ -47,11 +47,36 @@ module SwitchPoint
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
+
def transaction_with(*models, &block)
|
51
|
+
unless can_transaction_with?(*models)
|
52
|
+
raise RuntimeError.new("switch_point's model names must be consistent")
|
53
|
+
end
|
54
|
+
|
55
|
+
with_writable do
|
56
|
+
self.transaction(&block)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
50
60
|
private
|
51
61
|
|
52
62
|
def assert_existing_switch_point!(name)
|
53
63
|
SwitchPoint.config.fetch(name)
|
54
64
|
end
|
65
|
+
|
66
|
+
def can_transaction_with?(*models)
|
67
|
+
writable_switch_points = [self, *models].map do |model|
|
68
|
+
if model.instance_variable_defined?(:@switch_point_name)
|
69
|
+
SwitchPoint.config.model_name(
|
70
|
+
model.instance_variable_get(:@switch_point_name),
|
71
|
+
:writable
|
72
|
+
)
|
73
|
+
else
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
writable_switch_points.uniq.size == 1
|
79
|
+
end
|
55
80
|
end
|
56
81
|
end
|
57
82
|
end
|
data/lib/switch_point/proxy.rb
CHANGED
@@ -120,19 +120,27 @@ module SwitchPoint
|
|
120
120
|
@current_name = @initial_name
|
121
121
|
end
|
122
122
|
|
123
|
-
def
|
123
|
+
def model_for_connection
|
124
124
|
ProxyRepository.checkout(@current_name) # Ensure the target proxy is created
|
125
125
|
model_name = SwitchPoint.config.model_name(@current_name, mode)
|
126
126
|
if model_name
|
127
|
-
Proxy.const_get(model_name)
|
127
|
+
Proxy.const_get(model_name)
|
128
128
|
elsif mode == :readonly
|
129
129
|
# When only writable is specified, re-use writable connection.
|
130
130
|
with_writable do
|
131
|
-
|
131
|
+
model_for_connection
|
132
132
|
end
|
133
133
|
else
|
134
|
-
ActiveRecord::Base
|
134
|
+
ActiveRecord::Base
|
135
135
|
end
|
136
136
|
end
|
137
|
+
|
138
|
+
def connection
|
139
|
+
model_for_connection.connection
|
140
|
+
end
|
141
|
+
|
142
|
+
def connected?
|
143
|
+
model_for_connection.connected?
|
144
|
+
end
|
137
145
|
end
|
138
146
|
end
|
data/lib/switch_point/version.rb
CHANGED
data/spec/models.rb
CHANGED
@@ -2,6 +2,9 @@ SwitchPoint.configure do |config|
|
|
2
2
|
config.define_switch_point :main,
|
3
3
|
readonly: :main_readonly,
|
4
4
|
writable: :main_writable
|
5
|
+
config.define_switch_point :main2,
|
6
|
+
readonly: :main2_readonly,
|
7
|
+
writable: :main2_writable
|
5
8
|
config.define_switch_point :user,
|
6
9
|
readonly: :user,
|
7
10
|
writable: :user
|
@@ -31,6 +34,14 @@ class Book < ActiveRecord::Base
|
|
31
34
|
end
|
32
35
|
end
|
33
36
|
|
37
|
+
class Book2 < ActiveRecord::Base
|
38
|
+
use_switch_point :main
|
39
|
+
end
|
40
|
+
|
41
|
+
class Book3 < ActiveRecord::Base
|
42
|
+
use_switch_point :main2
|
43
|
+
end
|
44
|
+
|
34
45
|
class Publisher < ActiveRecord::Base
|
35
46
|
use_switch_point :main
|
36
47
|
end
|
@@ -66,6 +77,8 @@ base = { adapter: 'sqlite3' }
|
|
66
77
|
ActiveRecord::Base.configurations = {
|
67
78
|
'main_readonly' => base.merge(database: 'main_readonly.sqlite3'),
|
68
79
|
'main_writable' => base.merge(database: 'main_writable.sqlite3'),
|
80
|
+
'main2_readonly' => base.merge(database: 'main2_readonly.sqlite3'),
|
81
|
+
'main2_writable' => base.merge(database: 'main2_writable.sqlite3'),
|
69
82
|
'main_readonly_special' => base.merge(database: 'main_readonly_special.sqlite3'),
|
70
83
|
'user' => base.merge(database: 'user.sqlite3'),
|
71
84
|
'comment_readonly' => base.merge(database: 'comment_readonly.sqlite3'),
|
@@ -76,8 +89,20 @@ ActiveRecord::Base.establish_connection(:default)
|
|
76
89
|
|
77
90
|
# XXX: Check connection laziness
|
78
91
|
[Book, User, Note, Nanika1, ActiveRecord::Base].each do |model|
|
92
|
+
if model.connected?
|
93
|
+
raise "ActiveRecord::Base didn't establish connection lazily!"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
ActiveRecord::Base.connection # Create connection
|
97
|
+
|
98
|
+
[Book, User, Nanika3].each do |model|
|
79
99
|
model.with_writable do
|
80
|
-
if model.connected?
|
100
|
+
if model.switch_point_proxy.connected?
|
101
|
+
raise "#{model.name} didn't establish connection lazily!"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
model.with_readonly do
|
105
|
+
if model.switch_point_proxy.connected?
|
81
106
|
raise "#{model.name} didn't establish connection lazily!"
|
82
107
|
end
|
83
108
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -38,8 +38,19 @@ RSpec.configure do |config|
|
|
38
38
|
Book.with_writable do
|
39
39
|
Book.connection.execute('CREATE TABLE books (id integer primary key autoincrement)')
|
40
40
|
end
|
41
|
+
|
42
|
+
Book2.with_writable do
|
43
|
+
Book2.connection.execute('CREATE TABLE book2s (id integer primary key autoincrement)')
|
44
|
+
end
|
45
|
+
|
41
46
|
FileUtils.cp('main_writable.sqlite3', 'main_readonly.sqlite3')
|
42
47
|
|
48
|
+
Book3.with_writable do
|
49
|
+
Book3.connection.execute('CREATE TABLE book3s (id integer primary key autoincrement)')
|
50
|
+
end
|
51
|
+
|
52
|
+
FileUtils.cp('main2_writable.sqlite3', 'main2_readonly.sqlite3')
|
53
|
+
|
43
54
|
Note.connection.execute('CREATE TABLE notes (id integer primary key autoincrement)')
|
44
55
|
|
45
56
|
Nanika3.connection.execute('CREATE TABLE nanika3s (id integer primary key)')
|
@@ -261,4 +261,112 @@ RSpec.describe SwitchPoint::Model do
|
|
261
261
|
end
|
262
262
|
end
|
263
263
|
end
|
264
|
+
|
265
|
+
describe '.transaction_with' do
|
266
|
+
context "when each model has a same writable" do
|
267
|
+
before do
|
268
|
+
@before_book_count = Book.count
|
269
|
+
@before_book2_count = Book2.count
|
270
|
+
|
271
|
+
Book.transaction_with(Book2) do
|
272
|
+
new_book = Book.create
|
273
|
+
new_book2 = Book2.create
|
274
|
+
end
|
275
|
+
|
276
|
+
@after_book_count = Book.with_writable do
|
277
|
+
Book.count
|
278
|
+
end
|
279
|
+
@after_book2_count = Book2.with_writable do
|
280
|
+
Book2.count
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'should create a new record' do
|
285
|
+
expect(
|
286
|
+
Book.with_writable do
|
287
|
+
Book.count
|
288
|
+
end
|
289
|
+
).to be > @before_book_count
|
290
|
+
|
291
|
+
expect(
|
292
|
+
Book2.with_writable do
|
293
|
+
Book2.count
|
294
|
+
end
|
295
|
+
).to be > @before_book2_count
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
context "when each model has a other writable" do
|
300
|
+
it {
|
301
|
+
expect {
|
302
|
+
Book.transaction_with(Book3) do
|
303
|
+
new_book = Book.create
|
304
|
+
new_book3 = Book3.create
|
305
|
+
end
|
306
|
+
}.to raise_error RuntimeError
|
307
|
+
}
|
308
|
+
end
|
309
|
+
|
310
|
+
context "when raise exception in transaction that include some model, and models each have other writable" do
|
311
|
+
before do
|
312
|
+
@before_book_count = Book.count
|
313
|
+
@before_book3_count = Book3.count
|
314
|
+
|
315
|
+
Book.transaction_with(Book2) do
|
316
|
+
new_book = Book.create
|
317
|
+
new_book3 = Book3.with_writable do
|
318
|
+
Book3.create
|
319
|
+
end
|
320
|
+
raise ActiveRecord::Rollback
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
it 'Book should not create a new record (rollbacked)' do
|
325
|
+
expect(
|
326
|
+
Book.with_writable do
|
327
|
+
Book.count
|
328
|
+
end
|
329
|
+
).to eq @before_book_count
|
330
|
+
end
|
331
|
+
|
332
|
+
it 'Book3 should create a new record (not rollbacked)' do
|
333
|
+
expect(
|
334
|
+
Book3.with_writable do
|
335
|
+
Book3.count
|
336
|
+
end
|
337
|
+
).to be > @before_book3_count
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
context "when nested transaction_with then parent transaction rollbacked" do
|
342
|
+
before do
|
343
|
+
@before_book_count = Book.count
|
344
|
+
@before_book3_count = Book3.count
|
345
|
+
|
346
|
+
Book.transaction_with do
|
347
|
+
Book.create
|
348
|
+
|
349
|
+
Book3.transaction_with do
|
350
|
+
Book3.create
|
351
|
+
end
|
352
|
+
|
353
|
+
raise ActiveRecord::Rollback
|
354
|
+
end
|
355
|
+
|
356
|
+
it {
|
357
|
+
expect(
|
358
|
+
Book.with_writable do
|
359
|
+
Book.count
|
360
|
+
end
|
361
|
+
).to be = @before_book_count
|
362
|
+
|
363
|
+
expect(
|
364
|
+
Book3.with_writable do
|
365
|
+
Book3.count
|
366
|
+
end
|
367
|
+
).to be > @before_book3_count
|
368
|
+
}
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
264
372
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: switch_point
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kohei Suzuki
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: appraisal
|