ar-octopus 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/octopus.rb CHANGED
@@ -11,10 +11,16 @@ module Octopus
11
11
  end
12
12
 
13
13
  def self.config()
14
- @config ||= HashWithIndifferentAccess.new(YAML.load(ERB.new(File.open(Octopus.directory() + "/config/shards.yml").read()).result))[Octopus.env()]
14
+ file_name = Octopus.directory() + "/config/shards.yml"
15
15
 
16
- if @config && @config['environments']
17
- self.environments = @config['environments']
16
+ if File.exists? file_name
17
+ @config ||= HashWithIndifferentAccess.new(YAML.load(ERB.new(File.open(file_name).read()).result))[Octopus.env()]
18
+
19
+ if @config && @config['environments']
20
+ self.environments = @config['environments']
21
+ end
22
+ else
23
+ @config ||= HashWithIndifferentAccess.new
18
24
  end
19
25
 
20
26
  @config
@@ -49,6 +55,12 @@ module Octopus
49
55
  defined?(Rails)
50
56
  end
51
57
 
58
+ def self.shards=(shards)
59
+ @config ||= HashWithIndifferentAccess.new
60
+ @config[rails_env()] = HashWithIndifferentAccess.new(shards)
61
+ ActiveRecord::Base.connection.initialize_shards(@config)
62
+ end
63
+
52
64
  def self.using(shard, &block)
53
65
  ActiveRecord::Base.hijack_initializer()
54
66
  conn = ActiveRecord::Base.connection
@@ -71,6 +83,7 @@ require "octopus/association"
71
83
  if Octopus.rails3?
72
84
  require "octopus/rails3/association"
73
85
  require "octopus/rails3/persistence"
86
+ require "octopus/rails3/arel"
74
87
  else
75
88
  require "octopus/rails2/association"
76
89
  require "octopus/rails2/persistence"
@@ -78,4 +91,4 @@ end
78
91
 
79
92
  require "octopus/proxy"
80
93
  require "octopus/scope_proxy"
81
-
94
+ require "octopus/logger"
@@ -0,0 +1,14 @@
1
+ require "logger"
2
+
3
+ class Octopus::Logger < Logger
4
+ def format_message(severity, timestamp, progname, msg)
5
+ str = super
6
+
7
+ if ActiveRecord::Base.connection.respond_to?(:current_shard)
8
+ str += "Shard: #{ActiveRecord::Base.connection.current_shard} -"
9
+ end
10
+
11
+ str
12
+ end
13
+ end
14
+
data/lib/octopus/model.rb CHANGED
@@ -7,14 +7,22 @@ module Octopus::Model
7
7
 
8
8
  module SharedMethods
9
9
  def clean_table_name
10
- self.reset_table_name() if self != ActiveRecord::Base && self.respond_to?(:reset_table_name)
10
+ return unless self.connection_proxy.should_clean_table_name?
11
+ if self != ActiveRecord::Base && self.respond_to?(:reset_table_name) && !self.read_inheritable_attribute(:set_table_name)
12
+ self.reset_table_name()
13
+ end
14
+
15
+ if Octopus.rails3?
16
+ self.reset_column_information
17
+ self.instance_variable_set(:@quoted_table_name, nil)
18
+ end
11
19
  end
12
20
 
13
21
  def using(shard)
14
22
  return self if defined?(::Rails) && !Octopus.environments.include?(Rails.env.to_s)
15
23
 
16
- clean_table_name()
17
24
  hijack_initializer() if !respond_to?(:set_current_shard)
25
+ clean_table_name()
18
26
 
19
27
  self.connection_proxy.using_enabled = true
20
28
 
@@ -23,7 +31,6 @@ module Octopus::Model
23
31
 
24
32
  def hijack_initializer()
25
33
  attr_accessor :current_shard
26
- after_initialize :set_current_shard
27
34
  before_save :reload_connection
28
35
 
29
36
  def set_current_shard
