active_record_shards 5.0.0 → 5.2.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
  SHA256:
3
- metadata.gz: 07a2ae4e9b397abcc455655266c9d66c76af160e56ea963b401a130589f3f48c
4
- data.tar.gz: 45993e917fb0585637c72f89d6bee77f805e0192efb6ca3f476e86929d9192ab
3
+ metadata.gz: 15b0d33ae1fec065fc2c2763f52bf5385da900ddbc3d8b55089ac6f1f99f9b1c
4
+ data.tar.gz: 61de1ca1ad18611d9eb059dcec55eb85e4de55c965dd3ee33c60088a5d68f4f2
5
5
  SHA512:
6
- metadata.gz: 16309006259fadb5b3851ea470d8859618c2df4d10555e5ecb50c257d538ac3f36c69490a33547bc7e53e6a2962d5985623176021b5f0866f9a35973138000cc
7
- data.tar.gz: d23f2ae22180be953ba4a8bbb23000f73901ecf7950cae95858d371eec24bf01f2e7d6ee0c7225e8bbe2f76490261baae4059193718ae3cb17ffd78ab338f852
6
+ metadata.gz: 90e52914b1a63fbfb633882f60f2c2020a057b7ad16530c5800cc44f2e88d551c638fcdc31615f2c1c13d4fd031148ce568a10d4776c0082b0c917e9c7ee8dba
7
+ data.tar.gz: 8b215a24c9c0e1ff79e75499b9d47976b0143095023c0ec2a1ab4c03cc5e9c048957ef63703fe2a8eef5b92c72b3d156a95662ac3367a67ec6324f9527142913
data/README.md CHANGED
@@ -7,6 +7,8 @@ switch between database connections. We've made the implementation very small, a
7
7
 
8
8
  ActiveRecord Shards has been used and tested on Rails 5.x and 6.0, and has in some form or another been used in production on large Rails apps for several years.
9
9
 
