active_record_shards 3.11.2 → 3.19.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 +5 -5
- data/README.md +120 -57
- data/lib/active_record_shards/association_collection_connection_selection.rb +23 -16
- data/lib/active_record_shards/configuration_parser.rb +19 -5
- data/lib/active_record_shards/connection_handler.rb +3 -8
- data/lib/active_record_shards/connection_pool.rb +1 -0
- data/lib/active_record_shards/connection_specification.rb +7 -16
- data/lib/active_record_shards/connection_switcher-4-2.rb +56 -0
- data/lib/active_record_shards/connection_switcher-5-0.rb +1 -1
- data/lib/active_record_shards/connection_switcher-5-1.rb +1 -1
- data/lib/active_record_shards/connection_switcher.rb +74 -57
- data/lib/active_record_shards/default_replica_patches.rb +278 -0
- data/lib/active_record_shards/default_slave_patches.rb +3 -148
- data/lib/active_record_shards/deprecation.rb +12 -0
- data/lib/active_record_shards/migration.rb +35 -31
- data/lib/active_record_shards/model.rb +17 -12
- data/lib/active_record_shards/patches-4-2.rb +1 -5
- data/lib/active_record_shards/schema_dumper_extension.rb +6 -5
- data/lib/active_record_shards/shard_selection.rb +28 -26
- data/lib/active_record_shards/shard_support.rb +1 -0
- data/lib/active_record_shards/sql_comments.rb +11 -4
- data/lib/active_record_shards/tasks.rb +40 -35
- data/lib/active_record_shards.rb +111 -7
- metadata +61 -58
- data/lib/active_record_shards/connection_switcher-4-0.rb +0 -68
- data/lib/active_record_shards/patches-3-2.rb +0 -11
- data/lib/active_record_shards/patches-5-0.rb +0 -15
@@ -1,43 +1,50 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module ActiveRecord
|
3
4
|
class Migrator
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
send("#{m}_without_sharding", *args)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
alias_method :"#{m}_without_sharding", m.to_sym
|
15
|
-
alias_method m.to_sym, :"#{m}_with_sharding"
|
5
|
+
def self.shards_migration_context
|
6
|
+
if ActiveRecord::VERSION::MAJOR >= 6
|
7
|
+
ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths, ActiveRecord::SchemaMigration)
|
8
|
+
elsif ActiveRecord::VERSION::STRING >= '5.2.0'
|
9
|
+
ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths)
|
10
|
+
else
|
11
|
+
self
|
16
12
|
end
|
13
|
+
end
|
17
14
|
|
18
|
-
|
19
|
-
|
20
|
-
ActiveRecord::Base.on_shard(nil) do
|
21
|
-
migrations = ActiveRecord::Migrator.new(:up, migrations_path).migrated
|
22
|
-
end
|
15
|
+
def initialize_with_sharding(*args)
|
16
|
+
initialize_without_sharding(*args)
|
23
17
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
if this_migration
|
31
|
-
migrator.__send__(:record_version_state_after_migrating, this_migration)
|
32
|
-
end
|
18
|
+
# Rails creates the internal tables on the unsharded DB. We make them
|
19
|
+
# manually on the sharded DBs.
|
20
|
+
ActiveRecord::Base.on_all_shards do
|
21
|
+
ActiveRecord::SchemaMigration.create_table
|
22
|
+
if ActiveRecord::VERSION::MAJOR >= 5
|
23
|
+
ActiveRecord::InternalMetadata.create_table
|
33
24
|
end
|
34
25
|
end
|
35
26
|
end
|
27
|
+
alias_method :initialize_without_sharding, :initialize
|
28
|
+
alias_method :initialize, :initialize_with_sharding
|
29
|
+
|
30
|
+
def run_with_sharding
|
31
|
+
ActiveRecord::Base.on_shard(nil) { run_without_sharding }
|
32
|
+
ActiveRecord::Base.on_all_shards { run_without_sharding }
|
33
|
+
end
|
34
|
+
alias_method :run_without_sharding, :run
|
35
|
+
alias_method :run, :run_with_sharding
|
36
|
+
|
37
|
+
def migrate_with_sharding
|
38
|
+
ActiveRecord::Base.on_shard(nil) { migrate_without_sharding }
|
39
|
+
ActiveRecord::Base.on_all_shards { migrate_without_sharding }
|
40
|
+
end
|
41
|
+
alias_method :migrate_without_sharding, :migrate
|
42
|
+
alias_method :migrate, :migrate_with_sharding
|
36
43
|
|
37
44
|
# don't allow Migrator class to cache versions
|
38
45
|
undef migrated
|
39
46
|
def migrated
|
40
|
-
self.class.get_all_versions
|
47
|
+
self.class.shards_migration_context.get_all_versions
|
41
48
|
end
|
42
49
|
|
43
50
|
# list of pending migrations is any migrations that haven't run on all shards.
|
@@ -56,7 +63,7 @@ module ActiveRecord
|
|
56
63
|
missing = {}
|
57
64
|
|
58
65
|
collect = lambda do |shard|
|
59
|
-
migrated = get_all_versions
|
66
|
+
migrated = shards_migration_context.get_all_versions
|
60
67
|
|
61
68
|
p = versions - migrated
|
62
69
|
pending[shard] = p if p.any?
|
@@ -82,9 +89,6 @@ module ActiveRecordShards
|
|
82
89
|
end
|
83
90
|
end
|
84
91
|
|
85
|
-
# ok, so some 'splaining to do. Rails 3.1 puts the migrate() method on the instance of the
|
86
|
-
# migration, where it should have been. But this makes our monkey patch incompatible.
|
87
|
-
# So we're forced to *either* include or extend this.
|
88
92
|
module ActualMigrationExtension
|
89
93
|
def migrate_with_forced_shard(direction)
|
90
94
|
if migration_shard.blank?
|
@@ -6,10 +6,11 @@ module ActiveRecordShards
|
|
6
6
|
if self != ActiveRecord::Base && self != base_class
|
7
7
|
raise "You should only call not_sharded on direct descendants of ActiveRecord::Base"
|
8
8
|
end
|
9
|
+
|
9
10
|
self.sharded = false
|
10
11
|
end
|
11
12
|
|
12
|
-
def is_sharded? # rubocop:disable
|
13
|
+
def is_sharded? # rubocop:disable Naming/PredicateName
|
13
14
|
if self == ActiveRecord::Base
|
14
15
|
sharded != false && supports_sharding?
|
15
16
|
elsif self == base_class
|
@@ -23,34 +24,38 @@ module ActiveRecordShards
|
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
26
|
-
def
|
27
|
+
def on_replica_by_default?
|
27
28
|
if self == ActiveRecord::Base
|
28
29
|
false
|
29
30
|
else
|
30
31
|
base = base_class
|
31
|
-
if base.instance_variable_defined?(:@
|
32
|
-
base.instance_variable_get(:@
|
32
|
+
if base.instance_variable_defined?(:@on_replica_by_default)
|
33
|
+
base.instance_variable_get(:@on_replica_by_default)
|
33
34
|
end
|
34
35
|
end
|
35
36
|
end
|
37
|
+
alias_method :on_slave_by_default?, :on_replica_by_default?
|
36
38
|
|
37
|
-
def
|
39
|
+
def on_replica_by_default=(value)
|
38
40
|
if self == ActiveRecord::Base
|
39
|
-
raise ArgumentError, "Cannot set
|
41
|
+
raise ArgumentError, "Cannot set on_replica_by_default on ActiveRecord::Base"
|
40
42
|
else
|
41
|
-
base_class.instance_variable_set(:@
|
43
|
+
base_class.instance_variable_set(:@on_replica_by_default, value)
|
42
44
|
end
|
43
45
|
end
|
46
|
+
alias_method :on_slave_by_default=, :on_replica_by_default=
|
44
47
|
|
45
48
|
module InstanceMethods
|
46
|
-
def
|
47
|
-
@
|
49
|
+
def initialize_shard_and_replica
|
50
|
+
@from_replica = !!self.class.current_shard_selection.options[:replica]
|
48
51
|
@from_shard = self.class.current_shard_selection.options[:shard]
|
49
52
|
end
|
53
|
+
alias_method :initialize_shard_and_slave, :initialize_shard_and_replica
|
50
54
|
|
51
|
-
def
|
52
|
-
@
|
55
|
+
def from_replica?
|
56
|
+
@from_replica
|
53
57
|
end
|
58
|
+
alias_method :from_slave?, :from_replica?
|
54
59
|
|
55
60
|
def from_shard
|
56
61
|
@from_shard
|
@@ -59,7 +64,7 @@ module ActiveRecordShards
|
|
59
64
|
|
60
65
|
def self.extended(base)
|
61
66
|
base.send(:include, InstanceMethods)
|
62
|
-
base.after_initialize :
|
67
|
+
base.after_initialize :initialize_shard_and_replica
|
63
68
|
end
|
64
69
|
|
65
70
|
private
|
@@ -1,13 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'active_record_shards/connection_pool'
|
3
4
|
require 'active_record_shards/connection_handler'
|
4
5
|
require 'active_record_shards/connection_specification'
|
5
|
-
require 'active_record_shards/schema_dumper_extension'
|
6
6
|
|
7
7
|
ActiveRecordShards::ConnectionSpecification = ActiveRecord::ConnectionAdapters::ConnectionSpecification
|
8
8
|
methods_to_override = [:establish_connection, :remove_connection, :pool_for, :pool_from_any_process_for]
|
9
9
|
ActiveRecordShards.override_connection_handler_methods(methods_to_override)
|
10
|
-
|
11
|
-
ActiveRecord::Associations::Builder::HasAndBelongsToMany.include(ActiveRecordShards::DefaultSlavePatches::Rails41HasAndBelongsToManyBuilderExtension)
|
12
|
-
|
13
|
-
ActiveRecord::SchemaDumper.prepend(ActiveRecordShards::SchemaDumperExtension)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module ActiveRecordShards
|
3
4
|
module SchemaDumperExtension
|
4
5
|
def dump(stream)
|
@@ -23,15 +24,15 @@ module ActiveRecordShards
|
|
23
24
|
def shard_header(stream)
|
24
25
|
define_params = @version ? "version: #{@version}" : ""
|
25
26
|
|
26
|
-
stream.puts
|
27
|
+
stream.puts <<~HEADER
|
27
28
|
|
28
29
|
|
29
|
-
# This section generated by active_record_shards
|
30
|
+
# This section generated by active_record_shards
|
30
31
|
|
31
|
-
ActiveRecord::Base.on_all_shards do
|
32
|
-
ActiveRecord::Schema.define(#{define_params}) do
|
32
|
+
ActiveRecord::Base.on_all_shards do
|
33
|
+
ActiveRecord::Schema.define(#{define_params}) do
|
33
34
|
|
34
|
-
HEADER
|
35
|
+
HEADER
|
35
36
|
end
|
36
37
|
|
37
38
|
def shard_trailer(stream)
|
@@ -1,11 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module ActiveRecordShards
|
3
4
|
class ShardSelection
|
4
5
|
NO_SHARD = :_no_shard
|
5
6
|
cattr_accessor :default_shard
|
6
7
|
|
7
8
|
def initialize
|
8
|
-
@
|
9
|
+
@on_replica = false
|
9
10
|
@shard = nil
|
10
11
|
end
|
11
12
|
|
@@ -21,17 +22,17 @@ module ActiveRecordShards
|
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
|
-
def shard_name(klass = nil,
|
25
|
+
def shard_name(klass = nil, try_replica = true)
|
25
26
|
the_shard = shard(klass)
|
26
27
|
|
27
28
|
@shard_names ||= {}
|
28
29
|
@shard_names[ActiveRecordShards.rails_env] ||= {}
|
29
30
|
@shard_names[ActiveRecordShards.rails_env][the_shard] ||= {}
|
30
|
-
@shard_names[ActiveRecordShards.rails_env][the_shard][
|
31
|
-
@shard_names[ActiveRecordShards.rails_env][the_shard][
|
31
|
+
@shard_names[ActiveRecordShards.rails_env][the_shard][try_replica] ||= {}
|
32
|
+
@shard_names[ActiveRecordShards.rails_env][the_shard][try_replica][@on_replica] ||= begin
|
32
33
|
s = ActiveRecordShards.rails_env.dup
|
33
34
|
s << "_shard_#{the_shard}" if the_shard
|
34
|
-
s << "
|
35
|
+
s << "_replica" if @on_replica && try_replica
|
35
36
|
s
|
36
37
|
end
|
37
38
|
end
|
@@ -46,25 +47,24 @@ module ActiveRecordShards
|
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
49
|
-
PRIMARY = "primary"
|
50
|
+
PRIMARY = "primary"
|
50
51
|
def resolve_connection_name(sharded:, configurations:)
|
51
52
|
resolved_shard = sharded ? shard : nil
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
@
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
53
|
+
env = ActiveRecordShards.rails_env
|
54
|
+
|
55
|
+
@connection_names ||= {}
|
56
|
+
@connection_names[env] ||= {}
|
57
|
+
@connection_names[env][resolved_shard] ||= {}
|
58
|
+
@connection_names[env][resolved_shard][@on_replica] ||= begin
|
59
|
+
name = env.dup
|
60
|
+
name << "_shard_#{resolved_shard}" if resolved_shard
|
61
|
+
if @on_replica && configurations["#{name}_replica"]
|
62
|
+
"#{name}_replica"
|
63
|
+
else
|
64
|
+
# ActiveRecord always names its default connection pool 'primary'
|
65
|
+
# while everything else is named by the configuration name
|
66
|
+
resolved_shard ? name : PRIMARY
|
66
67
|
end
|
67
|
-
s
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -74,16 +74,18 @@ module ActiveRecordShards
|
|
74
74
|
@shard = (new_shard || NO_SHARD)
|
75
75
|
end
|
76
76
|
|
77
|
-
def
|
78
|
-
@
|
77
|
+
def on_replica?
|
78
|
+
@on_replica
|
79
79
|
end
|
80
|
+
alias_method :on_slave?, :on_replica?
|
80
81
|
|
81
|
-
def
|
82
|
-
@
|
82
|
+
def on_replica=(new_replica)
|
83
|
+
@on_replica = (new_replica == true)
|
83
84
|
end
|
85
|
+
alias_method :on_slave=, :on_replica=
|
84
86
|
|
85
87
|
def options
|
86
|
-
{ shard: @shard,
|
88
|
+
{ shard: @shard, replica: @on_replica }
|
87
89
|
end
|
88
90
|
end
|
89
91
|
end
|
@@ -1,16 +1,23 @@
|
|
1
|
-
# show which connection was picked to debug
|
1
|
+
# show which connection was picked to debug primary/replica slowness when both servers are the same
|
2
2
|
module ActiveRecordShards
|
3
3
|
module SqlComments
|
4
4
|
module Methods
|
5
5
|
def execute(query, name = nil)
|
6
|
-
|
7
|
-
|
6
|
+
shard = ActiveRecord::Base.current_shard_selection.shard
|
7
|
+
shard_text = shard ? "shard #{shard}" : 'unsharded'
|
8
|
+
replica = ActiveRecord::Base.current_shard_selection.on_replica?
|
9
|
+
replica_text = replica ? 'replica' : 'primary'
|
10
|
+
query = "/* #{shard_text} #{replica_text} */ " + query
|
8
11
|
super(query, name)
|
9
12
|
end
|
10
13
|
end
|
11
14
|
|
12
15
|
def self.enable
|
13
|
-
ActiveRecord::Base.
|
16
|
+
ActiveRecord::Base.on_replica do
|
17
|
+
ActiveRecord::Base.on_shard(nil) do
|
18
|
+
ActiveRecord::Base.connection.class.prepend(Methods)
|
19
|
+
end
|
20
|
+
end
|
14
21
|
end
|
15
22
|
end
|
16
23
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'active_record_shards'
|
3
4
|
|
4
5
|
%w[db:drop db:create db:abort_if_pending_migrations db:reset db:test:purge].each do |name|
|
@@ -8,15 +9,16 @@ end
|
|
8
9
|
namespace :db do
|
9
10
|
desc 'Drops the database for the current RAILS_ENV including shards'
|
10
11
|
task drop: :load_config do
|
11
|
-
ActiveRecord::Base.configurations.each do |key, conf|
|
12
|
-
next if !key.
|
12
|
+
ActiveRecord::Base.configurations.to_h.each do |key, conf|
|
13
|
+
next if !key.start_with?(ActiveRecordShards.rails_env) || key.end_with?("_replica", "_slave")
|
14
|
+
|
13
15
|
begin
|
14
16
|
ActiveRecordShards::Tasks.root_connection(conf).drop_database(conf['database'])
|
15
17
|
# rescue ActiveRecord::NoDatabaseError # TODO: exists in AR but never is raised here ...
|
16
18
|
# $stderr.puts "Database '#{conf['database']}' does not exist"
|
17
|
-
rescue StandardError =>
|
18
|
-
|
19
|
-
|
19
|
+
rescue StandardError => e
|
20
|
+
warn e, *e.backtrace
|
21
|
+
warn "Couldn't drop #{conf['database']}"
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
@@ -28,25 +30,22 @@ namespace :db do
|
|
28
30
|
|
29
31
|
desc "Create the database defined in config/database.yml for the current RAILS_ENV including shards"
|
30
32
|
task create: :load_config do
|
31
|
-
ActiveRecord::Base.configurations.each do |key, conf|
|
32
|
-
next if !key.
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
33
|
+
ActiveRecord::Base.configurations.to_h.each do |key, conf|
|
34
|
+
next if !key.start_with?(ActiveRecordShards.rails_env) || key.end_with?("_replica", "_slave")
|
35
|
+
|
36
|
+
begin
|
37
|
+
# MysqlAdapter takes charset instead of encoding in Rails 4.2 or greater
|
38
|
+
# https://github.com/rails/rails/blob/4-2-stable/activerecord/lib/active_record/tasks/mysql_database_tasks.rb#L85-L96
|
39
|
+
symbolized_configuration = conf.symbolize_keys
|
40
|
+
symbolized_configuration[:charset] = symbolized_configuration[:encoding]
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
42
|
+
ActiveRecordShards::Tasks.root_connection(conf).create_database(conf['database'], symbolized_configuration)
|
43
|
+
rescue ActiveRecord::StatementInvalid => e
|
44
|
+
if e.message.include?('database exists')
|
45
|
+
puts "#{conf['database']} already exists"
|
46
|
+
else
|
47
|
+
raise e
|
47
48
|
end
|
48
|
-
else
|
49
|
-
create_database(conf)
|
50
49
|
end
|
51
50
|
end
|
52
51
|
ActiveRecord::Base.establish_connection(ActiveRecordShards.rails_env.to_sym)
|
@@ -56,16 +55,20 @@ namespace :db do
|
|
56
55
|
task abort_if_pending_migrations: :environment do
|
57
56
|
if defined? ActiveRecord
|
58
57
|
pending_migrations =
|
59
|
-
if
|
60
|
-
|
58
|
+
if ActiveRecord::VERSION::MAJOR >= 6
|
59
|
+
migrations = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths, ActiveRecord::SchemaMigration).migrations
|
60
|
+
ActiveRecord::Migrator.new(:up, migrations, ActiveRecord::SchemaMigration).pending_migrations
|
61
|
+
elsif ActiveRecord::VERSION::STRING >= "5.2.0"
|
62
|
+
migrations = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths).migrations
|
63
|
+
ActiveRecord::Migrator.new(:up, migrations).pending_migrations
|
61
64
|
else
|
62
|
-
ActiveRecord::Base.on_shard(nil) { ActiveRecord::Migrator.
|
65
|
+
ActiveRecord::Base.on_shard(nil) { ActiveRecord::Migrator.open(ActiveRecord::Migrator.migrations_paths).pending_migrations }
|
63
66
|
end
|
64
67
|
|
65
68
|
if pending_migrations.any?
|
66
|
-
|
69
|
+
warn "You have #{pending_migrations.size} pending migrations:"
|
67
70
|
pending_migrations.each do |pending_migration|
|
68
|
-
|
71
|
+
warn ' %4d %s' % [pending_migration.version, pending_migration.name]
|
69
72
|
end
|
70
73
|
abort %(Run "rake db:migrate" to update your database then try again.)
|
71
74
|
end
|
@@ -89,17 +92,19 @@ end
|
|
89
92
|
|
90
93
|
module ActiveRecordShards
|
91
94
|
module Tasks
|
92
|
-
|
93
|
-
def
|
94
|
-
ActiveRecord::Base.send("#{conf['adapter']}_connection", conf.merge('database' => nil))
|
95
|
-
end
|
96
|
-
else
|
97
|
-
def self.root_connection(conf)
|
98
|
-
# this will trigger rails to load the adapter
|
95
|
+
class << self
|
96
|
+
def root_connection(conf)
|
99
97
|
conf = conf.merge('database' => nil)
|
98
|
+
spec = spec_for(conf)
|
99
|
+
|
100
|
+
ActiveRecord::Base.send("#{conf['adapter']}_connection", spec.config)
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def spec_for(conf)
|
100
106
|
resolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(ActiveRecord::Base.configurations)
|
101
107
|
resolver.spec(conf)
|
102
|
-
ActiveRecord::Base.send("#{conf['adapter']}_connection", conf)
|
103
108
|
end
|
104
109
|
end
|
105
110
|
end
|
data/lib/active_record_shards.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'active_record'
|
3
4
|
require 'active_record/base'
|
4
5
|
require 'active_record_shards/configuration_parser'
|
@@ -7,7 +8,8 @@ require 'active_record_shards/shard_selection'
|
|
7
8
|
require 'active_record_shards/connection_switcher'
|
8
9
|
require 'active_record_shards/association_collection_connection_selection'
|
9
10
|
require 'active_record_shards/migration'
|
10
|
-
require 'active_record_shards/
|
11
|
+
require 'active_record_shards/default_replica_patches'
|
12
|
+
require 'active_record_shards/schema_dumper_extension'
|
11
13
|
|
12
14
|
module ActiveRecordShards
|
13
15
|
def self.rails_env
|
@@ -21,17 +23,119 @@ end
|
|
21
23
|
ActiveRecord::Base.extend(ActiveRecordShards::ConfigurationParser)
|
22
24
|
ActiveRecord::Base.extend(ActiveRecordShards::Model)
|
23
25
|
ActiveRecord::Base.extend(ActiveRecordShards::ConnectionSwitcher)
|
24
|
-
ActiveRecord::Base.extend(ActiveRecordShards::
|
25
|
-
ActiveRecord::Relation.include(ActiveRecordShards::
|
26
|
+
ActiveRecord::Base.extend(ActiveRecordShards::DefaultReplicaPatches)
|
27
|
+
ActiveRecord::Relation.include(ActiveRecordShards::DefaultReplicaPatches::ActiveRelationPatches)
|
26
28
|
ActiveRecord::Associations::CollectionProxy.include(ActiveRecordShards::AssociationCollectionConnectionSelection)
|
29
|
+
ActiveRecord::Associations::Builder::HasAndBelongsToMany.include(ActiveRecordShards::DefaultReplicaPatches::Rails41HasAndBelongsToManyBuilderExtension)
|
30
|
+
ActiveRecord::SchemaDumper.prepend(ActiveRecordShards::SchemaDumperExtension)
|
27
31
|
|
28
32
|
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
29
|
-
when '3.2'
|
30
|
-
require 'active_record_shards/patches-3-2'
|
31
33
|
when '4.2'
|
32
34
|
require 'active_record_shards/patches-4-2'
|
33
|
-
|
34
|
-
|
35
|
+
|
36
|
+
# https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/association.rb#L97
|
37
|
+
ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationAssociationScopePatch)
|
38
|
+
|
39
|
+
# https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/singular_association.rb#L44-L53
|
40
|
+
ActiveRecord::Associations::SingularAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
|
41
|
+
|
42
|
+
# https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/collection_association.rb#L447-L456
|
43
|
+
ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
|
44
|
+
|
45
|
+
# https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/preloader/association.rb#L89
|
46
|
+
ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationAssociatedRecordsByOwnerPatch)
|
47
|
+
when '5.0'
|
48
|
+
# https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/association.rb#L97
|
49
|
+
ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationAssociationScopePatch)
|
50
|
+
|
51
|
+
# https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/singular_association.rb#L56-L65
|
52
|
+
ActiveRecord::Associations::SingularAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
|
53
|
+
|
54
|
+
# https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/collection_association.rb#L442-L451
|
55
|
+
ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
|
56
|
+
|
57
|
+
# https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/preloader/association.rb#L120
|
58
|
+
ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationLoadRecordsPatch)
|
59
|
+
when '5.1'
|
60
|
+
# https://github.com/rails/rails/blob/v5.1.7/activerecord/lib/active_record/associations/association.rb#L97
|
61
|
+
ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationAssociationScopePatch)
|
62
|
+
|
63
|
+
# https://github.com/rails/rails/blob/v5.1.7/activerecord/lib/active_record/associations/singular_association.rb#L41
|
64
|
+
ActiveRecord::Associations::SingularAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
|
65
|
+
|
66
|
+
# https://github.com/rails/rails/blob/v5.1.7/activerecord/lib/active_record/associations/collection_association.rb#L305
|
67
|
+
ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
|
68
|
+
|
69
|
+
# https://github.com/rails/rails/blob/v5.1.7/activerecord/lib/active_record/associations/preloader/association.rb#L120
|
70
|
+
ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationLoadRecordsPatch)
|
71
|
+
when '5.2'
|
72
|
+
# https://github.com/rails/rails/blob/v5.2.6/activerecord/lib/active_record/relation.rb#L530
|
73
|
+
# But the #exec_queries method also calls #connection, and I don't know if we should patch that one, too...
|
74
|
+
ActiveRecord::Relation.prepend(ActiveRecordShards::DefaultReplicaPatches::Rails52RelationPatches)
|
75
|
+
|
76
|
+
# https://github.com/rails/rails/blob/v5.2.6/activerecord/lib/active_record/associations/singular_association.rb#L42
|
77
|
+
ActiveRecord::Associations::SingularAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
|
78
|
+
|
79
|
+
# https://github.com/rails/rails/blob/v5.2.6/activerecord/lib/active_record/associations/collection_association.rb#L308
|
80
|
+
ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
|
81
|
+
|
82
|
+
# https://github.com/rails/rails/blob/v5.2.6/activerecord/lib/active_record/associations/preloader/association.rb#L96
|
83
|
+
ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationLoadRecordsPatch)
|
84
|
+
when '6.0'
|
85
|
+
# https://github.com/rails/rails/blob/v6.0.4/activerecord/lib/active_record/type_caster/connection.rb#L28
|
86
|
+
ActiveRecord::TypeCaster::Connection.prepend(ActiveRecordShards::DefaultReplicaPatches::TypeCasterConnectionConnectionPatch)
|
87
|
+
|
88
|
+
# https://github.com/rails/rails/blob/v6.0.4/activerecord/lib/active_record/schema.rb#L53-L54
|
89
|
+
ActiveRecord::Schema.prepend(ActiveRecordShards::DefaultReplicaPatches::SchemaDefinePatch)
|
90
|
+
|
91
|
+
# https://github.com/rails/rails/blob/v6.0.4/activerecord/lib/active_record/relation.rb#L739
|
92
|
+
# But the #exec_queries and #compute_cache_version methods also call #connection, and I don't know if we should patch those, too...
|
93
|
+
ActiveRecord::Relation.prepend(ActiveRecordShards::DefaultReplicaPatches::Rails52RelationPatches)
|
94
|
+
|
95
|
+
# https://github.com/rails/rails/blob/v6.0.4/activerecord/lib/active_record/associations/association.rb#L213
|
96
|
+
ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
|
35
97
|
else
|
36
98
|
raise "ActiveRecordShards is not compatible with #{ActiveRecord::VERSION::STRING}"
|
37
99
|
end
|
100
|
+
|
101
|
+
require 'active_record_shards/deprecation'
|
102
|
+
|
103
|
+
ActiveRecordShards::Deprecation.deprecate_methods(
|
104
|
+
ActiveRecordShards::AssociationCollectionConnectionSelection,
|
105
|
+
on_slave_if: :on_replica_if,
|
106
|
+
on_slave_unless: :on_replica_unless,
|
107
|
+
on_slave: :on_replica,
|
108
|
+
on_master: :on_primary,
|
109
|
+
on_master_if: :on_primary_if,
|
110
|
+
on_master_unless: :on_primary_unless
|
111
|
+
)
|
112
|
+
|
113
|
+
ActiveRecordShards::Deprecation.deprecate_methods(
|
114
|
+
ActiveRecordShards::ConnectionSwitcher,
|
115
|
+
on_slave_if: :on_replica_if,
|
116
|
+
on_slave_unless: :on_replica_unless,
|
117
|
+
on_master_or_slave: :on_primary_or_replica,
|
118
|
+
on_slave: :on_replica,
|
119
|
+
on_master: :on_primary,
|
120
|
+
on_master_if: :on_primary_if,
|
121
|
+
on_master_unless: :on_primary_unless,
|
122
|
+
on_slave?: :on_replica?
|
123
|
+
)
|
124
|
+
|
125
|
+
ActiveRecordShards::Deprecation.deprecate_methods(
|
126
|
+
ActiveRecordShards::DefaultReplicaPatches,
|
127
|
+
transaction_with_slave_off: :transaction_with_replica_off,
|
128
|
+
on_slave_unless_tx: :on_replica_unless_tx
|
129
|
+
)
|
130
|
+
|
131
|
+
ActiveRecordShards::Deprecation.deprecate_methods(
|
132
|
+
ActiveRecordShards::Model,
|
133
|
+
on_slave_by_default?: :on_replica_by_default?,
|
134
|
+
:on_slave_by_default= => :on_replica_by_default=
|
135
|
+
)
|
136
|
+
|
137
|
+
ActiveRecordShards::Deprecation.deprecate_methods(
|
138
|
+
ActiveRecordShards::ShardSelection,
|
139
|
+
on_slave?: :on_replica?,
|
140
|
+
:on_slave= => :on_replica=
|
141
|
+
)
|