module Switchman::ActiveRecord::Preloader::Association

Public Instance Methods

load_records() click to toggle source

significant changes:

* partition_by_shard the records_for call
* re-globalize the fetched owner id before looking up in the map
# File lib/switchman/active_record/association.rb, line 102
def load_records
  # owners can be duplicated when a relation has a collection association join
  # #compare_by_identity makes such owners different hash keys
  @records_by_owner = {}.compare_by_identity

  if owner_keys.empty?
    raw_records = []
  else
    # determine the shard to search for each owner
    if reflection.macro == :belongs_to
      # for belongs_to, it's the shard of the foreign_key
      partition_proc = lambda do |owner|
        if owner.class.sharded_column?(owner_key_name)
          Shard.shard_for(owner[owner_key_name], owner.shard)
        else
          Shard.current
        end
      end
    elsif !reflection.options[:multishard]
      # for non-multishard associations, it's *just* the owner's shard
      partition_proc = ->(owner) { owner.shard }
    end

    raw_records = Shard.partition_by_shard(owners, partition_proc) do |partitioned_owners|
      relative_owner_keys = partitioned_owners.map do |owner|
        key = owner[owner_key_name]
        if key && owner.class.sharded_column?(owner_key_name)
          key = Shard.relative_id_for(key, owner.shard,
                                      Shard.current(klass.connection_classes))
        end
        convert_key(key)
      end
      relative_owner_keys.compact!
      relative_owner_keys.uniq!
      records_for(relative_owner_keys)
    end
  end

  @preloaded_records = raw_records.select do |record|
    assignments = false

    owner_key = record[association_key_name]
    if owner_key && record.class.sharded_column?(association_key_name)
      owner_key = Shard.global_id_for(owner_key,
                                      record.shard)
    end

    owners_by_key[convert_key(owner_key)].each do |owner|
      entries = (@records_by_owner[owner] ||= [])

      if reflection.collection? || entries.empty?
        entries << record
        assignments = true
      end
    end

    assignments
  end
end
owners_by_key() click to toggle source

significant change: globalize keys on sharded columns

# File lib/switchman/active_record/association.rb, line 163
def owners_by_key
  @owners_by_key ||= owners.each_with_object({}) do |owner, result|
    key = owner[owner_key_name]
    key = Shard.global_id_for(key, owner.shard) if key && owner.class.sharded_column?(owner_key_name)
    key = convert_key(key)
    (result[key] ||= []) << owner if key
  end
end
records_for(ids) click to toggle source

Copypasta from Activerecord but with added global_id_for goodness.

# File lib/switchman/active_record/association.rb, line 86
def records_for(ids)
  scope.where(association_key_name => ids).load do |record|
    global_key = if model.connection_classes == UnshardedRecord
                   convert_key(record[association_key_name])
                 else
                   Shard.global_id_for(record[association_key_name], record.shard)
                 end
    owner = owners_by_key[convert_key(global_key)].first
    association = owner.association(reflection.name)
    association.set_inverse_instance(record)
  end
end
scope() click to toggle source

significant change: don't cache scope (since it could be for different shards)

# File lib/switchman/active_record/association.rb, line 173
def scope
  build_scope
end