active_record_shards 3.5.0.pre.alpha → 3.6.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 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.