switchman 2.0.9 → 2.0.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af9f8893be986771668662ceca8d3e36e28f5babf889a18e1e3efc237f7eae66
4
- data.tar.gz: 675bd5b18076e8da86feb8a6e6271fffc1cd27939dedc1eb51c61bf165122b63
3
+ metadata.gz: bce5f0819ee2570b0bf51ba3872af1f34c23273712cc33c35559225723fb13a0
4
+ data.tar.gz: 11e7c3d612263f94ea17bc5213580ae42e2c12743a13ff36e9f988feddda0a7e
5
5
  SHA512:
6
- metadata.gz: aadb4a342920dfe24e6110546380aa83a9aa4f61722e8c4c7265d0bf4494a2e8e04975d00504f7a26f143b87595bdb8c47ea09b4f9344f4925af08055c9d23e5
7
- data.tar.gz: 295a3b4490f511380dcaeb44a6a6985cdf97745e678054eaf46315fc89d3adafd7a84a7a3665ec4521a6baa3b9f787adfccdc6d814baab10999c148b75041773
6
+ metadata.gz: 0fad57a01e86f34533c5cf539cf92360605b129bdfdf77878fec72663c3783bad56e7a7a324f3b388e37a89296d05f309dc2c84084e30c1c44d20917e15d35e3
7
+ data.tar.gz: 002bcec40325a407c8be94432d2396c8ae812ad2828695266e591956d1e1e8195628906fce710c4681a3c72cc5f6ea8f1859a99aac22cbd3462be5dd6118bbdf
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
@@ -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")]
@@ -250,7 +250,7 @@ module Switchman
250
250
  remove = true if type == :primary &&
251
251
  remove_nonlocal_primary_keys &&
252
252
  predicate.left.relation.model == klass &&
253
- predicate.is_a?(::Arel::Nodes::Equality)
253
+ (predicate.is_a?(::Arel::Nodes::Equality) || predicate.is_a?(::Arel::Nodes::In))
254
254
 
255
255
  current_source_shard =
256
256
  if source_shard
@@ -265,7 +265,7 @@ module Switchman
265
265
  new_right_value =
266
266
  case predicate.right
267
267
  when Array
268
- predicate.right.map {|val| transpose_predicate_value(val, current_source_shard, target_shard, type, remove) }
268
+ predicate.right.map {|val| transpose_predicate_value(val, current_source_shard, target_shard, type, remove).presence }.compact
269
269
  else
270
270
  transpose_predicate_value(predicate.right, current_source_shard, target_shard, type, remove)
271
271
  end
@@ -340,7 +340,7 @@ module Switchman
340
340
  value
341
341
  else
342
342
  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
343
+ return nil if remove_non_local_ids && local_id.is_a?(Integer) && local_id > Shard::IDS_PER_SHARD
344
344
  if current_id != local_id
345
345
  # make a new bind param
346
346
  ::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.10"
5
5
  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.10
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-09 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: railties