class ProstoCache::ProstoModelCache
cache itself, contains pretty much all the logic
Constants
- MAX_CACHE_LIFE
Attributes
accessor_keys[R]
cache[RW]
model_class[R]
signature[RW]
sort_keys[R]
validated_at[RW]
Public Class Methods
fail_on_missing_value?(litmus)
click to toggle source
# File lib/prosto_cache/prosto_model_cache.rb, line 52 def self.fail_on_missing_value?(litmus) case litmus when Symbol true when String false else raise ArgumentError, "Unknown type of cache key #{litmus.inspect}" end end
new(model_class, accessor_keys, sort_keys)
click to toggle source
# File lib/prosto_cache/prosto_model_cache.rb, line 65 def initialize(model_class, accessor_keys, sort_keys) raise ArgumentError, "No model class provided" unless model_class @model_class = model_class @accessor_keys = [*(accessor_keys || :name)] @sort_keys = sort_keys ? [*(sort_keys)] : @accessor_keys end
Public Instance Methods
[](*keys)
click to toggle source
# File lib/prosto_cache/prosto_model_cache.rb, line 77 def [](*keys) unless keys.length == accessor_keys.length raise BadCacheKeyError, "Cached accessed by #{keys.length} keys, expected #{accessor_keys.length}" end keys.zip((1..keys.length)).inject(safe_cache) do |memo, (key, index)| value = memo[key] unless value if ProstoModelCache.fail_on_missing_value?(keys.last) raise BadCacheKeyError, key else value = ProstoHash.new unless index == keys.length end end value end end
invalidate()
click to toggle source
# File lib/prosto_cache/prosto_model_cache.rb, line 73 def invalidate self.cache = self.signature = self.validated_at = nil end
keys()
click to toggle source
# File lib/prosto_cache/prosto_model_cache.rb, line 96 def keys safe_cache.keys end
values()
click to toggle source
# File lib/prosto_cache/prosto_model_cache.rb, line 100 def values safe_cache.values end
Private Instance Methods
build_cache(objects, attributes=[])
click to toggle source
# File lib/prosto_cache/prosto_model_cache.rb, line 147 def build_cache(objects, attributes=[]) attributes = [*attributes] if attributes.empty? # terminal case raise BadCacheValuesError, "No cache entry found" if objects.nil? || objects.empty? raise BadCacheValuesError, "Non deterministic search result, more then one cache entry found" if objects.size > 1 return objects.first else reduced_attributes = attributes.dup attribute = reduced_attributes.delete_at(0).to_sym # first, bucketize to reduce problem's complexity array_map = objects.each_with_object({}) do |o, memo| key = o.public_send(attribute).to_s memo[key] ||= [] memo[key] << o end # second, recurse and build cache from those reduced buckets! array_map.each_with_object(ProstoHash.new) do |(attr_value, attr_bucket), memo| memo[attr_value] = build_cache(attr_bucket, reduced_attributes) end end end
load_cache(time, current_cache_signature = nil)
click to toggle source
# File lib/prosto_cache/prosto_model_cache.rb, line 133 def load_cache(time, current_cache_signature = nil) fail "Can not load already loaded cache" if cache current_cache_signature ||= query_cache_signature cache_values = model_class.all self.cache = build_cache(cache_values, accessor_keys) cache.values(sorted_cache_values(cache_values)) cache.keys(sorted_keys(cache.values)) self.validated_at = time self.signature = current_cache_signature end
query_cache_signature()
click to toggle source
# File lib/prosto_cache/prosto_model_cache.rb, line 188 def query_cache_signature raw_result = ActiveRecord::Base.connection.execute( "select max(updated_at) as max_updated_at, max(id) as max_id, count(id) as count from #{model_class.table_name}" ) array_result = case raw_result.class.name when 'Mysql::Result' [].tap { |rows| raw_result.each_hash { |h| rows << h } } when 'Mysql2::Result' [].tap { |rows| raw_result.each(:as => :hash) { |h| rows << h } } when 'PGresult', 'PG::Result' raw_result.map(&:to_hash) when 'Array' # assuming sqlite raw_result else fail "Result class #{raw_result.class.name} is unsupported" end array_result.map(&:symbolize_keys).first end
safe_cache()
click to toggle source
# File lib/prosto_cache/prosto_model_cache.rb, line 109 def safe_cache time = Time.now.to_i if cache && validated_at < time - MAX_CACHE_LIFE current_cache_signature = validate_cache_signature(time) end unless cache load_cache(time, current_cache_signature) end cache end
sorted_cache_values(cache_values)
click to toggle source
# File lib/prosto_cache/prosto_model_cache.rb, line 170 def sorted_cache_values(cache_values) cache_values.sort_by { |o| sort_keys.inject('') { |memo, k| memo << o.public_send(k) } } end
sorted_keys(cache_values)
click to toggle source
# File lib/prosto_cache/prosto_model_cache.rb, line 178 def sorted_keys(cache_values) cache_values.map { |o| accessor_keys.inject([]) { |memo, k| memo << o.public_send(k).to_sym } }.tap { |rtn| rtn.flatten! if accessor_keys.length == 1 } end
validate_cache_signature(time)
click to toggle source
# File lib/prosto_cache/prosto_model_cache.rb, line 123 def validate_cache_signature(time) query_cache_signature.tap { |current_cache_signature| if current_cache_signature == signature self.validated_at = time else invalidate end } end