switch_point 0.3.0 → 0.3.1

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: 4b8ceb04a21d6850779c5fcc61d2b0552bec494f
4
- data.tar.gz: 0d6cc9ce87e7f320b1b7e14ff7dd3be22578dbde
3
+ metadata.gz: d4e8e6fce7bc9a152422f2b1ede1df15b39791c6
4
+ data.tar.gz: 785d1e66b759b372edb68201454238bd62879ef1
5
5
  SHA512:
6
- metadata.gz: cfff954c906a2c517ea9a9fb70780bf3504d076ad25db2db6f37dcbd6eadf34017b5649465a6addc8cdbf477abb79559a8c680385f024a7b5d70a179734bf094
7
- data.tar.gz: 17a845a358c5ce19a13d8b42d0bef169ffb6c756efc36cc19176bdc4780776e5071982bacac0eb82ebe0ebf33ea8e59de96b23827b03bd6d159c3c74215fc254
6
+ metadata.gz: 83d13eaf42dcc9e266c1bc3e703b04798ca0bb17473591a819e36c09eb40a294e3a4c57b42970428a9b09f159ac3a20a443d2f158ced0a5f309cd894ebe6d769
7
+ data.tar.gz: e5c054d22e52bcb1f37ba3d46fb6487b1a462b53f7b443fd9f389195bdd0ed668bd5a3b9df13006a0b2104047febe8b87b02b46e59e8e5ea1342d2f4bbd86741
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.3.1 (2014-06-04)
2
+ - Support defaulting to writable ActiveRecord::Base connection
3
+ - When `:writable` key is omitted, ActiveRecord::Base is used for the writable connection.
4
+
1
5
  ## 0.3.0 (2014-06-04)
2
6
  - Improve thread safety
3
7
  - Raise appropriate error if unknown mode is given to with_connection
@@ -14,7 +14,11 @@ module SwitchPoint
14
14
  end
15
15
 
16
16
  def model_name(name, mode)
17
- "#{name}_#{mode}".camelize
17
+ if switch_points[name][mode]
18
+ "#{name}_#{mode}".camelize
19
+ else
20
+ nil
21
+ end
18
22
  end
19
23
 
20
24
  def fetch(name)
@@ -28,12 +32,15 @@ module SwitchPoint
28
32
  private
29
33
 
30
34
  def assert_valid_config!(config)
31
- [:readonly, :writable].each do |mode|
32
- unless config.has_key?(mode)
33
- raise ArgumentError.new("#{mode} key is required")
34
- end
35
- unless config[mode].is_a?(Symbol)
36
- raise TypeError.new("#{mode}'s value must be Symbol")
35
+ unless config.has_key?(:readonly)
36
+ raise ArgumentError.new(":readonly key is required")
37
+ end
38
+ unless config[:readonly].is_a?(Symbol)
39
+ raise TypeError.new(":readonly's value must be Symbol")
40
+ end
41
+ if config.has_key?(:writable)
42
+ unless config[:writable].is_a?(Symbol)
43
+ raise TypeError.new(":writable's value must be Symbol")
37
44
  end
38
45
  end
39
46
  nil
@@ -7,22 +7,44 @@ module SwitchPoint
7
7
 
8
8
  DESTRUCTIVE_METHODS.each do |method_name|
9
9
  define_method(:"#{method_name}_with_switch_point") do |*args, &block|
10
- switch_point = self.pool.instance_variable_get(:@switch_point)
11
10
  parent_method = :"#{method_name}_without_switch_point"
12
- if switch_point
11
+ if self.pool.equal?(ActiveRecord::Base.connection.pool)
12
+ Connection.handle_base_connection(self, parent_method, *args, &block)
13
+ else
14
+ Connection.handle_generated_connection(self, parent_method, method_name, *args, &block)
15
+ end
16
+ end
17
+ end
18
+
19
+ def self.handle_base_connection(conn, parent_method, *args, &block)
20
+ switch_points = conn.pool.instance_variable_get(:@switch_points)
21
+ if switch_points
22
+ switch_points.each do |switch_point|
13
23
  proxy = ProxyRepository.find(switch_point[:name])
14
- case switch_point[:mode]
15
- when :readonly
16
- Connection.proxy_to_writable(proxy, method_name, *args, &block)
17
- when :writable
18
- Connection.purge_readonly_query_cache(proxy)
19
- send(parent_method, *args, &block)
20
- else
21
- raise RuntimeError.new("Unknown mode #{switch_point[:mode]} is given with #{name}")
24
+ if switch_point[:mode] != :writable
25
+ raise RuntimeError.new("ActiveRecord::Base's switch_points must be writable, but #{switch_point[:name]} is #{switch_point[:mode]}")
22
26
  end
27
+ purge_readonly_query_cache(proxy)
28
+ end
29
+ end
30
+ conn.send(parent_method, *args, &block)
31
+ end
32
+
33
+ def self.handle_generated_connection(conn, parent_method, method_name, *args, &block)
34
+ switch_point = conn.pool.instance_variable_get(:@switch_point)
35
+ if switch_point
36
+ proxy = ProxyRepository.find(switch_point[:name])
37
+ case switch_point[:mode]
38
+ when :readonly
39
+ proxy_to_writable(proxy, method_name, *args, &block)
40
+ when :writable
41
+ purge_readonly_query_cache(proxy)
42
+ conn.send(parent_method, *args, &block)
23
43
  else
24
- send(parent_method, *args, &block)
44
+ raise RuntimeError.new("Unknown mode #{switch_point[:mode]} is given with #{name}")
25
45
  end
