lib/interlock/finders.rb in interlock-1.3 vs lib/interlock/finders.rb in interlock-1.4

- old
+ new

@@ -1,131 +1,155 @@ module Interlock module Finders + def self.included(klass) + class << klass + alias_method :find_via_db, :find + remove_method :find + end + + klass.extend ClassMethods + end + + module ClassMethods - # - # Cached find. - # - # Any other options besides ids short-circuit the cache, include an empty trailing Hash. - # - def find(*args) - return find_via_db(*args) if args.last.is_a? Hash or args.first.is_a? Symbol - records = find_via_cache(args.flatten, true) + # + # Cached find. + # + # Any other options besides ids short-circuit the cache. + # + def find(*args) + return find_via_db(*args) if args.last.is_a? Hash or args.first.is_a? Symbol + ids = args.flatten.compact.uniq + return find_via_db(ids) if ids.blank? + + records = find_via_cache(ids, true) - if args.length > 1 or args.first.is_a? Array - records - else - records.first - end + if ids.length > 1 or args.first.is_a?(Array) + records + else + records.first + end - end + end - # - # Cached find_by_id. Short-circuiting works the same as find. - # - def find_by_id(*args) - return method_missing(:find_by_id, *args) if args.last.is_a? Hash - find_via_cache(args, false).first - end + # + # Cached find_by_id. Short-circuiting works the same as find. + # + def find_by_id(*args) + return method_missing(:find_by_id, *args) if args.last.is_a? Hash + find_via_cache(args, false).first + end - # - # Cached find_all_by_id. Ultrasphinx uses this. Short-circuiting works the same as find. - # - def find_all_by_id(*args) - return method_missing(:find_all_by_id, *args) if args.last.is_a? Hash - find_via_cache(args, false) - end + # + # Cached find_all_by_id. Ultrasphinx uses this. Short-circuiting works the same as find. + # + def find_all_by_id(*args) + return method_missing(:find_all_by_id, *args) if args.last.is_a? Hash + find_via_cache(args, false) + end - # - # Build the model cache key for a particular id. - # - def caching_key(id) - Interlock.caching_key( - self.name, - "find", - id, - "default" - ) - end - - private - - def find_via_cache(ids, should_raise) #:doc: - results = [] + # + # Build the model cache key for a particular id. + # + def caching_key(id) + Interlock.caching_key( + self.base_class.name, + "find", + id, + "default" + ) + end - ordered_keys_to_ids = ids.map { |id| [caching_key(id), id.to_i] } - keys_to_ids = Hash[*ordered_keys_to_ids.flatten] + def finder_ttl + 0 + end - records = {} + private + + def find_via_cache(ids, should_raise) #:doc: + results = [] + + ordered_keys_to_ids = ids.flatten.map { |id| [caching_key(id), id.to_i] } + keys_to_ids = Hash[*ordered_keys_to_ids.flatten] + + records = {} - if ActionController::Base.perform_caching - load_from_local_cache(records, keys_to_ids) - load_from_memcached(records, keys_to_ids) - end + if ActionController::Base.perform_caching + load_from_local_cache(records, keys_to_ids) + load_from_memcached(records, keys_to_ids) + end - load_from_db(records, keys_to_ids) + load_from_db(records, keys_to_ids) - # Put them in order + # Put them in order - ordered_keys_to_ids.each do |key, | - record = records[key] - raise ActiveRecord::RecordNotFound, "Couldn't find #{self.name} with ID=#{keys_to_ids[key]}" if should_raise and !record - results << record + ordered_keys_to_ids.each do |key, | + record = records[key] + raise ActiveRecord::RecordNotFound, "Couldn't find #{self.name} with ID=#{keys_to_ids[key]}" if should_raise and !record + results << record + end + + # Don't return Nil objects, only the found records + results.compact end - - results - end - def load_from_local_cache(current, keys_to_ids) #:doc: - # Load from the local cache - records = {} - keys_to_ids.each do |key, | - record = Interlock.local_cache.read(key, nil) - records[key] = record if record - end - current.merge!(records) - end - - def load_from_memcached(current, keys_to_ids) #:doc: - # Drop to memcached if necessary - if current.size < keys_to_ids.size + def load_from_local_cache(current, keys_to_ids) #:doc: + # Load from the local cache records = {} - missed = keys_to_ids.reject { |key, | current[key] } + keys_to_ids.each do |key, | + record = Interlock.local_cache.read(key, nil) + records[key] = record if record + end + current.merge!(records) + end + + def load_from_memcached(current, keys_to_ids) #:doc: + # Drop to memcached if necessary + if current.size < keys_to_ids.size + records = {} + missed = keys_to_ids.reject { |key, | current[key] } - records = CACHE.get_multi(*missed.keys) + records = CACHE.get_multi(*missed.keys) - # Set missed to the caches - records.each do |key, value| - Interlock.say key, "is loading from memcached", "model" - Interlock.local_cache.write(key, value, nil) - end + # Set missed to the caches + records.each do |key, value| + Interlock.say key, "is loading from memcached", "model" + Interlock.local_cache.write(key, value, nil) + end - current.merge!(records) - end - end + current.merge!(records) + end + end - def load_from_db(current, keys_to_ids) #:doc: - # Drop to db if necessary - if current.size < keys_to_ids.size - missed = keys_to_ids.reject { |key, | current[key] } - ids_to_keys = keys_to_ids.invert + def load_from_db(current, keys_to_ids) #:doc: + # Drop to db if necessary + if current.size < keys_to_ids.size + missed = keys_to_ids.reject { |key, | current[key] } + ids_to_keys = keys_to_ids.invert - # Load from the db - records = find_all_by_id(missed.values, {}) - records = Hash[*(records.map do |record| - [ids_to_keys[record.id], record] - end.flatten)] + # Load from the db + ids_to_find = missed.values + if ids_to_find.length > 1 + records = send("find_all_by_#{primary_key}".to_sym, ids_to_find, {}) + else + records = [send("find_by_#{primary_key}".to_sym, ids_to_find.first, {})].compact # explicitly just look for one if that's all that's needed + end + + records = Hash[*(records.map do |record| + [ids_to_keys[record.id], record] + end.flatten)] - # Set missed to the caches - records.each do |key, value| - Interlock.say key, "is loading from the db", "model" - Interlock.local_cache.write(key, value, nil) - CACHE.set key, value - end + # Set missed to the caches + records.each do |key, value| + Interlock.say key, "is loading from the db", "model" + Interlock.local_cache.write(key, value, nil) + CACHE.set key, value, value.class.finder_ttl unless Interlock.config[:disabled] + end - current.merge!(records) - end + current.merge!(records) + end + end end - - end -end - \ No newline at end of file + end # Finders +end # Interlock +