active_record_shards 3.5.0.pre.alpha → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2f5934528264e0c87553401c8e2c2f46c54e7da9
4
- data.tar.gz: 5ab7c3b24998adf54238edaea4cb8bb088c103b3
3
+ metadata.gz: 9adfc3476e718a0178c8781868e0ef96fc77bc85
4
+ data.tar.gz: 678e2b636c88a52d427236523c417b67d32bc3e1
5
5
  SHA512:
6
- metadata.gz: 8198cd8aedfc3dbebdc413fbc8c5c6eb9ade10539853700c8cd1666e574c8dcdcc777d306d9d9615aef74e331082bbdbed15a713931a80a57f324190e43a4bfa
7
- data.tar.gz: 13d1be9a552f677a2ac9be01b82b372b1817868f1edeb07ffe3111b9388ab19d35563a25597fd46844385a112230d2ad2c4bedf44a661396ffae5f3d464f84ca
6
+ metadata.gz: 84e2df24248d209b3dcca3a6942064a84cbfabc2b2ef4afdbad24e4350b5ceca876d84e8ceec00b6821cca4c939e7aad2313fda4e06e39df0164c1dc997c188f
7
+ data.tar.gz: 678577457e7212e8b36c5498c0c5416a781fa0bffc31d49cd36085b0f6f4a1d7d9b09f592a13944a2df815b06578ae00d14827c704f8529cf7961267e926fb03
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  ActiveRecord Shards is an extension for ActiveRecord that provides support for sharded database and slaves. Basically it is just a nice way to
4
4
  switch between database connections. We've made the implementation very small, and have tried not to reinvent any wheels already present in ActiveRecord.
5
5
 
6
- ActiveRecord Shards has used and tested on Rails 3.0.x, 3.2.x, 4.0.x, and 4.1.x and has in some form or another been used in production on a large rails app for
6
+ ActiveRecord Shards has used and tested on Rails 3.2.x, 4.0.x, 4.1.x and 4.2.x and has in some form or another been used in production on a large rails app for
7
7
  more than a year.
8
8
 
9
9
  ## Installation
@@ -47,10 +47,10 @@ All the models that live on the shared database must be marked as not\_sharded:
47
47
 
48
48
  class Account < ActiveRecord::Base
49
49
  not_sharded
50
-
50
+
51
51
  has_many :projects
52
52
  end
53
-
53
+
54
54
  class Project < ActiveRecord::Base
55
55
  belongs_to :account
56
56
  end
@@ -62,10 +62,10 @@ in a rack middleware and switch to the right shard:
62
62
  def initialize(app)
63
63
  @app = app
64
64
  end
65
-
65
+
66
66
  def call(env)
67
67
  account = lookup_account(env)
68
-
68
+
69
69
  if account
70
70
  ActiveRecord::Base.on_shard(account.shard_id) do
71
71
  @app.call(env)
@@ -74,7 +74,7 @@ in a rack middleware and switch to the right shard:
74
74
  @app.call(env)
75
75
  end
76
76
  end
77
-
77
+
78
78
  def lookup_account(env)
79
79
  ...
80
80
  end
@@ -98,4 +98,3 @@ Copyright (c) 2011 Zendesk. See LICENSE for details.
98
98
  Mick Staugaard, Eric Chapweske
99
99
 
