switchman 3.4.2 → 3.5.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.
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
@@ -10,9 +10,9 @@ module Switchman
10
10
  def configs_for(include_replicas: false, name: nil, **)
11
11
  res = super
12
12
  if name && !include_replicas
13
- return nil unless name.end_with?('primary')
13
+ return nil unless name.end_with?("primary")
14
14
  elsif !include_replicas
15
- return res.select { |config| config.name.end_with?('primary') }
15
+ return res.select { |config| config.name.end_with?("primary") }
16
16
  end
17
17
  res
18
18
  end
@@ -29,19 +29,24 @@ module Switchman
29
29
  db_configs = configs.flat_map do |env_name, config|
30
30
  # It would be nice to do the auto-fallback that we want here, but we haven't
31
31
  # actually done that for years (or maybe ever) and it will be a big lift to get working
32
- roles = config.keys.select { |k| config[k].is_a?(Hash) || (config[k].is_a?(Array) && config[k].all? { |ck| ck.is_a?(Hash) }) }
32
+ roles = config.keys.select do |k|
33
+ config[k].is_a?(Hash) || (config[k].is_a?(Array) && config[k].all?(Hash))
34
+ end
33
35
  base_config = config.except(*roles)
34
36
 
35
37
  name = "#{env_name}/primary"
36
- name = 'primary' if env_name == default_env
38
+ name = "primary" if env_name == default_env
37
39
  base_db = build_db_config_from_raw_config(env_name, name, base_config)
38
40
  [base_db] + roles.map do |role|
39
- build_db_config_from_raw_config(env_name, "#{env_name}/#{role}",
40
- base_config.merge(config[role].is_a?(Array) ? config[role].first : config[role]))
41
+ build_db_config_from_raw_config(
42
+ env_name,
43
+ "#{env_name}/#{role}",
44
+ base_config.merge(config[role].is_a?(Array) ? config[role].first : config[role])
45
+ )
41
46
  end
42
47
  end
43
48
 
44
- db_configs << environment_url_config(default_env, 'primary', {}) unless db_configs.find(&:for_current_env?)
49
+ db_configs << environment_url_config(default_env, "primary", {}) unless db_configs.find(&:for_current_env?)
45
50
 
46
51
  merge_db_environment_variables(default_env, db_configs.compact)
47
52
  end
@@ -49,7 +49,7 @@ module Switchman
49
49
  relation = apply_join_dependency(eager_loading: false)
50
50
  return false if ::ActiveRecord::NullRelation === relation
51
51
 
52
- relation = relation.except(:select, :order).select('1 AS one').limit(1)
52
+ relation = relation.except(:select, :order).select("1 AS one").limit(1)
53
53
 
54
54
  case conditions
55
55
  when Array, Hash
@@ -14,14 +14,14 @@ module Switchman
14
14
 
15
15
  name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
16
16
  name = "CACHE #{name}" if payload[:cached]
17
- sql = payload[:sql].squeeze(' ')
17
+ sql = payload[:sql].squeeze(" ")
18
18
  binds = nil
19
19
  shard = payload[:shard]
20
20
  shard = " [#{shard[:database_server_id]}:#{shard[:id]} #{shard[:env]}]" if shard
21
21
 
22
22
  unless (payload[:binds] || []).empty?
23
23
  casted_params = type_casted_binds(payload[:type_casted_binds])
24
- binds = ' ' + payload[:binds].zip(casted_params).map do |attr, value|
24
+ binds = " " + payload[:binds].zip(casted_params).map do |attr, value|
25
25
  render_bind(attr, value)
26
26
  end.inspect
27
27
  end
@@ -14,7 +14,9 @@ module Switchman
14
14
 
15
15
  def connection
16
16
  conn = super
17
- ::ActiveRecord::Base.connection_pool.switch_database(conn) if conn.shard != ::ActiveRecord::Base.current_switchman_shard
17
+ if conn.shard != ::ActiveRecord::Base.current_switchman_shard
18
+ ::ActiveRecord::Base.connection_pool.switch_database(conn)
19
+ end
18
20
  conn
