switchman 3.0.9 → 3.1.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 +1 -1
  3. data/lib/switchman/action_controller/caching.rb +2 -2
  4. data/lib/switchman/active_record/abstract_adapter.rb +2 -4
  5. data/lib/switchman/active_record/associations.rb +223 -0
  6. data/lib/switchman/active_record/attribute_methods.rb +144 -84
  7. data/lib/switchman/active_record/base.rb +71 -31
  8. data/lib/switchman/active_record/calculations.rb +11 -4
  9. data/lib/switchman/active_record/connection_pool.rb +2 -4
  10. data/lib/switchman/active_record/database_configurations.rb +18 -2
  11. data/lib/switchman/active_record/finder_methods.rb +2 -2
  12. data/lib/switchman/active_record/model_schema.rb +1 -1
  13. data/lib/switchman/active_record/persistence.rb +3 -5
  14. data/lib/switchman/active_record/postgresql_adapter.rb +1 -1
  15. data/lib/switchman/active_record/query_methods.rb +20 -11
  16. data/lib/switchman/active_record/reflection.rb +1 -1
  17. data/lib/switchman/active_record/relation.rb +15 -18
  18. data/lib/switchman/active_record/statement_cache.rb +2 -2
  19. data/lib/switchman/active_record/table_definition.rb +1 -1
  20. data/lib/switchman/active_support/cache.rb +16 -0
  21. data/lib/switchman/database_server.rb +26 -18
  22. data/lib/switchman/default_shard.rb +0 -2
  23. data/lib/switchman/engine.rb +63 -125
  24. data/lib/switchman/errors.rb +4 -2
  25. data/lib/switchman/guard_rail/relation.rb +6 -9
  26. data/lib/switchman/guard_rail.rb +5 -0
  27. data/lib/switchman/parallel.rb +68 -0
  28. data/lib/switchman/r_spec_helper.rb +3 -0
  29. data/lib/switchman/rails.rb +2 -5
  30. data/{app/models → lib}/switchman/shard.rb +28 -133
  31. data/lib/switchman/sharded_instrumenter.rb +1 -1
  32. data/lib/switchman/standard_error.rb +10 -11
  33. data/{app/models → lib}/switchman/unsharded_record.rb +1 -1
  34. data/lib/switchman/version.rb +1 -1
  35. data/lib/switchman.rb +22 -2
  36. data/lib/tasks/switchman.rake +16 -9
  37. metadata +20 -20
  38. data/lib/switchman/active_record/association.rb +0 -206
  39. data/lib/switchman/open4.rb +0 -80
@@ -14,8 +14,6 @@ module Switchman
14
14
  def sharded_model
15
15
  self.abstract_class = true
16
16
 
17
- return if self == UnshardedRecord
18
-
19
17
  Shard.send(:add_sharded_model, self)
20
18
  end
21
19
 
@@ -27,20 +25,12 @@ module Switchman
27
25
  def transaction(**)
28
26
  if self != ::ActiveRecord::Base && current_scope
29
27
  current_scope.activate do
30
- db = Shard.current(connection_classes).database_server
31
- if ::GuardRail.environment == db.guard_rail_environment
32
- super
33
- else
34
- db.unguard { super }
35
- end
36
- end
37
- else
38
- db = Shard.current(connection_classes).database_server
39
- if ::GuardRail.environment == db.guard_rail_environment
40
- super
41
- else
28
+ db = Shard.current(connection_class_for_self).database_server
42
29
  db.unguard { super }
43
30
  end
31
+ else
32
+ db = Shard.current(connection_class_for_self).database_server
33
+ db.unguard { super }
44
34
  end
45
35
  end
46
36
 
@@ -68,11 +58,56 @@ module Switchman
68
58
  end
69
59
  end
70
60
 