@@ -34,7 +41,9 @@ module Octopus::Model
34
41
  end
35
42
  end
36
43
 
37
- if !Octopus.rails3?
44
+ if Octopus.rails3?
45
+ after_initialize :set_current_shard
46
+ else
38
47
  def after_initialize
39
48
  set_current_shard()
40
49
  end
@@ -90,7 +99,12 @@ module Octopus::Model
90
99
  write_inheritable_attribute(:establish_connection, true)
91
100
  establish_connection(spec)
92
101
  end
102
+
103
+ def octopus_set_table_name(value = nil, &block)
104
+ write_inheritable_attribute(:set_table_name, true)
105
+ set_table_name(value, &block)
106
+ end
93
107
  end
94
108
  end
95
109
 
96
- ActiveRecord::Base.extend(Octopus::Model)
110
+ ActiveRecord::Base.extend(Octopus::Model)
data/lib/octopus/proxy.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require "set"
2
+
1
3
  class Octopus::Proxy
2
4
  attr_accessor :current_model, :current_shard, :current_group, :block, :using_enabled, :last_current_shard, :config
3
5
 
@@ -7,8 +9,9 @@ class Octopus::Proxy
7
9
  end
8
10
 
9
11
  def initialize_shards(config)
10
- @shards = {}
11
- @groups = {}
12
+ @shards = HashWithIndifferentAccess.new
13
+ @groups = HashWithIndifferentAccess.new
14
+ @adapters = Set.new
12
15
  @shards[:master] = ActiveRecord::Base.connection_pool()
13
16
  @config = ActiveRecord::Base.connection_pool.connection.instance_variable_get(:@config)
14
17
  @current_shard = :master
@@ -87,6 +90,10 @@ class Octopus::Proxy
87
90
  current_shard.is_a?(Array) ? current_shard.first : current_shard
88
91
  end
89
92
 
93
+ def should_clean_table_name?
94
+ @adapters.size > 1
95
+ end
96
+
90
97
  def run_queries_on_shard(shard, &block)
91
98
  older_shard = self.current_shard
92
99
  last_block = self.block
@@ -143,12 +150,17 @@ class Octopus::Proxy
143
150
  end
144
151
  end
145
152
 
153
+ def respond_to?(method, include_private = false)
154
+ super || select_connection.respond_to?(method, include_private)
155
+ end
156
+
146
157
  protected
147
158
  def connection_pool_for(adapter, config)
148
159
  ActiveRecord::ConnectionAdapters::ConnectionPool.new(ActiveRecord::Base::ConnectionSpecification.new(adapter, config))
149
160
  end
150
161
 
151
162
  def initialize_adapter(adapter)
163
+ @adapters << adapter
152
164
  begin
153
165
  require "active_record/connection_adapters/#{adapter}_adapter"
154
166
  rescue LoadError
@@ -167,16 +179,19 @@ class Octopus::Proxy
167
179
  def send_queries_to_selected_slave(method, *args, &block)
168
180
  old_shard = self.current_shard
169
181
 
170
- if current_model.read_inheritable_attribute(:replicated) || @fully_replicated
171
- self.current_shard = @slaves_list.shift.to_sym
172
- @slaves_list << self.current_shard
173
- else
174
- self.current_shard = :master
175
- end
182
+ begin
183
+ if current_model.read_inheritable_attribute(:replicated) || @fully_replicated
184
+ self.current_shard = @slaves_list.shift.to_sym
185
+ @slaves_list << self.current_shard
186
+ else
187
+ self.current_shard = :master
188
+ end
176
189
 
177
- sql = select_connection().send(method, *args, &block)
178
- self.current_shard = old_shard
179
- @using_enabled = nil
180
- return sql
190
+ sql = select_connection().send(method, *args, &block)
191
+ return sql
192
+ ensure
193
+ self.current_shard = old_shard
194
+ @using_enabled = nil
195
+ end
181
196
  end
182
197
  end
