#require 'memcache-client' # in config.rb #CACHE = MemCache.new 'localhost:11211', :multithread => true, :namespace => 'reality_spec' module Sequel class Dataset def cache_proxy @opts[:cache_proxy] end def cache_by(*keys) @opts[:cache_proxy] = CacheProxy.new(@opts[:from]) @opts[:cache_keys] = keys end alias_method :orig_brackets, :[] def [](*args) if @opts[:cache_proxy] && (args.size == @opts[:cache_keys].size) && \ !args.first.is_a?(Hash) cached = @opts[:cache_proxy].get(args) return cached if cached end orig_brackets(args) end end class CacheProxy attr_reader :prefix attr_accessor :ttl def initialize(prefix, ttl = 900) @prefix = "#{prefix}#{__id___}" @ttl = ttl end def format_key(key) "#{@prefix}#{key.inspect}" end def get(key) CACHE.get(format_key(key)) end def set(key, value) CACHE.set(format_key(key), value, @ttl) end def delete(key) CACHE.delete(format_key(key)) end end end items = DB[:items].cache_by(:name) i1 = items['joojoo'] # DB hit i2 = items['joojoo'] # cache hit items.filter(:name => 'joojoo').update(:name => '10') # cache invalidated # composite cache keys attributes = DB[:items].cache_by(:node_id, :kind) i1 = attributes[@n_id, Attributes::SampleRate] # DB hit i2 = attributes[@n_id, Attributes::SampleRate] # cache hit attributes[@n_id, Attributes::SampleRate] = {:value => 10} # hit