switchman 1.16.0 → 2.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/models/switchman/shard.rb +10 -5
- data/db/migrate/20130328212039_create_switchman_shards.rb +2 -0
- data/db/migrate/20130328224244_create_default_shard.rb +3 -1
- data/db/migrate/20161206323434_add_back_default_string_limits_switchman.rb +2 -0
- data/db/migrate/20180828183945_add_default_shard_index.rb +2 -0
- data/db/migrate/20180828192111_add_timestamps_to_shards.rb +2 -0
- data/db/migrate/20190114212900_add_unique_name_indexes.rb +2 -0
- data/lib/switchman.rb +3 -1
- data/lib/switchman/action_controller/caching.rb +2 -0
- data/lib/switchman/active_record/abstract_adapter.rb +8 -2
- data/lib/switchman/active_record/association.rb +10 -4
- data/lib/switchman/active_record/attribute_methods.rb +2 -0
- data/lib/switchman/active_record/base.rb +13 -11
- data/lib/switchman/active_record/batches.rb +2 -0
- data/lib/switchman/active_record/calculations.rb +2 -0
- data/lib/switchman/active_record/connection_handler.rb +8 -6
- data/lib/switchman/active_record/connection_pool.rb +2 -0
- data/lib/switchman/active_record/finder_methods.rb +2 -0
- data/lib/switchman/active_record/log_subscriber.rb +2 -0
- data/lib/switchman/active_record/migration.rb +3 -1
- data/lib/switchman/active_record/model_schema.rb +2 -0
- data/lib/switchman/active_record/persistence.rb +3 -1
- data/lib/switchman/active_record/postgresql_adapter.rb +3 -1
- data/lib/switchman/active_record/predicate_builder.rb +2 -0
- data/lib/switchman/active_record/query_cache.rb +2 -0
- data/lib/switchman/active_record/query_methods.rb +121 -72
- data/lib/switchman/active_record/reflection.rb +2 -0
- data/lib/switchman/active_record/relation.rb +7 -5
- data/lib/switchman/active_record/spawn_methods.rb +2 -0
- data/lib/switchman/active_record/statement_cache.rb +3 -1
- data/lib/switchman/active_record/table_definition.rb +4 -2
- data/lib/switchman/active_record/type_caster.rb +2 -0
- data/lib/switchman/active_record/where_clause_factory.rb +2 -0
- data/lib/switchman/active_support/cache.rb +4 -2
- data/lib/switchman/arel.rb +2 -0
- data/lib/switchman/call_super.rb +2 -0
- data/lib/switchman/connection_pool_proxy.rb +13 -11
- data/lib/switchman/database_server.rb +18 -16
- data/lib/switchman/default_shard.rb +2 -0
- data/lib/switchman/engine.rb +10 -8
- data/lib/switchman/environment.rb +2 -0
- data/lib/switchman/errors.rb +2 -0
- data/lib/switchman/{shackles.rb → guard_rail.rb} +6 -4
- data/lib/switchman/{shackles → guard_rail}/relation.rb +7 -5
- data/lib/switchman/open4.rb +2 -0
- data/lib/switchman/r_spec_helper.rb +7 -5
- data/lib/switchman/rails.rb +2 -0
- data/lib/switchman/schema_cache.rb +2 -0
- data/lib/switchman/sharded_instrumenter.rb +3 -1
- data/lib/switchman/standard_error.rb +2 -0
- data/lib/switchman/test_helper.rb +5 -3
- data/lib/switchman/version.rb +3 -1
- data/lib/tasks/switchman.rake +3 -3
- metadata +30 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c544d2ed8498a6aecf33823f39b304393a65f213f6a68bf04f4d36610ebe3ac2
|
4
|
+
data.tar.gz: be685b315997b103dd13376f5223196f1b66a5be490502aac6bc401408899abc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fbdd769d90c831e1bbe6dd39def12775537989346daae7dbbab3103a330b89151e9d1c3b9fe216ab9ade75e3c01ee1b1c91062cc622707c3c2697f7dc3239ea8
|
7
|
+
data.tar.gz: 27d32eefa842a76debb1a1fc7875407b4df1398a45a71419c7cc13045fd8705ff5e4af724478a9cb854d517433ae8d16420baa13fc8e7459ab1953e626c0c80a
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'switchman/database_server'
|
2
4
|
require 'switchman/default_shard'
|
3
5
|
require 'switchman/environment'
|
@@ -38,7 +40,10 @@ module Switchman
|
|
38
40
|
end
|
39
41
|
|
40
42
|
def default(reload_deprecated = false, reload: false, with_fallback: false)
|
41
|
-
|
43
|
+
if reload_deprecated
|
44
|
+
reload = reload_deprecated
|
45
|
+
::ActiveSupport::Deprecation.warn("positional reload parameter to Switchman::Shard.default is deprecated; use `reload: true`")
|
46
|
+
end
|
42
47
|
if !@default || reload
|
43
48
|
# Have to create a dummy object so that several key methods still work
|
44
49
|
# (it's easier to do this in one place here, and just assume that sharding
|
@@ -351,8 +356,8 @@ module Switchman
|
|
351
356
|
# prune the prior connection unless it happened to be the same
|
352
357
|
if previous_shard && shard != previous_shard && !previous_shard.database_server.shareable?
|
353
358
|
previous_shard.activate do
|
354
|
-
::
|
355
|
-
::
|
359
|
+
::GuardRail.activated_environments.each do |env|
|
360
|
+
::GuardRail.activate(env) do
|
356
361
|
if ::ActiveRecord::Base.connected? && ::ActiveRecord::Base.connection.open_transactions == 0
|
357
362
|
::ActiveRecord::Base.connection_pool.current_pool.disconnect!
|
358
363
|
end
|
@@ -659,7 +664,7 @@ module Switchman
|
|
659
664
|
case adapter
|
660
665
|
when 'mysql', 'mysql2'
|
661
666
|
self.activate do
|
662
|
-
::
|
667
|
+
::GuardRail.activate(:deploy) do
|
663
668
|
drop_statement ||= "DROP DATABASE #{self.name}"
|
664
669
|
Array(drop_statement).each do |stmt|
|
665
670
|
::ActiveRecord::Base.connection.execute(stmt)
|
@@ -668,7 +673,7 @@ module Switchman
|
|
668
673
|
end
|
669
674
|
when 'postgresql'
|
670
675
|
self.activate do
|
671
|
-
::
|
676
|
+
::GuardRail.activate(:deploy) do
|
672
677
|
# Shut up, Postgres!
|
673
678
|
conn = ::ActiveRecord::Base.connection
|
674
679
|
old_proc = conn.raw_connection.set_notice_processor {}
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class CreateDefaultShard < ActiveRecord::Migration[4.2]
|
2
4
|
def up
|
3
5
|
unless Switchman::Shard.default.is_a?(Switchman::Shard)
|
4
6
|
Switchman::Shard.reset_column_information
|
5
7
|
Switchman::Shard.create!(:default => true)
|
6
|
-
Switchman::Shard.default(true)
|
8
|
+
Switchman::Shard.default(reload: true)
|
7
9
|
end
|
8
10
|
end
|
9
11
|
end
|
data/lib/switchman.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'switchman/sharded_instrumenter'
|
2
4
|
|
3
5
|
module Switchman
|
4
6
|
module ActiveRecord
|
5
7
|
module AbstractAdapter
|
6
8
|
module ForeignKeyCheck
|
7
|
-
def add_column(table, name, type,
|
8
|
-
Engine.foreign_key_check(name, type,
|
9
|
+
def add_column(table, name, type, limit: nil, **)
|
10
|
+
Engine.foreign_key_check(name, type, limit: limit)
|
9
11
|
super
|
10
12
|
end
|
11
13
|
end
|
@@ -27,6 +29,10 @@ module Switchman
|
|
27
29
|
quote_table_name(name)
|
28
30
|
end
|
29
31
|
|
32
|
+
def schema_migration
|
33
|
+
::ActiveRecord::SchemaMigration
|
34
|
+
end
|
35
|
+
|
30
36
|
protected
|
31
37
|
|
32
38
|
def log(*args, &block)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Switchman
|
2
4
|
module ActiveRecord
|
3
5
|
module Association
|
@@ -75,7 +77,7 @@ module Switchman
|
|
75
77
|
module Association
|
76
78
|
if ::Rails.version >= "5.2" and ::Rails.version < "6.0"
|
77
79
|
def run(preloader)
|
78
|
-
associated_records_by_owner
|
80
|
+
associated_records_by_owner.each do |owner, records|
|
79
81
|
associate_records_to_owner(owner, records)
|
80
82
|
end
|
81
83
|
end
|
@@ -102,6 +104,7 @@ module Switchman
|
|
102
104
|
end
|
103
105
|
|
104
106
|
def associated_records_by_owner(preloader = nil)
|
107
|
+
return @associated_records_by_owner if defined?(@associated_records_by_owner)
|
105
108
|
owners_map = owners_by_key
|
106
109
|
|
107
110
|
if klass.nil? || owners_map.empty?
|
@@ -149,10 +152,13 @@ module Switchman
|
|
149
152
|
records.flatten!
|
150
153
|
end
|
151
154
|
|
155
|
+
# This ivar may look unused, but remember this is an extension of
|
156
|
+
# rails' AR::Associations::Preloader::Association class. It gets used
|
157
|
+
# by that class (and its subclasses).
|
152
158
|
@preloaded_records = records
|
153
159
|
|
154
160
|
# Each record may have multiple owners, and vice-versa
|
155
|
-
|
161
|
+
@associated_records_by_owner = owners.each_with_object({}) do |owner,h|
|
156
162
|
h[owner] = []
|
157
163
|
end
|
158
164
|
records.each do |record|
|
@@ -161,10 +167,10 @@ module Switchman
|
|
161
167
|
|
162
168
|
owners_map[owner_key.to_s].each do |owner|
|
163
169
|
owner.association(reflection.name).set_inverse_instance(record)
|
164
|
-
|
170
|
+
@associated_records_by_owner[owner] << record
|
165
171
|
end
|
166
172
|
end
|
167
|
-
|
173
|
+
@associated_records_by_owner
|
168
174
|
end
|
169
175
|
|
170
176
|
def owners_by_key
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Switchman
|
2
4
|
module ActiveRecord
|
3
5
|
module Base
|
@@ -31,20 +33,20 @@ module Switchman
|
|
31
33
|
@integral_id
|
32
34
|
end
|
33
35
|
|
34
|
-
def transaction(
|
36
|
+
def transaction(**)
|
35
37
|
if self != ::ActiveRecord::Base && current_scope
|
36
38
|
current_scope.activate do
|
37
39
|
db = Shard.current(shard_category).database_server
|
38
|
-
if ::
|
39
|
-
db.
|
40
|
+
if ::GuardRail.environment != db.guard_rail_environment
|
41
|
+
db.unguard { super }
|
40
42
|
else
|
41
43
|
super
|
42
44
|
end
|
43
45
|
end
|
44
46
|
else
|
45
47
|
db = Shard.current(shard_category).database_server
|
46
|
-
if ::
|
47
|
-
db.
|
48
|
+
if ::GuardRail.environment != db.guard_rail_environment
|
49
|
+
db.unguard { super }
|
48
50
|
else
|
49
51
|
super
|
50
52
|
end
|
@@ -105,12 +107,12 @@ module Switchman
|
|
105
107
|
end
|
106
108
|
end
|
107
109
|
|
108
|
-
def save(
|
110
|
+
def save(*, **)
|
109
111
|
@shard_set_in_stone = true
|
110
112
|
(self.class.current_scope || self.class.default_scoped).shard(shard, :implicit).scoping { super }
|
111
113
|
end
|
112
114
|
|
113
|
-
def save!(
|
115
|
+
def save!(*, **)
|
114
116
|
@shard_set_in_stone = true
|
115
117
|
(self.class.current_scope || self.class.default_scoped).shard(shard, :implicit).scoping { super }
|
116
118
|
end
|
@@ -128,9 +130,9 @@ module Switchman
|
|
128
130
|
result
|
129
131
|
end
|
130
132
|
|
131
|
-
def transaction(
|
133
|
+
def transaction(**kwargs, &block)
|
132
134
|
shard.activate(self.class.shard_category) do
|
133
|
-
self.class.transaction(
|
135
|
+
self.class.transaction(**kwargs, &block)
|
134
136
|
end
|
135
137
|
end
|
136
138
|
|
@@ -157,8 +159,8 @@ module Switchman
|
|
157
159
|
|
158
160
|
def update_columns(*)
|
159
161
|
db = Shard.current(self.class.shard_category).database_server
|
160
|
-
if ::
|
161
|
-
return db.
|
162
|
+
if ::GuardRail.environment != db.guard_rail_environment
|
163
|
+
return db.unguard { super }
|
162
164
|
else
|
163
165
|
super
|
164
166
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'switchman/connection_pool_proxy'
|
2
4
|
|
3
5
|
module Switchman
|
@@ -55,7 +57,7 @@ module Switchman
|
|
55
57
|
Shard.default.remove_instance_variable(:@name) if Shard.default.instance_variable_defined?(:@name)
|
56
58
|
end
|
57
59
|
|
58
|
-
@shard_connection_pools ||= { [:
|
60
|
+
@shard_connection_pools ||= { [:primary, Shard.default.database_server.shareable? ? ::Rails.env : Shard.default] => pool}
|
59
61
|
|
60
62
|
category = pool.spec.name.to_sym
|
61
63
|
proxy = ConnectionPoolProxy.new(category,
|
@@ -64,13 +66,13 @@ module Switchman
|
|
64
66
|
owner_to_pool[pool.spec.name] = proxy
|
65
67
|
|
66
68
|
if first_time
|
67
|
-
if Shard.default.database_server.config[:
|
68
|
-
Shard.default.database_server.
|
69
|
+
if Shard.default.database_server.config[:prefer_secondary]
|
70
|
+
Shard.default.database_server.guard!
|
69
71
|
end
|
70
72
|
|
71
|
-
if Shard.default.is_a?(DefaultShard) && Shard.default.database_server.config[:
|
72
|
-
Shard.default.database_server.
|
73
|
-
Shard.default(true)
|
73
|
+
if Shard.default.is_a?(DefaultShard) && Shard.default.database_server.config[:secondary]
|
74
|
+
Shard.default.database_server.guard!
|
75
|
+
Shard.default(reload: true)
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Switchman
|
2
4
|
module ActiveRecord
|
3
5
|
module Migration
|
@@ -29,7 +31,7 @@ module Switchman
|
|
29
31
|
|
30
32
|
module Migrator
|
31
33
|
def generate_migrator_advisory_lock_id
|
32
|
-
shard_name_hash = Zlib.crc32(Shard.current.name)
|
34
|
+
shard_name_hash = Zlib.crc32("#{Shard.current.id}:#{Shard.current.name}")
|
33
35
|
::ActiveRecord::Migrator::MIGRATOR_SALT * shard_name_hash
|
34
36
|
end
|
35
37
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Switchman
|
2
4
|
module ActiveRecord
|
3
5
|
module Persistence
|
4
6
|
# touch reads the id attribute directly, so it's not relative to the current shard
|
5
|
-
def touch(
|
7
|
+
def touch(*, **)
|
6
8
|
shard.activate(self.class.shard_category) { super }
|
7
9
|
end
|
8
10
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Switchman
|
2
4
|
module ActiveRecord
|
3
5
|
module PostgreSQLAdapter
|
@@ -192,7 +194,7 @@ module Switchman
|
|
192
194
|
end
|
193
195
|
end
|
194
196
|
|
195
|
-
def add_index_options(_table_name, _column_name,
|
197
|
+
def add_index_options(_table_name, _column_name, **)
|
196
198
|
index_name, index_type, index_columns, index_options, algorithm, using = super
|
197
199
|
algorithm = nil if DatabaseServer.creating_new_shard && algorithm == "CONCURRENTLY"
|
198
200
|
[index_name, index_type, index_columns, index_options, algorithm, using]
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Switchman
|
2
4
|
module ActiveRecord
|
3
5
|
module QueryMethods
|
@@ -76,6 +78,10 @@ module Switchman
|
|
76
78
|
end
|
77
79
|
end
|
78
80
|
|
81
|
+
def or(other)
|
82
|
+
super(other.shard(self.primary_shard))
|
83
|
+
end
|
84
|
+
|
79
85
|
private
|
80
86
|
|
81
87
|
if ::Rails.version >= '5.2'
|
@@ -240,92 +246,135 @@ module Switchman
|
|
240
246
|
binds: nil,
|
241
247
|
dup_binds_on_mutation: false)
|
242
248
|
result = predicates.map do |predicate|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
249
|
+
transposed, binds = transpose_single_predicate(predicate, source_shard, target_shard, remove_nonlocal_primary_keys,
|
250
|
+
binds: binds, dup_binds_on_mutation: dup_binds_on_mutation)
|
251
|
+
transposed
|
252
|
+
end
|
253
|
+
result = [result, binds]
|
254
|
+
result
|
255
|
+
end
|
256
|
+
|
257
|
+
def transpose_single_predicate(predicate,
|
258
|
+
source_shard,
|
259
|
+
target_shard,
|
260
|
+
remove_nonlocal_primary_keys = false,
|
261
|
+
binds: nil,
|
262
|
+
dup_binds_on_mutation: false)
|
263
|
+
if predicate.is_a?(::Arel::Nodes::Grouping)
|
264
|
+
return predicate, binds unless predicate.expr.is_a?(::Arel::Nodes::Or)
|
265
|
+
# Dang, we have an OR. OK, that means we have other epxressions below this
|
266
|
+
# level, perhaps many, that may need transposition.
|
267
|
+
# the left side and right side must each be treated as predicate lists and
|
268
|
+
# transformed in kind, if neither of them changes we can just return the grouping as is.
|
269
|
+
# hold on, it's about to get recursive...
|
270
|
+
#
|
271
|
+
# TODO: "binds" is getting passed up and down
|
272
|
+
# this stack purely because of the necessary handling for rails <5.2
|
273
|
+
# Dropping support for 5.2 means we can remove the "binds" argument from
|
274
|
+
# all of this and yank the conditional below where we monkey with their instance state.
|
275
|
+
or_expr = predicate.expr
|
276
|
+
left_node = or_expr.left
|
277
|
+
right_node = or_expr.right
|
278
|
+
left_predicates = left_node.children
|
279
|
+
right_predicates = right_node.children
|
280
|
+
new_left_predicates, binds = transpose_predicates(left_predicates, source_shard,
|
281
|
+
target_shard, remove_nonlocal_primary_keys,
|
282
|
+
binds: binds, dup_binds_on_mutation: dup_binds_on_mutation)
|
283
|
+
new_right_predicates, binds = transpose_predicates(right_predicates, source_shard,
|
284
|
+
target_shard, remove_nonlocal_primary_keys,
|
285
|
+
binds: binds, dup_binds_on_mutation: dup_binds_on_mutation)
|
286
|
+
if new_left_predicates != left_predicates
|
287
|
+
left_node.instance_variable_set(:@children, new_left_predicates)
|
288
|
+
end
|
289
|
+
if new_right_predicates != right_predicates
|
290
|
+
right_node.instance_variable_set(:@children, new_right_predicates)
|
291
|
+
end
|
292
|
+
return predicate, binds
|
293
|
+
end
|
294
|
+
return predicate, binds unless predicate.is_a?(::Arel::Nodes::Binary)
|
295
|
+
return predicate, binds unless predicate.left.is_a?(::Arel::Attributes::Attribute)
|
296
|
+
relation, column = relation_and_column(predicate.left)
|
297
|
+
return predicate, binds unless (type = transposable_attribute_type(relation, column))
|
247
298
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
299
|
+
remove = true if type == :primary &&
|
300
|
+
remove_nonlocal_primary_keys &&
|
301
|
+
predicate.left.relation.model == klass &&
|
302
|
+
predicate.is_a?(::Arel::Nodes::Equality)
|
252
303
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
304
|
+
current_source_shard =
|
305
|
+
if source_shard
|
306
|
+
source_shard
|
307
|
+
elsif type == :primary
|
308
|
+
Shard.current(klass.shard_category)
|
309
|
+
elsif type == :foreign
|
310
|
+
source_shard_for_foreign_key(relation, column)
|
311
|
+
end
|
261
312
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
when Array
|
266
|
-
predicate.right.map {|val| transpose_predicate_value(val, current_source_shard, target_shard, type, remove) }
|
267
|
-
else
|
268
|
-
transpose_predicate_value(predicate.right, current_source_shard, target_shard, type, remove)
|
269
|
-
end
|
270
|
-
else
|
271
|
-
new_right_value = case predicate.right
|
313
|
+
if ::Rails.version >= "5.2"
|
314
|
+
new_right_value =
|
315
|
+
case predicate.right
|
272
316
|
when Array
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
317
|
+
predicate.right.map {|val| transpose_predicate_value(val, current_source_shard, target_shard, type, remove) }
|
318
|
+
else
|
319
|
+
transpose_predicate_value(predicate.right, current_source_shard, target_shard, type, remove)
|
320
|
+
end
|
321
|
+
else
|
322
|
+
new_right_value = case predicate.right
|
323
|
+
when Array
|
324
|
+
local_ids = []
|
325
|
+
predicate.right.each do |value|
|
326
|
+
local_id = Shard.relative_id_for(value, current_source_shard, target_shard)
|
327
|
+
next unless local_id
|
328
|
+
unless remove && local_id > Shard::IDS_PER_SHARD
|
329
|
+
if value.is_a?(::Arel::Nodes::Casted)
|
330
|
+
if local_id == value.val
|
331
|
+
local_id = value
|
332
|
+
elsif local_id != value
|
333
|
+
local_id = value.class.new(local_id, value.attribute)
|
284
334
|
end
|
285
|
-
local_ids << local_id
|
286
335
|
end
|
336
|
+
local_ids << local_id
|
287
337
|
end
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
338
|
+
end
|
339
|
+
local_ids
|
340
|
+
when ::Arel::Nodes::BindParam
|
341
|
+
# look for a bind param with a matching column name
|
342
|
+
if binds && bind = binds.detect{|b| b&.name.to_s == predicate.left.name.to_s}
|
343
|
+
# before we mutate, dup
|
344
|
+
if dup_binds_on_mutation
|
345
|
+
binds = binds.map(&:dup)
|
346
|
+
dup_binds_on_mutation = false
|
347
|
+
bind = binds.find { |b| b&.name.to_s == predicate.left.name.to_s }
|
348
|
+
end
|
349
|
+
if bind.value.is_a?(::ActiveRecord::StatementCache::Substitute)
|
350
|
+
bind.value.sharded = true # mark for transposition later
|
351
|
+
bind.value.primary = true if type == :primary
|
352
|
+
else
|
353
|
+
local_id = Shard.relative_id_for(bind.value, current_source_shard, target_shard)
|
354
|
+
local_id = [] if remove && local_id > Shard::IDS_PER_SHARD
|
355
|
+
bind.instance_variable_set(:@value, local_id)
|
356
|
+
bind.instance_variable_set(:@value_for_database, nil)
|
307
357
|
end
|
308
|
-
predicate.right
|
309
|
-
else
|
310
|
-
local_id = Shard.relative_id_for(predicate.right, current_source_shard, target_shard) || predicate.right
|
311
|
-
local_id = [] if remove && local_id.is_a?(Integer) && local_id > Shard::IDS_PER_SHARD
|
312
|
-
local_id
|
313
358
|
end
|
359
|
+
predicate.right
|
360
|
+
else
|
361
|
+
local_id = Shard.relative_id_for(predicate.right, current_source_shard, target_shard) || predicate.right
|
362
|
+
local_id = [] if remove && local_id.is_a?(Integer) && local_id > Shard::IDS_PER_SHARD
|
363
|
+
local_id
|
314
364
|
end
|
315
|
-
|
365
|
+
end
|
366
|
+
out_predicate = if new_right_value == predicate.right
|
367
|
+
predicate
|
368
|
+
elsif predicate.right.is_a?(::Arel::Nodes::Casted)
|
369
|
+
if new_right_value == predicate.right.val
|
316
370
|
predicate
|
317
|
-
elsif predicate.right.is_a?(::Arel::Nodes::Casted)
|
318
|
-
if new_right_value == predicate.right.val
|
319
|
-
predicate
|
320
|
-
else
|
321
|
-
predicate.class.new(predicate.left, predicate.right.class.new(new_right_value, predicate.right.attribute))
|
322
|
-
end
|
323
371
|
else
|
324
|
-
predicate.class.new(predicate.left, new_right_value)
|
372
|
+
predicate.class.new(predicate.left, predicate.right.class.new(new_right_value, predicate.right.attribute))
|
325
373
|
end
|
374
|
+
else
|
375
|
+
predicate.class.new(predicate.left, new_right_value)
|
326
376
|
end
|
327
|
-
|
328
|
-
result
|
377
|
+
return out_predicate, binds
|
329
378
|
end
|
330
379
|
|
331
380
|
def transpose_predicate_value(value, current_shard, target_shard, attribute_type, remove_non_local_ids)
|