switchman 2.0.9 → 2.0.11

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af9f8893be986771668662ceca8d3e36e28f5babf889a18e1e3efc237f7eae66
4
- data.tar.gz: 675bd5b18076e8da86feb8a6e6271fffc1cd27939dedc1eb51c61bf165122b63
3
+ metadata.gz: aa20d460683c12b9e6528f0956c83dec5fadcc4247d551fbd84361757d5452a0
4
+ data.tar.gz: 79a6a917b940d6e0bc5b10288f757d002635526e083f3c123698976fb5e96483
5
5
  SHA512:
6
- metadata.gz: aadb4a342920dfe24e6110546380aa83a9aa4f61722e8c4c7265d0bf4494a2e8e04975d00504f7a26f143b87595bdb8c47ea09b4f9344f4925af08055c9d23e5
7
- data.tar.gz: 295a3b4490f511380dcaeb44a6a6985cdf97745e678054eaf46315fc89d3adafd7a84a7a3665ec4521a6baa3b9f787adfccdc6d814baab10999c148b75041773
6
+ metadata.gz: 55aca398595c2fda0e32f4aa35e10f42ded64d3154d1dd9bb5cee8f0a0682d61317f8486b156e2722ed3c381dd6cc42710729e19d859b3ade543991469464835
7
+ data.tar.gz: 4b5bfb169f36aa3a69f716195316941f648d8b06ae3c9a9f09c5b5835dd67005ddbc7fe7cbe864b278aefeb3abdeaa8f65292f00dcd29c4cf1011c4e852bec64
@@ -87,7 +87,7 @@ module Switchman
87
87
  # Copypasta from Activerecord but with added global_id_for goodness.
88
88
  def records_for(ids)
89
89
  scope.where(association_key_name => ids).load do |record|
90
- global_key = if record.class.shard_category == :unsharded
90
+ global_key = if model.shard_category == :unsharded
91
91
  convert_key(record[association_key_name])
92
92
  else
93
93
  Shard.global_id_for(record[association_key_name], record.shard)
@@ -51,7 +51,7 @@ module Switchman
51
51
 
52
52
  def calculate_simple_average(column_name, distinct)
53
53
  # See activerecord#execute_simple_calculation
54
- relation = reorder(nil)
54
+ relation = except(:order)
55
55
  column = aggregate_column(column_name)
56
56
  relation.select_values = [operation_over_aggregate_column(column, "average", distinct).as("average"),
57
57
  operation_over_aggregate_column(column, "count", distinct).as("count")]
@@ -215,6 +215,10 @@ module Switchman
215
215
  name.quoted
216
216
  end
217
217
 
218
+ def with_global_table_name(&block)
219
+ with_local_table_name(false, &block)
220
+ end
221
+
218
222
  def with_local_table_name(enable = true)
219
223
  old_value = @use_local_table_name
220
224
  @use_local_table_name = enable
@@ -233,6 +233,10 @@ module Switchman
233
233
  connection.with_local_table_name { super }
234
234
  end
235
235
 
236
+ def table_name_matches?(from)
237
+ connection.with_global_table_name { super }
238
+ end
239
+
236
240
  # semi-private
237
241
  public
