switch_point 0.1.0 → 0.2.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 +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/switch_point.rb +9 -2
- data/lib/switch_point/config.rb +4 -0
- data/lib/switch_point/connection.rb +41 -0
- data/lib/switch_point/model.rb +12 -9
- data/lib/switch_point/proxy.rb +4 -6
- data/lib/switch_point/proxy_repository.rb +9 -1
- data/lib/switch_point/version.rb +1 -1
- data/spec/spec_helper.rb +2 -4
- data/spec/switch_point/model_spec.rb +37 -0
- metadata +3 -3
- data/lib/switch_point/writable_connection_hook.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c52a7c39b406241e2df69b1d0dfae3a6c45d15d3
|
4
|
+
data.tar.gz: 606dd78b88ad59873c9d7e187c110163899f1ffb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e9097c7f4e5696728fc57a0f190ccd6a4c65d665f1fbb7cfbc89e67cd77658f288d8a4f16a7360e3e34c103a1fdbb050b132eafc13e077901f1af25f1d8cf75
|
7
|
+
data.tar.gz: 02bcf5bc10f0c2c4a3b7ee04f3d33b1a94edcfc0f1b91ef1ff2251963052983c3d24cdb67f8a80b6e73daae802d1448352eb573a364d41559d228752efe89337
|
data/CHANGELOG.md
CHANGED
data/lib/switch_point.rb
CHANGED
@@ -19,7 +19,7 @@ module SwitchPoint
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def readonly!(name)
|
22
|
-
ProxyRepository.
|
22
|
+
ProxyRepository.checkout(name).readonly!
|
23
23
|
end
|
24
24
|
|
25
25
|
def writable_all!
|
@@ -29,7 +29,7 @@ module SwitchPoint
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def writable!(name)
|
32
|
-
ProxyRepository.
|
32
|
+
ProxyRepository.checkout(name).writable!
|
33
33
|
end
|
34
34
|
end
|
35
35
|
extend ClassMethods
|
@@ -37,5 +37,12 @@ end
|
|
37
37
|
|
38
38
|
ActiveSupport.on_load(:active_record) do
|
39
39
|
require 'switch_point/model'
|
40
|
+
require 'switch_point/connection'
|
40
41
|
ActiveRecord::Base.send(:include, SwitchPoint::Model)
|
42
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
|
43
|
+
include SwitchPoint::Connection
|
44
|
+
SwitchPoint::Connection::DESTRUCTIVE_METHODS.each do |method_name|
|
45
|
+
alias_method_chain method_name, :switch_point
|
46
|
+
end
|
47
|
+
end
|
41
48
|
end
|
data/lib/switch_point/config.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'switch_point/proxy_repository'
|
2
|
+
|
3
|
+
module SwitchPoint
|
4
|
+
module Connection
|
5
|
+
# See ActiveRecord::ConnectionAdapters::QueryCache
|
6
|
+
DESTRUCTIVE_METHODS = [:insert, :update, :delete]
|
7
|
+
|
8
|
+
DESTRUCTIVE_METHODS.each do |method_name|
|
9
|
+
define_method(:"#{method_name}_with_switch_point") do |*args, &block|
|
10
|
+
switch_point = self.pool.instance_variable_get(:@switch_point)
|
11
|
+
parent_method = :"#{method_name}_without_switch_point"
|
12
|
+
if switch_point
|
13
|
+
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}")
|
22
|
+
end
|
23
|
+
else
|
24
|
+
send(parent_method, *args, &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.proxy_to_writable(proxy, method_name, *args, &block)
|
30
|
+
proxy.with_writable do
|
31
|
+
proxy.connection.send(method_name, *args, &block)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.purge_readonly_query_cache(proxy)
|
36
|
+
proxy.with_readonly do
|
37
|
+
proxy.connection.clear_query_cache
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/switch_point/model.rb
CHANGED
@@ -5,21 +5,19 @@ module SwitchPoint
|
|
5
5
|
def self.included(model)
|
6
6
|
model.singleton_class.class_eval do
|
7
7
|
include ClassMethods
|
8
|
-
|
8
|
+
alias_method_chain :connection, :switch_point
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
module
|
13
|
-
def
|
12
|
+
module ClassMethods
|
13
|
+
def connection_with_switch_point
|
14
14
|
if @switch_point_name
|
15
15
|
switch_point_proxy.connection
|
16
16
|
else
|
17
|
-
|
17
|
+
connection_without_switch_point
|
18
18
|
end
|
19
19
|
end
|
20
|
-
end
|
21
20
|
|
22
|
-
module ClassMethods
|
23
21
|
def with_readonly(&block)
|
24
22
|
switch_point_proxy.with_readonly(&block)
|
25
23
|
end
|
@@ -28,14 +26,19 @@ module SwitchPoint
|
|
28
26
|
switch_point_proxy.with_writable(&block)
|
29
27
|
end
|
30
28
|
|
31
|
-
private
|
32
|
-
|
33
29
|
def use_switch_point(name)
|
30
|
+
assert_existing_switch_point!(name)
|
34
31
|
@switch_point_name = name
|
35
32
|
end
|
36
33
|
|
34
|
+
private
|
35
|
+
|
36
|
+
def assert_existing_switch_point!(name)
|
37
|
+
SwitchPoint.config.fetch(name)
|
38
|
+
end
|
39
|
+
|
37
40
|
def switch_point_proxy
|
38
|
-
|
41
|
+
ProxyRepository.checkout(@switch_point_name)
|
39
42
|
end
|
40
43
|
end
|
41
44
|
end
|
data/lib/switch_point/proxy.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'switch_point/writable_connection_hook'
|
2
|
-
|
3
1
|
module SwitchPoint
|
4
2
|
class Proxy
|
5
3
|
def initialize(name)
|
@@ -8,9 +6,8 @@ module SwitchPoint
|
|
8
6
|
model = define_model(SwitchPoint.config.model_name(name, mode))
|
9
7
|
@models[mode] = model
|
10
8
|
model.establish_connection(SwitchPoint.config.database_name(name, mode))
|
11
|
-
|
9
|
+
memorize_switch_point(name, mode, model.connection)
|
12
10
|
end
|
13
|
-
@models[:writable].connection.extend(WritableConnectionHook)
|
14
11
|
@mode = :readonly
|
15
12
|
end
|
16
13
|
|
@@ -20,8 +17,9 @@ module SwitchPoint
|
|
20
17
|
model
|
21
18
|
end
|
22
19
|
|
23
|
-
def
|
24
|
-
|
20
|
+
def memorize_switch_point(name, mode, connection)
|
21
|
+
switch_point = { name: name, mode: mode }
|
22
|
+
connection.pool.instance_variable_set(:@switch_point, switch_point)
|
25
23
|
end
|
26
24
|
|
27
25
|
def readonly!
|
@@ -5,14 +5,22 @@ module SwitchPoint
|
|
5
5
|
class ProxyRepository
|
6
6
|
include Singleton
|
7
7
|
|
8
|
+
def self.checkout(name)
|
9
|
+
instance.checkout(name)
|
10
|
+
end
|
11
|
+
|
8
12
|
def self.find(name)
|
9
13
|
instance.find(name)
|
10
14
|
end
|
11
15
|
|
12
|
-
def
|
16
|
+
def checkout(name)
|
13
17
|
proxies[name] ||= Proxy.new(name)
|
14
18
|
end
|
15
19
|
|
20
|
+
def find(name)
|
21
|
+
proxies.fetch(name)
|
22
|
+
end
|
23
|
+
|
16
24
|
def proxies
|
17
25
|
@proxies ||= {}
|
18
26
|
end
|
data/lib/switch_point/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -38,10 +38,8 @@ RSpec.configure do |config|
|
|
38
38
|
end
|
39
39
|
|
40
40
|
config.after(:each) do
|
41
|
-
Book.delete_all
|
42
|
-
|
43
|
-
Book.delete_all
|
44
|
-
end
|
41
|
+
Book.delete_all # This queries to writable database
|
42
|
+
FileUtils.cp('main_writable.sqlite3', 'main_readonly.sqlite3')
|
45
43
|
end
|
46
44
|
end
|
47
45
|
|
@@ -1,4 +1,26 @@
|
|
1
1
|
RSpec.describe SwitchPoint::Model do
|
2
|
+
describe '.use_switch_point' do
|
3
|
+
after do
|
4
|
+
Book.use_switch_point :main
|
5
|
+
end
|
6
|
+
|
7
|
+
it 'changes connection' do
|
8
|
+
expect(Book).to connect_to('main_readonly.sqlite3')
|
9
|
+
Book.use_switch_point :comment
|
10
|
+
expect(Book).to connect_to('comment_readonly.sqlite3')
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'with non-existing switch point name' do
|
14
|
+
it 'raises error' do
|
15
|
+
expect {
|
16
|
+
Class.new(ActiveRecord::Base) do
|
17
|
+
use_switch_point :not_found
|
18
|
+
end
|
19
|
+
}.to raise_error(KeyError)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
2
24
|
describe '.connection' do
|
3
25
|
it 'returns readonly connection by default' do
|
4
26
|
expect(Book).to connect_to('main_readonly.sqlite3')
|
@@ -8,6 +30,21 @@ RSpec.describe SwitchPoint::Model do
|
|
8
30
|
expect(Note).to connect_to('default.sqlite3')
|
9
31
|
end
|
10
32
|
|
33
|
+
it 'sends destructive queries to writable' do
|
34
|
+
Book.create
|
35
|
+
Book.with_readonly { expect(Book.count).to eq(0) }
|
36
|
+
Book.with_writable { expect(Book.count).to eq(1) }
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'works with newly checked-out connection' do
|
40
|
+
Thread.start do
|
41
|
+
expect(Book.connection.pool.connections.size).to be > 1 # Assertion
|
42
|
+
Book.create
|
43
|
+
Book.with_readonly { expect(Book.count).to eq(0) }
|
44
|
+
Book.with_writable { expect(Book.count).to eq(1) }
|
45
|
+
end.join
|
46
|
+
end
|
47
|
+
|
11
48
|
context 'without switch_point configuration' do
|
12
49
|
it 'returns default connection' do
|
13
50
|
expect(Note.connection).to equal(ActiveRecord::Base.connection)
|
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
|
+
version: 0.2.0
|
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-05-
|
11
|
+
date: 2014-05-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: appraisal
|
@@ -115,11 +115,11 @@ files:
|
|
115
115
|
- gemfiles/rails_4.1.gemfile
|
116
116
|
- lib/switch_point.rb
|
117
117
|
- lib/switch_point/config.rb
|
118
|
+
- lib/switch_point/connection.rb
|
118
119
|
- lib/switch_point/model.rb
|
119
120
|
- lib/switch_point/proxy.rb
|
120
121
|
- lib/switch_point/proxy_repository.rb
|
121
122
|
- lib/switch_point/version.rb
|
122
|
-
- lib/switch_point/writable_connection_hook.rb
|
123
123
|
- spec/models.rb
|
124
124
|
- spec/spec_helper.rb
|
125
125
|
- spec/switch_point/model_spec.rb
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'switch_point/proxy_repository'
|
2
|
-
|
3
|
-
module SwitchPoint
|
4
|
-
# Propagate clear_query_cache in writable connection to readonly connection
|
5
|
-
module WritableConnectionHook
|
6
|
-
# See ActiveRecord::ConnectionAdapters::QueryCache
|
7
|
-
[:insert, :update, :delete].each do |method_name|
|
8
|
-
define_method(method_name) do |*args, &block|
|
9
|
-
proxy = ProxyRepository.find(@switch_point_name)
|
10
|
-
proxy.with_readonly do
|
11
|
-
proxy.connection.clear_query_cache
|
12
|
-
end
|
13
|
-
super(*args, &block)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|