10
+ Rails 6.1 introduced new connection handling and support for sharding. Apps are encouraged to migrate to the native sharding logic but ActiveRecord Shards supports Rails 6.1 when `legacy_connection_handling` is set to `true`. For more information see [Rails 6.1 installation](#rails-61-installation) and Rails' [multiple databases guide](https://guides.rubyonrails.org/active_record_multiple_databases.html).
11
+
10
12
  - [Installation](#installation)
11
13
  - [Configuration](#configuration)
12
14
  - [Migrations](#migrations)
@@ -22,6 +24,22 @@ ActiveRecord Shards has been used and tested on Rails 5.x and 6.0, and has in so
22
24
 
23
25
  and make sure to require 'active\_record\_shards' in some way.
24
26
 
27
+ ### Rails 6.1 & 7.0 installation
28
+
29
+ Rails 6.1 & 7.0 are **only** supported with `legacy_connection_handling` set to `true`.
30
+
31
+ Enable the legacy handling in your configuration files e.g. `config/application.rb` by setting:
32
+
33
+ ``` Ruby
34
+ config.active_record.legacy_connection_handling = true
35
+ ```
36
+
37
+ or
38
+
39
+ ``` Ruby
40
+ ActiveRecord::Base.legacy_connection_handling = true
41
+ ```
42
+
25
43
  ## Configuration
26
44
 
27
45
  Add the replica and shard configuration to config/database.yml:
@@ -0,0 +1,31 @@
1
+ module ActiveRecordShards
2
+ module ConnectionSwitcher
3
+ def connection_specification_name
4
+ name = current_shard_selection.resolve_connection_name(sharded: is_sharded?, configurations: configurations)
5
+
6
+ @_ars_connection_specification_names ||= {}
7
+ unless @_ars_connection_specification_names.include?(name)
8
+ unless configurations.configs_for(env_name: name, include_replicas: true).any? || name == "ActiveRecord::Base"
9
+ raise ActiveRecord::AdapterNotSpecified, "No database defined by #{name} in your database config. (configurations: #{configurations.configurations.map(&:env_name).inspect})"
10
+ end
11
+
12
+ @_ars_connection_specification_names[name] = true
13
+ end
14
+
15
+ name
16
+ end
17
+
18
+ private
19
+
20
+ def ensure_shard_connection
21
+ # See if we've connected before. If not, call `#establish_connection`
22
+ # so that ActiveRecord can resolve connection_specification_name to an
23
+ # ARS connection.
24
+ spec_name = connection_specification_name
25
+
26
+ pool = connection_handler.retrieve_connection_pool(spec_name)
27
+
28
+ connection_handler.establish_connection(spec_name.to_sym) if pool.nil?
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ module ActiveRecordShards
2
+ module ConnectionSwitcher
3
+ def connection_specification_name
4
+ name = current_shard_selection.resolve_connection_name(sharded: is_sharded?, configurations: configurations)
5
+
6
+ @_ars_connection_specification_names ||= {}
7
+ unless @_ars_connection_specification_names.include?(name)
8
+ unless configurations.configs_for(env_name: name, include_hidden: true).any? || name == "ActiveRecord::Base"
9
+ raise ActiveRecord::AdapterNotSpecified, "No database defined by #{name} in your database config. (configurations: #{configurations.configurations.map(&:env_name).inspect})"
10
+ end
11
+
12
+ @_ars_connection_specification_names[name] = true
13
+ end
14
+
15
+ name
16
+ end
17
+
18
+ private
19
+
20
+ def ensure_shard_connection
21
+ # See if we've connected before. If not, call `#establish_connection`
22
+ # so that ActiveRecord can resolve connection_specification_name to an
23
+ # ARS connection.
24
+ spec_name = connection_specification_name
25
+
26
+ pool = connection_handler.retrieve_connection_pool(spec_name)
27
+
28
+ connection_handler.establish_connection(spec_name.to_sym) if pool.nil?
29
+ end
30
+ end
31
+ end
@@ -4,7 +4,12 @@ require 'active_record_shards/shard_support'
4
4
 
5
5
  module ActiveRecordShards
6
6
  module ConnectionSwitcher
7
- SHARD_NAMES_CONFIG_KEY = 'shard_names'
7
+ case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
8
+ when '6.1', '7.0'
9
+ SHARD_NAMES_CONFIG_KEY = :shard_names
10
+ else
11
+ SHARD_NAMES_CONFIG_KEY = 'shard_names'
12
+ end
8
13
 
9
14
  def self.extended(base)
10
15
  base.singleton_class.send(:alias_method, :load_schema_without_default_shard!, :load_schema!)
@@ -14,11 +19,6 @@ module ActiveRecordShards
14
19
  base.singleton_class.send(:alias_method, :table_exists?, :table_exists_with_default_shard?)
15
20
  end
16
21
 
17
- def default_shard=(new_default_shard)
18
- ActiveRecordShards::ShardSelection.default_shard = new_default_shard
19
- switch_connection(shard: new_default_shard)
20
- end
21
-
22
22
  def on_primary_db(&block)
23
23
  on_shard(nil, &block)
24
24
  end
@@ -145,7 +145,15 @@ module ActiveRecordShards
145
145
  def config_for_env
146
146
  @_ars_config_for_env ||= {}
147
147
  @_ars_config_for_env[shard_env] ||= begin
148
- unless config = configurations[shard_env]
148
+ case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
149
+ when '7.0'
150
+ config = configurations.configs_for(env_name: shard_env, include_hidden: true).first.configuration_hash
151
+ when '6.1'
152
+ config = configurations.configs_for(env_name: shard_env, include_replicas: true).first.configuration_hash
153
+ else
154
+ config = configurations[shard_env]
155
+ end
156
+ unless config
149
157
  raise "Did not find #{shard_env} in configurations, did you forget to add it to your database config? (configurations: #{configurations.to_h.keys.inspect})"
150
158
  end
151
159
 
@@ -211,6 +219,10 @@ when '5.1', '5.2'
211
219
  require 'active_record_shards/connection_switcher-5-1'
212
220
  when '6.0'
213
221
  require 'active_record_shards/connection_switcher-6-0'
222
+ when '6.1'
223
+ require 'active_record_shards/connection_switcher-6-1'
224
+ when '7.0'
225
+ require 'active_record_shards/connection_switcher-7-0'
214
226
  else
215
227
  raise "ActiveRecordShards is not compatible with #{ActiveRecord::VERSION::STRING}"
216
228
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecordShards
4
+ module DefaultShard
5
+ def default_shard=(new_default_shard)
6
+ if ars_shard_type?(new_default_shard)
7
+ ActiveRecordShards::ShardSelection.ars_default_shard = new_default_shard
8
+ switch_connection(shard: new_default_shard)
9
+ else
10
+ super
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def ars_shard_type?(shard)
17
+ return true if ActiveRecord.version < Gem::Version.new('6.1')
18
+ return true if shard.nil?
19
+ return true if shard == :_no_shard
20
+ return true if shard.is_a?(Integer)
21
+
22
+ false
23
+ end
24
+ end
25
+ end
26
+
27
+ ActiveRecord::Base.singleton_class.prepend(ActiveRecordShards::DefaultShard)
@@ -3,7 +3,7 @@
3
3
  module ActiveRecordShards
4
4
  class ShardSelection
5
5
  NO_SHARD = :_no_shard
6
- cattr_accessor :default_shard
6
+ cattr_accessor :ars_default_shard
7
7
 
8
8
  def initialize
9
9
  @on_replica = false
@@ -14,11 +14,15 @@ module ActiveRecordShards
14
14
  if @shard.nil? || @shard == NO_SHARD
15
15
  nil
16
16
  else
17
- @shard || self.class.default_shard
17
+ @shard || self.class.ars_default_shard
18
18
  end
19
19
  end
20
-
21
- PRIMARY = "primary"
20
+ case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
21
+ when '6.1', '7.0'
22
+ PRIMARY = "ActiveRecord::Base"
23
+ else
24
+ PRIMARY = "primary"
25
+ end
22
26
  def resolve_connection_name(sharded:, configurations:)
23
27
  resolved_shard = sharded ? shard : nil
24
28
  env = ActiveRecordShards.app_env
@@ -29,7 +33,17 @@ module ActiveRecordShards
29
33
  @connection_names[env][resolved_shard][@on_replica] ||= begin
30
34
  name = env.dup
31
35
  name << "_shard_#{resolved_shard}" if resolved_shard
32
- if @on_replica && configurations["#{name}_replica"]
36
+ replica_config = begin
37
+ case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
38
+ when '7.0'
39
+ configurations.configs_for(env_name: "#{name}_replica", include_hidden: true).any?
40
+ when '6.1'
41
+ configurations.configs_for(env_name: "#{name}_replica", include_replicas: true).any?
42
+ else
43
+ configurations["#{name}_replica"]
44
+ end
45
+ end
46
+ if @on_replica && replica_config
33
47
  "#{name}_replica"
34
48
  else
35
49
  # ActiveRecord always names its default connection pool 'primary'
@@ -9,10 +9,24 @@ end
9
9
  namespace :db do
10
10
  desc 'Drops the database for the current RAILS_ENV including shards'
11
11
  task drop: :load_config do
12
- ActiveRecord::Base.configurations.to_h.each do |key, conf|
12
+ configurations = begin
13
+ case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
14
+ when '6.1', '7.0'
15
+ ActiveRecord::Base.configurations.configurations.map { |configuration| [configuration.env_name, configuration.configuration_hash] }
16
+ else
17
+ ActiveRecord::Base.configurations.to_h
18
+ end
19
+ end
20
+
21
+ configurations.each do |key, conf|
13
22
  next if !key.start_with?(ActiveRecordShards.app_env) || key.end_with?("_replica")
14
23
 
15
24
  begin
25
+ case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
26
+ when '6.1', '7.0'
27
+ conf = conf.stringify_keys
28
+ end
29
+
16
30
  ActiveRecordShards::Tasks.root_connection(conf).drop_database(conf['database'])
17
31
  # rescue ActiveRecord::NoDatabaseError # TODO: exists in AR but never is raised here ...
18
32
  # $stderr.puts "Database '#{conf['database']}' does not exist"
@@ -30,13 +44,26 @@ namespace :db do
30
44
 
31
45
  desc "Create the database defined in config/database.yml for the current RAILS_ENV including shards"
32
46
  task create: :load_config do
33
- ActiveRecord::Base.configurations.to_h.each do |key, conf|
47
+ configurations = begin
48
+ case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
49
+ when '6.1', '7.0'
50
+ ActiveRecord::Base.configurations.configurations.map { |configuration| [configuration.env_name, configuration.configuration_hash] }
51
+ else
52
+ ActiveRecord::Base.configurations.to_h
53
+ end
54
+ end
55
+ configurations.each do |key, conf|
34
56
  next if !key.start_with?(ActiveRecordShards.app_env) || key.end_with?("_replica")
35
57
 
36
58
  begin
37
59
  # MysqlAdapter takes charset instead of encoding in Rails 4.2 or greater
38
60
  # https://github.com/rails/rails/blob/4-2-stable/activerecord/lib/active_record/tasks/mysql_database_tasks.rb#L85-L96
39
61
  symbolized_configuration = conf.symbolize_keys
62
+ case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
63
+ when '6.1', '7.0'
64
+ conf = conf.stringify_keys
65
+ end
66
+
40
67
  symbolized_configuration[:charset] = symbolized_configuration[:encoding]
41
68
 
42
69
  ActiveRecordShards::Tasks.root_connection(conf).create_database(conf['database'], symbolized_configuration)
@@ -94,15 +121,26 @@ module ActiveRecordShards
94
121
  def root_connection(conf)
95
122
  conf = conf.merge('database' => nil)
96
123
  spec = spec_for(conf)
97
-
98
- ActiveRecord::Base.send("#{conf['adapter']}_connection", spec.config)
124
+ case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
125
+ when '6.1', '7.0'
126
+ ActiveRecord::Base.send("#{conf['adapter']}_connection", spec.db_config.configuration_hash)
127
+ else
128
+ ActiveRecord::Base.send("#{conf['adapter']}_connection", spec.config)
129
+ end
99
130
  end
100
131
 
101
132
  private
102
133
 
103
134
  def spec_for(conf)
104
- resolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(ActiveRecord::Base.configurations)
105
- resolver.spec(conf)
135
+ case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
136
+ when '7.0'
137
+ ActiveRecord::Base.connection_handler.send(:resolve_pool_config, conf, ActiveRecord::Base, ActiveRecord::Base.current_role, ActiveRecord::Base.current_shard)
138
+ when '6.1'
139
+ ActiveRecord::Base.connection_handler.send(:resolve_pool_config, conf, ActiveRecord::Base)
140
+ else
141
+ resolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(ActiveRecord::Base.configurations)
142
+ resolver.spec(conf)
143
+ end
106
144
  end
107
145
  end
108
146
  end
@@ -9,6 +9,7 @@ require 'active_record_shards/connection_switcher'
9
9
  require 'active_record_shards/association_collection_connection_selection'
10
10
  require 'active_record_shards/migration'
11
11
  require 'active_record_shards/default_replica_patches'
12
+ require 'active_record_shards/default_shard'
12
13
  require 'active_record_shards/schema_dumper_extension'
13
14
 
14
15
  module ActiveRecordShards
@@ -61,7 +62,7 @@ when '5.2'
61
62
 
62
63
  # https://github.com/rails/rails/blob/v5.2.6/activerecord/lib/active_record/associations/preloader/association.rb#L96
63
64
  ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationLoadRecordsPatch)
64
- when '6.0'
65
+ when '6.0', '6.1', '7.0'
65
66
  # https://github.com/rails/rails/blob/v6.0.4/activerecord/lib/active_record/type_caster/connection.rb#L28
66
67
  ActiveRecord::TypeCaster::Connection.prepend(ActiveRecordShards::DefaultReplicaPatches::TypeCasterConnectionConnectionPatch)
67
68
 
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: 5.0.0
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin Quorning
@@ -10,10 +10,10 @@ authors:
10
10
  - Mick Staugaard
11
11
  - Eric Chapweske
12
12
  - Ben Osheroff
13
- autorequire:
13
+ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2022-07-06 00:00:00.000000000 Z
16
+ date: 2022-10-11 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: activerecord
@@ -24,7 +24,7 @@ dependencies:
24
24
  version: '5.1'
25
25
  - - "<"
26
26
  - !ruby/object:Gem::Version
27
- version: '6.1'
27
+ version: '7.1'
28
28
  type: :runtime
29
29
  prerelease: false
30
30
  version_requirements: !ruby/object:Gem::Requirement
@@ -34,7 +34,7 @@ dependencies:
34
34
  version: '5.1'
35
35
  - - "<"
36
36
  - !ruby/object:Gem::Version
37
- version: '6.1'
37
+ version: '7.1'
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: activesupport
40
40
  requirement: !ruby/object:Gem::Requirement
@@ -44,7 +44,7 @@ dependencies:
44
44
  version: '5.1'
45
45
  - - "<"
46
46
  - !ruby/object:Gem::Version
47
- version: '6.1'
47
+ version: '7.1'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: '5.1'
55
55
  - - "<"
56
56
  - !ruby/object:Gem::Version
57
- version: '6.1'
57
+ version: '7.1'
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: bump
60
60
  requirement: !ruby/object:Gem::Requirement
@@ -197,8 +197,11 @@ files:
197
197
  - lib/active_record_shards/configuration_parser.rb
198
198
  - lib/active_record_shards/connection_switcher-5-1.rb
199
199
  - lib/active_record_shards/connection_switcher-6-0.rb
200
+ - lib/active_record_shards/connection_switcher-6-1.rb
201
+ - lib/active_record_shards/connection_switcher-7-0.rb
200
202
  - lib/active_record_shards/connection_switcher.rb
201
203
  - lib/active_record_shards/default_replica_patches.rb
204
+ - lib/active_record_shards/default_shard.rb
202
205
  - lib/active_record_shards/migration.rb
203
206
  - lib/active_record_shards/model.rb
204
207
  - lib/active_record_shards/schema_dumper_extension.rb
@@ -210,7 +213,7 @@ homepage: https://github.com/zendesk/active_record_shards
210
213
  licenses:
211
214
  - MIT
212
215
  metadata: {}
213
- post_install_message:
216
+ post_install_message:
214
217
  rdoc_options: []
215
218
  require_paths:
216
219
  - lib
@@ -225,8 +228,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
228
  - !ruby/object:Gem::Version
226
229
  version: '0'
227
230
  requirements: []
228
- rubygems_version: 3.1.6
229
- signing_key:
231
+ rubygems_version: 3.0.3.1
232
+ signing_key:
230
233
  specification_version: 4
231
234
  summary: Simple database switching for ActiveRecord.
232
235
  test_files: []