100
100
  [![Build Status](https://secure.travis-ci.org/osheroff/active_record_shards.png)](http://travis-ci.org/osheroff/active_record_shards)
101
-
@@ -33,16 +33,16 @@ if ActiveRecord.const_defined?(:Relation)
33
33
  end
34
34
 
35
35
  if ActiveRecord::Associations.const_defined?(:Preloader) && ActiveRecord::Associations::Preloader.const_defined?(:HasAndBelongsToMany)
36
- ActiveRecord::Associations::Preloader::HasAndBelongsToMany.send(:include, ActiveRecordShards::DefaultSlavePatches::HasAndBelongsToManyPreloaderPatches)
36
+ ActiveRecord::Associations::Preloader::HasAndBelongsToMany.send(:prepend, ActiveRecordShards::DefaultSlavePatches::HasAndBelongsToManyPreloaderPatches)
37
37
  end
38
38
 
39
- if ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR >= 1
40
- ActiveRecord::Associations::Builder::HasAndBelongsToMany.send(:include, ActiveRecordShards::DefaultSlavePatches::Rails41HasAndBelongsToManyBuilderExtension)
39
+ if ActiveRecord::VERSION::STRING >= '4.1.0'
40
+ ActiveRecord::Associations::Builder::HasAndBelongsToMany.send(:prepend, ActiveRecordShards::DefaultSlavePatches::Rails41HasAndBelongsToManyBuilderExtension)
41
41
  end
42
42
 
43
43
  ActiveRecord::Associations::CollectionProxy.send(:include, ActiveRecordShards::AssociationCollectionConnectionSelection)
44
44
 
45
- if ActiveRecord::VERSION::MAJOR >= 4 && RUBY_VERSION >= '2'
45
+ if ActiveRecord::VERSION::MAJOR >= 4
46
46
  ActiveRecord::SchemaDumper.send(:prepend, ActiveRecordShards::SchemaDumperExtension)
47
47
  end
48
48
 
@@ -53,16 +53,17 @@ module ActiveRecordShards
53
53
  env ||= ENV['RAILS_ENV']
54
54
  env ||= 'development'
55
55
  end
56
- end
57
56
 
58
- ActiveRecord::Base.singleton_class.class_eval do
59
- def establish_connection_with_connection_pool_name(spec = nil)
60
- case spec
61
- when ActiveRecordShards::ConnectionSpecification
62
- connection_handler.establish_connection(connection_pool_name, spec)
63
- else
64
- establish_connection_without_connection_pool_name(spec)
57
+ module ActiveRecordConnectionPoolName
58
+ def establish_connection(spec = nil)
59
+ case spec
60
+ when ActiveRecordShards::ConnectionSpecification
61
+ connection_handler.establish_connection(connection_pool_name, spec)
62
+ else
63
+ super
64
+ end
65
65
  end
66
66
  end
67
- alias_method_chain :establish_connection, :connection_pool_name
68
67
  end
68
+
69
+ ActiveRecord::Base.singleton_class.send(:prepend, ActiveRecordShards::ActiveRecordConnectionPoolName)
@@ -35,16 +35,15 @@ module ActiveRecordShards
35
35
  end
36
36
  end
37
37
 
38
- def configurations_with_shard_explosion=(conf)
39
- self.configurations_without_shard_explosion = explode(conf)
38
+ module PrependMethods
39
+ def configurations=(conf)
40
+ super(explode(conf))
41
+ end
40
42
  end
41
43
 
42
44
  def ConfigurationParser.extended(klass)
43
- klass.singleton_class.alias_method_chain :configurations=, :shard_explosion
44
-
45
- if !klass.configurations.nil? && !klass.configurations.empty?
46
- klass.configurations = klass.configurations
47
- end
45
+ klass.singleton_class.send(:prepend, PrependMethods)
46
+ klass.configurations = klass.configurations if klass.configurations.present?
48
47
  end
49
48
  end
50
49
  end
@@ -13,21 +13,20 @@ module ActiveRecordShards
13
13
  # ActiveRecordShards.override_connection_handler_methods(methods_to_override)
14
14
  #
15
15
  def self.override_connection_handler_methods(method_names)
16
+ injected_module = Module.new
16
17
  method_names.each do |method_name|
17
- ActiveRecord::ConnectionAdapters::ConnectionHandler.class_eval do
18
- define_method("#{method_name}_with_connection_pool_name") do |*args|
19
- unless args[0].is_a? ConnectionPoolNameDecorator
20
- name = if args[0].is_a? String
21
- args[0]
22
- else
23
- args[0].connection_pool_name
24
- end
25
- args[0] = ConnectionPoolNameDecorator.new(name)
26
- end
27
- send("#{method_name}_without_connection_pool_name", *args)
18
+ injected_module.send(:define_method, method_name) do |*args|
19
+ unless args[0].is_a? ConnectionPoolNameDecorator
20
+ name = if args[0].is_a? String
21
+ args[0]
22
+ else
23
+ args[0].connection_pool_name
24
+ end
25
+ args[0] = ConnectionPoolNameDecorator.new(name)
28
26
  end
29
- alias_method_chain method_name, :connection_pool_name
27
+ super(*args)
30
28
  end
31
29
  end
30
+ ActiveRecord::ConnectionAdapters::ConnectionHandler.send(:prepend, injected_module)
32
31
  end
33
32
  end
@@ -1,6 +1,6 @@
1
1
  class ActiveRecord::Base
2
2
  def self.establish_connection(spec = ENV["DATABASE_URL"])
3
- if ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR >= 1
3
+ if ActiveRecord::VERSION::STRING >= '4.1.0'
4
4
  spec ||= ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
5
5
  spec = spec.to_sym if spec.is_a?(String)
6
6
  resolver = ActiveRecordShards::ConnectionSpecification::Resolver.new configurations
@@ -4,9 +4,28 @@ module ActiveRecordShards
4
4
  module ConnectionSwitcher
5
5
  SHARD_NAMES_CONFIG_KEY = 'shard_names'.freeze
6
6
 
7
+ module PrependMethods
8
+ def columns
9
+ if is_sharded? && current_shard_id.nil? && table_name != ActiveRecord::Migrator.schema_migrations_table_name
10
+ on_first_shard { super }
11
+ else
12
+ super
13
+ end
14
+ end
15
+
16
+ def table_exists?
17
+ result = super()
18
+
19
+ if !result && is_sharded? && (shard_name = shard_names.first)
20
+ result = on_shard(shard_name) { super }
21
+ end
22
+
23
+ result
24
+ end
25
+ end
26
+
7
27
  def self.extended(klass)
8
- klass.singleton_class.alias_method_chain :columns, :default_shard
9
- klass.singleton_class.alias_method_chain :table_exists?, :default_shard
28
+ klass.singleton_class.send(:prepend, ActiveRecordShards::ConnectionSwitcher::PrependMethods)
10
29
  end
11
30
 
12
31
  def default_shard=(new_default_shard)
@@ -181,7 +200,7 @@ module ActiveRecordShards
181
200
  # note that since we're subverting the standard establish_connection path, we have to handle the funky autoloading of the
182
201
  # connection adapter ourselves.
183
202
  specification_cache[name] ||= begin
184
- if ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR >= 1
203
+ if ActiveRecord::VERSION::STRING >= '4.1.0'
185
204
  resolver = ActiveRecordShards::ConnectionSpecification::Resolver.new configurations
186
205
  resolver.spec(spec)
187
206
  else
@@ -215,24 +234,6 @@ module ActiveRecordShards
215
234
  specs_to_pools.has_key?(connection_pool_key)
216
235
  end
217
236
 
218
- def columns_with_default_shard
219
- if is_sharded? && current_shard_id.nil? && table_name != ActiveRecord::Migrator.schema_migrations_table_name
220
- on_first_shard { columns_without_default_shard }
221
- else
222
- columns_without_default_shard
223
- end
224
- end
225
-
226
- def table_exists_with_default_shard?
227
- result = table_exists_without_default_shard?
228
-
229
- if !result && is_sharded? && (shard_name = shard_names.first)
230
- result = on_shard(shard_name) { table_exists_without_default_shard? }
231
- end
232
-
233
- result
234
- end
235
-
236
237
  def autoload_adapter(adapter_name)
237
238
  begin
238
239
  require 'rubygems'
@@ -9,66 +9,59 @@ module ActiveRecordShards
9
9
  end
10
10
 
11
11
  return unless base_methods.include?(method)
12
- _, method, punctuation = method.to_s.match(/^(.*?)([\?\!]?)$/).to_a
13
- base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
14
- #{class_method ? "class << self" : ""}
15
- def #{method}_with_default_slave#{punctuation}(*args, &block)
16
- on_slave_unless_tx do
17
- #{method}_without_default_slave#{punctuation}(*args, &block)
18
- end
19
- end
20
-
21
- alias_method_chain :#{method}#{punctuation}, :default_slave
22
- #{class_method ? "end" : ""}
23
- RUBY
12
+ injected_module = Module.new
13
+ injected_module.send(:define_method, method) do |*args, &block|
14
+ on_slave_unless_tx do
15
+ super(*args, &block)
16
+ end
17
+ end
18
+ (class_method ? base.singleton_class : base).send(:prepend, injected_module)
24
19
  end
25
20
 
26
21
  CLASS_SLAVE_METHODS = [ :find_by_sql, :count_by_sql, :calculate, :find_one, :find_some, :find_every, :quote_value, :sanitize_sql_hash_for_conditions, :exists?, :table_exists? ]
27
22
 
28
- def self.extended(base)
29
- CLASS_SLAVE_METHODS.each { |m| ActiveRecordShards::DefaultSlavePatches.wrap_method_in_on_slave(true, base, m) }
30
-
31
- base.class_eval do
32
- # fix ActiveRecord to do the right thing, and use our aliased quote_value
33
- def quote_value(*args, &block)
34
- self.class.quote_value(*args, &block)
23
+ module PrependClassMethods
24
+ def columns
25
+ if on_slave_by_default? && !Thread.current[:_active_record_shards_slave_off]
26
+ read_columns_from = :slave
27
+ else
28
+ read_columns_form = :master
35
29
  end
36
30
 
37
- def reload_with_slave_off(*args, &block)
38
- self.class.on_master { reload_without_slave_off(*args, &block) }
39
- end
40
- alias_method_chain :reload, :slave_off
41
-
42
- class << self
43
- def columns_with_default_slave(*args, &block)
44
- if on_slave_by_default? && !Thread.current[:_active_record_shards_slave_off]
45
- read_columns_from = :slave
46
- else
47
- read_columns_form = :master
48
- end
49
-
50
- on_cx_switch_block(read_columns_from, :construct_ro_scope => false) { columns_without_default_slave(*args, &block) }
51
- end
52
- alias_method_chain :columns, :default_slave
31
+ on_cx_switch_block(read_columns_from, construct_ro_scope: false) { super }
32
+ end
33
+
34
+ def transaction(*args, &block)
35
+ if on_slave_by_default?
36
+ old_val = Thread.current[:_active_record_shards_slave_off]
37
+ Thread.current[:_active_record_shards_slave_off] = true
53
38
  end
54
39
 
55
- class << self
56
- def transaction_with_slave_off(*args, &block)
57
- if on_slave_by_default?
58
- old_val = Thread.current[:_active_record_shards_slave_off]
59
- Thread.current[:_active_record_shards_slave_off] = true
60
- end
61
-
62
- transaction_without_slave_off(*args, &block)
63
- ensure
64
- if on_slave_by_default?
65
- Thread.current[:_active_record_shards_slave_off] = old_val
66
- end
67
- end
68
-
69
- alias_method_chain :transaction, :slave_off
40
+ super(*args, &block)
41
+ ensure
42
+ if on_slave_by_default?
43
+ Thread.current[:_active_record_shards_slave_off] = old_val
70
44
  end
71
45
  end
46
+ end
47
+
48
+ module PrependMethods
49
+ # fix ActiveRecord to do the right thing, and use our aliased quote_value
50
+ def quote_value(*args, &block)
51
+ self.class.quote_value(*args, &block)
52
+ end
53
+
54
+ def reload(*args, &block)
55
+ self.class.on_master { super(*args, &block) }
56
+ end
57
+ end
58
+
59
+ def self.extended(base)
60
+ base.send(:prepend, PrependMethods)
61
+ base.singleton_class.send(:prepend, PrependClassMethods)
62
+
63
+ CLASS_SLAVE_METHODS.each { |m| ActiveRecordShards::DefaultSlavePatches.wrap_method_in_on_slave(true, base, m) }
64
+
72
65
  if ActiveRecord::Associations.const_defined?(:HasAndBelongsToManyAssociation)
73
66
  ActiveRecordShards::DefaultSlavePatches.wrap_method_in_on_slave(false, ActiveRecord::Associations::HasAndBelongsToManyAssociation, :construct_sql)
74
67
  ActiveRecordShards::DefaultSlavePatches.wrap_method_in_on_slave(false, ActiveRecord::Associations::HasAndBelongsToManyAssociation, :construct_find_options!)
@@ -96,7 +89,7 @@ module ActiveRecordShards
96
89
  end
97
90
 
98
91
  module HasAndBelongsToManyPreloaderPatches
99
- def self.included(base)
92
+ def self.prepended(base)
100
93
  ActiveRecordShards::DefaultSlavePatches.wrap_method_in_on_slave(false, base, :records_for) rescue nil
101
94
  end
102
95
 
@@ -104,8 +97,8 @@ module ActiveRecordShards
104
97
  klass.on_slave_unless_tx { yield }
105
98
  end
106
99
 
107
- def exists_with_default_slave?(*args, &block)
108
- on_slave_unless_tx { exists_without_default_slave?(*args, &block) }
100
+ def exists?(*args, &block)
101
+ on_slave_unless_tx { super(*args, &block) }
109
102
  end
110
103
  end
111
104
 
@@ -113,14 +106,8 @@ module ActiveRecordShards
113
106
  # this simplifies the hell out of our existence, because all we have to do is inerit on-slave-by-default
114
107
  # down from the parent now.
115
108
  module Rails41HasAndBelongsToManyBuilderExtension
116
- def self.included(base)
117
- base.class_eval do
118
- alias_method_chain :through_model, :inherit_default_slave_from_lhs
119
- end
120
- end
121
-
122
- def through_model_with_inherit_default_slave_from_lhs
123
- model = through_model_without_inherit_default_slave_from_lhs
109
+ def through_model
110
+ model = super
124
111
  def model.on_slave_by_default?
125
112
  left_reflection.klass.on_slave_by_default?
126
113
  end
@@ -1,18 +1,23 @@
1
- module ActiveRecord
2
- class Migrator
3
- class << self
4
- [:up, :down, :run].each do |m|
5
- define_method("#{m}_with_sharding") do |*args|
6
- ActiveRecord::Base.on_shard(nil) do
7
- self.send("#{m}_without_sharding", *args)
8
- end
9
- ActiveRecord::Base.on_all_shards do
10
- self.send("#{m}_without_sharding", *args)
11
- end
1
+ module ActiveRecordShards
2
+ module Migrator
3
+ [:up, :down, :run].each do |m|
4
+ define_method(m) do |*args|
5
+ ActiveRecord::Base.on_shard(nil) do
6
+ super(*args)
7
+ end
8
+ ActiveRecord::Base.on_all_shards do
9
+ super(*args)
12
10
  end
13
- alias_method_chain m.to_sym, :sharding
14
11
  end
12
+ end
13
+ end
14
+ end
15
15
 
16
+ ActiveRecord::Migrator.singleton_class.send(:prepend, ActiveRecordShards::Migrator)
17
+
18
+ module ActiveRecord
19
+ class Migrator
20
+ class << self
16
21
  def bootstrap_migrations_from_nil_shard(migrations_path, this_migration=nil)
17
22
  migrations = nil
18
23
  ActiveRecord::Base.on_shard(nil) do
@@ -83,7 +88,7 @@ module ActiveRecordShards
83
88
  # migration, where it should have been. But this makes our monkey patch incompatible.
84
89
  # So we're forced to *either* include or extend this.
85
90
  module ActualMigrationExtension
86
- def migrate_with_forced_shard(direction)
91
+ def migrate(direction)
87
92
  if migration_shard.blank?
88
93
  raise RuntimeError, "#{self.name}: Can't run migrations without a shard spec: this may be :all, :none,
89
94
  or a specific shard (for data-fixups). please call shard(arg) in your migration."
@@ -98,7 +103,7 @@ module ActiveRecordShards
98
103
  return if migration_shard != :all && migration_shard.to_s != shard.to_s
99
104
  end
100
105
 
101
- migrate_without_forced_shard(direction)
106
+ super
102
107
  end
103
108
  end
104
109
  end
@@ -106,11 +111,10 @@ end
106
111
  ActiveRecord::Migration.class_eval do
107
112
  extend ActiveRecordShards::MigrationClassExtension
108
113
 
109
- include ActiveRecordShards::ActualMigrationExtension
114
+ prepend ActiveRecordShards::ActualMigrationExtension
110
115
  define_method :migration_shard do
111
116
  self.class.migration_shard
112
117
  end
113
- alias_method_chain :migrate, :forced_shard
114
118
  end
115
119
 
116
120
  ActiveRecord::MigrationProxy.delegate :migration_shard, :to => :migration
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_shards
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.5.0.pre.alpha
4
+ version: 3.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mick Staugaard
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-08-06 00:00:00.000000000 Z
13
+ date: 2015-12-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: 3.2.16
22
22
  - - "<"
23
23
  - !ruby/object:Gem::Version
24
- version: '5.0'
24
+ version: '5.1'
25
25
  type: :runtime
26
26
  prerelease: false
27
27
  version_requirements: !ruby/object:Gem::Requirement
@@ -31,7 +31,7 @@ dependencies:
31
31
  version: 3.2.16
32
32
  - - "<"
33
33
  - !ruby/object:Gem::Version
34
- version: '5.0'
34
+ version: '5.1'
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: activesupport
37
37
  requirement: !ruby/object:Gem::Requirement
@@ -41,7 +41,7 @@ dependencies:
41
41
  version: 3.2.16
42
42
  - - "<"
43
43
  - !ruby/object:Gem::Version
44
- version: '5.0'
44
+ version: '5.1'
45
45
  type: :runtime
46
46
  prerelease: false
47
47
  version_requirements: !ruby/object:Gem::Requirement
@@ -51,7 +51,7 @@ dependencies:
51
51
  version: 3.2.16
52
52
  - - "<"
53
53
  - !ruby/object:Gem::Version
54
- version: '5.0'
54
+ version: '5.1'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: wwtd
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -184,17 +184,17 @@ require_paths:
184
184
  - lib
185
185
  required_ruby_version: !ruby/object:Gem::Requirement
186
186
  requirements:
187
- - - ">="
187
+ - - "~>"
188
188
  - !ruby/object:Gem::Version
189
- version: '0'
189
+ version: '2.0'
190
190
  required_rubygems_version: !ruby/object:Gem::Requirement
191
191
  requirements:
192
- - - ">"
192
+ - - ">="
193
193
  - !ruby/object:Gem::Version
194
- version: 1.3.1
194
+ version: '0'
195
195
  requirements: []
196
196
  rubyforge_project:
197
- rubygems_version: 2.4.5
197
+ rubygems_version: 2.5.0
198
198
  signing_key:
199
199
  specification_version: 4
200
200
  summary: Simple database switching for ActiveRecord.