active_record_shards 5.0.0 → 5.2.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
  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: []