19
21
  end
20
22
  end
@@ -65,7 +67,7 @@ module Switchman
65
67
  return @migrations if instance_variable_defined?(:@migrations)
66
68
 
67
69
  migrations_cache = Thread.current[:migrations_cache] ||= {}
68
- key = Digest::MD5.hexdigest(migration_files.sort.join(','))
70
+ key = Digest::MD5.hexdigest(migration_files.sort.join(","))
69
71
  @migrations = migrations_cache[key] ||= super
70
72
  end
71
73
 
@@ -5,9 +5,9 @@ module Switchman
5
5
  module PostgreSQLAdapter
6
6
  # copy/paste; use quote_local_table_name
7
7
  def create_database(name, options = {})
8
- options = { encoding: 'utf8' }.merge!(options.symbolize_keys)
8
+ options = { encoding: "utf8" }.merge!(options.symbolize_keys)
9
9
 
10
- option_string = options.sum('') do |key, value|
10
+ option_string = options.sum("") do |key, value|
11
11
  case key
12
12
  when :owner
13
13
  " OWNER = \"#{value}\""
@@ -24,7 +24,7 @@ module Switchman
24
24
  when :connection_limit
25
25
  " CONNECTION LIMIT = #{value}"
26
26
  else
27
- ''
27
+ ""
28
28
  end
29
29
  end
30
30
 
@@ -37,7 +37,7 @@ module Switchman
37
37
  end
38
38
 
39
39
  def current_schemas
40
- select_values('SELECT * FROM unnest(current_schemas(false))')
40
+ select_values("SELECT * FROM unnest(current_schemas(false))")
41
41
  end
42
42
 
43
43
  def extract_schema_qualified_name(string)
@@ -49,13 +49,13 @@ module Switchman
49
49
  # significant change: use the shard name if no explicit schema
50
50
  def quoted_scope(name = nil, type: nil)
51
51
  schema, name = extract_schema_qualified_name(name)
52
- type = \
52
+ type =
53
53
  case type # rubocop:disable Style/HashLikeCase
54
- when 'BASE TABLE'
54
+ when "BASE TABLE"
55
55
  "'r','p'"
56
- when 'VIEW'
56
+ when "VIEW"
57
57
  "'v','m'"
58
- when 'FOREIGN TABLE'
58
+ when "FOREIGN TABLE"
59
59
  "'f'"
60
60
  end
61
61
  scope = {}
@@ -67,7 +67,8 @@ module Switchman
67
67
 
68
68
  def foreign_keys(table_name)
69
69
  super.each do |fk|
70
- to_table_qualified_name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(fk.to_table)
70
+ to_table_qualified_name =
71
+ ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(fk.to_table)
71
72
  fk.to_table = to_table_qualified_name.identifier if to_table_qualified_name.schema == shard.name
72
73
  end
73
74
  end
@@ -101,7 +102,7 @@ module Switchman
101
102
 
102
103
  def add_index_options(_table_name, _column_name, **)
103
104
  index, algorithm, if_not_exists = super
104
- algorithm = nil if DatabaseServer.creating_new_shard && algorithm == 'CONCURRENTLY'
105
+ algorithm = nil if DatabaseServer.creating_new_shard && algorithm == "CONCURRENTLY"
105
106
  [index, algorithm, if_not_exists]
106
107
  end
107
108
 
@@ -20,7 +20,7 @@ module Switchman
20
20
  type_casted_binds: -> { type_casted_binds(binds) }
21
21
  }
22
22
  ::ActiveSupport::Notifications.instrument(
23
- 'sql.active_record',
23
+ "sql.active_record",
24
24
  args
25
25
  )
26
26
  query_cache[sql][binds]
@@ -84,6 +84,14 @@ module Switchman
84
84
  super(other.shard(primary_shard))
