slavery 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cf1496eaaf7ad5d9839bf821fc4fafd5b48d2f4c
4
+ data.tar.gz: 6b3f1389be627e4e46af04b15b31a6efbba80907
5
+ SHA512:
6
+ metadata.gz: a5c25149caf8f300de53c07e7c2f3892ee1ff1d06972332357fae177a7a407aac2417467e0a60695f03e69552a38c5cd6aeea8670e2003220768770a01a7dd34
7
+ data.tar.gz: aa386b5a735bd33ff57338e20bcfb0928dc1d8e8aa9092e4452f0f87d8f10e05e522b1dc7f62a94f6345545c308ce18563f89364013bd906bd74a5fadb1f08e6
data/README.md CHANGED
@@ -22,13 +22,9 @@ And create slave configs for each environment.
22
22
 
23
23
  ```yaml
24
24
  development:
25
- adapter: mysql2
26
- username: root
27
25
  database: myapp_development
28
26
 
29
27
  development_slave:
30
- adapter: mysql2
31
- username: root
32
28
  database: myapp_development
33
29
  ```
34
30
 
@@ -36,7 +32,22 @@ By convention, config keys with `[env]_slave` are automatically used for slave r
36
32
 
37
33
  Notice that we just copied the settings of `development` to `development_slave`. For `development` and `test`, it's actually recommended as probably you don't want to have replicating multiple databases on your machine. Two connections to the same identical database should be fine for testing purpose.
38
34
 
39
- At this point, Slavery does nothing. Run tests and confirm that anything isn't broken.
35
+ In case you prefer DRYer definition, YAML's aliasing and key merging might help.
36
+
37
+ ```yaml
38
+ common: &common
39
+ adapter: mysql2
40
+ username: root
41
+ database: myapp_development
42
+
43
+ development:
44
+ <<: *common
45
+
46
+ development_slave:
47
+ <<: *common
48
+ ```
49
+
50
+ At this point, Slavery does nothing. Run tests and confirm that nothing is broken.
40
51
 
41
52
  ## Usage
42
53
 
@@ -58,15 +69,22 @@ Slavery.on_slave do
58
69
  end
59
70
  ```
60
71
 
72
+ Alternatively, you may call `on_slave` directly on the scope, so that the query will be read from slave when it's executed.
73
+
74
+ ```ruby
75
+ User.on_slave.where(active: true).count
76
+ ```
77
+
78
+ Caveat: `pluck` is not supported by the scope syntax, you still need `Slavery.on_slave` in this case.
79
+
61
80
  ## Read-only user
62
81
 
63
82
  For an extra safeguard, it is recommended to use a read-only user for slave access.
64
83
 
65
- ```ruby
84
+ ```yaml
66
85
  development_slave:
67
- adapter: mysql2
86
+ <<: *common
68
87
  username: readonly
69
- database: myapp_development
70
88
  ```
71
89
 
72
90
  With MySQL, `GRANT SELECT` creates a read-only user.
@@ -81,7 +99,7 @@ With this user, writes on slave should raises an exception.
81
99
  Slavery.on_slave { User.create } # => ActiveRecord::StatementInvalid: Mysql2::Error: INSERT command denied...