@@ -0,0 +1,13 @@
1
+ class Arel::Visitors::ToSql
2
+ def quote value, column = nil
3
+ ActiveRecord::Base.connection.quote value, column
4
+ end
5
+
6
+ def quote_table_name name
7
+ ActiveRecord::Base.connection.quote_table_name(name)
8
+ end
9
+
10
+ def quote_column_name name
11
+ Arel::Nodes::SqlLiteral === name ? name : ActiveRecord::Base.connection.quote_column_name(name)
12
+ end
13
+ end
@@ -24,11 +24,11 @@ class Octopus::ScopeProxy
24
24
  @klass.connection()
25
25
  end
26
26
 
27
- def method_missing(method, *args, &block)
27
+ def method_missing(method, *args, &block)
28
28
  @klass.connection.run_queries_on_shard(@shard) do
29
29
  @klass = @klass.send(method, *args, &block)
30
30
  end
31
-
31
+
32
32
  return @klass if @klass.is_a?(ActiveRecord::Base) or @klass.is_a?(Array) or @klass.is_a?(Fixnum) or @klass.nil?
33
33
  return self
34
34
  end
@@ -37,4 +37,4 @@ class Octopus::ScopeProxy
37
37
  @shard == other.shard
38
38
  @klass == other.klass
39
39
  end
40
- end
40
+ end
data/sample_app/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source :rubygems
2
2
 
3
- gem 'rails', '3.0.0'
3
+ gem 'rails', '3.0.5'
4
4
 
5
5
  # Bundle edge Rails instead:
6
6
  # gem 'rails', :git => 'git://github.com/rails/rails.git'
@@ -18,4 +18,4 @@ group :test do
18
18
  gem "rspec-rails", ">= 2.0.0.beta.16"
19
19
  gem 'ruby-debug' if RUBY_VERSION < "1.9"
20
20
  gem "aruba"
21
- end
21
+ end
@@ -1,130 +1,146 @@
1
1
  GIT
2
2
  remote: git://github.com/tchandy/octopus.git
3
- revision: ff16c71
3
+ revision: 13320d08a1d722f1cd4d12468b328a59367a2c88
4
4
  specs:
5
- ar-octopus (0.1.0)
5
+ ar-octopus (0.3.4)
6
6
  activerecord (>= 2.3)
7
7
 
8
8
  GEM
9
9
  remote: http://rubygems.org/
10
10
  specs:
11
11
  abstract (1.0.0)
12
- actionmailer (3.0.0)
13
- actionpack (= 3.0.0)
14
- mail (~> 2.2.5)
15
- actionpack (3.0.0)
16
- activemodel (= 3.0.0)
17
- activesupport (= 3.0.0)
12
+ actionmailer (3.0.5)
13
+ actionpack (= 3.0.5)
14
+ mail (~> 2.2.15)
15
+ actionpack (3.0.5)
16
+ activemodel (= 3.0.5)
17
+ activesupport (= 3.0.5)
18
18
  builder (~> 2.1.2)
19
19
  erubis (~> 2.6.6)
20
- i18n (~> 0.4.1)
20
+ i18n (~> 0.4)
21
21
  rack (~> 1.2.1)
22
- rack-mount (~> 0.6.12)
23
- rack-test (~> 0.5.4)
22
+ rack-mount (~> 0.6.13)
23
+ rack-test (~> 0.5.7)
24
24
  tzinfo (~> 0.3.23)
25
- activemodel (3.0.0)
26
- activesupport (= 3.0.0)
25
+ activemodel (3.0.5)
26
+ activesupport (= 3.0.5)
27
27
  builder (~> 2.1.2)
28
- i18n (~> 0.4.1)
29
- activerecord (3.0.0)
30
- activemodel (= 3.0.0)
31
- activesupport (= 3.0.0)
32
- arel (~> 1.0.0)
28
+ i18n (~> 0.4)
29
+ activerecord (3.0.5)
30
+ activemodel (= 3.0.5)
31
+ activesupport (= 3.0.5)
32
+ arel (~> 2.0.2)
33
33
  tzinfo (~> 0.3.23)