61
+ def role_overriden?(shard_id)
62
+ current_role(target_shard: shard_id) != current_role(without_overrides: true)
63
+ end
64
+
65
+ def establish_connection(config_or_env = nil)
66
+ 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
67
+
68
+ # Ensure we don't randomly surprise change the connection parms associated with a shard/role
69
+ config_or_env = nil if config_or_env == ::Rails.env.to_sym
70
+
71
+ config_or_env ||= if current_shard == ::Rails.env.to_sym && current_role == :primary
72
+ :primary
73
+ else
74
+ "#{current_shard}/#{current_role}".to_sym
75
+ end
76
+
77
+ super(config_or_env)
78
+ end
79
+
80
+ def connected_to_stack
81
+ return super if ::Rails.version < '7.0' ? Thread.current.thread_variable?(:ar_connected_to_stack) : ::ActiveSupport::IsolatedExecutionState.key?(:active_record_connected_to_stack)
82
+
83
+ ret = super
84
+ DatabaseServer.guard_servers
85
+ ret
86
+ end
87
+
88
+ # significant change: Allow per-shard roles
89
+ def current_role(without_overrides: false, target_shard: current_shard)
90
+ return super() if without_overrides
91
+
92
+ sharded_role = nil
93
+ connected_to_stack.reverse_each do |hash|
94
+ shard_role = hash.dig(:shard_roles, target_shard)
95
+ if shard_role && (hash[:klasses].include?(::ActiveRecord::Base) || hash[:klasses].include?(connection_class_for_self))
96
+ sharded_role = shard_role
97
+ break
98
+ end
99
+ end
100
+ # Allow a shard-specific role to be reverted to regular inheritance
101
+ return sharded_role if sharded_role && sharded_role != :_switchman_inherit
102
+
103
+ super()
104
+ end
105
+
71
106
  # significant change: _don't_ check if klasses.include?(Base)
72
107
  # i.e. other sharded models don't inherit the current shard of Base
73
108
  def current_shard
74
109
  connected_to_stack.reverse_each do |hash|
75
- return hash[:shard] if hash[:shard] && hash[:klasses].include?(connection_classes)
110
+ return hash[:shard] if hash[:shard] && hash[:klasses].include?(connection_class_for_self)
76
111
  end
77
112
 
78
113
  default_shard
@@ -80,11 +115,17 @@ module Switchman
80
115
 
81
116
  def current_switchman_shard
82
117
  connected_to_stack.reverse_each do |hash|
83
- return hash[:switchman_shard] if hash[:switchman_shard] && hash[:klasses].include?(connection_classes)
118
+ return hash[:switchman_shard] if hash[:switchman_shard] && hash[:klasses].include?(connection_class_for_self)
84
119
  end
85
120
 
86
121
  Shard.default
87
122
  end
123
+
124
+ if ::Rails.version < '7.0'
125
+ def connection_class_for_self
126
+ connection_classes
127
+ end
128
+ end
88
129
  end
89
130
 
90
131
  def self.prepended(klass)
@@ -93,15 +134,15 @@ module Switchman
93
134
 
94
135
  def _run_initialize_callbacks
95
136
  @shard ||= if self.class.sharded_primary_key?
96
- Shard.shard_for(self[self.class.primary_key], Shard.current(self.class.connection_classes))
137
+ Shard.shard_for(self[self.class.primary_key], Shard.current(self.class.connection_class_for_self))
97
138
  else
98
- Shard.current(self.class.connection_classes)
139
+ Shard.current(self.class.connection_class_for_self)
99
140
  end
100
141
  super
101
142
  end
102
143
 
103
144
  def shard
104
- @shard || Shard.current(self.class.connection_classes) || Shard.default
145
+ @shard || Shard.current(self.class.connection_class_for_self) || Shard.default
105
146
  end
106
147
 
107
148
  def shard=(new_shard)
@@ -126,7 +167,7 @@ module Switchman
126
167
  end
127
168
 
128
169
  def destroy
129
- shard.activate(self.class.connection_classes) { super }
170
+ shard.activate(self.class.connection_class_for_self) { super }
130
171
  end
131
172
 
132
173
  def clone
@@ -139,14 +180,15 @@ module Switchman
139
180
  end
140
181
 
141
182
  def transaction(**kwargs, &block)
142
- shard.activate(self.class.connection_classes) do
183
+ shard.activate(self.class.connection_class_for_self) do
143
184
  self.class.transaction(**kwargs, &block)
144
185
  end
145
186
  end
146
187
 
147
188
  def with_transaction_returning_status
148
- shard.activate(self.class.connection_classes) do
149
- super
189
+ shard.activate(self.class.connection_class_for_self) do
190
+ db = Shard.current(self.class.connection_class_for_self).database_server
191
+ db.unguard { super }
150
192
  end
151
193
  end
152
194
 
@@ -167,9 +209,7 @@ module Switchman
167
209
 
168
210
  def update_columns(*)
169
211
  db = shard.database_server
170
- return db.unguard { super } if ::GuardRail.environment != db.guard_rail_environment
171
-
172
- super
212
+ db.unguard { super }
173
213
  end
174
214
 
175
215
  def id_for_database
@@ -184,22 +224,22 @@ module Switchman
184
224
 
