arid_cache 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.rdoc +12 -7
- data/VERSION +1 -1
- data/arid_cache.gemspec +2 -2
- data/lib/arid_cache/cache_proxy.rb +9 -6
- data/test/arid_cache_test.rb +28 -2
- metadata +2 -2
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -40,7 +40,7 @@ You can also define caches that use compositions of methods or named scopes, or
|
|
40
40
|
|
41
41
|
If the result of your <tt>cached_</tt> call is an array of ActiveRecords, AridCache only stores the IDs in the cache (because it's a bad idea to store records in the cache).
|
42
42
|
|
43
|
-
On subsequent calls we call <tt>
|
43
|
+
On subsequent calls we call <tt>find_all_by_id</tt> on the target class passing in the ActiveRecord IDs that were stored in the cache. AridCache will preserve the original ordering of your collection (you can change this using the <tt>:order</tt>).
|
44
44
|
|
45
45
|
The idea here is to cache collections that are expensive to query. Once the cache is loaded, retrieving the cached records from the database simply involves a <tt>SELECT * FROM table WHERE id IN (ids, ...)</tt>.
|
46
46
|
|
@@ -136,11 +136,13 @@ AridCache cache keys are defined based on the methods you call to interact with
|
|
136
136
|
Album.cached_featured_albums => cache key is arid-cache-album-featured_albums
|
137
137
|
album.cached_top_tracks => cache key is arid-cache-albums/<id>-top_tracks
|
138
138
|
|
139
|
-
Caches on model instances can be set to automatically incorporate the ActiveRecord <tt>cache_key</tt> which includes the <tt>updated_at</tt> timestamp of that instance, making them auto-expire when the instance is updated.
|
139
|
+
Caches on model instances can be set to automatically incorporate the ActiveRecord <tt>cache_key</tt> which includes the <tt>updated_at</tt> timestamp of that instance, making them auto-expire when the instance is updated.
|
140
|
+
|
141
|
+
To incorporate the the <tt>cache_key</tt> pass <b><tt>:auto_expire => true</tt></b> to your cache method:
|
140
142
|
|
141
143
|
album.cached_top_tracks(:auto_expire => true) => cache key like arid-cache-albums/2-20091211120100-top_tracks
|
142
144
|
|
143
|
-
Or via the cache configuration
|
145
|
+
Or via the cache configuration:
|
144
146
|
|
145
147
|
Album.instance_caches do
|
146
148
|
top_tracks(:auto_expire => true)
|
@@ -163,14 +165,16 @@ AridCache provides methods to help you clear your caches:
|
|
163
165
|
Model.clear_instance_caches => expires instance-level caches for this model
|
164
166
|
Model.clear_class_caches => expires class-level caches for this model
|
165
167
|
|
166
|
-
|
168
|
+
The <tt>Model.clear_caches</tt> methods are also available on all model instances.
|
167
169
|
|
168
|
-
|
170
|
+
<B>Your cache store needs to support the <tt>delete_matched</tt> method for the above to work. Currently MemCacheStore and MemoryStore do not.</b>
|
171
|
+
|
172
|
+
Alternatively you can pass a <b><tt>:force => true</tt></b> option in your <tt>cached_</tt> calls to force a refresh of a particular cache, while still returning the refreshed results. For example:
|
169
173
|
|
170
174
|
Album.cached_featured_albums(:force => true) => returns featured albums
|
171
175
|
album.cached_top_tracks(:force => true) => returns top tracks
|
172
176
|
|
173
|
-
You can pass an <tt>:expires_in</tt> option to your caches to manage your cache expiry (if your cache store supports this option).
|
177
|
+
You can pass an <b><tt>:expires_in</tt></b> option to your caches to manage your cache expiry (if your cache store supports this option).
|
174
178
|
|
175
179
|
Album.cached_featured_albums(:expires_in => 1.day)
|
176
180
|
album.cached_top_tracks(:expires_in => 1.day)
|
@@ -277,7 +281,7 @@ The version of Rails shouldn't matter much, but it's working on 2.3.4.
|
|
277
281
|
|
278
282
|
== Known Issues
|
279
283
|
|
280
|
-
1. Caches that contains duplicate records (for example from the result of a join), will only return unique records on subsequent calls. This is because of the way <tt>find</tt> works when selecting multiple ids. For example, if your query returns <tt>[#<User id: 1>, #<User id: 1>, #<User id: 1>]</tt>, the IDs are cached as <tt>[1,1,1]</tt>. On the next call to the cache we load the IDs using <tt>User.
|
284
|
+
1. Caches that contains duplicate records (for example from the result of a join), will only return unique records on subsequent calls. This is because of the way <tt>find</tt> works when selecting multiple ids. For example, if your query returns <tt>[#<User id: 1>, #<User id: 1>, #<User id: 1>]</tt>, the IDs are cached as <tt>[1,1,1]</tt>. On the next call to the cache we load the IDs using <tt>User.find_all_by_id([1,1,1])</tt> which returns <tt>[#<User id: 1>]</tt>, not <tt>[#<User id: 1>, #<User id: 1>, #<User id: 1>]</tt> as you might have expected.
|
281
285
|
|
282
286
|
== Wish List / Coming Soon
|
283
287
|
|
@@ -285,6 +289,7 @@ The version of Rails shouldn't matter much, but it's working on 2.3.4.
|
|
285
289
|
* Priming caches. Warm up the cache for all models based on the information in the instance and class cache configurations. Would need to know when you want to prime counts as well.
|
286
290
|
* The ability to <tt>include AridCache</tt> on any class or module.
|
287
291
|
* An option to bypass ID caching when you want to store records in the cache.
|
292
|
+
* Option to turn off the <tt>respond_to?</tt> requirement for caches without blocks in cases where methods are implemented using method_missing and respond_to? hasn't been properly updated.
|
288
293
|
|
289
294
|
== Contributors
|
290
295
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.4
|
data/arid_cache.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{arid_cache}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.4"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Karl Varga"]
|
12
|
-
s.date = %q{2010-01-
|
12
|
+
s.date = %q{2010-01-20}
|
13
13
|
s.description = %q{AridCache makes caching easy and effective. AridCache supports caching on all your model named scopes, class methods and instance methods right out of the box. AridCache prevents caching logic from cluttering your models and clarifies your logic by making explicit calls to cached result sets.
|
14
14
|
AridCache is designed for handling large, expensive ActiveRecord collections but is equally useful for caching anything else as well.
|
15
15
|
}
|
@@ -107,7 +107,7 @@ module AridCache
|
|
107
107
|
elsif limit_or_offset?
|
108
108
|
fetch_and_limit
|
109
109
|
else
|
110
|
-
klass.
|
110
|
+
klass.find_all_by_id(cached.ids, opts_for_find)
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
@@ -116,17 +116,17 @@ module AridCache
|
|
116
116
|
klass.paginate(cached.ids, opts_for_find.merge(opts_for_paginate))
|
117
117
|
else # paginate in memory
|
118
118
|
paged_ids = cached.ids.paginate(opts_for_paginate)
|
119
|
-
paged_ids.replace(klass.
|
119
|
+
paged_ids.replace(klass.find_all_by_id(paged_ids, opts_for_find(paged_ids)))
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
123
|
def fetch_and_limit
|
124
124
|
if combined_options.include?(:order)
|
125
|
-
klass.
|
125
|
+
klass.find_all_by_id(cached.ids, opts_for_find)
|
126
126
|
else
|
127
127
|
offset, limit = combined_options.delete(:offset) || 0, combined_options.delete(:limit) || cached.count
|
128
128
|
ids = cached.ids[offset, limit]
|
129
|
-
klass.
|
129
|
+
klass.find_all_by_id(ids, opts_for_find(ids))
|
130
130
|
end
|
131
131
|
end
|
132
132
|
|
@@ -230,11 +230,12 @@ module AridCache
|
|
230
230
|
cached.respond_to?(:count) ? cached.count : cached
|
231
231
|
end
|
232
232
|
|
233
|
-
OPTIONS_FOR_PAGINATE = [:page, :per_page, :total_entries]
|
233
|
+
OPTIONS_FOR_PAGINATE = [:page, :per_page, :total_entries, :finder]
|
234
234
|
|
235
235
|
# Filter options for paginate, if *klass* is set, we get the :per_page value from it.
|
236
236
|
def opts_for_paginate
|
237
237
|
paginate_opts = combined_options.reject { |k,v| !OPTIONS_FOR_PAGINATE.include?(k) }
|
238
|
+
paginate_opts[:finder] = :find_all_by_id unless paginate_opts.include?(:finder)
|
238
239
|
paginate_opts[:per_page] = klass.per_page if klass && !paginate_opts.include?(:per_page)
|
239
240
|
paginate_opts
|
240
241
|
end
|
@@ -276,7 +277,9 @@ module AridCache
|
|
276
277
|
#
|
277
278
|
# TODO: is it quicker to sort in memory?
|
278
279
|
def preserve_order(ids)
|
279
|
-
if
|
280
|
+
if ids.empty?
|
281
|
+
nil
|
282
|
+
elsif ::ActiveRecord::Base.is_mysql_adapter?
|
280
283
|
"FIELD(id,#{ids.join(',')})"
|
281
284
|
else
|
282
285
|
order = ''
|
data/test/arid_cache_test.rb
CHANGED
@@ -291,7 +291,33 @@ class AridCacheTest < ActiveSupport::TestCase
|
|
291
291
|
assert_equal User.successful.find(:all, :order => 'name DESC'), User.cached_most_successful
|
292
292
|
assert_equal User.successful.find(:all, :order => 'name DESC'), User.cached_most_successful
|
293
293
|
end
|
294
|
-
|
294
|
+
|
295
|
+
test "should not raise an error if all cached ids cannot be found" do
|
296
|
+
@user.cached_companies
|
297
|
+
key = @user.arid_cache_key('companies')
|
298
|
+
cached_result = Rails.cache.read(key)
|
299
|
+
cached_result.ids.push(24342234, 243234132)
|
300
|
+
Rails.cache.write(key, cached_result)
|
301
|
+
assert_nothing_raised { @user.cached_companies }
|
302
|
+
assert_equal @user.cached_companies, @user.companies
|
303
|
+
end
|
304
|
+
|
305
|
+
test "should not raise an error if all cached ids cannot be found while paginating" do
|
306
|
+
@user.cached_companies
|
307
|
+
key = @user.arid_cache_key('companies')
|
308
|
+
cached_result = Rails.cache.read(key)
|
309
|
+
cached_result.ids.push(24342234, 243234132)
|
310
|
+
Rails.cache.write(key, cached_result)
|
311
|
+
assert_nothing_raised { @user.cached_companies(:page => 1, :order => 'name DESC') }
|
312
|
+
assert_equal @user.cached_companies(:page => 1, :order => 'name DESC'), @user.companies.paginate(:page => 1, :order => 'name DESC')
|
313
|
+
end
|
314
|
+
|
315
|
+
test "should handle empty collections" do
|
316
|
+
@user.cached_empty_collection { [] }
|
317
|
+
assert_nothing_raised { @user.cached_empty_collection }
|
318
|
+
assert_nothing_raised { @user.cached_empty_collection }
|
319
|
+
end
|
320
|
+
|
295
321
|
#
|
296
322
|
# Tests requiring manual verification by looking at the SQL logs.
|
297
323
|
# TODO move these to a separate class.
|
@@ -311,7 +337,7 @@ class AridCacheTest < ActiveSupport::TestCase
|
|
311
337
|
@user.cached_companies(:page => 2, :per_page => 3)
|
312
338
|
@user.cached_companies(:page => 1, :per_page => 3)
|
313
339
|
end
|
314
|
-
|
340
|
+
|
315
341
|
protected
|
316
342
|
|
317
343
|
def assert_queries(num = 1)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arid_cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karl Varga
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-20 00:00:00 +08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|