34
- activeresource (3.0.0)
35
- activemodel (= 3.0.0)
36
- activesupport (= 3.0.0)
37
- activesupport (3.0.0)
38
- arel (1.0.1)
39
- activesupport (~> 3.0.0)
40
- aruba (0.2.1)
34
+ activeresource (3.0.5)
35
+ activemodel (= 3.0.5)
36
+ activesupport (= 3.0.5)
37
+ activesupport (3.0.5)
38
+ arel (2.0.9)
39
+ aruba (0.2.7)
40
+ background_process
41
+ cucumber (~> 0.10.0)
42
+ background_process (1.2)
41
43
  builder (2.1.2)
42
- capybara (0.3.9)
44
+ capybara (0.4.1.2)
45
+ celerity (>= 0.7.9)
43
46
  culerity (>= 0.2.4)
44
47
  mime-types (>= 1.16)
45
48
  nokogiri (>= 1.3.3)
46
49
  rack (>= 1.0.0)
47
50
  rack-test (>= 0.5.4)
48
- selenium-webdriver (>= 0.0.3)
49
- columnize (0.3.1)
50
- configuration (1.1.0)
51
- cucumber (0.8.5)
52
- builder (~> 2.1.2)
51
+ selenium-webdriver (>= 0.0.27)
52
+ xpath (~> 0.1.3)
53
+ celerity (0.8.8)
54
+ childprocess (0.1.7)
55
+ ffi (~> 0.6.3)
56
+ columnize (0.3.2)
57
+ configuration (1.2.0)
58
+ cucumber (0.10.0)
59
+ builder (>= 2.1.2)
53
60
  diff-lcs (~> 1.1.2)
54
- gherkin (~> 2.1.4)
55
- json_pure (~> 1.4.3)
56
- term-ansicolor (~> 1.0.4)
61
+ gherkin (~> 2.3.2)
62
+ json (~> 1.4.6)
63
+ term-ansicolor (~> 1.0.5)
57
64
  cucumber-rails (0.3.2)
58
65
  cucumber (>= 0.8.0)
59
- culerity (0.2.12)
60
- database_cleaner (0.5.2)
66
+ culerity (0.2.15)
67
+ database_cleaner (0.6.4)
61
68
  diff-lcs (1.1.2)
62
69
  erubis (2.6.6)
63
70
  abstract (>= 1.0.0)
64
71
  ffi (0.6.3)
65
72
  rake (>= 0.8.7)
66
- gherkin (2.1.5)
67
- trollop (~> 1.16.2)
68
- i18n (0.4.1)
69
- json_pure (1.4.6)
73
+ gherkin (2.3.3)
74
+ json (~> 1.4.6)
75
+ i18n (0.5.0)
76
+ json (1.4.6)
77
+ json_pure (1.5.1)
70
78
  launchy (0.3.7)
71
79
  configuration (>= 0.0.5)
72
80
  rake (>= 0.8.1)
73
81
  linecache (0.43)
74
- mail (2.2.5)
82
+ mail (2.2.15)
75
83
  activesupport (>= 2.3.6)
76
- mime-types
77
- treetop (>= 1.4.5)
84
+ i18n (>= 0.4.0)
85
+ mime-types (~> 1.16)
86
+ treetop (~> 1.4.8)
78
87
  mime-types (1.16)
79
- nokogiri (1.4.3.1)
88
+ nokogiri (1.4.4)
80
89
  polyglot (0.3.1)
81
90
  rack (1.2.1)
82
91
  rack-mount (0.6.13)
83
92
  rack (>= 1.0.0)
84
- rack-test (0.5.4)
93
+ rack-test (0.5.7)
85
94
  rack (>= 1.0)
