switchman 1.16.0 → 2.0.5
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/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)
|