lib/cached_resource/caching.rb in cached_resource-2.0.1 vs lib/cached_resource/caching.rb in cached_resource-2.1.1a

- old
+ new

@@ -9,44 +9,94 @@ alias_method_chain :find, :cache end end module ClassMethods - # find a resource using the cache or resend the request - # if :reload is set to true or caching is disabled + # Find a resource using the cache or resend the request + # if :reload is set to true or caching is disabled. def find_with_cache(*arguments) arguments << {} unless arguments.last.is_a?(Hash) should_reload = arguments.last.delete(:reload) || !cached_resource.enabled arguments.pop if arguments.last.empty? key = cache_key(arguments) - begin - (should_reload ? find_via_reload(key, *arguments) : find_via_cache(key, *arguments)) - rescue ActiveResource::ServerError, ActiveResource::ConnectionError, SocketError => e - raise(e) - end + should_reload ? find_via_reload(key, *arguments) : find_via_cache(key, *arguments) end private - # try to find a cached response for the given key. If + # Try to find a cached response for the given key. If # no cache entry exists, send a new request. def find_via_cache(key, *arguments) - result = cached_resource.cache.read(key).try(:dup) - result && cached_resource.logger.info("#{CachedResource::Configuration::LOGGER_PREFIX} READ #{key} for #{arguments.inspect}") - result || find_via_reload(key, *arguments) + cache_read(key) || find_via_reload(key, *arguments) end - # re/send the request to fetch the resource. Cache the response + # Re/send the request to fetch the resource. Cache the response # for the request. def find_via_reload(key, *arguments) - result = find_without_cache(*arguments) - cached_resource.cache.write(key, result, :expires_in => cached_resource.ttl) - cached_resource.logger.info("#{CachedResource::Configuration::LOGGER_PREFIX} WRITE #{key} for #{arguments.inspect}") + object = find_without_cache(*arguments) + cache_collection_synchronize(object, *arguments) if cached_resource.collection_synchronize + cache_write(key, object) + object + end + + # If this is a pure, unadulterated "all" request + # write cache entries for all its members + # otherwise update an existing collection if possible. + def cache_collection_synchronize(object, *arguments) + if object.is_a? Array + update_singles_cache(object) + # update the collection only if this is a subset of it + update_collection_cache(object) unless is_collection?(*arguments) + else + update_collection_cache(object) + end + end + + # Update the cache of singles with an array of updates. + def update_singles_cache(updates) + updates = Array(updates) + updates.each { |object| cache_write(object.send(primary_key), object) } + end + + # Update the "mother" collection with an array of updates. + def update_collection_cache(updates) + updates = Array(updates) + collection = cache_read(cached_resource.collection_arguments) + + if collection && !updates.empty? + store = RUBY_VERSION.to_f < 1.9 ? ActiveSupport::OrderedHash.new : {} + index = collection.inject(store) { |hash, object| hash[object.send(primary_key)] = object; hash } + updates.each { |object| index[object.send(primary_key)] = object } + cache_write(cached_resource.collection_arguments, index.values) + end + end + + # Determine if the given arguments represent + # the entire collection of objects. + def is_collection?(*arguments) + arguments == cached_resource.collection_arguments + end + + # Read a entry from the cache for the given key. + # The key is processed to make sure it is valid. + def cache_read(key) + key = cache_key(Array(key)) unless key.is_a? String + object = cached_resource.cache.read(key).try(:dup) + object && cached_resource.logger.info("#{CachedResource::Configuration::LOGGER_PREFIX} READ #{key}") + object + end + + # Write an entry to the cache for the given key and value. + # The key is processed to make sure it is valid. + def cache_write(key, object) + key = cache_key(Array(key)) unless key.is_a? String + result = cached_resource.cache.write(key, object, :expires_in => cached_resource.ttl) + result && cached_resource.logger.info("#{CachedResource::Configuration::LOGGER_PREFIX} WRITE #{key}") result end - # generate the request cache key + # Generate the request cache key. def cache_key(*arguments) "#{name.parameterize.gsub("-", "/")}/#{arguments.join('/')}".downcase end end \ No newline at end of file