86
- rails (3.0.0)
87
- actionmailer (= 3.0.0)
88
- actionpack (= 3.0.0)
89
- activerecord (= 3.0.0)
90
- activeresource (= 3.0.0)
91
- activesupport (= 3.0.0)
92
- bundler (~> 1.0.0)
93
- railties (= 3.0.0)
94
- railties (3.0.0)
95
- actionpack (= 3.0.0)
96
- activesupport (= 3.0.0)
97
- rake (>= 0.8.4)
98
- thor (~> 0.14.0)
95
+ rails (3.0.5)
96
+ actionmailer (= 3.0.5)
97
+ actionpack (= 3.0.5)
98
+ activerecord (= 3.0.5)
99
+ activeresource (= 3.0.5)
100
+ activesupport (= 3.0.5)
101
+ bundler (~> 1.0)
102
+ railties (= 3.0.5)
103
+ railties (3.0.5)
104
+ actionpack (= 3.0.5)
105
+ activesupport (= 3.0.5)
106
+ rake (>= 0.8.7)
107
+ thor (~> 0.14.4)
99
108
  rake (0.8.7)
100
- rspec (2.0.0.beta.20)
101
- rspec-core (= 2.0.0.beta.20)
102
- rspec-expectations (= 2.0.0.beta.20)
103
- rspec-mocks (= 2.0.0.beta.20)
104
- rspec-core (2.0.0.beta.20)
105
- rspec-expectations (2.0.0.beta.20)
106
- diff-lcs (>= 1.1.2)
107
- rspec-mocks (2.0.0.beta.20)
108
- rspec-rails (2.0.0.beta.20)
109
- rspec (= 2.0.0.beta.20)
110
- ruby-debug (0.10.3)
109
+ rspec (2.5.0)
110
+ rspec-core (~> 2.5.0)
111
+ rspec-expectations (~> 2.5.0)
112
+ rspec-mocks (~> 2.5.0)
113
+ rspec-core (2.5.1)
114
+ rspec-expectations (2.5.0)
115
+ diff-lcs (~> 1.1.2)
116
+ rspec-mocks (2.5.0)
117
+ rspec-rails (2.5.0)
118
+ actionpack (~> 3.0)
119
+ activesupport (~> 3.0)
120
+ railties (~> 3.0)
121
+ rspec (~> 2.5.0)
122
+ ruby-debug (0.10.4)
111
123
  columnize (>= 0.1)
112
- ruby-debug-base (~> 0.10.3.0)
113
- ruby-debug-base (0.10.3)
124
+ ruby-debug-base (~> 0.10.4.0)
125
+ ruby-debug-base (0.10.4)
114
126
  linecache (>= 0.3)
115
127
  rubyzip (0.9.4)
116
- selenium-webdriver (0.0.28)
117
- ffi (>= 0.6.1)
128
+ selenium-webdriver (0.1.3)
129
+ childprocess (~> 0.1.5)
130
+ ffi (~> 0.6.3)
118
131
  json_pure
119
132
  rubyzip
120
133
  spork (0.8.4)
121
- sqlite3-ruby (1.3.1)
134
+ sqlite3 (1.3.3)
135
+ sqlite3-ruby (1.3.3)
136
+ sqlite3 (>= 1.3.3)
122
137
  term-ansicolor (1.0.5)
123
- thor (0.14.0)
124
- treetop (1.4.8)
138
+ thor (0.14.6)
139
+ treetop (1.4.9)
125
140
  polyglot (>= 0.3.1)
126
- trollop (1.16.2)
127
- tzinfo (0.3.23)
141
+ tzinfo (0.3.24)
142
+ xpath (0.1.3)
143
+ nokogiri (~> 1.3)
128
144
 
129
145
  PLATFORMS
130
146
  ruby
@@ -137,7 +153,7 @@ DEPENDENCIES
137
153
  cucumber-rails
138
154
  database_cleaner
139
155
  launchy
140
- rails (= 3.0.0)
156
+ rails (= 3.0.5)
141
157
  rspec-rails (>= 2.0.0.beta.16)
142
158
  ruby-debug
143
159
  spork