/
active_record.rb
81 lines (72 loc) · 1.99 KB
/
active_record.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
module Queris
module ActiveRecordMixin
def self.included base
base.after_create :create_redis_indices
base.before_save :update_redis_indices
base.before_destroy :delete_redis_indices
def changed_cacheable_attributes
changed
end
def all_cacheable_attributes
attribute_names
end
base.extend ActiveRecordClassMixin
end
module ActiveRecordClassMixin
def redis_query(arg={}, &block)
ActiveRecordQuery.new self, arg, &block
end
def find_all
find :all
end
def find_cached(id, cache_it=true)
#POTENTIAL OPTIMIZATION: accept Enumerable id, pipeline redis commands
cache = redis_index :all_attribute_hashcache, Queris::HashCache
if (obj = cache.fetch(id))
return obj
elsif cache_it
begin
obj = find(id)
rescue
obj = nil
end
cache.create obj if obj
obj
end
end
end
end
class ActiveRecordQuery < Query
attr_accessor :params
def initialize(model, arg=nil)
if model.kind_of?(Hash) and arg.nil?
arg, model = model, model[:model]
elsif arg.nil?
arg= {}
end
@params = {}
unless model.kind_of?(Class) && model < ActiveRecord::Base
raise ArgumentError, ":model arg must be an ActiveRecord model, got #{model.respond_to?(:superclass) ? model.superclass.name : model} instead."
end
super model, arg
end
def results(*arg)
res_ids = super(*arg)
res = []
res_ids.each_with_index do |id, i|
unless (cached = @model.find_cached id).nil?
res << cached
end
end
res
end
def subquery(arg={})
if arg.kind_of? Query #adopt a given query as subquery
raise "Trying to use a subquery from a different model" unless arg.model == model
else #create new subquery
arg[:model]=model
end
super arg
end
end
end