diff options
| author | Ethan Rowe <ethan@endpoint.com> | 2009-04-06 11:34:12 -0400 |
|---|---|---|
| committer | James Turnbull <james@lovedthanlost.net> | 2009-04-22 14:39:37 +1000 |
| commit | 75f1923049d5e1edfd3b9e9790a96b487cdef305 (patch) | |
| tree | 6cbea71de5c6c8e366b1435abb673d1d376179ff /lib | |
| parent | bab45c4a3006867c500b30df9b91b7b46c17dff9 (diff) | |
Initial implementation of a "cache accumulator" behavior.
Mix Puppet::Util::CacheAccumulator into an ActiveRecord-like class, and then for any
attribute in that class on which you are likely to call find_or_create_by_*, specify:
accumulates :foo
and instead of :find_or_create_by_foo use :accumulate_by_foo.
The class will cache known results keyed by values of :foo.
Do an initial bulk-lookup: class.accumulate_by_foo('foo1', 'foo2', 'foo3', 'foo4')
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/puppet/util/rails/cache_accumulator.rb | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/lib/puppet/util/rails/cache_accumulator.rb b/lib/puppet/util/rails/cache_accumulator.rb new file mode 100644 index 000000000..7c59a5d3f --- /dev/null +++ b/lib/puppet/util/rails/cache_accumulator.rb @@ -0,0 +1,65 @@ +require 'puppet/util' + +module Puppet::Util::CacheAccumulator + def self.included(klass) + klass.extend ClassMethods + end + + class Base + attr_reader :klass, :attribute + + def initialize(klass, attribute) + @klass = klass + @attribute = attribute + @find_or_create = "find_or_create_by_#{@attribute.to_s}".intern + end + + def store + @store || reset + end + + def reset + @store = {} + end + + def find(*keys) + result = nil + if keys.length == 1 + result = store[keys[0]] ||= @klass.send(@find_or_create, *keys) + else + found, missing = keys.partition {|k| store.include? k} + result = found.length + result += do_multi_find(missing) if missing.length > 0 + end + result + end + + def do_multi_find(keys) + result = 0 + @klass.find(:all, :conditions => {@attribute => keys}).each do |obj| + store[obj.send(@attribute)] = obj + result += 1 + end + result + end + end + + module ClassMethods + def accumulates(*attributes) + attributes.each {|attrib| install_accumulator(attrib)} + end + + def accumulators + @accumulators ||= {} + end + + def install_accumulator(attribute) + self.accumulators[attribute] = Base.new(self, attribute) + module_eval %{ + def self.accumulate_by_#{attribute.to_s}(*keys) + accumulators[:#{attribute.to_s}].find(*keys) + end + } + end + end +end |