85
85
  end
86
86
 
87
+ # use a temp variable so that the new where clause is built before self.where_clause is read,
88
+ # since build_where_clause might mutate self.where_clause
89
+ def where!(opts, *rest)
90
+ new_clause = build_where_clause(opts, rest)
91
+ self.where_clause += new_clause
92
+ self
93
+ end
94
+
87
95
  protected
88
96
 
89
97
  def remove_nonlocal_primary_keys!
@@ -93,7 +101,7 @@ module Switchman
93
101
  predicate.left.relation.klass == klass &&
94
102
  (predicate.is_a?(::Arel::Nodes::Equality) || predicate.is_a?(::Arel::Nodes::HomogeneousIn))
95
103
 
96
- value.is_a?(Integer) && value > Shard::IDS_PER_SHARD ? [] : value
104
+ (value.is_a?(Integer) && value > Shard::IDS_PER_SHARD) ? [] : value
97
105
  end
98
106
  self
99
107
  end
@@ -172,7 +180,7 @@ module Switchman
172
180
 
173
181
  def sharded_primary_key?(relation, column)
174
182
  column = column.to_s
175
- return column == 'id' if relation.klass == ::ActiveRecord::Base
183
+ return column == "id" if relation.klass == ::ActiveRecord::Base
176
184
 
177
185
  relation.klass.primary_key == column && relation.klass.integral_id?
178
186
  end
@@ -199,12 +207,11 @@ module Switchman
199
207
 
200
208
  case opts
201
209
  when String, Array
202
- values = Hash === rest.first ? rest.first.values : rest
210
+ values = (Hash === rest.first) ? rest.first.values : rest
203
211
 
204
- values.grep(ActiveRecord::Relation) do |rel|
205
- # serialize subqueries against the same shard as the outer query is currently
206
- # targeted to run against
207
- rel.shard!(primary_shard) if rel.shard_source_value == :implicit && rel.primary_shard != primary_shard
212
+ if values.grep(ActiveRecord::Relation).first
213
+ raise "Sub-queries are not allowed as simple substitutions; " \
214
+ "please build your relation with more structured methods so that Switchman is able to introspect it."
208
215
  end
209
216
 
210
217
  super
@@ -254,9 +261,10 @@ module Switchman
254
261
  send(clause_setter, new_clause)
255
262
  end
256
263
 
257
- def each_transposable_predicate(predicates = nil, &block)
264
+ def each_transposable_predicate(predicates, &block)
258
265
  each_predicate(predicates) do |predicate|
259
- if predicate.is_a?(::Arel::Nodes::Grouping)
266
+ case predicate
267
+ when ::Arel::Nodes::Grouping
260
268
  next predicate unless predicate.expr.is_a?(::Arel::Nodes::Or)
261
269
 
262
270
  or_expr = predicate.expr
@@ -267,6 +275,40 @@ module Switchman
267
275
  next predicate if new_left == old_left && new_right == old_right
268
276
 
269
277
  next predicate.class.new predicate.expr.class.new(new_left, new_right)
278
+ when ::Arel::Nodes::SelectStatement
279
+ new_cores = predicate.cores.map do |core|
280
+ next core unless core.is_a?(::Arel::Nodes::SelectCore) # just in case something weird is going on
281
+
282
+ new_wheres = each_transposable_predicate(core.wheres, &block)
283
+ new_havings = each_transposable_predicate(core.havings, &block)
284
+
285
+ next core if core.wheres == new_wheres && core.havings == new_havings
286
+
287
+ new_core = core.clone
288
+ new_core.wheres = new_wheres
289
+ new_core.havings = new_havings
290
+ new_core
291
+ end
292
+
293
+ next predicate if predicate.cores == new_cores
294
+
295
+ new_node = predicate.clone
296
+ new_node.instance_variable_set(:@cores, new_cores)
297
+ next new_node
298
+ when ::Arel::Nodes::Not
299
+ old_value = predicate.expr
300
+ new_value = each_transposable_predicate([old_value], &block).first
301
+
302
+ next predicate if old_value == new_value
303
+
304
+ next predicate.class.new(new_value)
305
+ when ::Arel::Nodes::Exists
306
+ old_value = predicate.expressions
307
+ new_value = each_transposable_predicate([old_value], &block).first
308
+
309
+ next predicate if old_value == new_value
310
+
311
+ next predicate.class.new(new_value)
270
312
  end