46
+ else
47
+ conn.send(parent_method, *args, &block)
26
48
  end
27
49
  end
28
50
 
@@ -9,22 +9,35 @@ module SwitchPoint
9
9
  @initial_name = name
10
10
  @current_name = name
11
11
  AVAILABLE_MODES.each do |mode|
12
- model = define_model(SwitchPoint.config.model_name(name, mode))
13
- model.establish_connection(SwitchPoint.config.database_name(name, mode))
12
+ model = define_model(name, mode)
14
13
  memorize_switch_point(name, mode, model.connection)
15
14
  end
16
15
  @global_mode = DEFAULT_MODE
17
16
  end
18
17
 
19
- def define_model(model_name)
18
+ def define_model(name, mode)
20
19
  model = Class.new(ActiveRecord::Base)
21
- Proxy.const_set(model_name, model)
20
+ model_name = SwitchPoint.config.model_name(name, mode)
21
+ if model_name
22
+ Proxy.const_set(model_name, model)
23
+ model.establish_connection(SwitchPoint.config.database_name(name, mode))
24
+ end
22
25
  model
23
26
  end
24
27
 
25
28
  def memorize_switch_point(name, mode, connection)
26
29
  switch_point = { name: name, mode: mode }
27
- connection.pool.instance_variable_set(:@switch_point, switch_point)
30
+ pool = connection.pool
31
+ if pool.equal?(ActiveRecord::Base.connection.pool)
32
+ if mode != :writable
33
+ raise RuntimeError.new("ActiveRecord::Base's switch_points must be writable, but #{name} is #{mode}")
34
+ end
35
+ switch_points = pool.instance_variable_get(:@switch_points) || []
36
+ switch_points << switch_point
37
+ pool.instance_variable_set(:@switch_points, switch_points)
38
+ else
39
+ pool.instance_variable_set(:@switch_point, switch_point)
40
+ end
28
41
  end
29
42
 
30
43
  def thread_local_mode
@@ -103,7 +116,12 @@ module SwitchPoint
103
116
 
104
117
  def connection
105
118
  ProxyRepository.checkout(@current_name) # Ensure the target proxy is created
106
- Proxy.const_get(SwitchPoint.config.model_name(@current_name, mode)).connection
119
+ model_name = SwitchPoint.config.model_name(@current_name, mode)
120
+ if model_name
121
+ Proxy.const_get(model_name).connection
122
+ else
123
+ ActiveRecord::Base.connection
124
+ end
107
125
  end
108
126
  end
109
127
  end
@@ -1,3 +1,3 @@
1
1
  module SwitchPoint
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
data/spec/models.rb CHANGED
@@ -11,6 +11,10 @@ SwitchPoint.configure do |config|
11
11
  config.define_switch_point :special,
12
12
  readonly: :main_readonly_special,
13
13
  writable: :main_writable
14
+ config.define_switch_point :nanika1,
15
+ readonly: :main_readonly
16
+ config.define_switch_point :nanika2,
17
+ readonly: :main_readonly
14
18
  end
15
19
 
16
20
  class Book < ActiveRecord::Base
@@ -36,6 +40,14 @@ end
36
40
  class Note < ActiveRecord::Base
37
41
  end
38
42
 
43
+ class Nanika1 < ActiveRecord::Base
44
+ use_switch_point :nanika1
45
+ end
46
+
47
+ class Nanika2 < ActiveRecord::Base
48
+ use_switch_point :nanika2
49
+ end
50
+
39
51
  base = { adapter: 'sqlite3' }
40
52
  ActiveRecord::Base.configurations = {
41
53
  'main_readonly' => base.merge(database: 'main_readonly.sqlite3'),
data/spec/spec_helper.rb CHANGED
@@ -24,11 +24,12 @@ RSpec.configure do |config|
24
24
  end
25
25
 
26
26
  config.before(:suite) do
27
- sql = 'CREATE TABLE books (id integer primary key autoincrement)'
28
- Book.connection.execute(sql)
29
27
  Book.with_writable do
30
- Book.connection.execute(sql)
28
+ Book.connection.execute('CREATE TABLE books (id integer primary key autoincrement)')
31
29
  end
30
+ FileUtils.cp('main_writable.sqlite3', 'main_readonly.sqlite3')
31
+
32
+ Note.connection.execute('CREATE TABLE notes (id integer primary key autoincrement)')
32
33
  end
33
34
 
34
35
  config.after(:suite) do
@@ -68,6 +68,23 @@ RSpec.describe SwitchPoint::Model do
68
68
  end
69
69
  end
70
70
  end
71
+
72
+ context 'without :writable' do
73
+ it 'sends destructive queries to ActiveRecord::Base' do
74
+ expect(Nanika1).to connect_to('main_readonly.sqlite3')
75
+ Nanika1.with_writable do
76
+ expect(Nanika1).to connect_to('default.sqlite3')
77
+ expect(Nanika1.connection).to equal(ActiveRecord::Base.connection)
78
+ end
79
+ end
80
+
81
+ it 'clears all query caches' do
82
+ expect(Nanika1.connection).to_not equal(Nanika2.connection)
83
+ expect(Nanika1.connection).to receive(:clear_query_cache).once
84
+ expect(Nanika2.connection).to receive(:clear_query_cache).once
85
+ Note.create
86
+ end
87
+ end
71
88
  end
72
89
 
73
90
  describe '.with_writable' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: switch_point
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kohei Suzuki