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
@@ -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