271
313
 
272
314
  next predicate unless predicate.is_a?(::Arel::Nodes::Binary) || predicate.is_a?(::Arel::Nodes::HomogeneousIn)
@@ -279,54 +321,56 @@ module Switchman
279
321
  end
280
322
  end
281
323
 
282
- def each_transposable_predicate_value(predicates = nil)
324
+ def each_transposable_predicate_value(predicates = nil, &block)
283
325
  each_transposable_predicate(predicates) do |predicate, relation, column, type|
284
- each_transposable_predicate_value_cb(predicate) do |value|
326
+ each_transposable_predicate_value_cb(predicate, block) do |value|
285
327
  yield(value, predicate, relation, column, type)
286
328
  end
287
329
  end
288
330
  end
289
331
 
290
- def each_transposable_predicate_value_cb(node, &block)
332
+ def each_transposable_predicate_value_cb(node, original_block, &block)
291
333
  case node
292
334
  when Array
293
- node.map { |val| each_transposable_predicate_value_cb(val, &block).presence }.compact
335
+ node.filter_map { |val| each_transposable_predicate_value_cb(val, original_block, &block).presence }
294
336
  when ::ActiveModel::Attribute
295
337
  old_value = node.value_before_type_cast
296
- new_value = each_transposable_predicate_value_cb(old_value, &block)
338
+ new_value = each_transposable_predicate_value_cb(old_value, original_block, &block)
297
339
 
298
- old_value == new_value ? node : node.class.new(node.name, new_value, node.type)
340
+ (old_value == new_value) ? node : node.class.new(node.name, new_value, node.type)
299
341
  when ::Arel::Nodes::And
300
342
  old_value = node.children
301
- new_value = each_transposable_predicate_value_cb(old_value, &block)
343
+ new_value = each_transposable_predicate_value_cb(old_value, original_block, &block)
302
344
 
303
- old_value == new_value ? node : node.class.new(new_value)
345
+ (old_value == new_value) ? node : node.class.new(new_value)
304
346
  when ::Arel::Nodes::BindParam
305
347
  old_value = node.value
306
- new_value = each_transposable_predicate_value_cb(old_value, &block)
348
+ new_value = each_transposable_predicate_value_cb(old_value, original_block, &block)
307
349
 
308
- old_value == new_value ? node : node.class.new(new_value)
350
+ (old_value == new_value) ? node : node.class.new(new_value)
309
351
  when ::Arel::Nodes::Casted
310
352
  old_value = node.value
311
- new_value = each_transposable_predicate_value_cb(old_value, &block)
353
+ new_value = each_transposable_predicate_value_cb(old_value, original_block, &block)
312
354
 
313
- old_value == new_value ? node : node.class.new(new_value, node.attribute)
355
+ (old_value == new_value) ? node : node.class.new(new_value, node.attribute)
314
356
  when ::Arel::Nodes::HomogeneousIn
315
357
  old_value = node.values
316
- new_value = each_transposable_predicate_value_cb(old_value, &block)
358
+ new_value = each_transposable_predicate_value_cb(old_value, original_block, &block)
317
359
 
318
360
  # switch to a regular In, so that Relation::WhereClause#contradiction? knows about it
319
361
  if new_value.empty?
320
- klass = node.type == :in ? ::Arel::Nodes::In : ::Arel::Nodes::NotIn
362
+ klass = (node.type == :in) ? ::Arel::Nodes::In : ::Arel::Nodes::NotIn
321
363
  klass.new(node.attribute, new_value)
322
364
  else
323
- old_value == new_value ? node : node.class.new(new_value, node.attribute, node.type)
365
+ (old_value == new_value) ? node : node.class.new(new_value, node.attribute, node.type)
324
366
  end
325
367
  when ::Arel::Nodes::Binary
326
368
  old_value = node.right
327
- new_value = each_transposable_predicate_value_cb(old_value, &block)
369
+ new_value = each_transposable_predicate_value_cb(old_value, original_block, &block)
328
370
 
329
- old_value == new_value ? node : node.class.new(node.left, new_value)
371
+ (old_value == new_value) ? node : node.class.new(node.left, new_value)
372
+ when ::Arel::Nodes::SelectStatement
373
+ each_transposable_predicate_value([node], &original_block).first
330
374
  else
331
375
  yield(node)
332
376
  end
@@ -343,6 +387,8 @@ module Switchman
343
387
  Shard.current(klass.connection_class_for_self)
344
388
  elsif type == :foreign
345
389
  source_shard_for_foreign_key(relation, column)
390
+ else
391
+ primary_shard
346
392
  end
347
393
 
348
394
  transpose_predicate_value(value, current_source_shard, target_shard, type)
@@ -49,7 +49,7 @@ module Switchman
49
49
  end
50
50
 
51
51
  def load(&block)
52
- if !loaded? || (::Rails.version >= '7.0' && scheduled?)
52
+ if !loaded? || (::Rails.version >= "7.0" && scheduled?)
53
53
  @records = activate { |relation| relation.send(:exec_queries, &block) }
54
54
  @loaded = true
55
55
  end
@@ -58,7 +58,7 @@ module Switchman
58
58
  end
59
59
 
60
60
  %I[update_all delete_all].each do |method|
61
- arg_params = RUBY_VERSION <= '2.8' ? '*args' : '*args, **kwargs'
61
+ arg_params = (RUBY_VERSION <= "2.8") ? "*args" : "*args, **kwargs"
62
62
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
63
63
  def #{method}(#{arg_params})
