switchman 3.6.8 → 4.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/switchman/active_record/associations.rb +1 -35
- data/lib/switchman/active_record/attribute_methods.rb +30 -28
- data/lib/switchman/active_record/base.rb +1 -11
- data/lib/switchman/active_record/calculations.rb +4 -13
- data/lib/switchman/active_record/connection_pool.rb +1 -1
- data/lib/switchman/active_record/relation.rb +1 -1
- data/lib/switchman/engine.rb +4 -17
- data/lib/switchman/sharded_instrumenter.rb +1 -5
- data/lib/switchman/version.rb +1 -1
- data/lib/tasks/switchman.rake +3 -33
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd3fc41cd455d5855db84fd49d132dca58c824dbe50e49ea4ab7c4cd0ee24d00
|
4
|
+
data.tar.gz: df1df2b43f521a5b5e424165ac167d2de351c4800db6fe50b5d83a78e8e17e16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b721c57764dc47c2da10b027b63fdeed4795c349b2dec36b0d440e98ff0294355a4bbb03d2176f30883de0b842e2f4a47f27ea2fa2f56405594f53d4a278f6c
|
7
|
+
data.tar.gz: 2729dfb39b1e3d8e3df84bcf1bd321ac39de73e552d8a6c0f15f48f6b9fdb47611a076f8e11fbcbfeb4fd8097c2e6a49a2eab7d76942af92ed769c03b1b9f7d0
|
@@ -203,41 +203,7 @@ module Switchman
|
|
203
203
|
# #compare_by_identity makes such owners different hash keys
|
204
204
|
@records_by_owner = {}.compare_by_identity
|
205
205
|
|
206
|
-
|
207
|
-
raw_records ||= loader_query.records_for([self])
|
208
|
-
elsif owner_keys.empty?
|
209
|
-
raw_records ||= []
|
210
|
-
else
|
211
|
-
# determine the shard to search for each owner
|
212
|
-
if reflection.macro == :belongs_to
|
213
|
-
# for belongs_to, it's the shard of the foreign_key
|
214
|
-
partition_proc = lambda do |owner|
|
215
|
-
if owner.class.sharded_column?(owner_key_name)
|
216
|
-
Shard.shard_for(owner[owner_key_name], owner.shard)
|
217
|
-
else
|
218
|
-
Shard.current
|
219
|
-
end
|
220
|
-
end
|
221
|
-
elsif !reflection.options[:multishard]
|
222
|
-
# for non-multishard associations, it's *just* the owner's shard
|
223
|
-
partition_proc = ->(owner) { owner.shard }
|
224
|
-
end
|
225
|
-
|
226
|
-
raw_records ||= Shard.partition_by_shard(owners, partition_proc) do |partitioned_owners|
|
227
|
-
relative_owner_keys = partitioned_owners.map do |owner|
|
228
|
-
key = owner[owner_key_name]
|
229
|
-
if key && owner.class.sharded_column?(owner_key_name)
|
230
|
-
key = Shard.relative_id_for(key,
|
231
|
-
owner.shard,
|
232
|
-
Shard.current(klass.connection_class_for_self))
|
233
|
-
end
|
234
|
-
convert_key(key)
|
235
|
-
end
|
236
|
-
relative_owner_keys.compact!
|
237
|
-
relative_owner_keys.uniq!
|
238
|
-
records_for(relative_owner_keys)
|
239
|
-
end
|
240
|
-
end
|
206
|
+
raw_records ||= loader_query.records_for([self])
|
241
207
|
|
242
208
|
@preloaded_records = raw_records.select do |record|
|
243
209
|
assignments = false
|
@@ -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
|
@@ -55,19 +56,20 @@ module Switchman
|
|
55
56
|
end
|
56
57
|
|
57
58
|
def define_cached_method(owner, name, namespace:, as:, &block)
|
58
|
-
if ::Rails.version < "7.
|
59
|
-
|
60
|
-
|
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: namespace, as: name, &block)
|
61
63
|
else
|
62
64
|
owner.define_cached_method(name, namespace: namespace, as: as, &block)
|
63
65
|
end
|
64
66
|
end
|
65
67
|
|
66
|
-
def define_method_global_attribute(attr_name, owner:)
|
68
|
+
def define_method_global_attribute(attr_name, owner:, as: attr_name)
|
67
69
|
if sharded_column?(attr_name)
|
68
70
|
define_cached_method(owner,
|
69
|
-
"
|
70
|
-
as: "
|
71
|
+
"sharded_global_#{attr_name}",
|
72
|
+
as: "global_#{as}",
|
71
73
|
namespace: :switchman) do |batch|
|
72
74
|
batch << <<-RUBY
|
73
75
|
def sharded_global_#{attr_name}
|
@@ -84,11 +86,11 @@ module Switchman
|
|
84
86
|
end
|
85
87
|
end
|
86
88
|
|
87
|
-
def define_method_local_attribute(attr_name, owner:)
|
89
|
+
def define_method_local_attribute(attr_name, owner:, as: attr_name)
|
88
90
|
if sharded_column?(attr_name)
|
89
91
|
define_cached_method(owner,
|
90
|
-
"
|
91
|
-
as: "
|
92
|
+
"sharded_local_#{attr_name}",
|
93
|
+
as: "local_#{as}",
|
92
94
|
namespace: :switchman) do |batch|
|
93
95
|
batch << <<-RUBY
|
94
96
|
def sharded_local_#{attr_name}
|
@@ -127,21 +129,21 @@ module Switchman
|
|
127
129
|
end
|
128
130
|
end
|
129
131
|
|
130
|
-
def define_method_attribute(attr_name, owner:)
|
132
|
+
def define_method_attribute(attr_name, owner:, as: attr_name)
|
131
133
|
if sharded_column?(attr_name)
|
132
134
|
reflection = reflection_for_integer_attribute(attr_name)
|
133
135
|
class_name = connection_class_for_self_code_for_reflection(reflection)
|
134
136
|
safe_class_name = class_name.unpack1("h*")
|
135
137
|
define_cached_method(owner,
|
136
|
-
attr_name,
|
137
|
-
as:
|
138
|
+
"sharded_#{safe_class_name}_#{attr_name}",
|
139
|
+
as: as,
|
138
140
|
namespace: :switchman) do |batch|
|
139
141
|
batch << build_sharded_getter("sharded_#{safe_class_name}_#{attr_name}",
|
140
|
-
"original_#{
|
142
|
+
"original_#{as}",
|
141
143
|
class_name)
|
142
144
|
end
|
143
145
|
else
|
144
|
-
define_cached_method(owner,
|
146
|
+
define_cached_method(owner, "plain_#{attr_name}", as: as, namespace: :switchman) do |batch|
|
145
147
|
batch << <<-RUBY
|
146
148
|
def plain_#{attr_name}
|
147
149
|
_read_attribute("#{attr_name}") { |n| missing_attribute(n, caller) }
|
@@ -174,19 +176,19 @@ module Switchman
|
|
174
176
|
RUBY
|
175
177
|
end
|
176
178
|
|
177
|
-
def define_method_attribute=(attr_name, owner:)
|
179
|
+
def define_method_attribute=(attr_name, owner:, as: attr_name)
|
178
180
|
if sharded_column?(attr_name)
|
179
181
|
reflection = reflection_for_integer_attribute(attr_name)
|
180
182
|
class_name = connection_class_for_self_code_for_reflection(reflection)
|
181
183
|
safe_class_name = class_name.unpack1("h*")
|
182
184
|
define_cached_method(owner,
|
183
|
-
"#{attr_name}=",
|
184
|
-
as: "
|
185
|
+
"sharded_#{safe_class_name}_#{attr_name}=",
|
186
|
+
as: "#{as}=",
|
185
187
|
namespace: :switchman) do |batch|
|
186
188
|
batch << build_sharded_setter("sharded_#{safe_class_name}_#{attr_name}", attr_name, class_name)
|
187
189
|
end
|
188
190
|
else
|
189
|
-
define_cached_method(owner, "#{attr_name}=", as: "
|
191
|
+
define_cached_method(owner, "plain_#{attr_name}=", as: "#{as}=", namespace: :switchman) do |batch|
|
190
192
|
batch << <<-RUBY
|
191
193
|
def plain_#{attr_name}=(new_value)
|
192
194
|
_write_attribute('#{attr_name}', new_value)
|
@@ -204,11 +206,11 @@ module Switchman
|
|
204
206
|
RUBY
|
205
207
|
end
|
206
208
|
|
207
|
-
def define_method_original_attribute(attr_name, owner:)
|
209
|
+
def define_method_original_attribute(attr_name, owner:, as: attr_name)
|
208
210
|
if sharded_column?(attr_name)
|
209
211
|
define_cached_method(owner,
|
210
|
-
"
|
211
|
-
as: "
|
212
|
+
"sharded_original_#{attr_name}",
|
213
|
+
as: "original_#{as}",
|
212
214
|
namespace: :switchman) do |batch|
|
213
215
|
batch << <<-RUBY
|
214
216
|
def sharded_original_#{attr_name}
|
@@ -221,12 +223,12 @@ module Switchman
|
|
221
223
|
end
|
222
224
|
end
|
223
225
|
|
224
|
-
def define_method_original_attribute=(attr_name, owner:)
|
226
|
+
def define_method_original_attribute=(attr_name, owner:, as: attr_name)
|
225
227
|
return unless sharded_column?(attr_name)
|
226
228
|
|
227
229
|
define_cached_method(owner,
|
228
|
-
"
|
229
|
-
as: "
|
230
|
+
"sharded_original_#{attr_name}=",
|
231
|
+
as: "original_#{as}=",
|
230
232
|
namespace: :switchman) do |batch|
|
231
233
|
batch << <<-RUBY
|
232
234
|
def sharded_original_#{attr_name}=(new_value)
|
@@ -240,8 +242,8 @@ module Switchman
|
|
240
242
|
return if columns_hash["#{prefix}_#{attr_name}"] || attr_name == "id"
|
241
243
|
|
242
244
|
define_cached_method(owner,
|
243
|
-
"#{prefix}_#{attr_name}",
|
244
|
-
as: "
|
245
|
+
"unsharded_#{prefix}_#{attr_name}",
|
246
|
+
as: "#{prefix}_#{attr_name}",
|
245
247
|
namespace: :switchman) do |batch|
|
246
248
|
batch << <<-RUBY
|
247
249
|
def unsharded_#{prefix}_#{attr_name}
|
@@ -136,11 +136,7 @@ module Switchman
|
|
136
136
|
end
|
137
137
|
|
138
138
|
def connected_to_stack
|
139
|
-
has_own_stack =
|
140
|
-
Thread.current.thread_variable?(:ar_connected_to_stack)
|
141
|
-
else
|
142
|
-
::ActiveSupport::IsolatedExecutionState.key?(:active_record_connected_to_stack)
|
143
|
-
end
|
139
|
+
has_own_stack = ::ActiveSupport::IsolatedExecutionState.key?(:active_record_connected_to_stack)
|
144
140
|
|
145
141
|
ret = super
|
146
142
|
return ret if has_own_stack
|
@@ -189,12 +185,6 @@ module Switchman
|
|
189
185
|
|
190
186
|
Shard.default
|
191
187
|
end
|
192
|
-
|
193
|
-
if ::Rails.version < "7.0"
|
194
|
-
def connection_class_for_self
|
195
|
-
connection_classes
|
196
|
-
end
|
197
|
-
end
|
198
188
|
end
|
199
189
|
|
200
190
|
def self.prepended(klass)
|
@@ -148,19 +148,10 @@ module Switchman
|
|
148
148
|
private
|
149
149
|
|
150
150
|
def type_cast_calculated_value_switchman(value, column_name, operation)
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
lookup_cast_type_from_join_dependencies(column_name.to_s) || ::ActiveRecord::Type.default_value
|
156
|
-
type.deserialize(val)
|
157
|
-
end
|
158
|
-
else
|
159
|
-
column = aggregate_column(column_name)
|
160
|
-
type ||= column.try(:type_caster) ||
|
161
|
-
lookup_cast_type_from_join_dependencies(column_name.to_s) || ::ActiveRecord::Type.default_value
|
162
|
-
type_cast_calculated_value(value, operation, type)
|
163
|
-
end
|
151
|
+
column = aggregate_column(column_name)
|
152
|
+
type ||= column.try(:type_caster) ||
|
153
|
+
lookup_cast_type_from_join_dependencies(column_name.to_s) || ::ActiveRecord::Type.default_value
|
154
|
+
type_cast_calculated_value(value, operation, type)
|
164
155
|
end
|
165
156
|
|
166
157
|
def column_name_for(field)
|
data/lib/switchman/engine.rb
CHANGED
@@ -10,20 +10,9 @@ module Switchman
|
|
10
10
|
|
11
11
|
::GuardRail.singleton_class.prepend(GuardRail::ClassMethods)
|
12
12
|
|
13
|
-
# after :initialize_dependency_mechanism to ensure autoloading is
|
14
|
-
# configured for any downstream initializers that care. In rails 7.0 we
|
15
|
-
# should be able to just use an explicit after on configuring the once
|
16
|
-
# autoloaders and not need to go monkey around with initializer order
|
17
|
-
if ::Rails.version < "7.0"
|
18
|
-
initialize_dependency_mechanism = ::Rails::Application::Bootstrap.initializers.find do |i|
|
19
|
-
i.name == :initialize_dependency_mechanism
|
20
|
-
end
|
21
|
-
initialize_dependency_mechanism.instance_variable_get(:@options)[:after] = :set_autoload_paths
|
22
|
-
end
|
23
|
-
|
24
13
|
initializer "switchman.active_record_patch",
|
25
14
|
before: "active_record.initialize_database",
|
26
|
-
after:
|
15
|
+
after: :setup_once_autoloader do
|
27
16
|
::ActiveSupport.on_load(:active_record) do
|
28
17
|
# Switchman requires postgres, so just always load the pg adapter
|
29
18
|
require "active_record/connection_adapters/postgresql_adapter"
|
@@ -54,11 +43,9 @@ module Switchman
|
|
54
43
|
::ActiveRecord::Associations::CollectionProxy.include(ActiveRecord::Associations::CollectionProxy)
|
55
44
|
|
56
45
|
::ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecord::Associations::Preloader::Association)
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
)
|
61
|
-
end
|
46
|
+
::ActiveRecord::Associations::Preloader::Association::LoaderRecords.prepend(
|
47
|
+
ActiveRecord::Associations::Preloader::Association::LoaderRecords
|
48
|
+
)
|
62
49
|
::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::AbstractAdapter)
|
63
50
|
unless ::Rails.version < "7.1"
|
64
51
|
::ActiveRecord::ConnectionAdapters::ConnectionHandler.prepend(ActiveRecord::ConnectionHandler)
|
@@ -16,11 +16,7 @@ module Switchman
|
|
16
16
|
payload[:shard] = {
|
17
17
|
database_server_id: shard.database_server.id,
|
18
18
|
id: shard.id,
|
19
|
-
env:
|
20
|
-
@shard_host.pool.connection_klass&.current_role
|
21
|
-
else
|
22
|
-
@shard_host.pool.connection_class&.current_role
|
23
|
-
end
|
19
|
+
env: @shard_host.pool.connection_class&.current_role
|
24
20
|
}
|
25
21
|
end
|
26
22
|
super(name, payload)
|
data/lib/switchman/version.rb
CHANGED
data/lib/tasks/switchman.rake
CHANGED
@@ -1,16 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# In rails 7.0+ if you have only 1 db in the env it doesn't try to do explicit activation
|
4
|
-
# (and for rails purposes we only have one db per env because each database server is a separate env)
|
5
|
-
if Rails.version < "7.0"
|
6
|
-
task_prefix = Rake::Task.task_defined?("app:db:migrate") ? "app:db" : "db"
|
7
|
-
Rake::Task["#{task_prefix}:migrate"].clear_actions.enhance do
|
8
|
-
ActiveRecord::Tasks::DatabaseTasks.migrate
|
9
|
-
# Ensure this doesn't blow up when running inside the dummy app
|
10
|
-
Rake::Task["#{task_prefix}:_dump"].invoke
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
3
|
module Switchman
|
15
4
|
module Rake
|
16
5
|
def self.filter_database_servers
|
@@ -265,28 +254,9 @@ module Switchman
|
|
265
254
|
|
266
255
|
module ActiveRecord
|
267
256
|
module PostgreSQLDatabaseTasks
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
args = ["--schema-only", "--no-privileges", "--no-owner", "--file", filename]
|
272
|
-
args.concat(Array(extra_flags)) if extra_flags
|
273
|
-
shard = Shard.current.name
|
274
|
-
serialized_search_path = shard
|
275
|
-
args << "--schema=#{Shellwords.escape(shard)}"
|
276
|
-
|
277
|
-
ignore_tables = ::ActiveRecord::SchemaDumper.ignore_tables
|
278
|
-
args += ignore_tables.flat_map { |table| ["-T", table] } if ignore_tables.any?
|
279
|
-
|
280
|
-
args << db_config.database
|
281
|
-
run_cmd("pg_dump", args, "dumping")
|
282
|
-
remove_sql_header_comments(filename)
|
283
|
-
File.open(filename, "a") { |f| f << "SET search_path TO #{serialized_search_path};\n\n" }
|
284
|
-
end
|
285
|
-
else
|
286
|
-
def structure_dump(...)
|
287
|
-
::ActiveRecord.dump_schemas = Switchman::Shard.current.name
|
288
|
-
super
|
289
|
-
end
|
257
|
+
def structure_dump(...)
|
258
|
+
::ActiveRecord.dump_schemas = Switchman::Shard.current.name
|
259
|
+
super
|
290
260
|
end
|
291
261
|
end
|
292
262
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: switchman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cody Cutrer
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2025-
|
13
|
+
date: 2025-02-18 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ">="
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: '7.0'
|
22
22
|
- - "<"
|
23
23
|
- !ruby/object:Gem::Version
|
24
24
|
version: '7.2'
|
@@ -28,7 +28,7 @@ dependencies:
|
|
28
28
|
requirements:
|
29
29
|
- - ">="
|
30
30
|
- !ruby/object:Gem::Version
|
31
|
-
version:
|
31
|
+
version: '7.0'
|
32
32
|
- - "<"
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '7.2'
|
@@ -66,7 +66,7 @@ dependencies:
|
|
66
66
|
requirements:
|
67
67
|
- - ">="
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
69
|
+
version: '7.0'
|
70
70
|
- - "<"
|
71
71
|
- !ruby/object:Gem::Version
|
72
72
|
version: '7.2'
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
requirements:
|
77
77
|
- - ">="
|
78
78
|
- !ruby/object:Gem::Version
|
79
|
-
version: '
|
79
|
+
version: '7.0'
|
80
80
|
- - "<"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '7.2'
|