switchman 3.4.2 → 3.5.1

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.
Files changed (40) 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/persistence.rb +18 -0
  15. data/lib/switchman/active_record/postgresql_adapter.rb +11 -10
  16. data/lib/switchman/active_record/query_cache.rb +1 -1
  17. data/lib/switchman/active_record/query_methods.rb +72 -26
  18. data/lib/switchman/active_record/relation.rb +13 -7
  19. data/lib/switchman/active_record/spawn_methods.rb +2 -2
  20. data/lib/switchman/active_record/statement_cache.rb +2 -2
  21. data/lib/switchman/active_record/tasks/database_tasks.rb +1 -1
  22. data/lib/switchman/active_record/test_fixtures.rb +19 -16
  23. data/lib/switchman/active_support/cache.rb +4 -1
  24. data/lib/switchman/arel.rb +6 -6
  25. data/lib/switchman/call_super.rb +1 -1
  26. data/lib/switchman/database_server.rb +20 -16
  27. data/lib/switchman/default_shard.rb +3 -3
  28. data/lib/switchman/engine.rb +33 -18
  29. data/lib/switchman/environment.rb +2 -2
  30. data/lib/switchman/errors.rb +4 -1
  31. data/lib/switchman/guard_rail/relation.rb +1 -1
  32. data/lib/switchman/parallel.rb +1 -1
  33. data/lib/switchman/r_spec_helper.rb +10 -10
  34. data/lib/switchman/shard.rb +30 -23
  35. data/lib/switchman/sharded_instrumenter.rb +5 -1
  36. data/lib/switchman/test_helper.rb +1 -1
  37. data/lib/switchman/version.rb +1 -1
  38. data/lib/switchman.rb +12 -4
  39. data/lib/tasks/switchman.rake +40 -37
  40. 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: f381ad09908e23b0560c685c530f7ffae1a0adcbbaf6640b5ae4f267dd9323f3
4
+ data.tar.gz: 1ca68afa9a03005c7c5966f8bc8a6be06f552c086ca469fe4b9eab1a54e819ae
5
5
  SHA512:
6
- metadata.gz: 94c9b870a65599c0d5775d32cd9dd1bfc3235c541eeb07127e5e8e8c773447da3ba1e0460ce8a340709354aceede546b9d6ccf8dd0360bff7e494f267a6791e1
7
- data.tar.gz: 6ea8348a8aaa9eb80ae763d2c8ccca23949e329f0f9ae2df7eef59344fdf3d4660b6e7419f479bc5d67be5e42fdd73f49abf7f0ceb853c0469c38b0899559424
6
+ metadata.gz: 3340807bd81183c24527ba2739732e6ac5aa413d1184c22d4b1ad2d3cc0674b5222d1cf5ddb7abad158108a35e6c226bf9c7614f55fc890debbee0f20147ef98
7
+ data.tar.gz: e67e961f5f4085ed7d0b00c272d8f8c911d14b284415e8bab2f528c25177db8504c8c7e8ceafa5e4ac5389e0f3f548f8d069838e21c6f8099864a91d5655d5a9
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