Skip to content

Commit

Permalink
Update cache entries when a subset of all is retrieved
Browse files Browse the repository at this point in the history
Signed-off-by: David Souza <david@souza.net>
  • Loading branch information
Morgan Brown authored and davidsouza committed Apr 5, 2012
1 parent 1b5a323 commit 7b0bd10
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 5 deletions.
35 changes: 30 additions & 5 deletions lib/cached_resource/caching.rb
Expand Up @@ -43,14 +43,39 @@ def find_via_reload(key, *arguments)
# write cache entries for all its members
# otherwise update an existing collection if possible.
def cache_collection_synchronize(object, *arguments)
if arguments.length == 1 && arguments[0] == :all
object.each {|r| cache_write(r.send(primary_key), r)}
elsif !arguments.include?(:all) && (collection = cache_read(:all))
collection.each_with_index {|member, i| collection[i] = object if member.send(primary_key) == object.send(primary_key)}
cache_write(:all, collection)
if object.is_a? Array
update_singles_cache(object)
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(:all)

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(:all, index.values)
end
end

# Determine if the given arguments represent
# the entire collection of objects.
def is_collection?(*arguments)
arguments.length == 1 && arguments[0] == :all
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)
Expand Down
20 changes: 20 additions & 0 deletions spec/cached_resource/caching_spec.rb
Expand Up @@ -138,6 +138,26 @@ class Thing < ActiveResource::Base
Thing.cached_resource.cache.read("thing/all")[0].should == result
Thing.cached_resource.cache.read("thing/all")[0].name.should == result.name
end

it "should update both the collection and the member cache entries when a subset of the collection is retrieved" do
# create cache entries for
old_individual = Thing.find(1)
old_collection = Thing.all

# change the server
ActiveResource::HttpMock.respond_to do |mock|
mock.get "/things.json?name=Ari", {}, [@other_thing[:thing]].to_json(:root => :thing)
end

# make a request for a subset of the "mother" collection
result = Thing.find(:all, :params => {:name => "Ari"})
# the collection should be updated to reflect the server change
Thing.cached_resource.cache.read("thing/all")[0].should == result[0]
Thing.cached_resource.cache.read("thing/all")[0].name.should == result[0].name
# the individual should be updated to reflect the server change
Thing.cached_resource.cache.read("thing/1").should == result[0]
Thing.cached_resource.cache.read("thing/1").name.should == result[0].name
end
end

describe "when collection synchronize is disabled" do
Expand Down

0 comments on commit 7b0bd10

Please sign in to comment.