switch_point 0.3.0 → 0.3.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 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