module RecordCache::Strategy::Util

Constants

ATTRIBUTES_KEY
CLASS_KEY
NIL_COMES_FIRST

If x.nil? this class will return -1 for +x <=> y+

Public Class Methods

deserialize(serialized) click to toggle source

deserialize a cached record

# File lib/record_cache/strategy/util.rb, line 18
def deserialize(serialized)
  record = serialized[CLASS_KEY].constantize.allocate
  attributes = serialized[ATTRIBUTES_KEY].clone
  record.class.serialized_attributes.keys.each do |attribute|
    if attributes[attribute].respond_to?(:unserialize)
      if attributes[attribute].method(:unserialize).arity > 0
        attributes[attribute] = attributes[attribute].unserialize(attributes[attribute].value)
      else
        attributes[attribute] = attributes[attribute].unserialize
      end
    end
  end
  record.init_with('attributes' => attributes)
  record
end
filter!(records, wheres) click to toggle source

Filter the cached records in memory only simple x = y or x IN (a,b,c) can be handled string comparison is case insensitive Example:

RecordCache::Strategy::Util.filter!(Apple.all, :price => [0.49, 0.59, 0.69], :name => "Green Apple")
# File lib/record_cache/strategy/util.rb, line 39
def filter!(records, wheres)
  wheres.each_pair do |attr, value|
    attr = attr.to_sym
    if value.is_a?(Array)
      where_values = Set.new(value.first.respond_to?(:downcase) ? value.map(&:downcase) : value)
      records.to_a.select! do |record|
        attribute_value = record.send(attr)
        attribute_value = attribute_value.downcase if attribute_value.respond_to?(:downcase)
        where_values.include?(attribute_value)
      end
    else
      where_value = value.respond_to?(:downcase) ? value.downcase : value
      records.to_a.select! do |record|
        attribute_value = record.send(attr)
        attribute_value = attribute_value.downcase if attribute_value.respond_to?(:downcase)
        attribute_value == where_value
      end
    end
  end
end
serialize(record) click to toggle source

serialize one record before adding it to the cache creates a shallow clone with a version and without associations

# File lib/record_cache/strategy/util.rb, line 12
def serialize(record)
  {CLASS_KEY => record.class.name,
   ATTRIBUTES_KEY => record.instance_variable_get(:@attributes).dup}
end
sort!(records, *sort_orders) click to toggle source

Sort the cached records in memory, similar to MySql sorting rules including collatiom Simply provide the Symbols of the attributes to sort in Ascending order, or use

<attribute>, false

for Descending order.

Example:

RecordCache::Strategy::Util.sort!(Apple.all, :name)
RecordCache::Strategy::Util.sort!(Apple.all, [:name, false])
RecordCache::Strategy::Util.sort!(Apple.all, [:price, false], :name)
RecordCache::Strategy::Util.sort!(Apple.all, [:price, false], [:name, true])
RecordCache::Strategy::Util.sort!(Apple.all, [[:price, false], [:name, true]])
# File lib/record_cache/strategy/util.rb, line 69
def sort!(records, *sort_orders)
  return records if records.empty? || sort_orders.empty?
  if sort_orders.first.is_a?(Array) && sort_orders.first.first.is_a?(Array)
    sort_orders = sort_orders.first
  else
    sort_orders = sort_orders.map{ |order| order.is_a?(Array) ? order : [order, true] } unless sort_orders.all?{ |order| order.is_a?(Array) }
  end
  records.sort!(&sort_proc(records.first.class, sort_orders))
  Collator.clear
  records
end

Private Class Methods

sort_proc(base, sort_orders) click to toggle source

Retrieve the Proc based on the order by attributes Note: Case insensitive sorting with collation is used for Strings

# File lib/record_cache/strategy/util.rb, line 85
def sort_proc(base, sort_orders)
  # [['(COLLATER.collate(x.name) || NIL_COMES_FIRST)', 'COLLATER.collate(y.name)'], ['(y.updated_at || NIL_COMES_FIRST)', 'x.updated_at']]
  sort = sort_orders.map do |attr, asc|
    attr = attr.to_s
    lr = ["x.", "y."]
    lr.reverse! unless asc
    lr.each{ |s| s << attr }
    lr.each{ |s| s.replace("Collator.collate(#{s})") } if base.columns_hash[attr].type == :string
    lr[0].replace("(#{lr[0]} || NIL_COMES_FIRST)")
    lr
  end
  # ['[(COLLATER.collate(x.name) || NIL_COMES_FIRST), (y.updated_at || NIL_COMES_FIRST)]', '[COLLATER.collate(y.name), x.updated_at]']
  sort = sort.transpose.map{|s| s.size == 1 ? s.first : "[#{s.join(',')}]"}
  # Proc.new{ |x,y| { ([(COLLATER.collate(x.name) || NIL_COMES_FIRST), (y.updated_at || NIL_COMES_FIRST)] <=> [COLLATER.collate(y.name), x.updated_at]) || 1 }
  eval("Proc.new{ |x,y| (#{sort[0]} <=> #{sort[1]}) || 1 }")
end