switchman 2.0.7 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +10 -2
- data/app/models/switchman/shard.rb +234 -270
- 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 +1 -1
- 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 -3
- 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 +73 -66
- 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 +5 -14
- 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 +42 -53
- data/lib/switchman/active_record/predicate_builder.rb +1 -1
- data/lib/switchman/active_record/query_cache.rb +18 -19
- data/lib/switchman/active_record/query_methods.rb +172 -181
- data/lib/switchman/active_record/reflection.rb +6 -10
- data/lib/switchman/active_record/relation.rb +27 -21
- 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 -57
- 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 -1
- data/lib/switchman/sharded_instrumenter.rb +1 -1
- data/lib/switchman/standard_error.rb +15 -3
- data/lib/switchman/test_helper.rb +6 -10
- data/lib/switchman/version.rb +1 -1
- data/lib/tasks/switchman.rake +54 -69
- metadata +90 -48
- 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 -169
@@ -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,101 +239,86 @@ module Switchman
|
|
233
239
|
connection.with_local_table_name { super }
|
234
240
|
end
|
235
241
|
|
236
|
-
# semi-private
|
237
|
-
public
|
238
242
|
def transpose_predicates(predicates,
|
239
243
|
source_shard,
|
240
244
|
target_shard,
|
241
|
-
remove_nonlocal_primary_keys
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
relation, column = relation_and_column(predicate.left)
|
248
|
-
next predicate unless (type = transposable_attribute_type(relation, column))
|
249
|
-
|
250
|
-
remove = true if type == :primary &&
|
251
|
-
remove_nonlocal_primary_keys &&
|
252
|
-
predicate.left.relation.model == klass &&
|
253
|
-
predicate.is_a?(::Arel::Nodes::Equality)
|
254
|
-
|
255
|
-
current_source_shard =
|
256
|
-
if source_shard
|
257
|
-
source_shard
|
258
|
-
elsif type == :primary
|
259
|
-
Shard.current(klass.shard_category)
|
260
|
-
elsif type == :foreign
|
261
|
-
source_shard_for_foreign_key(relation, column)
|
262
|
-
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
|
263
251
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
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)
|
258
|
+
|
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
|
303
297
|
else
|
304
|
-
|
305
|
-
local_id = [] if remove && local_id > Shard::IDS_PER_SHARD
|
306
|
-
bind.instance_variable_set(:@value, local_id)
|
307
|
-
bind.instance_variable_set(:@value_for_database, nil)
|
298
|
+
predicate.right
|
308
299
|
end
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
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)
|
316
307
|
end
|
317
|
-
|
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
|
318
313
|
predicate
|
319
|
-
elsif predicate.right.is_a?(::Arel::Nodes::Casted)
|
320
|
-
if new_right_value == predicate.right.val
|
321
|
-
predicate
|
322
|
-
else
|
323
|
-
predicate.class.new(predicate.left, predicate.right.class.new(new_right_value, predicate.right.attribute))
|
324
|
-
end
|
325
314
|
else
|
326
|
-
predicate.class.new(predicate.left, new_right_value)
|
315
|
+
predicate.class.new(predicate.left, right.class.new(new_right_value, right.attribute))
|
327
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)
|
328
321
|
end
|
329
|
-
result = [result, binds]
|
330
|
-
result
|
331
322
|
end
|
332
323
|
|
333
324
|
def transpose_predicate_value(value, current_shard, target_shard, attribute_type, remove_non_local_ids)
|
@@ -341,11 +332,11 @@ module Switchman
|
|
341
332
|
else
|
342
333
|
local_id = Shard.relative_id_for(current_id, current_shard, target_shard) || current_id
|
343
334
|
local_id = [] if remove_non_local_ids && local_id.is_a?(Integer) && local_id > Shard::IDS_PER_SHARD
|
344
|
-
if current_id
|
335
|
+
if current_id == local_id
|
345
336
|
# make a new bind param
|
346
|
-
::Arel::Nodes::BindParam.new(query_att.class.new(query_att.name, local_id, query_att.type))
|
347
|
-
else
|
348
337
|
value
|
338
|
+
else
|
339
|
+
::Arel::Nodes::BindParam.new(query_att.class.new(query_att.name, local_id, query_att.type))
|
349
340
|
end
|
350
341
|
end
|
351
342
|
else
|