switchman 3.4.2 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +15 -14
  3. data/db/migrate/20180828183945_add_default_shard_index.rb +1 -1
  4. data/db/migrate/20190114212900_add_unique_name_indexes.rb +10 -4
  5. data/lib/switchman/active_record/associations.rb +16 -5
  6. data/lib/switchman/active_record/attribute_methods.rb +67 -22
  7. data/lib/switchman/active_record/base.rb +32 -12
  8. data/lib/switchman/active_record/calculations.rb +37 -33
  9. data/lib/switchman/active_record/connection_pool.rb +4 -2
  10. data/lib/switchman/active_record/database_configurations.rb +12 -7
  11. data/lib/switchman/active_record/finder_methods.rb +1 -1
  12. data/lib/switchman/active_record/log_subscriber.rb +2 -2
  13. data/lib/switchman/active_record/migration.rb +4 -2
  14. data/lib/switchman/active_record/postgresql_adapter.rb +11 -10
  15. data/lib/switchman/active_record/query_cache.rb +1 -1
  16. data/lib/switchman/active_record/query_methods.rb +72 -26
  17. data/lib/switchman/active_record/relation.rb +13 -7
  18. data/lib/switchman/active_record/spawn_methods.rb +2 -2
  19. data/lib/switchman/active_record/statement_cache.rb +2 -2
  20. data/lib/switchman/active_record/tasks/database_tasks.rb +1 -1
  21. data/lib/switchman/active_record/test_fixtures.rb +19 -16
  22. data/lib/switchman/active_support/cache.rb +4 -1
  23. data/lib/switchman/arel.rb +6 -6
  24. data/lib/switchman/call_super.rb +1 -1
  25. data/lib/switchman/database_server.rb +20 -16
  26. data/lib/switchman/default_shard.rb +3 -3
  27. data/lib/switchman/engine.rb +33 -18
  28. data/lib/switchman/environment.rb +2 -2
  29. data/lib/switchman/errors.rb +4 -1
  30. data/lib/switchman/guard_rail/relation.rb +1 -1
  31. data/lib/switchman/parallel.rb +1 -1
  32. data/lib/switchman/r_spec_helper.rb +10 -10
  33. data/lib/switchman/shard.rb +30 -23
  34. data/lib/switchman/sharded_instrumenter.rb +5 -1
  35. data/lib/switchman/test_helper.rb +1 -1
  36. data/lib/switchman/version.rb +1 -1
  37. data/lib/switchman.rb +10 -4
  38. data/lib/tasks/switchman.rake +40 -37
  39. metadata +9 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28d87755bf2331cbbf2931e7d35dddd688983c168c583b27dd60ae58d78072db
4
- data.tar.gz: 500e141f914db02c5dd51cd9a595abc00306750a418641ceb09adb7cee207de7
3
+ metadata.gz: 1f6f878b1a2a9ba1dc0c75ce4fcd5d299178ea7940a048190bd4b181ae306339
4
+ data.tar.gz: 19b31ce1e456fbecf2a9ba9b15644bc6073cd521b6a604da81a0c5f8977f579a
5
5
  SHA512:
6
- metadata.gz: 94c9b870a65599c0d5775d32cd9dd1bfc3235c541eeb07127e5e8e8c773447da3ba1e0460ce8a340709354aceede546b9d6ccf8dd0360bff7e494f267a6791e1
7
- data.tar.gz: 6ea8348a8aaa9eb80ae763d2c8ccca23949e329f0f9ae2df7eef59344fdf3d4660b6e7419f479bc5d67be5e42fdd73f49abf7f0ceb853c0469c38b0899559424
6
+ metadata.gz: bad542adf6c09d1e1e50ef3054a8ca8d106bd3eedb7cb9dbbe544e44dd88c7f19226e7dd0d805ad5a5685009be7b9c9fe20623182c8c624c88724d00d7bc5656
7
+ data.tar.gz: 43b76369798a3683f838e392466cec0628d0c4a309354db7ccadcafca604f6eeffdcc460e036ca8d0f105c7abed2987baa23d51b830e628951c057adb554f305
data/Rakefile CHANGED
@@ -2,37 +2,38 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  begin
5
- require 'bundler/setup'
5
+ require "bundler/setup"
6
6
  rescue LoadError
