class RedMatryoshka::Cache

Public Class Methods

new(cache_klass) click to toggle source
# File lib/red_matryoshka/cache.rb, line 3
def initialize(cache_klass)
  @cache_klass = cache_klass
end

Public Instance Methods

cache(object) click to toggle source
# File lib/red_matryoshka/cache.rb, line 13
def cache(object)
  key = cache_keys(object.id)

  doll = cache_doll(object)

  RedMatryoshka.configuration.redis.mapped_hmset key, doll.flatten

  doll.expand
end
cache_doll(object) click to toggle source

TODO: Right a test only for this method

# File lib/red_matryoshka/cache.rb, line 24
def cache_doll(object)
  RedMatryoshka::Doll.new(
    merge_dependent_hashes_and_main_hash(
      @cache_klass.to_hash(object),
      associate_object(object)
    ),
    @cache_klass
  )
end
delete(object_id) click to toggle source
# File lib/red_matryoshka/cache.rb, line 34
def delete(object_id)
  key = cache_keys(object_id)
  RedMatryoshka.configuration.redis.del key
end
fetch(ids) click to toggle source
# File lib/red_matryoshka/cache.rb, line 7
def fetch(ids)
  @cache_klass.after_fetch(
    fetch_objects(ids)
  )
end

Private Instance Methods

associate_object(object) click to toggle source
# File lib/red_matryoshka/cache.rb, line 100
def associate_object(object)
  @cache_klass.classes_to_depends_on.inject({}) do |associates, dependence|
    d = associate_object_id(dependence)
    d_id = @cache_klass.to_hash(object)[associate_object_id(dependence)]

    return associates if d_id.nil?

    associate_object = associate_object_key_formatter(
      transform_class_name(dependence[0]),
      d_id,
      self.class.new(
        cache_klass_with_module(dependence[0]).constantize.new
      ).send(:fetch_objects, d_id)
    )

    associates.merge(d => associate_object)
  end
end
associate_object_field(dependence) click to toggle source
# File lib/red_matryoshka/cache.rb, line 119
def associate_object_field(dependence)
  base_fetch_class = cache_klass_with_module(dependence[0]).constantize.class_to_fetch_from
  associate_id = dependence[1][:for] || base_fetch_class.to_s + "_id"

  transform_class_name(associate_id)
rescue NameError
  base_fetch_class.to_s + "_id"
end
associate_object_id(dependence) click to toggle source
# File lib/red_matryoshka/cache.rb, line 128
def associate_object_id(dependence)
  associate_object_field(dependence).to_sym
end
associate_object_key_formatter(dependence_name, dependence_id, fetch_object) click to toggle source
# File lib/red_matryoshka/cache.rb, line 132
def associate_object_key_formatter(dependence_name, dependence_id, fetch_object)
  if dependence_id.is_a? Array
    dependence_id.map.with_index do |id, i|
      object_formatter(dependence_name, id, fetch_object[i])
    end
  else
    object_formatter(dependence_name, dependence_id, fetch_object.first)
  end
end
cache_keys(*object_ids) click to toggle source
# File lib/red_matryoshka/cache.rb, line 78
def cache_keys(*object_ids)
  object_ids.map do |id|
    @cache_klass.cache_key id
  end
end
cache_klass_with_module(klass) click to toggle source
# File lib/red_matryoshka/cache.rb, line 152
def cache_klass_with_module(klass)
  if RedMatryoshka.configuration.module.present?
    "#{RedMatryoshka.configuration.module}::#{klass}"
  else
    klass
  end
end
fetch_objects(ids) click to toggle source
# File lib/red_matryoshka/cache.rb, line 41
def fetch_objects(ids)
  ids = [ids] unless ids.is_a? Array
  ids = ids[0] if ids[0].is_a? Array

  hashes = object_from_cache(*ids)
  keys_to_retrieve = object_id_to_retrieve_from_db(ids, hashes)
  fetch_objects_from_db(keys_to_retrieve).each do |object|
    i = ids.find_index(object.id)
    hashes[i] = cache(object)
  end

  hashes.map { |hash| RedMatryoshka::Doll.new(hash, @cache_klass).expand }
end
fetch_objects_from_db(object_ids_to_fetch = []) click to toggle source
# File lib/red_matryoshka/cache.rb, line 73
def fetch_objects_from_db(object_ids_to_fetch = [])
  return [] unless object_ids_to_fetch.any?
  @cache_klass.class_to_fetch_from.constantize.find(object_ids_to_fetch)
end
merge_dependent_hashes_and_main_hash(hash, dependent_hashes) click to toggle source
# File lib/red_matryoshka/cache.rb, line 84
def merge_dependent_hashes_and_main_hash(hash, dependent_hashes)
  if dependent_hashes.any? && dependent_hashes.keys.any?
    dependent_hashes.each do |dependence|
      if dependent_hashes[dependence[0]].is_a?(Array) && dependent_hashes[dependence[0]].any?
        hash.merge! dependent_hashes[dependence[0]].inject(&:merge)
      elsif dependent_hashes[dependence[0]].is_a? Hash
        hash.merge! dependent_hashes[dependence[0]]
      end

      hash.delete dependence[0]
    end
  end

  hash
end
object_formatter(dependence_name, dependence_id, fetch_object) click to toggle source
# File lib/red_matryoshka/cache.rb, line 142
def object_formatter(dependence_name, dependence_id, fetch_object)
  RedMatryoshka::Doll.new(fetch_object).flatten.inject({}) do |format_hash, (k, v)|
    format_hash.merge "#{dependence_name}:#{dependence_id}:#{k}" => v
  end
end
object_from_cache(*object_ids) click to toggle source
# File lib/red_matryoshka/cache.rb, line 55
def object_from_cache(*object_ids)
  keys = cache_keys(*object_ids)
  keys = [keys] if keys.is_a? String

  RedMatryoshka.configuration.redis.multi do |redis|
    keys.each do |key|
      redis.hgetall(key)
    end
  end
end
object_id_to_retrieve_from_db(object_ids, redis_objects_hash) click to toggle source
# File lib/red_matryoshka/cache.rb, line 66
def object_id_to_retrieve_from_db(object_ids, redis_objects_hash)
  redis_objects_hash.each_with_index.inject([]) do |keys, (v, i)|
    keys << object_ids[i] if v.empty?
    keys # Force return to avoid case where `keys` is empty
  end
end
transform_class_name(klass_name) click to toggle source
# File lib/red_matryoshka/cache.rb, line 148
def transform_class_name(klass_name)
  klass_name.to_s.split(/(?=[A-Z])/).map(&:downcase).join("_")
end