Module: Switchman::ActiveRecord::Relation

Defined in:
lib/switchman/active_record/relation.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.prepended(klass) ⇒ Object



4
5
6
# File 'lib/switchman/active_record/relation.rb', line 4

def self.prepended(klass)
  klass::SINGLE_VALUE_METHODS.concat [ :shard, :shard_source ]
end

Instance Method Details

#activate(&block) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/switchman/active_record/relation.rb', line 98

def activate(&block)
  shards = all_shards
  if (Array === shards && shards.length == 1)
    if shards.first == DefaultShard || shards.first == Shard.current(klass.shard_category)
      yield(self, shards.first)
    else
      shards.first.activate(klass.shard_category) { yield(self, shards.first) }
    end
  else
    # TODO: implement local limit to avoid querying extra shards
    Shard.with_each_shard(shards, [klass.shard_category]) do
      shard(Shard.current(klass.shard_category), :to_a).activate(&block)
    end
  end
end

#cloneObject



14
15
16
17
18
# File 'lib/switchman/active_record/relation.rb', line 14

def clone
  result = super
  result.shard_value = Shard.current(klass ? klass.shard_category : :primary) unless shard_value
  result
end

#create(*args, &block) ⇒ Object



33
34
35
# File 'lib/switchman/active_record/relation.rb', line 33

def create(*args, &block)
  primary_shard.activate(klass.shard_category) { super }
end

#create!(*args, &block) ⇒ Object



37
38
39
# File 'lib/switchman/active_record/relation.rb', line 37

def create!(*args, &block)
  primary_shard.activate(klass.shard_category) { super }
end

#explainObject



45
46
47
# File 'lib/switchman/active_record/relation.rb', line 45

def explain
  self.activate { |relation| relation.call_super(:explain, Relation) }
end

#find_ids_in_ranges(options = {}) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/switchman/active_record/relation.rb', line 70

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 = options[:start_at] ? subquery_scope.where("#{quoted_primary_key} >= ?", options[:start_at]) : subquery_scope

  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

#initialize(*args) ⇒ Object



8
9
10
11
12
# File 'lib/switchman/active_record/relation.rb', line 8

def initialize(*args)
  super
  self.shard_value = Shard.current(klass ? klass.shard_category : :primary) unless shard_value
  self.shard_source_value = :implicit unless shard_source_value
end

#merge(*args) ⇒ Object



20
21
22
23
24
25
26
27
# File 'lib/switchman/active_record/relation.rb', line 20

def merge(*args)
  relation = super
  if relation.shard_value != self.shard_value && relation.shard_source_value == :implicit
    relation.shard_value = self.shard_value
    relation.shard_source_value = self.shard_source_value
  end
  relation
end

#new(*args, &block) ⇒ Object



29
30
31
# File 'lib/switchman/active_record/relation.rb', line 29

def new(*args, &block)
  primary_shard.activate(klass.shard_category) { super }
end

#recordsObject



49
50
51
52
53
54
55
56
57
58
# File 'lib/switchman/active_record/relation.rb', line 49

def records
  return @records if loaded?
  results = self.activate { |relation| relation.call_super(:records, Relation) }
  case shard_value
  when Array, ::ActiveRecord::Relation, ::ActiveRecord::Base
    @records = results
    @loaded = true
  end
  results
end

#to_sqlObject



41
42
43
# File 'lib/switchman/active_record/relation.rb', line 41

def to_sql
  primary_shard.activate(klass.shard_category) { super }
end