7
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ puts "You must `gem install bundler` and `bundle install` to run rake tasks"
8
8
  end
9
9
  begin
10
- require 'rdoc/task'
10
+ require "rdoc/task"
11
11
  rescue LoadError
12
- require 'rdoc/rdoc'
13
- require 'rake/rdoctask'
12
+ require "rdoc/rdoc"
13
+ require "rake/rdoctask"
14
14
  RDoc::Task = Rake::RDocTask
15
15
  end
16
16
 
17
17
  RDoc::Task.new(:rdoc) do |rdoc|
18
- rdoc.rdoc_dir = 'rdoc'
19
- rdoc.title = 'Switchman'
20
- rdoc.options << '--line-numbers'
21
- rdoc.rdoc_files.include('lib/**/*.rb')
18
+ rdoc.rdoc_dir = "rdoc"
19
+ rdoc.title = "Switchman"
20
+ rdoc.options << "--line-numbers"
21
+ rdoc.rdoc_files.include("lib/**/*.rb")
22
22
  end
23
23
 
24
- APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
25
- load 'rails/tasks/engine.rake'
24
+ load "./spec/tasks/coverage.rake"
25
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
26
+ load "rails/tasks/engine.rake"
26
27
 
27
28
  Bundler::GemHelper.install_tasks
28
29
 
29
- require 'rspec/core/rake_task'
30
+ require "rspec/core/rake_task"
30
31
  RSpec::Core::RakeTask.new
31
32
 
32
- require 'rubocop/rake_task'
33
+ require "rubocop/rake_task"
33
34
 
34
35
  RuboCop::RakeTask.new do |task|
35
- task.options = ['-S']
36
+ task.options = ["-S"]
36
37
  end
37
38
 
38
39
  task default: %i[spec]
@@ -5,7 +5,7 @@ class AddDefaultShardIndex < ActiveRecord::Migration[4.2]
5
5
  Switchman::Shard.where(default: nil).update_all(default: false) if Switchman::Shard.current.default?
6
6
  change_column_default :switchman_shards, :default, false
7
7
  change_column_null :switchman_shards, :default, false
8
- options = if connection.adapter_name == 'PostgreSQL'
8
+ options = if connection.adapter_name == "PostgreSQL"
9
9
  { unique: true, where: '"default"' }
10
10
  else
11
11
  {}
@@ -3,9 +3,15 @@
3
3
  class AddUniqueNameIndexes < ActiveRecord::Migration[4.2]
4
4
  def change
5
5
  add_index :switchman_shards, %i[database_server_id name], unique: true
6
- add_index :switchman_shards, :database_server_id, unique: true, where: 'name IS NULL',
7
- name: 'index_switchman_shards_unique_primary_shard'
8
- add_index :switchman_shards, '(true)', unique: true, where: 'database_server_id IS NULL AND name IS NULL',
9
- name: 'index_switchman_shards_unique_primary_db_and_shard'
6
+ add_index :switchman_shards,
7
+ :database_server_id,
8
+ unique: true,
9
+ where: "name IS NULL",
10
+ name: "index_switchman_shards_unique_primary_shard"
11
+ add_index :switchman_shards,
12
+ "(true)",
13
+ unique: true,
14
+ where: "database_server_id IS NULL AND name IS NULL",
15
+ name: "index_switchman_shards_unique_primary_db_and_shard"
10
16
  end
11
17
  end
@@ -24,10 +24,15 @@ module Switchman
24
24
 
25
25
  module CollectionAssociation
26
26
  def find_target
27
- shards = reflection.options[:multishard] && owner.respond_to?(:associated_shards) ? owner.associated_shards : [shard]
27
+ shards = if reflection.options[:multishard] && owner.respond_to?(:associated_shards)
28
+ owner.associated_shards
29
+ else
30
+ [shard]
31
+ end
28
32
  # activate both the owner and the target's shard category, so that Reflection#join_id_for,
29
33
  # when called for the owner, will be returned relative to shard the query will execute on
30
- Shard.with_each_shard(shards, [klass.connection_class_for_self, owner.class.connection_class_for_self].uniq) do
34
+ Shard.with_each_shard(shards,
35
+ [klass.connection_class_for_self, owner.class.connection_class_for_self].uniq) do
31
36
  super