185
225
  protected
186
226
 
187
- # see also AttributeMethods#connection_classes_code_for_reflection
188
- def connection_classes_for_reflection(reflection)
227
+ # see also AttributeMethods#connection_class_for_self_code_for_reflection
228
+ def connection_class_for_self_for_reflection(reflection)
189
229
  if reflection
190
230
  if reflection.options[:polymorphic]
191
231
  begin
192
- read_attribute(reflection.foreign_type)&.constantize&.connection_classes || ::ActiveRecord::Base
232
+ read_attribute(reflection.foreign_type)&.constantize&.connection_class_for_self || ::ActiveRecord::Base
193
233
  rescue NameError
194
234
  # in case someone is abusing foreign_type to not point to an actual class
195
235
  ::ActiveRecord::Base
196
236
  end
197
237
  else
198
238
  # otherwise we can just return a symbol for the statically known type of the association
199
- reflection.klass.connection_classes
239
+ reflection.klass.connection_class_for_self
200
240
  end
201
241
  else
202
- self.class.connection_classes
242
+ self.class.connection_class_for_self
203
243
  end
204
244
  end
205
245
  end
@@ -4,7 +4,7 @@ module Switchman
4
4
  module ActiveRecord
5
5
  module Calculations
6
6
  def pluck(*column_names)
7
- target_shard = Shard.current(klass.connection_classes)
7
+ target_shard = Shard.current(klass.connection_class_for_self)
8
8
  shard_count = 0
9
9
  result = activate do |relation, shard|
10
10
  shard_count += 1
@@ -109,11 +109,18 @@ module Switchman
109
109
  private
110
110
 
111
111
  def type_cast_calculated_value_switchman(value, column_name, operation)
112
- type_cast_calculated_value(value, operation) do |val|
112
+ if ::Rails.version < '7.0'
113
+ type_cast_calculated_value(value, operation) do |val|
114
+ column = aggregate_column(column_name)
115
+ type ||= column.try(:type_caster) ||
116
+ lookup_cast_type_from_join_dependencies(column_name.to_s) || ::ActiveRecord::Type.default_value
117
+ type.deserialize(val)
118
+ end
119
+ else
113
120
  column = aggregate_column(column_name)
114
121
  type ||= column.try(:type_caster) ||
115
- lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
116
- type.deserialize(val)
122
+ lookup_cast_type_from_join_dependencies(column_name.to_s) || ::ActiveRecord::Type.default_value
123
+ type_cast_calculated_value(value, operation, type)
117
124
  end
118
125
  end
119
126
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'switchman/errors'
4
-
5
3
  module Switchman
6
4
  module ActiveRecord
7
5
  module ConnectionPool
@@ -20,7 +18,7 @@ module Switchman
20
18
 
21
19
  def connection(switch_shard: true)
22
20
  conn = super()
23
- raise NonExistentShardError if current_shard.new_record?
21
+ raise Errors::NonExistentShardError if current_shard.new_record?
24
22
 
25
23
  switch_database(conn) if conn.shard != current_shard && switch_shard
26
24
  conn
@@ -41,7 +39,7 @@ module Switchman
41
39
  private
42
40
 
43
41
  def current_shard
44
- connection_klass.current_switchman_shard
42
+ ::Rails.version < '7.0' ? connection_klass.current_switchman_shard : connection_class.current_switchman_shard
45
43
  end
46
44
 
47
45
  def tls_key
@@ -3,6 +3,20 @@
3
3
  module Switchman
4
4
  module ActiveRecord
5
5
  module DatabaseConfigurations
6
+ # key difference: For each env name, ensure only one writable config is returned
7
+ # since all should point to the same data, even if multiple are writable
8
+ # (Picks 'primary' since it is guaranteed to exist and switchman handles activating
9
+ # deploy through other means)
10
+ def configs_for(include_replicas: false, name: nil, **)
11
+ res = super
12
+ if name && !include_replicas
13
+ return nil unless name.end_with?('primary')
14
+ elsif !include_replicas
15
+ return res.select { |config| config.name.end_with?('primary') }
16
+ end
17
+ res
18
+ end
19
+
6
20
  private
7
21
 
8
22
  # key difference: assumes a hybrid two-tier structure; each third tier
@@ -13,7 +27,9 @@ module Switchman
13
27
  return configs if configs.is_a?(Array)
14
28
 
15
29
  db_configs = configs.flat_map do |env_name, config|