238
242
  def transpose_predicates(predicates,
@@ -250,7 +254,7 @@ module Switchman
250
254
  remove = true if type == :primary &&
251
255
  remove_nonlocal_primary_keys &&
252
256
  predicate.left.relation.model == klass &&
253
- predicate.is_a?(::Arel::Nodes::Equality)
257
+ (predicate.is_a?(::Arel::Nodes::Equality) || predicate.is_a?(::Arel::Nodes::In))
254
258
 
255
259
  current_source_shard =
256
260
  if source_shard
@@ -265,7 +269,7 @@ module Switchman
265
269
  new_right_value =
266
270
  case predicate.right
267
271
  when Array
268
- predicate.right.map {|val| transpose_predicate_value(val, current_source_shard, target_shard, type, remove) }
272
+ predicate.right.map {|val| transpose_predicate_value(val, current_source_shard, target_shard, type, remove).presence }.compact
269
273
  else
270
274
  transpose_predicate_value(predicate.right, current_source_shard, target_shard, type, remove)
271
275
  end
@@ -340,7 +344,7 @@ module Switchman
340
344
  value
341
345
  else
342
346
  local_id = Shard.relative_id_for(current_id, current_shard, target_shard) || current_id
343
- local_id = [] if remove_non_local_ids && local_id.is_a?(Integer) && local_id > Shard::IDS_PER_SHARD
347
+ return nil if remove_non_local_ids && local_id.is_a?(Integer) && local_id > Shard::IDS_PER_SHARD
344
348
  if current_id != local_id
345
349
  # make a new bind param
346
350
  ::Arel::Nodes::BindParam.new(query_att.class.new(query_att.name, local_id, query_att.type))
@@ -106,10 +106,62 @@ module Switchman
106
106
  shards.first.activate(klass.shard_category) { yield(self, shards.first) }
107
107
  end
108
108
  else
109
- # TODO: implement local limit to avoid querying extra shards
110
- Shard.with_each_shard(shards, [klass.shard_category]) do
111
- shard(Shard.current(klass.shard_category), :to_a).activate(&block)
109
+ result_count = 0
110
+ can_order = false
111
+ result = Shard.with_each_shard(shards, [klass.shard_category]) do
112
+ # don't even query other shards if we're already past the limit
113
+ next if limit_value && result_count >= limit_value && order_values.empty?
114
+
115
+ relation = shard(Shard.current(klass.shard_category), :to_a)
116
+ # do a minimal query if possible
117
+ relation = relation.limit(limit_value - result_count) if limit_value && !result_count.zero? && order_values.empty?
118
+
119
+ shard_results = relation.activate(&block)
120
+
121
+ if shard_results.present?
122
+ can_order ||= can_order_cross_shard_results? unless order_values.empty?
123
+ raise OrderOnMultiShardQuery if !can_order && !order_values.empty? && result_count.positive?
124
+
125
+ result_count += shard_results.is_a?(Array) ? shard_results.length : 1
126
+ end
127
+ shard_results
128
+ end
129
+
130
+ result = reorder_cross_shard_results(result) if can_order
131
+ result.slice!(limit_value..-1) if limit_value
132
+ result
133
+ end
134
+ end
135
+
136
+ def can_order_cross_shard_results?
137
+ # we only presume to be able to post-sort the most basic of orderings
138
+ order_values.all? { |ov| ov.is_a?(::Arel::Nodes::Ordering) && ov.expr.is_a?(::Arel::Attributes::Attribute) }
139
+ end
140
+
141
+ def reorder_cross_shard_results(results)
142
+ results.sort! do |l, r|
143
+ result = 0
144
+ order_values.each do |ov|
145
+ if l.respond_to?(ov.expr.name)
146
+ a = l.send(ov.expr.name)
147
+ b = r.send(ov.expr.name)
148
+ else
149
+ a = l.attributes[ov.expr.name]
150
+ b = r.attributes[ov.expr.name]
151
+ end
152
+ next if a == b
153
+
154
+ if a.nil? || b.nil?
155
+ result = 1 if a.nil?
156
+ result *= -1 if ov.is_a?(::Arel::Nodes::Descending)
157
+ else
158
+ result = a <=> b
159
+ end
160
+
161
+ result *= -1 if ov.is_a?(::Arel::Nodes::Descending)
162
+ break unless result.zero?
112
163
  end
164
+ result
113
165
  end
114
166
  end
115
167
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Switchman
4
- VERSION = "2.0.9"
4
+ VERSION = "2.0.11"
5
5
  end
data/lib/switchman.rb CHANGED
@@ -17,4 +17,6 @@ module Switchman
17
17
  def self.cache=(cache)
18
18
  @cache = cache
19
19
  end
20
+
21
+ class OrderOnMultiShardQuery < RuntimeError; end
20
22
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: switchman
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.9
4
+ version: 2.0.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-04-16 00:00:00.000000000 Z
13
+ date: 2021-06-11 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: railties