module ActiveRecord::ShardFor::Model::ClassMethods

Public Instance Methods

all_shards() click to toggle source

Returns all generated shard model class. Useful to query to all shards. @return [Array<Class>] An array of shard models @example

User.all_shards.flat_map {|m| m.find_by(name: 'alice') }.compact
# File lib/activerecord/shard_for/model.rb, line 130
def all_shards
  shard_repository.all
end
all_shards_in_parallel() click to toggle source

@return [ActiveRecord::ShardFor::AllShardsInParallel] @example

User.all_shards_in_parallel.map {|m| m.where.find_by(name: 'Alice') }.compact
# File lib/activerecord/shard_for/model.rb, line 137
def all_shards_in_parallel
  AllShardsInParallel.new(all_shards, service: service)
end
Also aliased as: parallel
before_put(&block) click to toggle source

Register hook to assign auto-generated distkey or something. Sometimes you want to generates distkey value before validation. Since activerecord-shard_for generates sub class of your models, AR's callback is not useless for this usecase, so activerecord-shard_for offers its own callback method. @example

class User
  include ActiveRecord::ShardFor::Model
  use_cluster :user
  def_distkey :name
  before_put do |attributes|
    attributes[:name] = generate_name unless attributes[:name]
  end
end
# File lib/activerecord/shard_for/model.rb, line 95
def before_put(&block)
  @before_put_callback = block
end
def_distkey(column) click to toggle source

Distkey is a column. activerecord-shard_for gave to connection_router that value and connection_router determine which shard to store. @param [Symbol] column

# File lib/activerecord/shard_for/model.rb, line 122
def def_distkey(column)
  self.distkey = column.to_sym
end
get(key) click to toggle source

Returns nil when not found. Except that, is same as `.get!`. @param [String] key @return [ActiveRecord::Base, nil] A shard model instance

# File lib/activerecord/shard_for/model.rb, line 102
def get(key)
  shard_for(key).find_by(distkey => key)
end
get!(key) click to toggle source

`.get!` raises ActiveRecord::ShardFor::RecordNotFound which is child class of `ActiveRecord::RecordNotFound` so you can rescue that exception as same as AR's RecordNotFound. @param [String] key @return [ActiveRecord::Base] A shard model instance @raise [ActiveRecord::ShardFor::RecordNotFound]

# File lib/activerecord/shard_for/model.rb, line 112
def get!(key)
  model = get(key)
  return model if model

  raise ActiveRecord::ShardFor::RecordNotFound
end
parallel()
put!(attributes) click to toggle source

Create new record with given attributes in proper shard for given key. When distkey value is empty, raises ActiveRecord::ShardFor::MissingDistkeyAttribute error. @param [Hash] attributes @return [ActiveRecord::Base] A shard model instance @raise [ActiveRecord::ShardFor::MissingDistkeyAttribute]

# File lib/activerecord/shard_for/model.rb, line 70
def put!(attributes)
  raise '`distkey` is not defined. Use `def_distkey`.' unless distkey

  @before_put_callback.call(attributes) if defined?(@before_put_callback) && @before_put_callback

  key = fetch_distkey_from_attributes(attributes)

  raise ActiveRecord::ShardFor::MissingDistkeyAttribute unless key

  shard_for(key).create!(attributes)
end
replicates_with(mapping) click to toggle source

@param [Hash{Symbol => Symbol}] mapping A pairs of role name and

AR model class name.
# File lib/activerecord/shard_for/model.rb, line 144
def replicates_with(mapping)
  self.replication_mapping = ActiveRecord::ShardFor::ReplicationMapping.new(mapping)
end
shard_eval(&block) click to toggle source

Evaluate block in all shard instances.

# File lib/activerecord/shard_for/model.rb, line 58
def shard_eval(&block)
  all_shards.each do |shard|
    shard.class_eval(&block)
  end
end
shard_for(key) click to toggle source

Returns a generated model class of included model class which has proper connection config for the shard for given key. @param [String] key A value of distkey @return [Class] A generated model class for given distkey value

# File lib/activerecord/shard_for/model.rb, line 52
def shard_for(key)
  connection_name = connection_router.fetch_connection_name(key)
  shard_repository.fetch(connection_name)
end
switch(role_name, &block) click to toggle source

See example definitions in `spec/models.rb`. @param [Symbol] A role name of target cluster. @return [Class, Object] if block given then yielded result else

target shard model.

@example

UserReadonly.all_shards.each do |m|
  target_ids = m.where(age: 1).pluck(:id)
  m.switch(:master) do |master|
    master.where(id: target_ids).delete_all
  end
end
# File lib/activerecord/shard_for/model.rb, line 159
def switch(role_name, &block)
  replication_mapping.switch(self, role_name, &block)
end
use_cluster(name, router_name, thread_pool_size_base: 3) click to toggle source

The cluster config must be defined before `use_cluster` @param [Symbol] name A cluster name which is set by ActiveRecord::ShardFor.configure

# File lib/activerecord/shard_for/model.rb, line 21
def use_cluster(name, router_name, thread_pool_size_base: 3)
  cluster_config = ActiveRecord::ShardFor.config.fetch_cluster_config(name)
  connection_router_class = ActiveRecord::ShardFor.config.fetch_connection_router(router_name)
  self.connection_router = connection_router_class.new(cluster_config)
  self.shard_repository = ActiveRecord::ShardFor::ShardRepository.new(cluster_config, self)
  thread_size = (shard_repository.all.size * thread_pool_size_base)
  self.service = Expeditor::Service.new(
    executor: Concurrent::ThreadPoolExecutor.new(
      min_threads: thread_size,
      max_threads: thread_size,
      max_queue: shard_repository.all.size,
      fallback_policy: :abort
    )
  )
  self.abstract_class = true
end
using(shard_key) { |model| ... } click to toggle source

Returns a generated model class of included model which specific connection. @param [Object] shard_key key of a shard connection @yield [Class] generated model class which key of shard connection @return [Class] generated model class which key of shard connection

# File lib/activerecord/shard_for/model.rb, line 42
def using(shard_key)
  model = shard_repository.fetch_by_key(shard_key)
  yield model if block_given?
  model
end

Private Instance Methods

fetch_distkey_from_attributes(attributes) click to toggle source

@param [Hash] attributes @return [Object or nil] distkey

# File lib/activerecord/shard_for/model.rb, line 167
def fetch_distkey_from_attributes(attributes)
  key = attributes[distkey] || attributes[distkey.to_s]
  return key if key

  instance = all_shards.first.new(attributes)
  return unless instance.respond_to?(distkey)

  instance.send(distkey)
end