16
- roles = config.keys.select { |k| config[k].is_a?(Hash) }
30
+ # It would be nice to do the auto-fallback that we want here, but we haven't
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) }) }
17
33
  base_config = config.except(*roles)
18
34
 
19
35
  name = "#{env_name}/primary"
@@ -21,7 +37,7 @@ module Switchman
21
37
  base_db = build_db_config_from_raw_config(env_name, name, base_config)
22
38
  [base_db] + roles.map do |role|
23
39
  build_db_config_from_raw_config(env_name, "#{env_name}/#{role}",
24
- base_config.merge(config[role]).merge(replica: true))
40
+ base_config.merge(config[role].is_a?(Array) ? config[role].first : config[role]))
25
41
  end
26
42
  end
27
43
 
@@ -7,7 +7,7 @@ module Switchman
7
7
  return super(id) unless klass.integral_id?
8
8
 
9
9
  if shard_source_value != :implicit
10
- current_shard = Shard.current(klass.connection_classes)
10
+ current_shard = Shard.current(klass.connection_class_for_self)
11
11
  result = activate do |relation, shard|
12
12
  current_id = Shard.relative_id_for(id, current_shard, shard)
13
13
  # current_id will be nil for non-integral id
@@ -33,7 +33,7 @@ module Switchman
33
33
  end
34
34
 
35
35
  def find_some_ordered(ids)
36
- current_shard = Shard.current(klass.connection_classes)
36
+ current_shard = Shard.current(klass.connection_class_for_self)
37
37
  ids = ids.map { |id| Shard.relative_id_for(id, current_shard, current_shard) }
38
38
  super(ids)
39
39
  end
@@ -6,7 +6,7 @@ module Switchman
6
6
  module ClassMethods
7
7
  def quoted_table_name
8
8
  @quoted_table_name ||= {}
9
- @quoted_table_name[Shard.current(connection_classes).id] ||= connection.quote_table_name(table_name)
9
+ @quoted_table_name[Shard.current(connection_class_for_self).id] ||= connection.quote_table_name(table_name)
10
10
  end
11
11
  end
12
12
  end
@@ -5,18 +5,16 @@ module Switchman
5
5
  module Persistence
6
6
  # touch reads the id attribute directly, so it's not relative to the current shard
7
7
  def touch(*, **)
8
- shard.activate(self.class.connection_classes) { super }
8
+ shard.activate(self.class.connection_class_for_self) { super }
9
9
  end
10
10
 
11
11
  def update_columns(*)
12
- shard.activate(self.class.connection_classes) { super }
12
+ shard.activate(self.class.connection_class_for_self) { super }
13
13
  end
14
14
 
15
15
  def delete
16
16
  db = shard.database_server
17
- return db.unguard { super } unless ::GuardRail.environment == db.guard_rail_environment
18
-
19
- super
17
+ db.unguard { super }
20
18
  end
21
19
  end
22
20
  end
@@ -7,7 +7,7 @@ module Switchman
7
7
  def create_database(name, options = {})
8
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}\""
@@ -65,7 +65,7 @@ module Switchman
65
65
  when ::ActiveRecord::Relation
66
66
  Shard.default
67
67
  when nil
68
- Shard.current(klass.connection_classes)
68
+ Shard.current(klass.connection_class_for_self)
69
69
  else
70
70
  raise ArgumentError, "invalid shard value #{shard_value}"
71
71
  end
@@ -79,7 +79,7 @@ module Switchman
79
79
  when ::ActiveRecord::Base
80
80
  shard_value.respond_to?(:associated_shards) ? shard_value.associated_shards : [shard_value.shard]
81
81
  when nil
82
- [Shard.current(klass.connection_classes)]
82
+ [Shard.current(klass.connection_class_for_self)]
83
83
  else
84
84
  shard_value
85
85
  end
@@ -131,7 +131,7 @@ module Switchman
131
131
  id_shards = Set.new
132
132
  right.each do |value|
133
133
  local_id, id_shard = Shard.local_id_for(value)
134
- id_shard ||= Shard.current(klass.connection_classes) if local_id
134
+ id_shard ||= Shard.current(klass.connection_class_for_self) if local_id
135
135
  id_shards << id_shard if id_shard
136
136
  end
137
137
  return if id_shards.empty?
@@ -151,10 +151,13 @@ module Switchman
151
151
  end
152
152
  when ::Arel::Nodes::BindParam
153
153
  local_id, id_shard = Shard.local_id_for(right.value.value_before_type_cast)
