slavery 1.4.3 → 2.0.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/README.md +16 -18
- data/lib/slavery.rb +23 -79
- data/lib/slavery/active_record/base.rb +27 -0
- data/lib/slavery/active_record/relation.rb +28 -0
- data/lib/slavery/base.rb +36 -0
- data/lib/slavery/error.rb +4 -0
- data/lib/slavery/slave_connection_holder.rb +13 -0
- data/lib/slavery/version.rb +1 -1
- data/spec/slavery_spec.rb +47 -31
- data/spec/spec_helper.rb +8 -16
- metadata +7 -4
- data/lib/slavery/railtie.rb +0 -11
- data/lib/slavery/relation.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 844d663a8d247cdb698ca1e17d781749372d980c
|
4
|
+
data.tar.gz: 7fb134582dfa4eb45971cd1afb35f08286aef10f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a227e3ba41594385d60c96692969dbbd59d16c5e952ccfa54daf423526025b25dcc99464f9f7eee4458e8f941db1873d3f57d66d9548f9d80625e7b6c600f241
|
7
|
+
data.tar.gz: 1321abb5bd5394ac032bd5531117a707873251c4fd9026456ad08e3c27fb9383e45f1cdfdc4a6aad4f9080c8bf4de3270432854cfef96d5bb2395c70eb724595
|
data/README.md
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
# Slavery - Simple, conservative slave reads for ActiveRecord
|
2
2
|
|
3
|
-
Slavery is a simple, easy to use
|
3
|
+
Slavery is a simple, easy to use gem for ActiveRecord that enables conservative slave reads, which means it doesn't automatically redirect all SELECTs to slaves.
|
4
4
|
|
5
|
-
|
5
|
+
Instead, you can do `Slavery.on_slave { User.count }` to send a particular query to a slave.
|
6
|
+
|
7
|
+
Background: Probably your app started off with one single database. As it grows, you would upgrade to a master-slave replication for redundancy. At this point, all queries still go to the master and slaves are just backups. With that configuration, it's tempting to run some long-running queries on the slave. And that's exactly what Slavery does.
|
6
8
|
|
7
9
|
* Conservative - Safe by default. Installing Slavery won't change your app's current behavior.
|
8
|
-
* Future proof - No dirty hacks
|
9
|
-
* Simple -
|
10
|
+
* Future proof - No dirty hacks. Simply works as a proxy for `ActiveRecord::Base.connection`.
|
11
|
+
* Simple code - Intentionally small. You can read the entire source and completely stay in control.
|
10
12
|
|
11
13
|
Slavery works with ActiveRecord 3 or later.
|
12
14
|
|
@@ -93,7 +95,7 @@ With MySQL, `GRANT SELECT` creates a read-only user.
|
|
93
95
|
GRANT SELECT ON *.* TO 'readonly'@'localhost';
|
94
96
|
```
|
95
97
|
|
96
|
-
With this user, writes on slave should
|
98
|
+
With this user, writes on slave should raise an exception.
|
97
99
|
|
98
100
|
```ruby
|
99
101
|
Slavery.on_slave { User.create } # => ActiveRecord::StatementInvalid: Mysql2::Error: INSERT command denied...
|
@@ -101,26 +103,24 @@ Slavery.on_slave { User.create } # => ActiveRecord::StatementInvalid: Mysql2::E
|
|
101
103
|
|
102
104
|
It is a good idea to confirm this behavior in your test code as well.
|
103
105
|
|
104
|
-
##
|
105
|
-
|
106
|
-
When one of the master or the slave goes down, you would rewrite `database.yml` to make all queries go to the surviving database, until you restore or rebuild the failed one.
|
106
|
+
## Disable temporarily
|
107
107
|
|
108
|
-
|
108
|
+
You can quickly disable slave reads by dropping the following line in `config/initializers/slavery.rb`.
|
109
109
|
|
110
110
|
```ruby
|
111
111
|
Slavely.disabled = true
|
112
112
|
```
|
113
113
|
|
114
|
-
With this line, Slavery stops connection switching and all queries go to the
|
114
|
+
With this line, Slavery stops connection switching and all queries go to the master.
|
115
|
+
|
116
|
+
This may be useful when one of the master or the slave goes down. You would rewrite `database.yml` to make all queries go to the surviving database, until you restore or rebuild the failed one.
|
115
117
|
|
116
118
|
## Support for non-Rails apps
|
117
119
|
|
118
|
-
If you're using ActiveRecord in a non-Rails app (e.g. Sinatra), be sure to set `
|
120
|
+
If you're using ActiveRecord in a non-Rails app (e.g. Sinatra), be sure to set `RACK_ENV` environment variable in the boot sequence, then:
|
119
121
|
|
120
122
|
```ruby
|
121
|
-
|
122
|
-
|
123
|
-
ActiveRecord::Base.send(:include, Slavery)
|
123
|
+
require 'slavery'
|
124
124
|
|
125
125
|
ActiveRecord::Base.configurations = {
|
126
126
|
'development' => { adapter: 'mysql2', ... },
|
@@ -137,8 +137,6 @@ This is useful for deploying on EngineYard where the configuration key in databa
|
|
137
137
|
Slavery.spec_key = "slave" #instead of production_slave
|
138
138
|
```
|
139
139
|
|
140
|
-
|
140
|
+
## Changelog
|
141
141
|
|
142
|
-
|
143
|
-
Slavery.spec_key = lambda{ "#{Slavery.env}_slave" }
|
144
|
-
```
|
142
|
+
* v2.0.0: Rails 5 support
|
data/lib/slavery.rb
CHANGED
@@ -1,105 +1,49 @@
|
|
1
|
-
require 'slavery/version'
|
2
|
-
require 'slavery/railtie'
|
3
1
|
require 'active_record'
|
2
|
+
require 'slavery/base'
|
3
|
+
require 'slavery/error'
|
4
|
+
require 'slavery/slave_connection_holder'
|
5
|
+
require 'slavery/version'
|
6
|
+
require 'slavery/active_record/base'
|
7
|
+
require 'slavery/active_record/relation'
|
4
8
|
|
5
9
|
module Slavery
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
included do
|
9
|
-
require 'slavery/relation'
|
10
|
-
|
11
|
-
class << self
|
12
|
-
alias_method_chain :connection, :slavery
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class Error < StandardError; end
|
17
|
-
|
18
10
|
class << self
|
19
11
|
attr_accessor :disabled
|
20
|
-
attr_writer :
|
12
|
+
attr_writer :spec_key
|
21
13
|
|
22
14
|
def spec_key
|
23
15
|
case @spec_key
|
24
16
|
when String then @spec_key
|
25
|
-
when
|
26
|
-
when NilClass then @spec_key = "#{Slavery.env}_slave"
|
17
|
+
when NilClass then @spec_key = "#{ActiveRecord::ConnectionHandling::RAILS_ENV.call}_slave"
|
27
18
|
end
|
28
19
|
end
|
29
20
|
|
30
21
|
def on_slave(&block)
|
31
|
-
run
|
22
|
+
Base.new(:slave).run &block
|
32
23
|
end
|
33
24
|
|
34
25
|
def on_master(&block)
|
35
|
-
run
|
36
|
-
end
|
37
|
-
|
38
|
-
def run(new_value)
|
39
|
-
old_value = Thread.current[:on_slave] # Save for recursive nested calls
|
40
|
-
Thread.current[:on_slave] = new_value
|
41
|
-
yield
|
42
|
-
ensure
|
43
|
-
Thread.current[:on_slave] = old_value
|
44
|
-
end
|
45
|
-
|
46
|
-
def env
|
47
|
-
@env ||= defined?(Rails) ? Rails.env.to_s : 'development'
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
module ClassMethods
|
52
|
-
def on_slave
|
53
|
-
# Why where(nil)?
|
54
|
-
# http://stackoverflow.com/questions/18198963/with-rails-4-model-scoped-is-deprecated-but-model-all-cant-replace-it
|
55
|
-
context = where(nil)
|
56
|
-
context.slavery_target = :slave
|
57
|
-
context
|
26
|
+
Base.new(:master).run &block
|
58
27
|
end
|
59
28
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
master_connection
|
29
|
+
def slave_connection_holder
|
30
|
+
@slave_connection_holder ||= begin
|
31
|
+
SlaveConnectionHolder.activate
|
32
|
+
SlaveConnectionHolder
|
65
33
|
end
|
66
34
|
end
|
67
35
|
|
68
|
-
def
|
36
|
+
def base_transaction_depth
|
69
37
|
@base_transaction_depth ||= begin
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
!Slavery.disabled
|
78
|
-
end
|
79
|
-
|
80
|
-
def master_connection
|
81
|
-
connection_without_slavery
|
82
|
-
end
|
83
|
-
|
84
|
-
def slave_connection
|
85
|
-
slave_connection_holder.connection_without_slavery
|
86
|
-
end
|
87
|
-
|
88
|
-
# Create an anonymous AR class to hold slave connection
|
89
|
-
def slave_connection_holder
|
90
|
-
@slave_connection_holder ||= Class.new(ActiveRecord::Base) {
|
91
|
-
self.abstract_class = true
|
92
|
-
|
93
|
-
def self.name
|
94
|
-
"SlaveConnectionHolder"
|
38
|
+
testcase = ActiveSupport::TestCase
|
39
|
+
if defined?(testcase) &&
|
40
|
+
testcase.respond_to?(:use_transactional_fixtures) &&
|
41
|
+
testcase.try(:use_transactional_fixtures)
|
42
|
+
1
|
43
|
+
else
|
44
|
+
0
|
95
45
|
end
|
96
|
-
|
97
|
-
spec = [Slavery.spec_key, Slavery.env].find do |spec_key|
|
98
|
-
ActiveRecord::Base.configurations[spec_key]
|
99
|
-
end or raise Error.new("#{Slavery.spec_key} or #{Slavery.env} must exist!")
|
100
|
-
|
101
|
-
establish_connection spec.to_sym
|
102
|
-
}
|
46
|
+
end
|
103
47
|
end
|
104
48
|
end
|
105
49
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Base
|
3
|
+
class << self
|
4
|
+
alias_method :connection_without_slavery, :connection
|
5
|
+
|
6
|
+
def connection
|
7
|
+
case Thread.current[:slavery]
|
8
|
+
when :slave
|
9
|
+
Slavery.slave_connection_holder.connection_without_slavery
|
10
|
+
when :master, NilClass
|
11
|
+
connection_without_slavery
|
12
|
+
else
|
13
|
+
raise Slavery::Error.new("invalid target: #{Thread.current[:slavery]}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Generate scope at top level e.g. User.on_slave
|
18
|
+
def on_slave
|
19
|
+
# Why where(nil)?
|
20
|
+
# http://stackoverflow.com/questions/18198963/with-rails-4-model-scoped-is-deprecated-but-model-all-cant-replace-it
|
21
|
+
context = where(nil)
|
22
|
+
context.slavery_target = :slave
|
23
|
+
context
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Relation
|
3
|
+
attr_accessor :slavery_target
|
4
|
+
|
5
|
+
# Supports queries like User.on_slave.to_a
|
6
|
+
alias_method :exec_queries_without_slavery, :exec_queries
|
7
|
+
|
8
|
+
def exec_queries
|
9
|
+
if slavery_target == :slave
|
10
|
+
Slavery.on_slave { exec_queries_without_slavery }
|
11
|
+
else
|
12
|
+
exec_queries_without_slavery
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# Supports queries like User.on_slave.count
|
18
|
+
alias_method :calculate_without_slavery, :calculate
|
19
|
+
|
20
|
+
def calculate(*args)
|
21
|
+
if slavery_target == :slave
|
22
|
+
Slavery.on_slave { calculate_without_slavery(*args) }
|
23
|
+
else
|
24
|
+
calculate_without_slavery(*args)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/slavery/base.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Slavery
|
2
|
+
class Base
|
3
|
+
def initialize(target)
|
4
|
+
@target = decide_with(target)
|
5
|
+
end
|
6
|
+
|
7
|
+
def run(&block)
|
8
|
+
run_on @target, &block
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def decide_with(target)
|
14
|
+
raise Slavery::Error.new('on_slave cannot be used inside transaction block!') if inside_transaction?
|
15
|
+
|
16
|
+
if Slavery.disabled
|
17
|
+
:master
|
18
|
+
else
|
19
|
+
target
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def inside_transaction?
|
24
|
+
open_transactions = run_on(:master) { ActiveRecord::Base.connection.open_transactions }
|
25
|
+
open_transactions > Slavery.base_transaction_depth
|
26
|
+
end
|
27
|
+
|
28
|
+
def run_on(target)
|
29
|
+
backup = Thread.current[:slavery] # Save for recursive nested calls
|
30
|
+
Thread.current[:slavery] = target
|
31
|
+
yield
|
32
|
+
ensure
|
33
|
+
Thread.current[:slavery] = backup
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Slavery
|
2
|
+
class SlaveConnectionHolder < ActiveRecord::Base
|
3
|
+
self.abstract_class = true
|
4
|
+
|
5
|
+
class << self
|
6
|
+
# for delayed activation
|
7
|
+
def activate
|
8
|
+
raise Error.new('Slavery.spec_key invalid!') unless ActiveRecord::Base.configurations[Slavery.spec_key]
|
9
|
+
establish_connection Slavery.spec_key.to_sym
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/slavery/version.rb
CHANGED
data/spec/slavery_spec.rb
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Slavery do
|
4
|
+
def slavery_value
|
5
|
+
Thread.current[:slavery]
|
6
|
+
end
|
7
|
+
|
4
8
|
def on_slave?
|
5
|
-
|
9
|
+
slavery_value == :slave
|
6
10
|
end
|
7
11
|
|
8
12
|
it 'sets thread local' do
|
9
|
-
Slavery.on_master { expect(
|
10
|
-
Slavery.on_slave { expect(
|
13
|
+
Slavery.on_master { expect(slavery_value).to be :master }
|
14
|
+
Slavery.on_slave { expect(slavery_value).to be :slave }
|
11
15
|
end
|
12
16
|
|
13
17
|
it 'returns value from block' do
|
@@ -39,36 +43,46 @@ describe Slavery do
|
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
42
|
-
it '
|
46
|
+
it 'raises error in transaction' do
|
43
47
|
User.transaction do
|
44
|
-
expect { User.
|
48
|
+
expect { Slavery.on_slave { User.first } }.to raise_error(Slavery::Error)
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
48
52
|
it 'disables by configuration' do
|
49
|
-
|
50
|
-
|
53
|
+
backup = Slavery.disabled
|
54
|
+
|
55
|
+
Slavery.disabled = false
|
56
|
+
Slavery.on_slave { expect(slavery_value).to be :slave }
|
51
57
|
|
52
|
-
|
53
|
-
Slavery.on_slave { expect(
|
58
|
+
Slavery.disabled = true
|
59
|
+
Slavery.on_slave { expect(slavery_value).to be :master }
|
60
|
+
|
61
|
+
Slavery.disabled = backup
|
54
62
|
end
|
55
63
|
|
56
64
|
it 'sets the Slavery database spec name by configuration' do
|
57
|
-
Slavery.spec_key =
|
65
|
+
Slavery.spec_key = 'custom_slave'
|
58
66
|
expect(Slavery.spec_key).to eq 'custom_slave'
|
67
|
+
end
|
59
68
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
expect(Slavery.spec_key).to eq "kewl_slave"
|
69
|
+
it 'avoids stack overflow with 3rdparty gem that defines alias_method. namely newrelic...' do
|
70
|
+
class ActiveRecord::Relation
|
71
|
+
alias_method :calculate_without_thirdparty, :calculate
|
64
72
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
73
|
+
def calculate(*args)
|
74
|
+
calculate_without_thirdparty(*args)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
expect(User.count).to be 2
|
79
|
+
|
80
|
+
class ActiveRecord::Relation
|
81
|
+
alias_method :calculate, :calculate_without_thirdparty
|
82
|
+
end
|
69
83
|
end
|
70
84
|
|
71
|
-
it 'works with scopes' do
|
85
|
+
it 'works with any scopes' do
|
72
86
|
expect(User.count).to be 2
|
73
87
|
expect(User.on_slave.count).to be 1
|
74
88
|
|
@@ -81,28 +95,30 @@ describe Slavery do
|
|
81
95
|
describe 'configuration' do
|
82
96
|
before do
|
83
97
|
# Backup connection and configs
|
84
|
-
@
|
85
|
-
@
|
86
|
-
|
98
|
+
@backup_conn = Slavery.instance_variable_get :@slave_connection_holder
|
99
|
+
@backup_config = ActiveRecord::Base.configurations.dup
|
100
|
+
@backup_disabled = Slavery.disabled
|
101
|
+
Slavery.instance_variable_set :@slave_connection_holder, nil
|
87
102
|
end
|
88
103
|
|
89
104
|
after do
|
90
105
|
# Restore connection and configs
|
91
|
-
|
92
|
-
ActiveRecord::Base.configurations = @
|
106
|
+
Slavery.instance_variable_set :@slave_connection_holder, @backup_conn
|
107
|
+
ActiveRecord::Base.configurations = @backup_config
|
108
|
+
Slavery.disabled = @backup_disabled
|
93
109
|
end
|
94
110
|
|
95
|
-
it '
|
96
|
-
ActiveRecord::Base.configurations[
|
111
|
+
it 'raises error if slave configuration not specified' do
|
112
|
+
ActiveRecord::Base.configurations['test_slave'] = nil
|
97
113
|
|
98
|
-
expect
|
114
|
+
expect { Slavery.on_slave { User.count } }.to raise_error(Slavery::Error)
|
99
115
|
end
|
100
116
|
|
101
|
-
it '
|
102
|
-
ActiveRecord::Base.configurations['
|
103
|
-
|
117
|
+
it 'connects to master if slave configuration not specified' do
|
118
|
+
ActiveRecord::Base.configurations['test_slave'] = nil
|
119
|
+
Slavery.disabled = true
|
104
120
|
|
105
|
-
expect
|
121
|
+
expect(Slavery.on_slave { User.count }).to be 2
|
106
122
|
end
|
107
123
|
end
|
108
124
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,36 +1,28 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'bundler/setup'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
# Activate Slavery
|
7
|
-
ActiveRecord::Base.send(:include, Slavery)
|
4
|
+
ENV['RACK_ENV'] = 'test'
|
8
5
|
|
9
|
-
|
10
|
-
class User < ActiveRecord::Base
|
11
|
-
end
|
12
|
-
|
13
|
-
# Should be equal to Rails.env
|
14
|
-
Slavery.env = 'test'
|
6
|
+
require 'slavery'
|
15
7
|
|
16
8
|
ActiveRecord::Base.configurations = {
|
17
9
|
'test' => { adapter: 'sqlite3', database: 'test_db' },
|
18
10
|
'test_slave' => { adapter: 'sqlite3', database: 'test_slave_db' }
|
19
11
|
}
|
20
12
|
|
13
|
+
# Prepare databases
|
14
|
+
class User < ActiveRecord::Base
|
15
|
+
end
|
16
|
+
|
21
17
|
# Create two records on master
|
22
18
|
ActiveRecord::Base.establish_connection(:test)
|
23
|
-
ActiveRecord::Base.connection.create_table :users, force: true
|
24
|
-
t.boolean :disabled
|
25
|
-
end
|
19
|
+
ActiveRecord::Base.connection.create_table :users, force: true
|
26
20
|
User.create
|
27
21
|
User.create
|
28
22
|
|
29
23
|
# Create one record on slave, emulating replication lag
|
30
24
|
ActiveRecord::Base.establish_connection(:test_slave)
|
31
|
-
ActiveRecord::Base.connection.create_table :users, force: true
|
32
|
-
t.boolean :disabled
|
33
|
-
end
|
25
|
+
ActiveRecord::Base.connection.create_table :users, force: true
|
34
26
|
User.create
|
35
27
|
|
36
28
|
# Reconnect to master
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: slavery
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kenn Ejima
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -66,8 +66,11 @@ files:
|
|
66
66
|
- README.md
|
67
67
|
- Rakefile
|
68
68
|
- lib/slavery.rb
|
69
|
-
- lib/slavery/
|
70
|
-
- lib/slavery/relation.rb
|
69
|
+
- lib/slavery/active_record/base.rb
|
70
|
+
- lib/slavery/active_record/relation.rb
|
71
|
+
- lib/slavery/base.rb
|
72
|
+
- lib/slavery/error.rb
|
73
|
+
- lib/slavery/slave_connection_holder.rb
|
71
74
|
- lib/slavery/version.rb
|
72
75
|
- slavery.gemspec
|
73
76
|
- spec/slavery_spec.rb
|
data/lib/slavery/railtie.rb
DELETED
data/lib/slavery/relation.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
class ActiveRecord::Relation
|
2
|
-
attr_accessor :slavery_target
|
3
|
-
|
4
|
-
# Supports queries like User.on_slave.to_a
|
5
|
-
def exec_queries_with_slavery
|
6
|
-
if slavery_target == :slave
|
7
|
-
Slavery.on_slave { exec_queries_without_slavery }
|
8
|
-
else
|
9
|
-
exec_queries_without_slavery
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
# Supports queries like User.on_slave.count
|
14
|
-
def calculate_with_slavery(operation, column_name, options = {})
|
15
|
-
if slavery_target == :slave
|
16
|
-
Slavery.on_slave { calculate_without_slavery(operation, column_name, options) }
|
17
|
-
else
|
18
|
-
calculate_without_slavery(operation, column_name, options)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
alias_method_chain :exec_queries, :slavery
|
23
|
-
alias_method_chain :calculate, :slavery
|
24
|
-
end
|