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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 77687087fa3661aba6aace55de51de3f92de2e93
4
- data.tar.gz: ec806bac134278e915188fa93d988d640b8e50ac
3
+ metadata.gz: 7e586669d11f096afeeb93a78957547b262583dd
4
+ data.tar.gz: 72070196c4ca9a4ace102c2e70e24924eac98859
5
5
  SHA512:
6
- metadata.gz: e5d6a8c24fa34a4cdefd0e87786c62bc9e861beb2d848478445cb9329362b9457bfdfe06f64ad27c451a21731feddd2a7a7d70b9d4b6a361c9177701640a6a9c
7
- data.tar.gz: 90bcacff53ac17022d2494584c564daa56942f978e30fd7c0322a93063f7a193b057d241a2837767b043bae06a6f79dd96c43fc95cfa0d3cd7232333d4d9efd4
6
+ metadata.gz: bcd62b44be847b7466f31083b10eb9662061e27f33855d75bc5867ba5c12b43ac6fd57e2fb539e5a3234755540e397b9c5a3c1b30a036cbb09b60ef63d6ed282
7
+ data.tar.gz: 56249e61ef7b33a5b170680a1fd9350e8fdc42a54d051790e2c6bbb53b2056661e93c9fed7a66d9cdc1a9b4b49ef6926073f12d5dc2ba7764e27a8fbbac4ef2c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 0.4.3 (2014-06-24)
2
+ - Add Model.transaction_with method (#2, @ryopeko)
3
+
1
4
  ## 0.4.2 (2014-06-19)
2
5
  - Establish connection lazily
3
6
  - Just like ActiveRecord::Base, real connection isn't created until `.connection` is called
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.
@@ -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
@@ -120,19 +120,27 @@ module SwitchPoint
120
120
  @current_name = @initial_name
121
121
  end
122
122
 
123
- def connection
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).connection
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
- connection
131
+ model_for_connection
132
132
  end
133
133
  else
134
- ActiveRecord::Base.connection
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
@@ -1,3 +1,3 @@
1
1
  module SwitchPoint
2
- VERSION = "0.4.2"
2
+ VERSION = "0.4.3"
3
3
  end
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.2
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-19 00:00:00.000000000 Z
11
+ date: 2014-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appraisal