154
- id_shard ||= Shard.current(klass.connection_classes) if local_id
154
+ id_shard ||= Shard.current(klass.connection_class_for_self) if local_id
155
+ when ::ActiveModel::Attribute
156
+ local_id, id_shard = Shard.local_id_for(right.value_before_type_cast)
157
+ id_shard ||= Shard.current(klass.connection_class_for_self) if local_id
155
158
  else
156
159
  local_id, id_shard = Shard.local_id_for(right)
157
- id_shard ||= Shard.current(klass.connection_classes) if local_id
160
+ id_shard ||= Shard.current(klass.connection_class_for_self) if local_id
158
161
  end
159
162
 
160
163
  return if !id_shard || id_shard == primary_shard
@@ -193,9 +196,9 @@ module Switchman
193
196
  reflection = model.send(:reflection_for_integer_attribute, column)
194
197
  break if reflection
195
198
  end
196
- return Shard.current(klass.connection_classes) if reflection.options[:polymorphic]
199
+ return Shard.current(klass.connection_class_for_self) if reflection.options[:polymorphic]
197
200
 
198
- Shard.current(reflection.klass.connection_classes)
201
+ Shard.current(reflection.klass.connection_class_for_self)
199
202
  end
200
203
 
201
204
  def relation_and_column(attribute)
@@ -291,7 +294,7 @@ module Switchman
291
294
  if source_shard
292
295
  source_shard
293
296
  elsif type == :primary
294
- Shard.current(klass.connection_classes)
297
+ Shard.current(klass.connection_class_for_self)
295
298
  elsif type == :foreign
296
299
  source_shard_for_foreign_key(relation, column)
297
300
  end
@@ -332,8 +335,9 @@ module Switchman
332
335
  end
333
336
 
334
337
  def transpose_predicate_value(value, current_shard, target_shard, attribute_type, remove_non_local_ids)
335
- if value.is_a?(::Arel::Nodes::BindParam)
336
- query_att = value.value
338
+ case value
339
+ when ::Arel::Nodes::BindParam, ::ActiveModel::Attribute
340
+ query_att = value.is_a?(::ActiveModel::Attribute) ? value : value.value
337
341
  current_id = query_att.value_before_type_cast
338
342
  if current_id.is_a?(::ActiveRecord::StatementCache::Substitute)
339
343
  current_id.sharded = true # mark for transposition later
@@ -346,7 +350,12 @@ module Switchman
346
350
  # make a new bind param
347
351
  value
348
352
  else
349
- ::Arel::Nodes::BindParam.new(query_att.class.new(query_att.name, local_id, query_att.type))
353
+ new_att = query_att.class.new(query_att.name, local_id, query_att.type)
354
+ if value.is_a?(::ActiveModel::Attribute)
355
+ new_att
356
+ else
357
+ ::Arel::Nodes::BindParam.new(new_att)
358
+ end
350
359
  end
351
360
  end
352
361
  else
@@ -5,7 +5,7 @@ module Switchman
5
5
  module Reflection
6
6
  module AbstractReflection
7
7
  def shard(owner)
8
- if polymorphic? || klass.connection_classes == owner.class.connection_classes
8
+ if polymorphic? || klass.connection_class_for_self == owner.class.connection_class_for_self
9
9
  # polymorphic associations assume the same shard as the owning item
10
10
  owner.shard
11
11
  else
@@ -9,13 +9,13 @@ module Switchman
9
9
 
10
10
  def initialize(*, **)
11
11
  super
12
- self.shard_value = Shard.current(klass ? klass.connection_classes : :primary) unless shard_value
12
+ self.shard_value = Shard.current(klass ? klass.connection_class_for_self : :primary) unless shard_value
13
13
  self.shard_source_value = :implicit unless shard_source_value
14
14
  end
15
15
 
16
16
  def clone
17
17
  result = super
18
- result.shard_value = Shard.current(klass ? klass.connection_classes : :primary) unless shard_value
18
+ result.shard_value = Shard.current(klass ? klass.connection_class_for_self : :primary) unless shard_value
19
19
  result
20
20
  end
21
21
 
@@ -29,35 +29,32 @@ module Switchman
29
29
  end
30
30
 
31
31
  def new(*, &block)
32
- primary_shard.activate(klass.connection_classes) { super }
32
+ primary_shard.activate(klass.connection_class_for_self) { super }
33
33
  end
34
34
 
35
35
  def create(*, &block)
36
- primary_shard.activate(klass.connection_classes) { super }
36
+ primary_shard.activate(klass.connection_class_for_self) { super }
37
37
  end