32
37
  end
33
38
  end
@@ -128,7 +133,12 @@ module Switchman
128
133
  Shard.lookup(shard).activate do
129
134
  scope_was = loader_query.scope
130
135
  begin
131
- loader_query.instance_variable_set(:@scope, loader_query.scope.shard(Shard.current(loader_query.scope.model.connection_class_for_self)))
136
+ loader_query.instance_variable_set(
137
+ :@scope,
138
+ loader_query.scope.shard(
139
+ Shard.current(loader_query.scope.model.connection_class_for_self)
140
+ )
141
+ )
132
142
  ret += loader_query.load_records_for_keys(keys) do |record|
133
143
  loaders.each { |l| l.set_inverse(record) }
134
144
  end
@@ -186,7 +196,7 @@ module Switchman
186
196
  # #compare_by_identity makes such owners different hash keys
187
197
  @records_by_owner = {}.compare_by_identity
188
198
 
189
- if ::Rails.version >= '7.0'
199
+ if ::Rails.version >= "7.0"
190
200
  raw_records ||= loader_query.records_for([self])
191
201
  elsif owner_keys.empty?
192
202
  raw_records ||= []
@@ -210,7 +220,8 @@ module Switchman
210
220
  relative_owner_keys = partitioned_owners.map do |owner|
211
221
  key = owner[owner_key_name]
212
222
  if key && owner.class.sharded_column?(owner_key_name)