64
64
  result = self.activate(unordered: true) { |relation| relation.call_super(#{method.inspect}, Relation, #{arg_params}) }
@@ -73,12 +73,16 @@ module Switchman
73
73
  loose_mode = options[:loose] && is_integer
74
74
  # loose_mode: if we don't care about getting exactly batch_size ids in between
75
75
  # don't get the max - just get the min and add batch_size so we get that many _at most_
76
- values = loose_mode ? 'MIN(id)' : 'MIN(id), MAX(id)'
76
+ values = loose_mode ? "MIN(id)" : "MIN(id), MAX(id)"
77
77
 
78
78
  batch_size = options[:batch_size].try(:to_i) || 1000
79
- quoted_primary_key = "#{klass.connection.quote_local_table_name(table_name)}.#{klass.connection.quote_column_name(primary_key)}"
80
- as_id = ' AS id' unless primary_key == 'id'
81
- subquery_scope = except(:select).select("#{quoted_primary_key}#{as_id}").reorder(primary_key.to_sym).limit(loose_mode ? 1 : batch_size)
79
+ quoted_primary_key =
80
+ "#{klass.connection.quote_local_table_name(table_name)}.#{klass.connection.quote_column_name(primary_key)}"
81
+ as_id = " AS id" unless primary_key == "id"
82
+ subquery_scope = except(:select)
83
+ .select("#{quoted_primary_key}#{as_id}")
84
+ .reorder(primary_key.to_sym)
85
+ .limit(loose_mode ? 1 : batch_size)
82
86
  subquery_scope = subquery_scope.where("#{quoted_primary_key} <= ?", options[:end_at]) if options[:end_at]
83
87
 
84
88
  first_subquery_scope = if options[:start_at]
@@ -121,7 +125,9 @@ module Switchman
121
125
  relation = shard(Shard.current(klass.connection_class_for_self))
122
126
  relation.remove_nonlocal_primary_keys!
123
127
  # do a minimal query if possible
124
- relation = relation.limit(limit_value - result_count) if limit_value && !result_count.zero? && order_values.empty?
128
+ if limit_value && !result_count.zero? && order_values.empty?
129
+ relation = relation.limit(limit_value - result_count)
130
+ end
125
131
 
126
132
  shard_results = relation.activate(&block)
127
133
 
@@ -17,7 +17,7 @@ module Switchman
17
17
  final_shard_source_value = %i[explicit association].detect do |source_value|
18
18
  shard_source_value == source_value || rhs.shard_source_value == source_value
19
19
  end
20
- raise 'unknown shard_source_value' unless final_shard_source_value
20
+ raise "unknown shard_source_value" unless final_shard_source_value
21
21
 
22
22
  # have to merge shard_value
23
23
  lhs_shard_value = all_shards
@@ -36,7 +36,7 @@ module Switchman
36
36
  final_shard_source_value = %i[explicit association implicit].detect do |source_value|
37
37
  shard_source_value == source_value || rhs.shard_source_value == source_value
38
38
  end
39
- raise 'unknown shard_source_value' unless final_shard_source_value
39
+ raise "unknown shard_source_value" unless final_shard_source_value
40
40
  end
41
41
 
42
42
  [final_shard_value, final_primary_shard, final_shard_source_value]
@@ -4,8 +4,8 @@ module Switchman
4
4
  module ActiveRecord
5
5
  module StatementCache
6
6
  module ClassMethods
7
- def create(connection, &block)
8
- relation = block.call ::ActiveRecord::StatementCache::Params.new
7
+ def create(connection)
8
+ relation = yield ::ActiveRecord::StatementCache::Params.new
9
9
 
10
10
  _query_builder, binds = connection.cacheable_query(self, relation.arel)
11
11
  bind_map = ::ActiveRecord::StatementCache::BindMap.new(binds)
@@ -7,7 +7,7 @@ module Switchman
7
7
  def drop(*)
8
8
  super
9
9
  # no really, it's gone
10
- Switchman.cache.delete('default_shard')
10
+ Switchman.cache.delete("default_shard")
11
11
  Shard.default(reload: true)
12
12
  end
13
13
  end
@@ -12,31 +12,34 @@ module Switchman
12
12
  # Replace the one that activerecord natively uses with a switchman-optimized one
13
13
  ::ActiveSupport::Notifications.unsubscribe(@connection_subscriber)
14
14
  # Code adapted from the code in rails proper
15
- @connection_subscriber = ::ActiveSupport::Notifications.subscribe('!connection.active_record') do |_, _, _, _, payload|
16
- spec_name = payload[:spec_name] if payload.key?(:spec_name)
17
- shard = payload[:shard] if payload.key?(:shard)
18
- setup_shared_connection_pool
15
+ @connection_subscriber =
16
+ ::ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
17
+ spec_name = payload[:spec_name] if payload.key?(:spec_name)
18
+ shard = payload[:shard] if payload.key?(:shard)
19
+ setup_shared_connection_pool
19
20
 
20
- if spec_name && !FORBIDDEN_DB_ENVS.include?(shard)
21
- begin
22
- connection = ::ActiveRecord::Base.connection_handler.retrieve_connection(spec_name, shard: shard)
23
- rescue ::ActiveRecord::ConnectionNotEstablished, ::ActiveRecord::NoDatabaseError
24
- connection = nil
25
- end
21
+ if spec_name && !FORBIDDEN_DB_ENVS.include?(shard)
22
+ begin
23
+ connection = ::ActiveRecord::Base.connection_handler.retrieve_connection(spec_name, shard: shard)
24
+ rescue ::ActiveRecord::ConnectionNotEstablished, ::ActiveRecord::NoDatabaseError
25
+ connection = nil
26
+ end
26
27
 
27
- if connection && !@fixture_connections.include?(connection)
28
- connection.begin_transaction joinable: false, _lazy: false
29
- connection.pool.lock_thread = true if lock_threads
30
- @fixture_connections << connection
28
+ if connection && !@fixture_connections.include?(connection)
29
+ connection.begin_transaction joinable: false, _lazy: false
30
+ connection.pool.lock_thread = true if lock_threads
31
+ @fixture_connections << connection
32
+ end
31
33
  end
32
34
  end
33
- end
34
35
  end
35
36
 
36
37
  def enlist_fixture_connections
37
38
  setup_shared_connection_pool
38
39
 
39
- ::ActiveRecord::Base.connection_handler.connection_pool_list.reject { |cp| FORBIDDEN_DB_ENVS.include?(cp.db_config.env_name.to_sym) }.map(&:connection)
40
+ ::ActiveRecord::Base.connection_handler.connection_pool_list.reject do |cp|
41
+ FORBIDDEN_DB_ENVS.include?(cp.db_config.env_name.to_sym)
42
+ end.map(&:connection)
40
43
  end
41
44
  end
42
45
  end
@@ -24,7 +24,10 @@ module Switchman
24
24
  store = super
25
25
  # can't use defined?, because it's a _ruby_ autoloaded constant,
26
26
  # so just checking that will cause it to get required
27
- ::ActiveSupport::Cache::RedisCacheStore.prepend(RedisCacheStore) if store.instance_of?(ActiveSupport::Cache::RedisCacheStore) && !::ActiveSupport::Cache::RedisCacheStore.ancestors.include?(RedisCacheStore)
27
+ if store.instance_of?(ActiveSupport::Cache::RedisCacheStore) &&
28
+ !::ActiveSupport::Cache::RedisCacheStore <= RedisCacheStore
29
+ ::ActiveSupport::Cache::RedisCacheStore.prepend(RedisCacheStore)
30
+ end
28
31
  store.options[:namespace] ||= -> { Shard.current.default? ? nil : "shard_#{Shard.current.id}" }
29
32
  store
30
33
  end
@@ -15,24 +15,24 @@ module Switchman
15
15
 
16
16
  def visit_Arel_Nodes_TableAlias(o, collector)
17
17
  collector = visit o.relation, collector
18
- collector << ' '
18
+ collector << " "
19
19
  collector << quote_local_table_name(o.name)
20
20
  end
21
21
 
22
22
  def visit_Arel_Attributes_Attribute(o, collector)
23
23
  join_name = o.relation.table_alias || o.relation.name
24
- collector << quote_local_table_name(join_name) << '.' << quote_column_name(o.name)
24
+ collector << quote_local_table_name(join_name) << "." << quote_column_name(o.name)
25
25
  end
26
26
 
27
27
  def visit_Arel_Nodes_HomogeneousIn(o, collector)
28
28
  collector.preparable = false
29
29
 
30
- collector << quote_local_table_name(o.table_name) << '.' << quote_column_name(o.column_name)
30
+ collector << quote_local_table_name(o.table_name) << "." << quote_column_name(o.column_name)
31
31
 
32
32
  collector << if o.type == :in
33
- ' IN ('
33
+ " IN ("
34
34
  else
35
- ' NOT IN ('
35
+ " NOT IN ("
36
36
  end
37
37
 
38
38
  values = o.casted_values
@@ -43,7 +43,7 @@ module Switchman
43
43
  collector.add_binds(values, o.proc_for_binds, &bind_block)
44
44
  end
45
45
 
46
- collector << ')'
46
+ collector << ")"
47
47
  collector
48
48
  end
49
49
 
@@ -12,7 +12,7 @@ module Switchman
12
12
  method.super_method
13
13
  end
14
14
 
15
- if RUBY_VERSION <= '2.8'
15
+ if RUBY_VERSION <= "2.8"
16
16
  def call_super(method, above_module, *args, &block)
17
17
  super_method_above(method, above_module).call(*args, &block)
18
18
  end