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 CHANGED
@@ -21,3 +21,4 @@ pkg
21
21
  ## PROJECT::SPECIFIC
22
22
  test/**/*.log
23
23
  test/tmp/*
24
+ tmp
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>find</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>).
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. To turn it on pass <tt>:auto_expire => true</tt> to your cache.
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
- (The <tt>Model.clear_caches</tt> methods are also available on all model instances. Your cache store will need to support the <tt>delete_matched</tt> method for these to work.)
168
+ The <tt>Model.clear_caches</tt> methods are also available on all model instances.
167
169
 
168
- Alternatively you can pass a <tt>:force => true</tt> option in your <tt>cached_</tt> calls to force a refresh of a particular cache, while still returning the refreshed results. For example:
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.find([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.
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.3
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.3"
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-19}
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.find(cached.ids, opts_for_find)
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.find(paged_ids, opts_for_find(paged_ids)))
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.find(cached.ids, opts_for_find)
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.find(ids, opts_for_find(ids))
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 ::ActiveRecord::Base.is_mysql_adapter?
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 = ''
@@ -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.3
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-19 00:00:00 +08:00
12
+ date: 2010-01-20 00:00:00 +08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency