switchman 2.0.13 → 3.0.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/Rakefile +10 -2
- data/app/models/switchman/shard.rb +234 -271
- data/app/models/switchman/unsharded_record.rb +7 -0
- data/db/migrate/20130328212039_create_switchman_shards.rb +1 -1
- data/db/migrate/20130328224244_create_default_shard.rb +5 -5
- data/db/migrate/20161206323434_add_back_default_string_limits_switchman.rb +1 -0
- data/db/migrate/20180828183945_add_default_shard_index.rb +2 -2
- data/db/migrate/20180828192111_add_timestamps_to_shards.rb +7 -5
- data/db/migrate/20190114212900_add_unique_name_indexes.rb +5 -3
- data/lib/switchman.rb +3 -5
- data/lib/switchman/action_controller/caching.rb +2 -2
- data/lib/switchman/active_record/abstract_adapter.rb +1 -0
- data/lib/switchman/active_record/association.rb +78 -89
- data/lib/switchman/active_record/attribute_methods.rb +58 -52
- data/lib/switchman/active_record/base.rb +58 -59
- data/lib/switchman/active_record/calculations.rb +74 -67
- data/lib/switchman/active_record/connection_pool.rb +14 -41
- data/lib/switchman/active_record/database_configurations.rb +34 -0
- data/lib/switchman/active_record/database_configurations/database_config.rb +13 -0
- data/lib/switchman/active_record/finder_methods.rb +11 -16
- data/lib/switchman/active_record/log_subscriber.rb +4 -8
- data/lib/switchman/active_record/migration.rb +6 -47
- data/lib/switchman/active_record/model_schema.rb +1 -1
- data/lib/switchman/active_record/persistence.rb +4 -6
- data/lib/switchman/active_record/postgresql_adapter.rb +124 -168
- data/lib/switchman/active_record/predicate_builder.rb +2 -2
- data/lib/switchman/active_record/query_cache.rb +18 -19
- data/lib/switchman/active_record/query_methods.rb +172 -197
- data/lib/switchman/active_record/reflection.rb +6 -10
- data/lib/switchman/active_record/relation.rb +30 -78
- data/lib/switchman/active_record/spawn_methods.rb +27 -29
- data/lib/switchman/active_record/statement_cache.rb +18 -35
- data/lib/switchman/active_record/tasks/database_tasks.rb +16 -0
- data/lib/switchman/active_support/cache.rb +3 -5
- data/lib/switchman/arel.rb +13 -8
- data/lib/switchman/database_server.rb +121 -142
- data/lib/switchman/default_shard.rb +52 -16
- data/lib/switchman/engine.rb +61 -58
- data/lib/switchman/environment.rb +4 -8
- data/lib/switchman/errors.rb +1 -0
- data/lib/switchman/guard_rail.rb +6 -19
- data/lib/switchman/guard_rail/relation.rb +5 -7
- data/lib/switchman/r_spec_helper.rb +29 -37
- data/lib/switchman/rails.rb +14 -12
- data/lib/switchman/schema_cache.rb +1 -9
- data/lib/switchman/sharded_instrumenter.rb +1 -1
- data/lib/switchman/standard_error.rb +15 -3
- data/lib/switchman/test_helper.rb +7 -11
- data/lib/switchman/version.rb +1 -1
- data/lib/tasks/switchman.rake +54 -69
- metadata +87 -45
- data/lib/switchman/active_record/batches.rb +0 -11
- data/lib/switchman/active_record/connection_handler.rb +0 -172
- data/lib/switchman/active_record/where_clause_factory.rb +0 -36
- data/lib/switchman/connection_pool_proxy.rb +0 -173
@@ -3,31 +3,30 @@
|
|
3
3
|
module Switchman
|
4
4
|
module ActiveRecord
|
5
5
|
module QueryCache
|
6
|
-
|
7
6
|
private
|
8
7
|
|
9
8
|
def cache_sql(sql, name, binds)
|
10
9
|
# have to include the shard id in the cache key because of switching dbs on the same connection
|
11
|
-
sql = "#{
|
10
|
+
sql = "#{shard.id}::#{sql}"
|
12
11
|
@lock.synchronize do
|
13
12
|
result =
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
}
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
13
|
+
if query_cache[sql].key?(binds)
|
14
|
+
args = {
|
15
|
+
sql: sql,
|
16
|
+
binds: binds,
|
17
|
+
name: name,
|
18
|
+
connection_id: object_id,
|
19
|
+
cached: true,
|
20
|
+
type_casted_binds: -> { type_casted_binds(binds) }
|
21
|
+
}
|
22
|
+
::ActiveSupport::Notifications.instrument(
|
23
|
+
'sql.active_record',
|
24
|
+
args
|
25
|
+
)
|
26
|
+
query_cache[sql][binds]
|
27
|
+
else
|
28
|
+
query_cache[sql][binds] = yield
|
29
|
+
end
|
31
30
|
result.dup
|
32
31
|
end
|
33
32
|
end
|
@@ -17,15 +17,20 @@ module Switchman
|
|
17
17
|
def shard_value
|
18
18
|
@values[:shard]
|
19
19
|
end
|
20
|
+
|
20
21
|
def shard_source_value
|
21
22
|
@values[:shard_source]
|
22
23
|
end
|
24
|
+
|
23
25
|
def shard_value=(value)
|
24
26
|
raise ::ActiveRecord::ImmutableRelation if @loaded
|
27
|
+
|
25
28
|
@values[:shard] = value
|
26
29
|
end
|
30
|
+
|
27
31
|
def shard_source_value=(value)
|
28
32
|
raise ::ActiveRecord::ImmutableRelation if @loaded
|
33
|
+
|
29
34
|
@values[:shard_source] = value
|
30
35
|
end
|
31
36
|
|
@@ -35,11 +40,13 @@ module Switchman
|
|
35
40
|
|
36
41
|
def shard!(value, source = :explicit)
|
37
42
|
raise ArgumentError, "shard can't be nil" unless value
|
38
|
-
|
43
|
+
|
44
|
+
old_primary_shard = primary_shard
|
39
45
|
self.shard_value = value
|
40
46
|
self.shard_source_value = source
|
41
|
-
if
|
42
|
-
transpose_clauses(old_primary_shard,
|
47
|
+
if old_primary_shard != primary_shard || source == :to_a
|
48
|
+
transpose_clauses(old_primary_shard, primary_shard,
|
49
|
+
remove_nonlocal_primary_keys: source == :to_a)
|
43
50
|
end
|
44
51
|
self
|
45
52
|
end
|
@@ -58,7 +65,7 @@ module Switchman
|
|
58
65
|
when ::ActiveRecord::Relation
|
59
66
|
Shard.default
|
60
67
|
when nil
|
61
|
-
Shard.current(klass.
|
68
|
+
Shard.current(klass.connection_classes)
|
62
69
|
else
|
63
70
|
raise ArgumentError, "invalid shard value #{shard_value}"
|
64
71
|
end
|
@@ -72,114 +79,88 @@ module Switchman
|
|
72
79
|
when ::ActiveRecord::Base
|
73
80
|
shard_value.respond_to?(:associated_shards) ? shard_value.associated_shards : [shard_value.shard]
|
74
81
|
when nil
|
75
|
-
[Shard.current(klass.
|
82
|
+
[Shard.current(klass.connection_classes)]
|
76
83
|
else
|
77
84
|
shard_value
|
78
85
|
end
|
79
86
|
end
|
80
87
|
|
88
|
+
def or(other)
|
89
|
+
super(other.shard(primary_shard))
|
90
|
+
end
|
91
|
+
|
81
92
|
private
|
82
93
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
94
|
+
%i[where having].each do |type|
|
95
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
96
|
+
def transpose_#{type}_clauses(source_shard, target_shard, remove_nonlocal_primary_keys:)
|
97
|
+
unless (predicates = #{type}_clause.send(:predicates)).empty?
|
98
|
+
new_predicates = transpose_predicates(predicates, source_shard,
|
99
|
+
target_shard, remove_nonlocal_primary_keys: remove_nonlocal_primary_keys)
|
100
|
+
if new_predicates != predicates
|
101
|
+
self.#{type}_clause = #{type}_clause.dup
|
90
102
|
if new_predicates != predicates
|
91
|
-
|
92
|
-
if new_predicates != predicates
|
93
|
-
#{type}_clause.instance_variable_set(:@predicates, new_predicates)
|
94
|
-
end
|
103
|
+
#{type}_clause.instance_variable_set(:@predicates, new_predicates)
|
95
104
|
end
|
96
105
|
end
|
97
106
|
end
|
98
|
-
RUBY
|
99
|
-
end
|
100
|
-
else
|
101
|
-
[:where, :having].each do |type|
|
102
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
103
|
-
def transpose_#{type}_clauses(source_shard, target_shard, remove_nonlocal_primary_keys)
|
104
|
-
unless (predicates = #{type}_clause.send(:predicates)).empty?
|
105
|
-
new_predicates, new_binds = transpose_predicates(predicates, source_shard,
|
106
|
-
target_shard, remove_nonlocal_primary_keys,
|
107
|
-
binds: #{type}_clause.binds,
|
108
|
-
dup_binds_on_mutation: true)
|
109
|
-
if new_predicates != predicates || !new_binds.equal?(#{type}_clause.binds)
|
110
|
-
self.#{type}_clause = #{type}_clause.dup
|
111
|
-
if new_predicates != predicates
|
112
|
-
#{type}_clause.instance_variable_set(:@predicates, new_predicates)
|
113
|
-
end
|
114
|
-
if !new_binds.equal?(#{type}_clause.binds)
|
115
|
-
#{type}_clause.instance_variable_set(:@binds, new_binds)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
RUBY
|
121
107
|
end
|
108
|
+
RUBY
|
122
109
|
end
|
123
110
|
|
124
|
-
def transpose_clauses(source_shard, target_shard, remove_nonlocal_primary_keys
|
125
|
-
transpose_where_clauses(source_shard, target_shard, remove_nonlocal_primary_keys)
|
126
|
-
transpose_having_clauses(source_shard, target_shard, remove_nonlocal_primary_keys)
|
111
|
+
def transpose_clauses(source_shard, target_shard, remove_nonlocal_primary_keys: false)
|
112
|
+
transpose_where_clauses(source_shard, target_shard, remove_nonlocal_primary_keys: remove_nonlocal_primary_keys)
|
113
|
+
transpose_having_clauses(source_shard, target_shard, remove_nonlocal_primary_keys: remove_nonlocal_primary_keys)
|
127
114
|
end
|
128
115
|
|
129
|
-
def infer_shards_from_primary_key(predicates
|
116
|
+
def infer_shards_from_primary_key(predicates)
|
130
117
|
return unless klass.integral_id?
|
131
118
|
|
132
119
|
primary_key = predicates.detect do |predicate|
|
133
|
-
predicate.is_a?(::Arel::Nodes::Binary)
|
134
|
-
predicate.left.
|
120
|
+
(predicate.is_a?(::Arel::Nodes::Binary) || predicate.is_a?(::Arel::Nodes::HomogeneousIn)) &&
|
121
|
+
predicate.left.is_a?(::Arel::Attributes::Attribute) &&
|
122
|
+
predicate.left.relation.is_a?(::Arel::Table) && predicate.left.relation.klass == klass &&
|
135
123
|
klass.primary_key == predicate.left.name
|
136
124
|
end
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
if
|
147
|
-
|
148
|
-
elsif id_shards.length == 1
|
149
|
-
id_shard = id_shards.first
|
150
|
-
# prefer to not change the shard
|
151
|
-
elsif id_shards.include?(primary_shard)
|
152
|
-
id_shards.delete(primary_shard)
|
153
|
-
self.shard_value = [primary_shard] + id_shards.to_a
|
154
|
-
return
|
155
|
-
else
|
156
|
-
id_shards = id_shards.to_a
|
157
|
-
transpose_clauses(primary_shard, id_shards.first)
|
158
|
-
self.shard_value = id_shards
|
159
|
-
return
|
160
|
-
end
|
161
|
-
when ::Arel::Nodes::BindParam
|
162
|
-
if ::Rails.version >= "5.2"
|
163
|
-
local_id, id_shard = Shard.local_id_for(primary_key.right.value.value_before_type_cast)
|
164
|
-
id_shard ||= Shard.current(klass.shard_category) if local_id
|
165
|
-
else
|
166
|
-
# look for a bind param with a matching column name
|
167
|
-
if binds && bind = binds.detect{|b| b&.name.to_s == klass.primary_key.to_s}
|
168
|
-
unless bind.value.is_a?(::ActiveRecord::StatementCache::Substitute)
|
169
|
-
local_id, id_shard = Shard.local_id_for(bind.value)
|
170
|
-
id_shard ||= Shard.current(klass.shard_category) if local_id
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
else
|
175
|
-
local_id, id_shard = Shard.local_id_for(primary_key.right)
|
176
|
-
id_shard ||= Shard.current(klass.shard_category) if local_id
|
125
|
+
return unless primary_key
|
126
|
+
|
127
|
+
right = primary_key.is_a?(::Arel::Nodes::HomogeneousIn) ? primary_key.values : primary_key.right
|
128
|
+
|
129
|
+
case right
|
130
|
+
when Array
|
131
|
+
id_shards = Set.new
|
132
|
+
right.each do |value|
|
133
|
+
local_id, id_shard = Shard.local_id_for(value)
|
134
|
+
id_shard ||= Shard.current(klass.connection_classes) if local_id
|
135
|
+
id_shards << id_shard if id_shard
|
177
136
|
end
|
137
|
+
return if id_shards.empty?
|
178
138
|
|
179
|
-
|
180
|
-
|
181
|
-
|
139
|
+
if id_shards.length == 1
|
140
|
+
id_shard = id_shards.first
|
141
|
+
# prefer to not change the shard
|
142
|
+
elsif id_shards.include?(primary_shard)
|
143
|
+
id_shards.delete(primary_shard)
|
144
|
+
self.shard_value = [primary_shard] + id_shards.to_a
|
145
|
+
return
|
146
|
+
else
|
147
|
+
id_shards = id_shards.to_a
|
148
|
+
transpose_clauses(primary_shard, id_shards.first)
|
149
|
+
self.shard_value = id_shards
|
150
|
+
return
|
151
|
+
end
|
152
|
+
when ::Arel::Nodes::BindParam
|
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
|
155
|
+
else
|
156
|
+
local_id, id_shard = Shard.local_id_for(right)
|
157
|
+
id_shard ||= Shard.current(klass.connection_classes) if local_id
|
182
158
|
end
|
159
|
+
|
160
|
+
return if !id_shard || id_shard == primary_shard
|
161
|
+
|
162
|
+
transpose_clauses(primary_shard, id_shard)
|
163
|
+
self.shard_value = id_shard
|
183
164
|
end
|
184
165
|
|
185
166
|
def transposable_attribute_type(relation, column)
|
@@ -201,8 +182,9 @@ module Switchman
|
|
201
182
|
|
202
183
|
def sharded_primary_key?(relation, column)
|
203
184
|
column = column.to_s
|
204
|
-
return column == 'id' if relation.
|
205
|
-
|
185
|
+
return column == 'id' if relation.klass == ::ActiveRecord::Base
|
186
|
+
|
187
|
+
relation.klass.primary_key == column && relation.klass.integral_id?
|
206
188
|
end
|
207
189
|
|
208
190
|
def source_shard_for_foreign_key(relation, column)
|
@@ -211,8 +193,9 @@ module Switchman
|
|
211
193
|
reflection = model.send(:reflection_for_integer_attribute, column)
|
212
194
|
break if reflection
|
213
195
|
end
|
214
|
-
return Shard.current(klass.
|
215
|
-
|
196
|
+
return Shard.current(klass.connection_classes) if reflection.options[:polymorphic]
|
197
|
+
|
198
|
+
Shard.current(reflection.klass.connection_classes)
|
216
199
|
end
|
217
200
|
|
218
201
|
def relation_and_column(attribute)
|
@@ -221,8 +204,31 @@ module Switchman
|
|
221
204
|
[attribute.relation, column]
|
222
205
|
end
|
223
206
|
|
224
|
-
def
|
225
|
-
|
207
|
+
def build_where_clause(opts, rest = [])
|
208
|
+
opts = sanitize_forbidden_attributes(opts)
|
209
|
+
|
210
|
+
case opts
|
211
|
+
when String, Array
|
212
|
+
values = Hash === rest.first ? rest.first.values : rest
|
213
|
+
|
214
|
+
values.grep(ActiveRecord::Relation) do |rel|
|
215
|
+
# serialize subqueries against the same shard as the outer query is currently
|
216
|
+
# targeted to run against
|
217
|
+
rel.shard!(primary_shard) if rel.shard_source_value == :implicit && rel.primary_shard != primary_shard
|
218
|
+
end
|
219
|
+
|
220
|
+
super
|
221
|
+
when Hash, ::Arel::Nodes::Node
|
222
|
+
where_clause = super
|
223
|
+
|
224
|
+
predicates = where_clause.send(:predicates)
|
225
|
+
infer_shards_from_primary_key(predicates) if shard_source_value == :implicit && shard_value.is_a?(Shard)
|
226
|
+
predicates = transpose_predicates(predicates, nil, primary_shard)
|
227
|
+
where_clause.instance_variable_set(:@predicates, predicates)
|
228
|
+
where_clause
|
229
|
+
else
|
230
|
+
super
|
231
|
+
end
|
226
232
|
end
|
227
233
|
|
228
234
|
def arel_columns(columns)
|
@@ -233,117 +239,86 @@ module Switchman
|
|
233
239
|
connection.with_local_table_name { super }
|
234
240
|
end
|
235
241
|
|
236
|
-
def table_name_matches?(from)
|
237
|
-
connection.with_global_table_name { super }
|
238
|
-
end
|
239
|
-
|
240
|
-
# semi-private
|
241
|
-
public
|
242
242
|
def transpose_predicates(predicates,
|
243
243
|
source_shard,
|
244
244
|
target_shard,
|
245
|
-
remove_nonlocal_primary_keys
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
remove_nonlocal_primary_keys,
|
252
|
-
binds: binds,
|
253
|
-
dup_binds_on_mutation: dup_binds_on_mutation)
|
254
|
-
next (if new_predicates == predicate.children
|
255
|
-
predicate
|
256
|
-
else
|
257
|
-
::Arel::Nodes::And.new(new_predicates)
|
258
|
-
end)
|
259
|
-
end
|
245
|
+
remove_nonlocal_primary_keys: false)
|
246
|
+
predicates.map do |predicate|
|
247
|
+
transpose_single_predicate(predicate, source_shard, target_shard,
|
248
|
+
remove_nonlocal_primary_keys: remove_nonlocal_primary_keys)
|
249
|
+
end
|
250
|
+
end
|
260
251
|
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
remove_nonlocal_primary_keys &&
|
268
|
-
predicate.left.relation.model == klass &&
|
269
|
-
(predicate.is_a?(::Arel::Nodes::Equality) || predicate.is_a?(::Arel::Nodes::In))
|
270
|
-
|
271
|
-
current_source_shard =
|
272
|
-
if source_shard
|
273
|
-
source_shard
|
274
|
-
elsif type == :primary
|
275
|
-
Shard.current(klass.shard_category)
|
276
|
-
elsif type == :foreign
|
277
|
-
source_shard_for_foreign_key(relation, column)
|
278
|
-
end
|
252
|
+
def transpose_single_predicate(predicate,
|
253
|
+
source_shard,
|
254
|
+
target_shard,
|
255
|
+
remove_nonlocal_primary_keys: false)
|
256
|
+
if predicate.is_a?(::Arel::Nodes::Grouping)
|
257
|
+
return predicate unless predicate.expr.is_a?(::Arel::Nodes::Or)
|
279
258
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
bind.value.primary = true if type == :primary
|
259
|
+
# Dang, we have an OR. OK, that means we have other epxressions below this
|
260
|
+
# level, perhaps many, that may need transposition.
|
261
|
+
# the left side and right side must each be treated as predicate lists and
|
262
|
+
# transformed in kind, if neither of them changes we can just return the grouping as is.
|
263
|
+
# hold on, it's about to get recursive...
|
264
|
+
or_expr = predicate.expr
|
265
|
+
left_node = or_expr.left
|
266
|
+
right_node = or_expr.right
|
267
|
+
new_left_predicates = transpose_single_predicate(left_node, source_shard,
|
268
|
+
target_shard, remove_nonlocal_primary_keys: remove_nonlocal_primary_keys)
|
269
|
+
or_expr.instance_variable_set(:@left, new_left_predicates) if new_left_predicates != left_node
|
270
|
+
new_right_predicates = transpose_single_predicate(right_node, source_shard,
|
271
|
+
target_shard, remove_nonlocal_primary_keys: remove_nonlocal_primary_keys)
|
272
|
+
or_expr.instance_variable_set(:@right, new_right_predicates) if new_right_predicates != right_node
|
273
|
+
return predicate
|
274
|
+
end
|
275
|
+
return predicate unless predicate.is_a?(::Arel::Nodes::Binary) || predicate.is_a?(::Arel::Nodes::HomogeneousIn)
|
276
|
+
return predicate unless predicate.left.is_a?(::Arel::Attributes::Attribute)
|
277
|
+
|
278
|
+
relation, column = relation_and_column(predicate.left)
|
279
|
+
return predicate unless (type = transposable_attribute_type(relation, column))
|
280
|
+
|
281
|
+
remove = true if type == :primary &&
|
282
|
+
remove_nonlocal_primary_keys &&
|
283
|
+
predicate.left.relation.klass == klass &&
|
284
|
+
predicate.is_a?(::Arel::Nodes::Equality)
|
285
|
+
|
286
|
+
current_source_shard =
|
287
|
+
if source_shard
|
288
|
+
source_shard
|
289
|
+
elsif type == :primary
|
290
|
+
Shard.current(klass.connection_classes)
|
291
|
+
elsif type == :foreign
|
292
|
+
source_shard_for_foreign_key(relation, column)
|
293
|
+
end
|
294
|
+
|
295
|
+
right = if predicate.is_a?(::Arel::Nodes::HomogeneousIn)
|
296
|
+
predicate.values
|
319
297
|
else
|
320
|
-
|
321
|
-
local_id = [] if remove && local_id > Shard::IDS_PER_SHARD
|
322
|
-
bind.instance_variable_set(:@value, local_id)
|
323
|
-
bind.instance_variable_set(:@value_for_database, nil)
|
298
|
+
predicate.right
|
324
299
|
end
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
300
|
+
|
301
|
+
new_right_value =
|
302
|
+
case right
|
303
|
+
when Array
|
304
|
+
right.map { |val| transpose_predicate_value(val, current_source_shard, target_shard, type, remove) }
|
305
|
+
else
|
306
|
+
transpose_predicate_value(right, current_source_shard, target_shard, type, remove)
|
332
307
|
end
|
333
|
-
|
308
|
+
|
309
|
+
if new_right_value == right
|
310
|
+
predicate
|
311
|
+
elsif predicate.right.is_a?(::Arel::Nodes::Casted)
|
312
|
+
if new_right_value == right.value
|
334
313
|
predicate
|
335
|
-
elsif predicate.right.is_a?(::Arel::Nodes::Casted)
|
336
|
-
if new_right_value == predicate.right.val
|
337
|
-
predicate
|
338
|
-
else
|
339
|
-
predicate.class.new(predicate.left, predicate.right.class.new(new_right_value, predicate.right.attribute))
|
340
|
-
end
|
341
314
|
else
|
342
|
-
predicate.class.new(predicate.left, new_right_value)
|
315
|
+
predicate.class.new(predicate.left, right.class.new(new_right_value, right.attribute))
|
343
316
|
end
|
317
|
+
elsif predicate.is_a?(::Arel::Nodes::HomogeneousIn)
|
318
|
+
predicate.class.new(new_right_value, predicate.attribute, predicate.type)
|
319
|
+
else
|
320
|
+
predicate.class.new(predicate.left, new_right_value)
|
344
321
|
end
|
345
|
-
result = [result, binds]
|
346
|
-
result
|
347
322
|
end
|
348
323
|
|
349
324
|
def transpose_predicate_value(value, current_shard, target_shard, attribute_type, remove_non_local_ids)
|
@@ -356,12 +331,12 @@ module Switchman
|
|
356
331
|
value
|
357
332
|
else
|
358
333
|
local_id = Shard.relative_id_for(current_id, current_shard, target_shard) || current_id
|
359
|
-
|
360
|
-
if current_id
|
334
|
+
local_id = [] if remove_non_local_ids && local_id.is_a?(Integer) && local_id > Shard::IDS_PER_SHARD
|
335
|
+
if current_id == local_id
|
361
336
|
# make a new bind param
|
362
|
-
::Arel::Nodes::BindParam.new(query_att.class.new(query_att.name, local_id, query_att.type))
|
363
|
-
else
|
364
337
|
value
|
338
|
+
else
|
339
|
+
::Arel::Nodes::BindParam.new(query_att.class.new(query_att.name, local_id, query_att.type))
|
365
340
|
end
|
366
341
|
end
|
367
342
|
else
|