213
- key = Shard.relative_id_for(key, owner.shard,
223
+ key = Shard.relative_id_for(key,
224
+ owner.shard,
214
225
  Shard.current(klass.connection_class_for_self))
215
226
  end
216
227
  convert_key(key)
@@ -31,8 +31,16 @@ module Switchman
31
31
  # and not the silly one in AR::AttributeMethods::PrimaryKey
32
32
  return unless sharded_column?(@primary_key)
33
33
 
34
- class_eval(build_sharded_getter('id', '_read_attribute(@primary_key)', "::#{connection_class_for_self.name}"), __FILE__, __LINE__)
35
- class_eval(build_sharded_setter('id', @primary_key, "::#{connection_class_for_self.name}"), __FILE__, __LINE__)
34
+ class_eval(
35
+ build_sharded_getter("id",
36
+ "_read_attribute(@primary_key)",
37
+ "::#{connection_class_for_self.name}"),
38
+ __FILE__,
39
+ __LINE__
40
+ )
41
+ class_eval(build_sharded_setter("id", @primary_key, "::#{connection_class_for_self.name}"),
42
+ __FILE__,
43
+ __LINE__)
36
44
  end
37
45
 
38
46
  protected
@@ -47,7 +55,7 @@ module Switchman
47
55
  end
48
56
 
49
57
  def define_cached_method(owner, name, namespace:, as:, &block)
50
- if ::Rails.version < '7.0'
58
+ if ::Rails.version < "7.0"
51
59
  yield owner
52
60
  owner.rename_method(as, name)
53
61
  else
@@ -57,7 +65,10 @@ module Switchman
57
65
 
58
66
  def define_method_global_attribute(attr_name, owner:)
59
67
  if sharded_column?(attr_name)
60
- define_cached_method(owner, "global_#{attr_name}", as: "sharded_global_#{attr_name}", namespace: :switchman) do |batch|
68
+ define_cached_method(owner,
69
+ "global_#{attr_name}",
70
+ as: "sharded_global_#{attr_name}",
71
+ namespace: :switchman) do |batch|
61
72
  batch << <<-RUBY
62
73
  def sharded_global_#{attr_name}
63
74
  raw_value = original_#{attr_name}
@@ -69,13 +80,16 @@ module Switchman
69
80
  RUBY
70
81
  end
71
82
  else
72
- define_method_unsharded_column(attr_name, 'global', owner)
83
+ define_method_unsharded_column(attr_name, "global", owner)
73
84
  end
74
85
  end
75
86
 
76
87
  def define_method_local_attribute(attr_name, owner:)
77
88
  if sharded_column?(attr_name)
78
- define_cached_method(owner, "local_#{attr_name}", as: "sharded_local_#{attr_name}", namespace: :switchman) do |batch|
89
+ define_cached_method(owner,
90
+ "local_#{attr_name}",
91
+ as: "sharded_local_#{attr_name}",
92
+ namespace: :switchman) do |batch|
79
93
  batch << <<-RUBY
80
94
  def sharded_local_#{attr_name}
81
95
  raw_value = original_#{attr_name}
@@ -85,7 +99,7 @@ module Switchman
85
99
  RUBY
86
100
  end
87
101
  else
88
- define_method_unsharded_column(attr_name, 'local', owner)
102
+ define_method_unsharded_column(attr_name, "local", owner)
89
103
  end
90
104
  end
91
105
 
@@ -97,7 +111,13 @@ module Switchman
97
111
  if reflection.options[:polymorphic]
98
112
  # a polymorphic association has to be discovered at runtime. This code ends up being something like
99
113
  # context_type.&.constantize&.connection_class_for_self
100
- "begin;read_attribute(:#{reflection.foreign_type})&.constantize&.connection_class_for_self;rescue NameError;::ActiveRecord::Base;end"
114
+ <<~RUBY
115
+ begin
116
+ read_attribute(:#{reflection.foreign_type})&.constantize&.connection_class_for_self
117
+ rescue NameError
118
+ ::ActiveRecord::Base
119
+ end
120
+ RUBY
101
121
  else
102
122
  # otherwise we can just return a symbol for the statically known type of the association
103
123
  "::#{reflection.klass.connection_class_for_self.name}"
@@ -111,9 +131,14 @@ module Switchman
111
131
  if sharded_column?(attr_name)
112
132
  reflection = reflection_for_integer_attribute(attr_name)
113
133
  class_name = connection_class_for_self_code_for_reflection(reflection)
114
- safe_class_name = class_name.unpack1('h*')
115
- define_cached_method(owner, attr_name, as: "sharded_#{safe_class_name}_#{attr_name}", namespace: :switchman) do |batch|
116
- batch << build_sharded_getter("sharded_#{safe_class_name}_#{attr_name}", "original_#{attr_name}", class_name)
134
+ safe_class_name = class_name.unpack1("h*")
135
+ define_cached_method(owner,
136
+ attr_name,
137
+ as: "sharded_#{safe_class_name}_#{attr_name}",
138
+ namespace: :switchman) do |batch|
139
+ batch << build_sharded_getter("sharded_#{safe_class_name}_#{attr_name}",
140
+ "original_#{attr_name}",
141
+ class_name)
117
142
  end
118
143
  else
119
144
  define_cached_method(owner, attr_name, as: "plain_#{attr_name}", namespace: :switchman) do |batch|
@@ -153,8 +178,11 @@ module Switchman
153
178
  if sharded_column?(attr_name)
154
179
  reflection = reflection_for_integer_attribute(attr_name)
155
180
  class_name = connection_class_for_self_code_for_reflection(reflection)
156
- safe_class_name = class_name.unpack1('h*')
157
- define_cached_method(owner, "#{attr_name}=", as: "sharded_#{safe_class_name}_#{attr_name}=", namespace: :switchman) do |batch|
181
+ safe_class_name = class_name.unpack1("h*")
182
+ define_cached_method(owner,
183
+ "#{attr_name}=",
184
+ as: "sharded_#{safe_class_name}_#{attr_name}=",
185
+ namespace: :switchman) do |batch|
158
186
  batch << build_sharded_setter("sharded_#{safe_class_name}_#{attr_name}", attr_name, class_name)
159
187
  end
160
188
  else
@@ -178,7 +206,10 @@ module Switchman
178
206
 
179
207
  def define_method_original_attribute(attr_name, owner:)
180
208
  if sharded_column?(attr_name)
181
- define_cached_method(owner, "original_#{attr_name}", as: "sharded_original_#{attr_name}", namespace: :switchman) do |batch|
209
+ define_cached_method(owner,
210
+ "original_#{attr_name}",
211
+ as: "sharded_original_#{attr_name}",
212
+ namespace: :switchman) do |batch|
182
213
  batch << <<-RUBY
183
214
  def sharded_original_#{attr_name}
184
215
  _read_attribute("#{attr_name}") { |n| missing_attribute(n, caller) }
@@ -186,14 +217,17 @@ module Switchman
186
217
  RUBY
187
218
  end
188
219
  else
189
- define_method_unsharded_column(attr_name, 'global', owner)
220
+ define_method_unsharded_column(attr_name, "global", owner)
190
221
  end
191
222
  end
192
223
 
193
224
  def define_method_original_attribute=(attr_name, owner:)
194
225
  return unless sharded_column?(attr_name)
195
226
 
196
- define_cached_method(owner, "original_#{attr_name}=", as: "sharded_original_#{attr_name}=", namespace: :switchman) do |batch|
227
+ define_cached_method(owner,
228
+ "original_#{attr_name}=",
229
+ as: "sharded_original_#{attr_name}=",
230
+ namespace: :switchman) do |batch|
197
231
  batch << <<-RUBY
198
232
  def sharded_original_#{attr_name}=(new_value)
199
233
  _write_attribute('#{attr_name}', new_value)
@@ -203,9 +237,12 @@ module Switchman
203
237
  end
204
238
 
205
239
  def define_method_unsharded_column(attr_name, prefix, owner)
206
- return if columns_hash["#{prefix}_#{attr_name}"] || attr_name == 'id'
240
+ return if columns_hash["#{prefix}_#{attr_name}"] || attr_name == "id"
207
241
 
208
- define_cached_method(owner, "#{prefix}_#{attr_name}", as: "unsharded_#{prefix}_#{attr_name}", namespace: :switchman) do |batch|
242
+ define_cached_method(owner,
243
+ "#{prefix}_#{attr_name}",
244
+ as: "unsharded_#{prefix}_#{attr_name}",
245
+ namespace: :switchman) do |batch|
209
246
  batch << <<-RUBY
210
247
  def unsharded_#{prefix}_#{attr_name}
211
248
  raise NoMethodError, "undefined method `#{prefix}_#{attr_name}'; are you missing an association?"
@@ -217,8 +254,8 @@ module Switchman
217
254
 
218
255
  def self.prepended(klass)
219
256
  klass.singleton_class.prepend(ClassMethods)
220
- klass.attribute_method_prefix 'global_', 'local_', 'original_'
221
- klass.attribute_method_affix prefix: 'original_', suffix: '='
257
+ klass.attribute_method_prefix "global_", "local_", "original_"
258
+ klass.attribute_method_affix prefix: "original_", suffix: "="
222
259
  end
223
260
 
224
261
  # these are called if the specific methods haven't been defined yet
@@ -226,7 +263,11 @@ module Switchman
226
263
  return super unless self.class.sharded_column?(attr_name)
227
264
 
228
265
  reflection = self.class.send(:reflection_for_integer_attribute, attr_name)
229
- ::Switchman::Shard.relative_id_for(super, shard, ::Switchman::Shard.current(connection_class_for_self_for_reflection(reflection)))
266
+ ::Switchman::Shard.relative_id_for(
267
+ super,
268
+ shard,
269
+ ::Switchman::Shard.current(connection_class_for_self_for_reflection(reflection))
270
+ )
230
271
  end
231
272
 
232
273
  def attribute=(attr_name, new_value)
@@ -236,7 +277,11 @@ module Switchman
236
277
  end
237
278
 
238
279
  reflection = self.class.send(:reflection_for_integer_attribute, attr_name)
239
- super(::Switchman::Shard.relative_id_for(new_value, ::Switchman::Shard.current(connection_class_for_self_for_reflection(reflection)), shard))
280
+ super(::Switchman::Shard.relative_id_for(
281
+ new_value,
282
+ ::Switchman::Shard.current(connection_class_for_self_for_reflection(reflection)),
283
+ shard
284
+ ))
240
285
  end
241
286
 
242
287
  def global_attribute(attr_name)
@@ -67,7 +67,10 @@ module Switchman
67
67
  end
68
68
 
69
69
  def establish_connection(config_or_env = nil)
70
- raise ArgumentError, 'establish connection cannot be used on the non-current shard/role' if config_or_env.is_a?(Symbol) && config_or_env != ::Rails.env.to_sym
70
+ if config_or_env.is_a?(Symbol) && config_or_env != ::Rails.env.to_sym
71
+ raise ArgumentError,
72
+ "establish connection cannot be used on the non-current shard/role"
73
+ end
71
74
 
72
75
  # Ensure we don't randomly surprise change the connection parms associated with a shard/role
73
76
  config_or_env = nil if config_or_env == ::Rails.env.to_sym
@@ -82,9 +85,15 @@ module Switchman
82
85
  end
83
86
 
84
87
  def connected_to_stack
85
- return super if ::Rails.version < '7.0' ? Thread.current.thread_variable?(:ar_connected_to_stack) : ::ActiveSupport::IsolatedExecutionState.key?(:active_record_connected_to_stack)
88
+ has_own_stack = if ::Rails.version < "7.0"
89
+ Thread.current.thread_variable?(:ar_connected_to_stack)
90
+ else
91
+ ::ActiveSupport::IsolatedExecutionState.key?(:active_record_connected_to_stack)
92
+ end
86
93
 
87
94
  ret = super
95
+ return ret if has_own_stack
96
+
88
97
  DatabaseServer.guard_servers
89
98
  ret
90
99
  end
@@ -96,10 +105,13 @@ module Switchman
96
105
  sharded_role = nil
97
106
  connected_to_stack.reverse_each do |hash|
98
107
  shard_role = hash.dig(:shard_roles, target_shard)
99
- if shard_role && (hash[:klasses].include?(::ActiveRecord::Base) || hash[:klasses].include?(connection_class_for_self))
100
- sharded_role = shard_role
101
- break
108
+ unless shard_role &&
109
+ (hash[:klasses].include?(::ActiveRecord::Base) || hash[:klasses].include?(connection_class_for_self))
110
+ next
102
111
  end
112
+
113
+ sharded_role = shard_role
114
+ break
103
115
  end
104
116
  # Allow a shard-specific role to be reverted to regular inheritance
105
117
  return sharded_role if sharded_role && sharded_role != :_switchman_inherit
@@ -119,13 +131,15 @@ module Switchman
119
131
 
120
132
  def current_switchman_shard
121
133
  connected_to_stack.reverse_each do |hash|
122
- return hash[:switchman_shard] if hash[:switchman_shard] && hash[:klasses].include?(connection_class_for_self)
134
+ if hash[:switchman_shard] && hash[:klasses].include?(connection_class_for_self)
135
+ return hash[:switchman_shard]
136
+ end
123
137
  end
124
138
 
125
139
  Shard.default
126
140
  end
127
141
 
128
- if ::Rails.version < '7.0'
142
+ if ::Rails.version < "7.0"
129
143
  def connection_class_for_self
130
144
  connection_classes
131
145
  end
@@ -172,13 +186,17 @@ module Switchman
172
186
  end
173
187
 
174
188
  def destroy_shadow_records(target_shards: [Shard.current])
175
- raise Errors::ShadowRecordError, 'Cannot be called on a shadow record.' if shadow_record?
176
- raise Errors::MethodUnsupportedForUnshardedTableError, 'Cannot be called on a record belonging to an unsharded table.' unless self.class.sharded_column?(self.class.primary_key)
189
+ raise Errors::ShadowRecordError, "Cannot be called on a shadow record." if shadow_record?
190
+
191
+ unless self.class.sharded_column?(self.class.primary_key)
192
+ raise Errors::MethodUnsupportedForUnshardedTableError,
193
+ "Cannot be called on a record belonging to an unsharded table."
194
+ end
177
195
 
178
196
  Array(target_shards).each do |target_shard|
179
197
  next if target_shard == shard
180
198
 
181
- target_shard.activate { self.class.where('id = ?', global_id).delete_all }
199
+ target_shard.activate { self.class.where("id = ?", global_id).delete_all }
182
200
  end
183
201
  end
184
202
 
@@ -270,8 +288,10 @@ module Switchman
270
288
 
271
289
  def id_for_database
272
290
  if self.class.sharded_primary_key?
273
- # It's an int, so so it's safe to just return it without passing it through anything else
274
- # In theory we should do `@attributes[@primary_key].type.serialize(id)`, but that seems to have surprising side-effects
291
+ # It's an int, so it's safe to just return it without passing it
292
+ # through anything else. In theory we should do
293
+ # `@attributes[@primary_key].type.serialize(id)`, but that seems to
294
+ # have surprising side-effects
275
295
  id
276
296
  else
277
297
  super
@@ -28,7 +28,7 @@ module Switchman
28
28
 
29
29
  def execute_simple_calculation(operation, column_name, distinct)
30
30
  operation = operation.to_s.downcase
31
- if operation == 'average'
31
+ if operation == "average"
32
32
  result = calculate_simple_average(column_name, distinct)
33
33
  else
34
34
  result = activate do |relation|
@@ -36,11 +36,11 @@ module Switchman
36
36
  end
37
37
  if result.is_a?(Array)
38
38
  case operation
39
- when 'count', 'sum'
39
+ when "count", "sum"
40
40
  result = result.sum
41
- when 'minimum'
41
+ when "minimum"
42
42
  result = result.min
43
- when 'maximum'
43
+ when "maximum"
44
44
  result = result.max
45
45
  end
46
46
  end
@@ -52,20 +52,20 @@ module Switchman
52
52
  # See activerecord#execute_simple_calculation
53
53
  relation = except(:order)
54
54
  column = aggregate_column(column_name)
55
- relation.select_values = [operation_over_aggregate_column(column, 'average', distinct).as('average'),
56
- operation_over_aggregate_column(column, 'count', distinct).as('count')]
55
+ relation.select_values = [operation_over_aggregate_column(column, "average", distinct).as("average"),
56
+ operation_over_aggregate_column(column, "count", distinct).as("count")]
57
57
 
58
58
  initial_results = relation.activate { |rel| klass.connection.select_all(rel) }
59
59
  if initial_results.is_a?(Array)
60
60
  initial_results.each do |r|
61
- r['average'] = type_cast_calculated_value_switchman(r['average'], column_name, 'average')
62
- r['count'] = type_cast_calculated_value_switchman(r['count'], column_name, 'count')
61
+ r["average"] = type_cast_calculated_value_switchman(r["average"], column_name, "average")
62
+ r["count"] = type_cast_calculated_value_switchman(r["count"], column_name, "count")
63
63
  end
64
- result = initial_results.map { |r| r['average'] * r['count'] }.sum / initial_results.map do |r|
65
- r['count']
66
- end.sum
64
+ result = initial_results.sum { |r| r["average"] * r["count"] } / initial_results.sum do |r|
65
+ r["count"]
66
+ end
67
67
  else
68
- result = type_cast_calculated_value_switchman(initial_results.first['average'], column_name, 'average')
68
+ result = type_cast_calculated_value_switchman(initial_results.first["average"], column_name, "average")
69
69
  end
70
70
  result
71
71
  end
@@ -90,7 +90,7 @@ module Switchman
90
90
  row[opts[:aggregate_alias]] = type_cast_calculated_value_switchman(
91
91
  row[opts[:aggregate_alias]], column_name, opts[:operation]
92
92
  )
93
- row['count'] = row['count'].to_i if opts[:operation] == 'average'
93
+ row["count"] = row["count"].to_i if opts[:operation] == "average"
94
94
 
95
95
  opts[:group_columns].each do |aliaz, _type, group_column_name|
96
96
  if opts[:associated] && (aliaz == opts[:group_aliases].first)
@@ -109,7 +109,7 @@ module Switchman
109
109
  private
110
110
 
111
111
  def type_cast_calculated_value_switchman(value, column_name, operation)
112
- if ::Rails.version < '7.0'
112
+ if ::Rails.version < "7.0"
113
113
  type_cast_calculated_value(value, operation) do |val|
114
114
  column = aggregate_column(column_name)
115
115
  type ||= column.try(:type_caster) ||
@@ -125,7 +125,7 @@ module Switchman
125
125
  end
126
126
 
127
127
  def column_name_for(field)
128
- field.respond_to?(:name) ? field.name.to_s : field.to_s.split('.').last
128
+ field.respond_to?(:name) ? field.name.to_s : field.to_s.split(".").last
129
129
  end
130
130
 
131
131
  def grouped_calculation_options(operation, column_name, distinct)
@@ -135,7 +135,8 @@ module Switchman
135
135
  group_attrs = group_values
136
136
  if group_attrs.first.respond_to?(:to_sym)
137
137
  association = klass.reflect_on_association(group_attrs.first.to_sym)
138
- associated = group_attrs.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations
138
+ # only count belongs_to associations
139
+ associated = group_attrs.size == 1 && association && association.macro == :belongs_to
139
140
  group_fields = Array(associated ? association.foreign_key : group_attrs)
140
141
  else
141
142
  group_fields = group_attrs
@@ -146,18 +147,20 @@ module Switchman
146
147
  group_columns = group_aliases.zip(group_fields).map do |aliaz, field|
147
148
  [aliaz, type_for(field), column_name_for(field)]
148
149
  end
149
- opts.merge!(association: association, associated: associated,
150
- group_aliases: group_aliases, group_columns: group_columns,
150
+ opts.merge!(association: association,
151
+ associated: associated,
152
+ group_aliases: group_aliases,
153
+ group_columns: group_columns,
151
154
  group_fields: group_fields)
152
155
 
153
156
  opts
154
157
  end
155
158
 
156
159
  def aggregate_alias_for(operation, column_name)
157
- if operation == 'count' && column_name == :all
158
- 'count_all'
159
- elsif operation == 'average'
160
- 'average'
160
+ if operation == "count" && column_name == :all
161
+ "count_all"
162
+ elsif operation == "average"
163
+ "average"
161
164
  else
162
165
  column_alias_for("#{operation} #{column_name}")
163
166
  end
@@ -173,13 +176,14 @@ module Switchman
173
176
  opts[:distinct]
174
177
  ).as(opts[:aggregate_alias])
175
178
  ]
176
- if opts[:operation] == 'average'
179
+ if opts[:operation] == "average"
177
180
  # include count in average so we can recalculate the average
178
181
  # across all shards if needed
179
182
  select_values << operation_over_aggregate_column(
180
183
  aggregate_column(opts[:column_name]),
181
- 'count', opts[:distinct]
182
- ).as('count')
184
+ "count",
185
+ opts[:distinct]
186
+ ).as("count")
183
187
  end
