switchman 2.0.6 → 3.0.1
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 +235 -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 +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 -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 +106 -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 +18 -15
- 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 +45 -144
- 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 +122 -144
- 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/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 +90 -49
- 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
- data/lib/switchman/schema_cache.rb +0 -20
@@ -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
|