switchman 4.0.0 → 4.2.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.
- checksums.yaml +4 -4
- data/lib/switchman/active_record/abstract_adapter.rb +1 -7
- data/lib/switchman/active_record/associations.rb +44 -60
- data/lib/switchman/active_record/attribute_methods.rb +34 -27
- data/lib/switchman/active_record/base.rb +12 -61
- data/lib/switchman/active_record/calculations.rb +37 -48
- data/lib/switchman/active_record/connection_pool.rb +37 -23
- data/lib/switchman/active_record/database_configurations.rb +7 -19
- data/lib/switchman/active_record/finder_methods.rb +21 -45
- data/lib/switchman/active_record/log_subscriber.rb +1 -10
- data/lib/switchman/active_record/migration.rb +12 -24
- data/lib/switchman/active_record/persistence.rb +1 -1
- data/lib/switchman/active_record/postgresql_adapter.rb +26 -12
- data/lib/switchman/active_record/query_cache.rb +22 -42
- data/lib/switchman/active_record/query_methods.rb +63 -22
- data/lib/switchman/active_record/reflection.rb +9 -2
- data/lib/switchman/active_record/relation.rb +56 -3
- data/lib/switchman/active_record/spawn_methods.rb +1 -5
- data/lib/switchman/active_record/statement_cache.rb +2 -2
- data/lib/switchman/active_record/table_definition.rb +1 -1
- data/lib/switchman/active_record/test_fixtures.rb +71 -35
- data/lib/switchman/arel.rb +0 -25
- data/lib/switchman/database_server.rb +5 -9
- data/lib/switchman/engine.rb +10 -5
- data/lib/switchman/shard.rb +9 -11
- data/lib/switchman/sharded_instrumenter.rb +1 -1
- data/lib/switchman/test_helper.rb +1 -1
- data/lib/switchman/version.rb +1 -1
- data/lib/tasks/switchman.rake +1 -1
- metadata +33 -19
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cfb4e89f881628a5d90c8f309ddf587fdc5bfebe5bc7985c79fea9dd06e7168c
|
|
4
|
+
data.tar.gz: baa3202cd9fb68347d71d43adecdbe3124fe3f4f604558f92546e8fa5c5b4773
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c351d3ff898e668ac7a8c8ab40e9cf2249f428a2d2bbc9a16573334e1599cb9bcac20a47a3534e70b7900fd76ca55f6f4a8625c9dc7c8bb3ef1b4ade95a17ff3
|
|
7
|
+
data.tar.gz: e3205573c3bbf8d8bf8a1e87beaaaed1adc2dba268f53ec1bac8c870f29f51ecdce923028eaa8528cffb9250965fc7b72d8d2dce4882c63edb0ad0d66d624a57
|
|
@@ -5,7 +5,7 @@ module Switchman
|
|
|
5
5
|
module AbstractAdapter
|
|
6
6
|
module ForeignKeyCheck
|
|
7
7
|
def add_column(table, name, type, limit: nil, **)
|
|
8
|
-
Switchman.foreign_key_check(name, type, limit:
|
|
8
|
+
Switchman.foreign_key_check(name, type, limit:)
|
|
9
9
|
super
|
|
10
10
|
end
|
|
11
11
|
end
|
|
@@ -27,12 +27,6 @@ module Switchman
|
|
|
27
27
|
quote_table_name(name)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
if ::Rails.version < "7.1"
|
|
31
|
-
def schema_migration
|
|
32
|
-
::ActiveRecord::SchemaMigration
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
30
|
protected
|
|
37
31
|
|
|
38
32
|
def log(...)
|
|
@@ -23,7 +23,7 @@ module Switchman
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
module CollectionAssociation
|
|
26
|
-
def find_target
|
|
26
|
+
def find_target(async: false)
|
|
27
27
|
shards = if reflection.options[:multishard] && owner.respond_to?(:associated_shards)
|
|
28
28
|
owner.associated_shards
|
|
29
29
|
else
|
|
@@ -38,6 +38,8 @@ module Switchman
|
|
|
38
38
|
# otherwise, the super call will set the shard_value to the object, causing it to iterate too many times
|
|
39
39
|
# over the associated shards
|
|
40
40
|
scope.shard(Shard.current(scope.klass.connection_class_for_self), :association).to_a
|
|
41
|
+
elsif ::Rails.version < "8.0"
|
|
42
|
+
super()
|
|
41
43
|
else
|
|
42
44
|
super
|
|
43
45
|
end
|
|
@@ -174,7 +176,7 @@ module Switchman
|
|
|
174
176
|
end
|
|
175
177
|
|
|
176
178
|
# Disabling to keep closer to rails original
|
|
177
|
-
# rubocop:disable Naming/AccessorMethodName
|
|
179
|
+
# rubocop:disable Naming/AccessorMethodName
|
|
178
180
|
# significant changes:
|
|
179
181
|
# * globalize the key to lookup
|
|
180
182
|
def set_inverse(record)
|
|
@@ -191,7 +193,7 @@ module Switchman
|
|
|
191
193
|
association.set_inverse_instance(record)
|
|
192
194
|
end
|
|
193
195
|
end
|
|
194
|
-
# rubocop:enable Naming/AccessorMethodName
|
|
196
|
+
# rubocop:enable Naming/AccessorMethodName
|
|
195
197
|
|
|
196
198
|
# significant changes:
|
|
197
199
|
# * partition_by_shard the records_for call
|
|
@@ -251,78 +253,60 @@ module Switchman
|
|
|
251
253
|
self.shard_source_value = :association
|
|
252
254
|
end
|
|
253
255
|
|
|
254
|
-
def shard(*
|
|
255
|
-
scope.shard(*
|
|
256
|
+
def shard(*)
|
|
257
|
+
scope.shard(*)
|
|
256
258
|
end
|
|
257
259
|
end
|
|
258
260
|
|
|
259
261
|
module AutosaveAssociation
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
return false if reflection.through_reflection?
|
|
262
|
+
def association_foreign_key_changed?(reflection, record, key)
|
|
263
|
+
return false if reflection.through_reflection?
|
|
263
264
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
def save_belongs_to_association(reflection)
|
|
269
|
-
# this seems counter-intuitive, but the autosave code will assign to attribute bypassing switchman,
|
|
270
|
-
# after reading the id attribute _without_ bypassing switchman. So we need Shard.current for the
|
|
271
|
-
# category of the associated record to match Shard.current for the category of self
|
|
272
|
-
shard.activate(connection_class_for_self_for_reflection(reflection)) { super }
|
|
273
|
-
end
|
|
274
|
-
else
|
|
275
|
-
def association_foreign_key_changed?(reflection, record, key)
|
|
276
|
-
return false if reflection.through_reflection?
|
|
265
|
+
foreign_key = Array(reflection.foreign_key)
|
|
266
|
+
return false unless foreign_key.all? { |k| record._has_attribute?(k) }
|
|
277
267
|
|
|
278
|
-
|
|
279
|
-
|
|
268
|
+
# have to use send instead of _read_attribute because sharding
|
|
269
|
+
foreign_key.map { |k| record.send(k) } != Array(key)
|
|
270
|
+
end
|
|
280
271
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
272
|
+
def save_belongs_to_association(reflection)
|
|
273
|
+
association = association_instance_get(reflection.name)
|
|
274
|
+
return unless association&.loaded? && !association.stale_target?
|
|
284
275
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
return unless association&.loaded? && !association.stale_target?
|
|
276
|
+
record = association.load_target
|
|
277
|
+
return unless record && !record.destroyed?
|
|
288
278
|
|
|
289
|
-
|
|
290
|
-
return unless record && !record.destroyed?
|
|
279
|
+
autosave = reflection.options[:autosave]
|
|
291
280
|
|
|
292
|
-
|
|
281
|
+
if autosave && record.marked_for_destruction?
|
|
282
|
+
foreign_key = Array(reflection.foreign_key)
|
|
283
|
+
foreign_key.each { |key| self[key] = nil }
|
|
284
|
+
record.destroy
|
|
285
|
+
elsif autosave != false
|
|
286
|
+
saved = record.save(validate: !autosave) if record.new_record? || (autosave && record.changed_for_autosave?)
|
|
293
287
|
|
|
294
|
-
if
|
|
288
|
+
if association.updated?
|
|
289
|
+
primary_key = Array(compute_primary_key(reflection, record)).map(&:to_s)
|
|
295
290
|
foreign_key = Array(reflection.foreign_key)
|
|
296
|
-
foreign_key.each { |key| self[key] = nil }
|
|
297
|
-
record.destroy
|
|
298
|
-
elsif autosave != false
|
|
299
|
-
if record.new_record? || (autosave && record.changed_for_autosave?)
|
|
300
|
-
saved = record.save(validate: !autosave)
|
|
301
|
-
end
|
|
302
291
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
else
|
|
317
|
-
record._read_attribute(pk)
|
|
318
|
-
end
|
|
319
|
-
self[fk] = association_id unless self[fk] == association_id
|
|
320
|
-
end
|
|
321
|
-
association.loaded!
|
|
292
|
+
primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
|
|
293
|
+
primary_key_foreign_key_pairs.each do |pk, fk|
|
|
294
|
+
# Notable change: add relative_id_for here
|
|
295
|
+
association_id = if record.class.sharded_column?(pk)
|
|
296
|
+
Shard.relative_id_for(
|
|
297
|
+
record._read_attribute(pk),
|
|
298
|
+
record.shard,
|
|
299
|
+
shard
|
|
300
|
+
)
|
|
301
|
+
else
|
|
302
|
+
record._read_attribute(pk)
|
|
303
|
+
end
|
|
304
|
+
self[fk] = association_id unless self[fk] == association_id
|
|
322
305
|
end
|
|
323
|
-
|
|
324
|
-
saved if autosave
|
|
306
|
+
association.loaded!
|
|
325
307
|
end
|
|
308
|
+
|
|
309
|
+
saved if autosave
|
|
326
310
|
end
|
|
327
311
|
end
|
|
328
312
|
end
|
|
@@ -26,10 +26,10 @@ module Switchman
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def define_attribute_methods
|
|
29
|
-
super
|
|
29
|
+
result = super
|
|
30
30
|
# ensure that we're using the sharded attribute method
|
|
31
31
|
# and not the silly one in AR::AttributeMethods::PrimaryKey
|
|
32
|
-
return unless sharded_column?(@primary_key)
|
|
32
|
+
return result unless sharded_column?(@primary_key)
|
|
33
33
|
|
|
34
34
|
class_eval(
|
|
35
35
|
build_sharded_getter("id",
|
|
@@ -41,6 +41,7 @@ module Switchman
|
|
|
41
41
|
class_eval(build_sharded_setter("id", @primary_key, "::#{connection_class_for_self.name}"),
|
|
42
42
|
__FILE__,
|
|
43
43
|
__LINE__)
|
|
44
|
+
result
|
|
44
45
|
end
|
|
45
46
|
|
|
46
47
|
protected
|
|
@@ -54,15 +55,21 @@ module Switchman
|
|
|
54
55
|
raise if connection.open_transactions.positive?
|
|
55
56
|
end
|
|
56
57
|
|
|
57
|
-
def define_cached_method(owner, name, namespace:, as:, &
|
|
58
|
-
|
|
58
|
+
def define_cached_method(owner, name, namespace:, as:, &)
|
|
59
|
+
if ::Rails.version < "7.1.4"
|
|
60
|
+
# https://github.com/rails/rails/commit/a2a12fc2e3f4e6d06f81d4c74c88f8e6b3369ee6#diff-5b59ece6d9396b596f06271cec0ea726e3360911383511c49b1a66f454bfc2b6L30
|
|
61
|
+
# These arguments were effectively swapped in Rails 7.1.4, so previous versions need them reversed
|
|
62
|
+
owner.define_cached_method(as, namespace:, as: name, &)
|
|
63
|
+
else
|
|
64
|
+
owner.define_cached_method(name, namespace:, as:, &)
|
|
65
|
+
end
|
|
59
66
|
end
|
|
60
67
|
|
|
61
|
-
def define_method_global_attribute(attr_name, owner:)
|
|
68
|
+
def define_method_global_attribute(attr_name, owner:, as: attr_name)
|
|
62
69
|
if sharded_column?(attr_name)
|
|
63
70
|
define_cached_method(owner,
|
|
64
|
-
"
|
|
65
|
-
as: "
|
|
71
|
+
"sharded_global_#{attr_name}",
|
|
72
|
+
as: "global_#{as}",
|
|
66
73
|
namespace: :switchman) do |batch|
|
|
67
74
|
batch << <<-RUBY
|
|
68
75
|
def sharded_global_#{attr_name}
|
|
@@ -79,11 +86,11 @@ module Switchman
|
|
|
79
86
|
end
|
|
80
87
|
end
|
|
81
88
|
|
|
82
|
-
def define_method_local_attribute(attr_name, owner:)
|
|
89
|
+
def define_method_local_attribute(attr_name, owner:, as: attr_name)
|
|
83
90
|
if sharded_column?(attr_name)
|
|
84
91
|
define_cached_method(owner,
|
|
85
|
-
"
|
|
86
|
-
as: "
|
|
92
|
+
"sharded_local_#{attr_name}",
|
|
93
|
+
as: "local_#{as}",
|
|
87
94
|
namespace: :switchman) do |batch|
|
|
88
95
|
batch << <<-RUBY
|
|
89
96
|
def sharded_local_#{attr_name}
|
|
@@ -122,21 +129,21 @@ module Switchman
|
|
|
122
129
|
end
|
|
123
130
|
end
|
|
124
131
|
|
|
125
|
-
def define_method_attribute(attr_name, owner:)
|
|
132
|
+
def define_method_attribute(attr_name, owner:, as: attr_name)
|
|
126
133
|
if sharded_column?(attr_name)
|
|
127
134
|
reflection = reflection_for_integer_attribute(attr_name)
|
|
128
135
|
class_name = connection_class_for_self_code_for_reflection(reflection)
|
|
129
136
|
safe_class_name = class_name.unpack1("h*")
|
|
130
137
|
define_cached_method(owner,
|
|
131
|
-
attr_name,
|
|
132
|
-
as
|
|
138
|
+
"sharded_#{safe_class_name}_#{attr_name}",
|
|
139
|
+
as:,
|
|
133
140
|
namespace: :switchman) do |batch|
|
|
134
141
|
batch << build_sharded_getter("sharded_#{safe_class_name}_#{attr_name}",
|
|
135
|
-
"original_#{
|
|
142
|
+
"original_#{as}",
|
|
136
143
|
class_name)
|
|
137
144
|
end
|
|
138
145
|
else
|
|
139
|
-
define_cached_method(owner,
|
|
146
|
+
define_cached_method(owner, "plain_#{attr_name}", as:, namespace: :switchman) do |batch|
|
|
140
147
|
batch << <<-RUBY
|
|
141
148
|
def plain_#{attr_name}
|
|
142
149
|
_read_attribute("#{attr_name}") { |n| missing_attribute(n, caller) }
|
|
@@ -169,19 +176,19 @@ module Switchman
|
|
|
169
176
|
RUBY
|
|
170
177
|
end
|
|
171
178
|
|
|
172
|
-
def define_method_attribute=(attr_name, owner:)
|
|
179
|
+
def define_method_attribute=(attr_name, owner:, as: attr_name)
|
|
173
180
|
if sharded_column?(attr_name)
|
|
174
181
|
reflection = reflection_for_integer_attribute(attr_name)
|
|
175
182
|
class_name = connection_class_for_self_code_for_reflection(reflection)
|
|
176
183
|
safe_class_name = class_name.unpack1("h*")
|
|
177
184
|
define_cached_method(owner,
|
|
178
|
-
"#{attr_name}=",
|
|
179
|
-
as: "
|
|
185
|
+
"sharded_#{safe_class_name}_#{attr_name}=",
|
|
186
|
+
as: "#{as}=",
|
|
180
187
|
namespace: :switchman) do |batch|
|
|
181
188
|
batch << build_sharded_setter("sharded_#{safe_class_name}_#{attr_name}", attr_name, class_name)
|
|
182
189
|
end
|
|
183
190
|
else
|
|
184
|
-
define_cached_method(owner, "#{attr_name}=", as: "
|
|
191
|
+
define_cached_method(owner, "plain_#{attr_name}=", as: "#{as}=", namespace: :switchman) do |batch|
|
|
185
192
|
batch << <<-RUBY
|
|
186
193
|
def plain_#{attr_name}=(new_value)
|
|
187
194
|
_write_attribute('#{attr_name}', new_value)
|
|
@@ -199,11 +206,11 @@ module Switchman
|
|
|
199
206
|
RUBY
|
|
200
207
|
end
|
|
201
208
|
|
|
202
|
-
def define_method_original_attribute(attr_name, owner:)
|
|
209
|
+
def define_method_original_attribute(attr_name, owner:, as: attr_name)
|
|
203
210
|
if sharded_column?(attr_name)
|
|
204
211
|
define_cached_method(owner,
|
|
205
|
-
"
|
|
206
|
-
as: "
|
|
212
|
+
"sharded_original_#{attr_name}",
|
|
213
|
+
as: "original_#{as}",
|
|
207
214
|
namespace: :switchman) do |batch|
|
|
208
215
|
batch << <<-RUBY
|
|
209
216
|
def sharded_original_#{attr_name}
|
|
@@ -216,12 +223,12 @@ module Switchman
|
|
|
216
223
|
end
|
|
217
224
|
end
|
|
218
225
|
|
|
219
|
-
def define_method_original_attribute=(attr_name, owner:)
|
|
226
|
+
def define_method_original_attribute=(attr_name, owner:, as: attr_name)
|
|
220
227
|
return unless sharded_column?(attr_name)
|
|
221
228
|
|
|
222
229
|
define_cached_method(owner,
|
|
223
|
-
"
|
|
224
|
-
as: "
|
|
230
|
+
"sharded_original_#{attr_name}=",
|
|
231
|
+
as: "original_#{as}=",
|
|
225
232
|
namespace: :switchman) do |batch|
|
|
226
233
|
batch << <<-RUBY
|
|
227
234
|
def sharded_original_#{attr_name}=(new_value)
|
|
@@ -235,8 +242,8 @@ module Switchman
|
|
|
235
242
|
return if columns_hash["#{prefix}_#{attr_name}"] || attr_name == "id"
|
|
236
243
|
|
|
237
244
|
define_cached_method(owner,
|
|
238
|
-
"#{prefix}_#{attr_name}",
|
|
239
|
-
as: "
|
|
245
|
+
"unsharded_#{prefix}_#{attr_name}",
|
|
246
|
+
as: "#{prefix}_#{attr_name}",
|
|
240
247
|
namespace: :switchman) do |batch|
|
|
241
248
|
batch << <<-RUBY
|
|
242
249
|
def unsharded_#{prefix}_#{attr_name}
|
|
@@ -6,9 +6,9 @@ module Switchman
|
|
|
6
6
|
module ClassMethods
|
|
7
7
|
delegate :shard, to: :all
|
|
8
8
|
|
|
9
|
-
def find_ids_in_ranges(opts = {}, &
|
|
9
|
+
def find_ids_in_ranges(opts = {}, &)
|
|
10
10
|
opts.reverse_merge!(loose: true)
|
|
11
|
-
all.find_ids_in_ranges(opts, &
|
|
11
|
+
all.find_ids_in_ranges(opts, &)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def sharded_model
|
|
@@ -34,56 +34,6 @@ module Switchman
|
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
# NOTE: `returning` values are _not_ transposed back to the current shard
|
|
38
|
-
%w[insert_all upsert_all].each do |method|
|
|
39
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
40
|
-
def #{method}(attributes, returning: nil, **)
|
|
41
|
-
scope = self != ::ActiveRecord::Base && current_scope
|
|
42
|
-
if (target_shard = scope&.primary_shard) == (current_shard = Shard.current(connection_class_for_self))
|
|
43
|
-
scope = nil
|
|
44
|
-
end
|
|
45
|
-
if scope
|
|
46
|
-
dupped = false
|
|
47
|
-
attributes.each_with_index do |hash, i|
|
|
48
|
-
if dupped || hash.any? { |k, v| sharded_column?(k) }
|
|
49
|
-
unless dupped
|
|
50
|
-
attributes = attributes.dup
|
|
51
|
-
dupped = true
|
|
52
|
-
end
|
|
53
|
-
attributes[i] = hash.to_h do |k, v|
|
|
54
|
-
if sharded_column?(k)
|
|
55
|
-
[k, Shard.relative_id_for(v, current_shard, target_shard)]
|
|
56
|
-
else
|
|
57
|
-
[k, v]
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
if scope
|
|
65
|
-
scope.activate do
|
|
66
|
-
db = Shard.current(connection_class_for_self).database_server
|
|
67
|
-
result = db.unguard { super }
|
|
68
|
-
if result&.columns&.any? { |c| sharded_column?(c) }
|
|
69
|
-
transposed_rows = result.rows.map do |row|
|
|
70
|
-
row.map.with_index do |value, i|
|
|
71
|
-
sharded_column?(result.columns[i]) ? Shard.relative_id_for(value, target_shard, current_shard) : value
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
result = ::ActiveRecord::Result.new(result.columns, transposed_rows, result.column_types)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
result
|
|
78
|
-
end
|
|
79
|
-
else
|
|
80
|
-
db = Shard.current(connection_class_for_self).database_server
|
|
81
|
-
db.unguard { super }
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
RUBY
|
|
85
|
-
end
|
|
86
|
-
|
|
87
37
|
def reset_column_information
|
|
88
38
|
@sharded_column_values = {}
|
|
89
39
|
super
|
|
@@ -103,13 +53,13 @@ module Switchman
|
|
|
103
53
|
end
|
|
104
54
|
|
|
105
55
|
def clear_query_caches_for_current_thread
|
|
106
|
-
pools =
|
|
107
|
-
::ActiveRecord::Base.connection_handler.connection_pool_list
|
|
108
|
-
else
|
|
109
|
-
::ActiveRecord::Base.connection_handler.connection_pool_list(:all)
|
|
110
|
-
end
|
|
56
|
+
pools = ::ActiveRecord::Base.connection_handler.connection_pool_list(:all)
|
|
111
57
|
pools.each do |pool|
|
|
112
|
-
|
|
58
|
+
if ::Rails.version < "7.2"
|
|
59
|
+
pool.connection(switch_shard: false).clear_query_cache if pool.active_connection?
|
|
60
|
+
elsif pool.active_connection?
|
|
61
|
+
pool.lease_connection(switch_shard: false).clear_query_cache
|
|
62
|
+
end
|
|
113
63
|
end
|
|
114
64
|
end
|
|
115
65
|
|
|
@@ -132,7 +82,7 @@ module Switchman
|
|
|
132
82
|
:"#{current_shard}/#{current_role}"
|
|
133
83
|
end
|
|
134
84
|
|
|
135
|
-
super
|
|
85
|
+
super
|
|
136
86
|
end
|
|
137
87
|
|
|
138
88
|
def connected_to_stack
|
|
@@ -189,8 +139,9 @@ module Switchman
|
|
|
189
139
|
|
|
190
140
|
def self.prepended(klass)
|
|
191
141
|
klass.singleton_class.prepend(ClassMethods)
|
|
142
|
+
klass.singleton_class.prepend(Switchman::ActiveRecord::Relation::InsertUpsertAll) if ::Rails.version < "7.2"
|
|
192
143
|
klass.scope :non_shadow, lambda { |key = primary_key|
|
|
193
|
-
where(key => (QueryMethods::NonTransposingValue.new(0)
|
|
144
|
+
where(key => (QueryMethods::NonTransposingValue.new(0)...
|
|
194
145
|
QueryMethods::NonTransposingValue.new(Shard::IDS_PER_SHARD)))
|
|
195
146
|
}
|
|
196
147
|
klass.scope :shadow, lambda { |key = primary_key|
|
|
@@ -241,7 +192,7 @@ module Switchman
|
|
|
241
192
|
end
|
|
242
193
|
end
|
|
243
194
|
target_shard.activate do
|
|
244
|
-
self.class.
|
|
195
|
+
self.class.upsert_all([shadow_attrs], unique_by: self.class.primary_key)
|
|
245
196
|
end
|
|
246
197
|
end
|
|
247
198
|
|
|
@@ -95,7 +95,7 @@ module Switchman
|
|
|
95
95
|
opts[:group_columns].each do |aliaz, _type, group_column_name|
|
|
96
96
|
if opts[:associated] && (aliaz == opts[:group_aliases].first)
|
|
97
97
|
row[aliaz] = key_records[Shard.relative_id_for(row[aliaz], shard, target_shard)]
|
|
98
|
-
elsif group_column_name &&
|
|
98
|
+
elsif group_column_name && klass.sharded_column?(group_column_name)
|
|
99
99
|
row[aliaz] = Shard.relative_id_for(row[aliaz], shard, target_shard)
|
|
100
100
|
end
|
|
101
101
|
end
|
|
@@ -106,41 +106,39 @@ module Switchman
|
|
|
106
106
|
compact_grouped_calculation_rows(rows, opts)
|
|
107
107
|
end
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return super unless klass.sharded_primary_key?
|
|
109
|
+
def ids
|
|
110
|
+
return super unless klass.sharded_primary_key?
|
|
112
111
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
end
|
|
119
|
-
return @async ? Promise::Complete.new(result) : result
|
|
112
|
+
if loaded?
|
|
113
|
+
result = records.map do |record|
|
|
114
|
+
Shard.relative_id_for(record._read_attribute(primary_key),
|
|
115
|
+
record.shard,
|
|
116
|
+
Shard.current(klass.connection_class_for_self))
|
|
120
117
|
end
|
|
118
|
+
return @async ? Promise::Complete.new(result) : result
|
|
119
|
+
end
|
|
121
120
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
121
|
+
if has_include?(primary_key)
|
|
122
|
+
relation = apply_join_dependency.group(primary_key)
|
|
123
|
+
return relation.ids
|
|
124
|
+
end
|
|
126
125
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
end
|
|
126
|
+
columns = arel_columns([primary_key])
|
|
127
|
+
base_shard = Shard.current(klass.connection_class_for_self)
|
|
128
|
+
activate do |r|
|
|
129
|
+
relation = r.spawn
|
|
130
|
+
relation.select_values = columns
|
|
131
|
+
|
|
132
|
+
result = if relation.where_clause.contradiction?
|
|
133
|
+
::ActiveRecord::Result.empty
|
|
134
|
+
else
|
|
135
|
+
skip_query_cache_if_necessary do
|
|
136
|
+
klass.connection.select_all(relation, "#{klass.name} Ids", async: @async)
|
|
139
137
|
end
|
|
138
|
+
end
|
|
140
139
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
end
|
|
140
|
+
result.then do |res|
|
|
141
|
+
type_cast_pluck_values(res, columns).map { |id| Shard.relative_id_for(id, Shard.current, base_shard) }
|
|
144
142
|
end
|
|
145
143
|
end
|
|
146
144
|
end
|
|
@@ -159,12 +157,9 @@ module Switchman
|
|
|
159
157
|
end
|
|
160
158
|
|
|
161
159
|
def grouped_calculation_options(operation, column_name, distinct)
|
|
162
|
-
opts = { operation
|
|
160
|
+
opts = { operation:, column_name:, distinct: }
|
|
163
161
|
|
|
164
|
-
|
|
165
|
-
if defined?(::ActiveRecord::Calculations::ColumnAliasTracker)
|
|
166
|
-
column_alias_tracker = ::ActiveRecord::Calculations::ColumnAliasTracker.new(connection)
|
|
167
|
-
end
|
|
162
|
+
column_alias_tracker = ::ActiveRecord::Calculations::ColumnAliasTracker.new(connection)
|
|
168
163
|
|
|
169
164
|
opts[:aggregate_alias] = aggregate_alias_for(operation, column_name, column_alias_tracker)
|
|
170
165
|
group_attrs = group_values
|
|
@@ -179,20 +174,16 @@ module Switchman
|
|
|
179
174
|
|
|
180
175
|
group_aliases = group_fields.map do |field|
|
|
181
176
|
field = connection.visitor.compile(field) if ::Arel.arel_node?(field)
|
|
182
|
-
|
|
183
|
-
column_alias_tracker.alias_for(field.to_s.downcase)
|
|
184
|
-
else
|
|
185
|
-
column_alias_for(field.to_s.downcase)
|
|
186
|
-
end
|
|
177
|
+
column_alias_tracker.alias_for(field.to_s.downcase)
|
|
187
178
|
end
|
|
188
179
|
group_columns = group_aliases.zip(group_fields).map do |aliaz, field|
|
|
189
180
|
[aliaz, type_for(field), column_name_for(field)]
|
|
190
181
|
end
|
|
191
|
-
opts.merge!(association
|
|
192
|
-
associated
|
|
193
|
-
group_aliases
|
|
194
|
-
group_columns
|
|
195
|
-
group_fields:
|
|
182
|
+
opts.merge!(association:,
|
|
183
|
+
associated:,
|
|
184
|
+
group_aliases:,
|
|
185
|
+
group_columns:,
|
|
186
|
+
group_fields:)
|
|
196
187
|
|
|
197
188
|
opts
|
|
198
189
|
end
|
|
@@ -202,10 +193,8 @@ module Switchman
|
|
|
202
193
|
"count_all"
|
|
203
194
|
elsif operation == "average"
|
|
204
195
|
"average"
|
|
205
|
-
elsif column_alias_tracker
|
|
206
|
-
column_alias_tracker.alias_for("#{operation} #{column_name}")
|
|
207
196
|
else
|
|
208
|
-
|
|
197
|
+
column_alias_tracker.alias_for("#{operation} #{column_name}")
|
|
209
198
|
end
|
|
210
199
|
end
|
|
211
200
|
|