184
188
 
185
189
  haves = having_clause.send(:predicates)
@@ -205,22 +209,22 @@ module Switchman
205
209
  key = key.first if key.size == 1
206
210
  value = row[opts[:aggregate_alias]]
207
211
 
208
- if opts[:operation] == 'average'
212
+ if opts[:operation] == "average"
209
213
  if result.key?(key)
210
214
  old_value, old_count = result[key]
211
- new_count = old_count + row['count']
212
- new_value = ((old_value * old_count) + (value * row['count'])) / new_count
215
+ new_count = old_count + row["count"]
216
+ new_value = ((old_value * old_count) + (value * row["count"])) / new_count
213
217
  result[key] = [new_value, new_count]
214
218
  else
215
- result[key] = [value, row['count']]
219
+ result[key] = [value, row["count"]]
216
220
  end
217
221
  elsif result.key?(key)
218
222
  case opts[:operation]
219
- when 'count', 'sum'
223
+ when "count", "sum"
220
224
  result[key] += value
221
- when 'minimum'
225
+ when "minimum"
222
226
  result[key] = value if value < result[key]
223
- when 'maximum'
227
+ when "maximum"
224
228
  result[key] = value if value > result[key]
225
229
  end
226
230
  else
@@ -228,7 +232,7 @@ module Switchman
228
232
  end
229
233
  end
230
234
 
231
- result.transform_values!(&:first) if opts[:operation] == 'average'
235
+ result.transform_values!(&:first) if opts[:operation] == "average"
232
236
 
233
237
  result
234
238
  end
@@ -48,7 +48,9 @@ module Switchman
48
48
  end
49
49
 
50
50
  def switch_database(conn)
51
- @schemas = conn.current_schemas if !@schemas && conn.adapter_name == 'PostgreSQL' && !current_shard.database_server.config[:shard_name]
51
+ if !@schemas && conn.adapter_name == "PostgreSQL" && !current_shard.database_server.config[:shard_name]
52
+ @schemas = conn.current_schemas
53
+ end
52
54
 
53
55
  conn.shard = current_shard
54
56
  end
@@ -56,7 +58,7 @@ module Switchman
56
58
  private
57
59
 
58
60
  def current_shard
59
- ::Rails.version < '7.0' ? connection_klass.current_switchman_shard : connection_class.current_switchman_shard
61
+ (::Rails.version < "7.0") ? connection_klass.current_switchman_shard : connection_class.current_switchman_shard
60
62
  end
61
63
 
62
64
  def tls_key