82
100
  ```
83
101
 
84
- It is a good idea to confirm this behavior in your test code.
102
+ It is a good idea to confirm this behavior in your test code as well.
85
103
 
86
104
  ## Database failure
87
105
 
@@ -7,6 +7,8 @@ module Slavery
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
+ require 'slavery/relation'
11
+
10
12
  class << self
11
13
  alias_method_chain :connection, :slavery
12
14
  end
@@ -16,13 +18,21 @@ module Slavery
16
18
 
17
19
  mattr_accessor :disabled
18
20
 
19
- module ModuleFunctions
21
+ class << self
20
22
  def on_slave(&block)
21
- ActiveRecord::Base.on_slave(&block)
23
+ run true, &block
22
24
  end
23
25
 
24
26
  def on_master(&block)
25
- ActiveRecord::Base.on_master(&block)
27
+ run false, &block
28
+ end
29
+
30
+ def run(new_value)
31
+ old_value = Thread.current[:on_slave] # Save for recursive nested calls
32
+ Thread.current[:on_slave] = new_value
33
+ yield
34
+ ensure
35
+ Thread.current[:on_slave] = old_value
26
36
  end
27
37
 
28
38
  def env
@@ -34,23 +44,12 @@ module Slavery
34
44
  @env = ActiveSupport::StringInquirer.new(string)
35
45
  end
36
46
  end
37
- extend ModuleFunctions
38
47
 
39
48
  module ClassMethods
40
- def on_slave(&block)
41
- with_slavery true, &block
42
- end
43
-
44
- def on_master(&block)
45
- with_slavery false, &block
46
- end
47
-
48
- def with_slavery(new_value)
49
- old_value = Thread.current[:on_slave] # Save for recursive nested calls
50
- Thread.current[:on_slave] = new_value
51
- yield
52
- ensure
53
- Thread.current[:on_slave] = old_value
49
+ def on_slave
50
+ context = scoped
51
+ context.slavery_target = :slave
52
+ context
54
53
  end
55
54
 
56
55
  def connection_with_slavery
@@ -0,0 +1,24 @@
1
+ class ActiveRecord::Relation
2
+ attr_accessor :slavery_target
3
+
4
+ # Supports queries like User.on_slave.all
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
@@ -1,3 +1,3 @@
1
1
  module Slavery
2
- VERSION = '1.1.1'
2
+ VERSION = '1.2.0'
3
3
  end
@@ -53,6 +53,14 @@ describe Slavery do
53
53
  Slavery.on_slave { User.slaveryable?.should == false }
54
54
  end
55
55
 
56
+ it 'works with scopes' do
57
+ User.count.should == 2
58
+ User.on_slave.count.should == 1
59
+
60
+ User.scoped.to_a.size.should == 2
61
+ User.on_slave.scoped.to_a.size.should == 1
62
+ end
63
+
56
64
  describe 'configuration' do
57
65
  before do
58
66
  # Backup connection and configs
metadata CHANGED
@@ -1,62 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slavery
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
5
- prerelease:
4
+ version: 1.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Kenn Ejima
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-10-02 00:00:00.000000000 Z
11
+ date: 2013-05-23 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: activerecord
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: 3.0.0
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: 3.0.0
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rspec
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: sqlite3
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - '>='
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - '>='
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  description: Simple, conservative slave reads for ActiveRecord
@@ -74,35 +67,34 @@ files:
74
67
  - Rakefile
75
68
  - lib/slavery.rb
76
69
  - lib/slavery/railtie.rb
70
+ - lib/slavery/relation.rb
77
71
  - lib/slavery/version.rb
78
72
  - slavery.gemspec
79
73
  - spec/slavery_spec.rb
80
74
  - spec/spec_helper.rb
81
75
  homepage: https://github.com/kenn/slavery
82
76
  licenses: []
77
+ metadata: {}
83
78
  post_install_message:
84
79
  rdoc_options: []
85
80
  require_paths:
86
81
  - lib
87
82
  required_ruby_version: !ruby/object:Gem::Requirement
88
- none: false
89
83
  requirements:
90
- - - ! '>='
84
+ - - '>='
91
85
  - !ruby/object:Gem::Version
92
86
  version: '0'
93
87
  required_rubygems_version: !ruby/object:Gem::Requirement
94
- none: false
95
88
  requirements:
96
- - - ! '>='
89
+ - - '>='
97
90
  - !ruby/object:Gem::Version
98
91
  version: '0'
99
92
  requirements: []
100
93
  rubyforge_project:
101
- rubygems_version: 1.8.19
94
+ rubygems_version: 2.0.3
102
95
  signing_key:
103
- specification_version: 3
96
+ specification_version: 4
104
97
  summary: Simple, conservative slave reads for ActiveRecord
105
98
  test_files:
106
99
  - spec/slavery_spec.rb
107
100
  - spec/spec_helper.rb
108
- has_rdoc: