module Switchman::ActiveRecord::Relation
Public Class Methods
new(*, **)
click to toggle source
Calls superclass method
# File lib/switchman/active_record/relation.rb, line 10 def initialize(*, **) super self.shard_value = Shard.current(klass ? klass.connection_classes : :primary) unless shard_value self.shard_source_value = :implicit unless shard_source_value end
prepended(klass)
click to toggle source
# File lib/switchman/active_record/relation.rb, line 6 def self.prepended(klass) klass::SINGLE_VALUE_METHODS.concat %i[shard shard_source] end
Public Instance Methods
activate(unordered: false) { |self, first| ... }
click to toggle source
# File lib/switchman/active_record/relation.rb, line 106 def activate(unordered: false, &block) shards = all_shards if Array === shards && shards.length == 1 if shards.first == DefaultShard || shards.first == Shard.current(klass.connection_classes) yield(self, shards.first) else shards.first.activate(klass.connection_classes) { yield(self, shards.first) } end else result_count = 0 can_order = false result = Shard.with_each_shard(shards, [klass.connection_classes]) do # don't even query other shards if we're already past the limit next if limit_value && result_count >= limit_value && order_values.empty? relation = shard(Shard.current(klass.connection_classes), :to_a) # do a minimal query if possible relation = relation.limit(limit_value - result_count) if limit_value && !result_count.zero? && order_values.empty? shard_results = relation.activate(&block) if shard_results.present? && !unordered can_order ||= can_order_cross_shard_results? unless order_values.empty? raise OrderOnMultiShardQuery if !can_order && !order_values.empty? && result_count.positive? result_count += shard_results.is_a?(Array) ? shard_results.length : 1 end shard_results end result = reorder_cross_shard_results(result) if can_order result.slice!(limit_value..-1) if limit_value result end end
can_order_cross_shard_results?()
click to toggle source
# File lib/switchman/active_record/relation.rb, line 142 def can_order_cross_shard_results? # we only presume to be able to post-sort the most basic of orderings order_values.all? { |ov| ov.is_a?(::Arel::Nodes::Ordering) && ov.expr.is_a?(::Arel::Attributes::Attribute) } end
clone()
click to toggle source
Calls superclass method
# File lib/switchman/active_record/relation.rb, line 16 def clone result = super result.shard_value = Shard.current(klass ? klass.connection_classes : :primary) unless shard_value result end
create(*, &block)
click to toggle source
Calls superclass method
# File lib/switchman/active_record/relation.rb, line 35 def create(*, &block) primary_shard.activate(klass.connection_classes) { super } end
create!(*, &block)
click to toggle source
Calls superclass method
# File lib/switchman/active_record/relation.rb, line 39 def create!(*, &block) primary_shard.activate(klass.connection_classes) { super } end
explain()
click to toggle source
# File lib/switchman/active_record/relation.rb, line 47 def explain activate { |relation| relation.call_super(:explain, Relation) } end
find_ids_in_ranges(options = {}) { |*ids| ... }
click to toggle source
# File lib/switchman/active_record/relation.rb, line 73 def find_ids_in_ranges(options = {}) is_integer = columns_hash[primary_key.to_s].type == :integer loose_mode = options[:loose] && is_integer # loose_mode: if we don't care about getting exactly batch_size ids in between # don't get the max - just get the min and add batch_size so we get that many _at most_ values = loose_mode ? 'MIN(id)' : 'MIN(id), MAX(id)' batch_size = options[:batch_size].try(:to_i) || 1000 quoted_primary_key = "#{klass.connection.quote_local_table_name(table_name)}.#{klass.connection.quote_column_name(primary_key)}" as_id = ' AS id' unless primary_key == 'id' subquery_scope = except(:select).select("#{quoted_primary_key}#{as_id}").reorder(primary_key.to_sym).limit(loose_mode ? 1 : batch_size) subquery_scope = subquery_scope.where("#{quoted_primary_key} <= ?", options[:end_at]) if options[:end_at] first_subquery_scope = if options[:start_at] subquery_scope.where("#{quoted_primary_key} >= ?", options[:start_at]) else subquery_scope end ids = connection.select_rows("SELECT #{values} FROM (#{first_subquery_scope.to_sql}) AS subquery").first while ids.first.present? ids.map!(&:to_i) if is_integer ids << ids.first + batch_size if loose_mode yield(*ids) last_value = ids.last next_subquery_scope = subquery_scope.where(["#{quoted_primary_key}>?", last_value]) ids = connection.select_rows("SELECT #{values} FROM (#{next_subquery_scope.to_sql}) AS subquery").first end end
merge(*)
click to toggle source
Calls superclass method
# File lib/switchman/active_record/relation.rb, line 22 def merge(*) relation = super if relation.shard_value != shard_value && relation.shard_source_value == :implicit relation.shard_value = shard_value relation.shard_source_value = shard_source_value end relation end
new(*, &block)
click to toggle source
Calls superclass method
# File lib/switchman/active_record/relation.rb, line 31 def new(*, &block) primary_shard.activate(klass.connection_classes) { super } end
records()
click to toggle source
# File lib/switchman/active_record/relation.rb, line 51 def records return @records if loaded? results = activate { |relation| relation.call_super(:records, Relation) } case shard_value when Array, ::ActiveRecord::Relation, ::ActiveRecord::Base @records = results @loaded = true end results end
reorder_cross_shard_results(results)
click to toggle source
# File lib/switchman/active_record/relation.rb, line 147 def reorder_cross_shard_results(results) results.sort! do |l, r| result = 0 order_values.each do |ov| if l.is_a?(::ActiveRecord::Base) a = l.attribute(ov.expr.name) b = r.attribute(ov.expr.name) else a, b = l, r end next if a == b if a.nil? || b.nil? result = 1 if a.nil? result *= -1 if ov.is_a?(::Arel::Nodes::Descending) else result = a <=> b end result *= -1 if ov.is_a?(::Arel::Nodes::Descending) break unless result.zero? end result end end
to_sql()
click to toggle source
Calls superclass method
# File lib/switchman/active_record/relation.rb, line 43 def to_sql primary_shard.activate(klass.connection_classes) { super } end