38
38
 
39
39
  def create!(*, &block)
40
- primary_shard.activate(klass.connection_classes) { super }
40
+ primary_shard.activate(klass.connection_class_for_self) { super }
41
41
  end
42
42
 
43
43
  def to_sql
44
- primary_shard.activate(klass.connection_classes) { super }
44
+ primary_shard.activate(klass.connection_class_for_self) { super }
45
45
  end
46
46
 
47
47
  def explain
48
48
  activate { |relation| relation.call_super(:explain, Relation) }
49
49
  end
50
50
 
51
- def records
52
- return @records if loaded?
53
-
54
- results = activate { |relation| relation.call_super(:records, Relation) }
55
- case shard_value
56
- when Array, ::ActiveRecord::Relation, ::ActiveRecord::Base
57
- @records = results
51
+ def load(&block)
52
+ if !loaded? || (::Rails.version >= '7.0' && scheduled?)
53
+ @records = activate { |relation| relation.send(:exec_queries, &block) }
58
54
  @loaded = true
59
55
  end
60
- results
56
+
57
+ self
61
58
  end
62
59
 
63
60
  %I[update_all delete_all].each do |method|
@@ -106,19 +103,19 @@ module Switchman
106
103
  def activate(unordered: false, &block)
107
104
  shards = all_shards
108
105
  if Array === shards && shards.length == 1
109
- if shards.first == DefaultShard || shards.first == Shard.current(klass.connection_classes)
106
+ if shards.first == DefaultShard || shards.first == Shard.current(klass.connection_class_for_self)
110
107
  yield(self, shards.first)
111
108
  else
112
- shards.first.activate(klass.connection_classes) { yield(self, shards.first) }
109
+ shards.first.activate(klass.connection_class_for_self) { yield(self, shards.first) }
113
110
  end
114
111
  else
115
112
  result_count = 0
116
113
  can_order = false
117
- result = Shard.with_each_shard(shards, [klass.connection_classes]) do
114
+ result = Shard.with_each_shard(shards, [klass.connection_class_for_self]) do
118
115
  # don't even query other shards if we're already past the limit
119
116
  next if limit_value && result_count >= limit_value && order_values.empty?
120
117
 
121
- relation = shard(Shard.current(klass.connection_classes), :to_a)
118
+ relation = shard(Shard.current(klass.connection_class_for_self), :to_a)
122
119
  # do a minimal query if possible
123
120
  relation = relation.limit(limit_value - result_count) if limit_value && !result_count.zero? && order_values.empty?
124
121
 
@@ -33,12 +33,12 @@ module Switchman
33
33
  primary_value = params[primary_index]
34
34
  target_shard = Shard.local_id_for(primary_value)[1]
35
35
  end
36
- current_shard = Shard.current(klass.connection_classes)
36
+ current_shard = Shard.current(klass.connection_class_for_self)
37
37
  target_shard ||= current_shard
38
38
 
39
39
  bind_values = bind_map.bind(params, current_shard, target_shard)
40
40
 
41
- target_shard.activate(klass.connection_classes) do
41
+ target_shard.activate(klass.connection_class_for_self) do
42
42
  sql = qualified_query_builder(target_shard, klass).sql_for(bind_values, connection)
43
43
  klass.find_by_sql(sql, bind_values)
44
44
  end
@@ -4,7 +4,7 @@ module Switchman
4
4
  module ActiveRecord
5
5
  module TableDefinition
6
6
  def column(name, type, limit: nil, **)
7
- Engine.foreign_key_check(name, type, limit: limit)
7
+ Switchman.foreign_key_check(name, type, limit: limit)
8
8
  super
9
9
  end
10
10
  end
@@ -4,6 +4,22 @@ module Switchman
4
4
  module ActiveSupport
5
5
  module Cache
6
6
  module ClassMethods
7
+ def lookup_stores(cache_store_config)
8
+ result = {}
9
+ cache_store_config.each do |key, value|
10
+ next if value.is_a?(String)
11
+
12
+ result[key] = ::ActiveSupport::Cache.lookup_store(value)
13
+ end
14
+
15
+ cache_store_config.each do |key, value| # rubocop:disable Style/CombinableLoops
16
+ next unless value.is_a?(String)
17
+
18
+ result[key] = result[value]
19
+ end
20
+ result
21
+ end
22
+
7
23
  def lookup_store(*store_options)
8
24
  store = super
9
25
  # can't use defined?, because it's a _ruby_ autoloaded constant,