bulk_cache_fetcher 0.0.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f2012f42799511be205c0a27036b7a447dbf56b3
4
- data.tar.gz: 54172b0aea06cbec9d7549bbe9963bb5ebcb7bea
3
+ metadata.gz: 164f9631e7c60c573ea490d677851e3ae2c1994a
4
+ data.tar.gz: a27506b07291839747eff96c8b6098c12eac5d8c
5
5
  SHA512:
6
- metadata.gz: ea8c5960bc5df03785da93819ba29fae48390ccdcc5c6fae2fb25bb67b8e0052229e38e67eb3be8444a508c05c2573648ac22531f9aa5bcf9034087418d26102
7
- data.tar.gz: 5142b31a0a0c5e8fab81ef56acabf45c35e44beade392b077950763e4abdff93ae521efcd070d39c7a36fd5727d5d95341629f8411c26623b9d784d185d3fc72
6
+ metadata.gz: e24adcc2d3df76a46634720f77cbcf9d22fa5e66120a996bd42999ec7dfd3375649d7d17be8d28b1b4b17dbae300a44890cfb50e19a8d3b6fa144b56695b97b2
7
+ data.tar.gz: 84a0977c2db53ad7dec3d13fc446094f775faff28e6c8191d51cbdd3cc63d2d023d87118dd34dd2e7a5653f48abb9f6b57baddb1ca347926c8188444d85a034a
data/README.md CHANGED
@@ -14,6 +14,23 @@ Bulk Cache Fetcher allows you to query the cache for a list of
14
14
  objects, and gives you the opportunity to fetch all of the cache
15
15
  misses at once, using whatever `:include`s you want.
16
16
 
17
+ For example, if you have a list of objects by id to fetch, and a list
18
+ of keys you want them to be cached under, you'd use Bulk Cache Fetcher
19
+ like this:
20
+
21
+ ```ruby
22
+ identifiers = {:cache_key_1 => 1, :cache_key_2 => 2, :cache_key_3 => 3}
23
+ BulkCacheFetcher.new(Rails.cache).fetch(identifiers) do |uncached_keys_and_ids|
24
+ ids = uncached_keys_and_ids.values
25
+ BlogPost.where(:id => ids).includes([:author, :comments])
26
+ end
27
+ ```
28
+
29
+ This will include and cache each `BlogPost`, with comments and
30
+ authors, as if you did the `.where.includes` without caching. If a
31
+ `BlogPost` is cached already, it won't fetch it (or its includes) from
32
+ the database.
33
+
17
34
  ## Installation
18
35
 
19
36
  Add this line to your application's Gemfile:
@@ -5,7 +5,7 @@
5
5
  # Rails' nested caching while avoiding the n+1 queries problem in the
6
6
  # uncached case.
7
7
  class BulkCacheFetcher
8
- VERSION = '0.0.3'
8
+ VERSION = '1.0.0'
9
9
 
10
10
  # Creates a new bulk cache fetcher, backed by +cache+. Cache must
11
11
  # respond to the standard Rails cache API, described on
@@ -28,41 +28,38 @@ class BulkCacheFetcher
28
28
  # objects, so you can use it for things like setting cache
29
29
  # expiration.
30
30
  def fetch(object_identifiers, options = {}, &finder_block)
31
- cached_objects, uncached_identifiers = partition(object_identifiers)
32
- coalesce(cached_objects, find(uncached_identifiers, options, &finder_block))
31
+ object_identifiers = normalize(object_identifiers)
32
+ cached_keys_with_objects, uncached_identifiers = partition(object_identifiers)
33
+ found_objects = find(uncached_identifiers, options, &finder_block)
34
+ coalesce(cache_keys(object_identifiers), cached_keys_with_objects, found_objects)
33
35
  end
34
36
 
35
37
  private
36
38
 
37
- # Partitions a list of identifiers into two lists. The first list
38
- # contains all of the objects we were able to serve from the cache,
39
- # while the second is a list of all of the identifiers for objects
40
- # that weren't cached.
39
+ # Splits a list of identifiers into two objects. The first is a hash
40
+ # of <tt>{cache_key: object}</tt> for all the objects we were able to serve
41
+ # from the cache. The second is a list of all of the identifiers for
42
+ # objects that weren't cached.
41
43
  def partition(object_identifiers)
42
- object_identifiers = normalize(object_identifiers)
43
- cached_objects = []
44
44
  uncached_identifiers = object_identifiers.dup
45
45
 
46
46
  cache_keys = cache_keys(object_identifiers)
47
- found_objects = @cache.read_multi(*cache_keys)
47
+ cached_keys_with_objects = @cache.read_multi(*cache_keys)
48
48
 
49
49
  cache_keys.each do |cache_key|
50
- cached_object = found_objects[cache_key]
51
- uncached_identifiers.delete(cache_key) if cached_object
52
- cached_objects << cached_object
50
+ uncached_identifiers.delete(cache_key) if cached_keys_with_objects.has_key?(cache_key)
53
51
  end
54
52
 
55
- [cached_objects, uncached_identifiers]
53
+ [cached_keys_with_objects, uncached_identifiers]
56
54
  end
57
55
 
58
56
  # Finds all of the objects identified by +identifiers+, using the
59
57
  # +finder_block+. Will pass +options+ on to the cache.
60
58
  def find(identifiers, options = {}, &finder_block)
61
- unless identifiers.empty?
62
- Array(finder_block.(identifiers)).tap do |objects|
63
- verify_equal_key_and_value_counts!(identifiers, objects)
64
- cache_all(identifiers, objects, options)
65
- end
59
+ return [] if identifiers.empty?
60
+ Array(finder_block.call(identifiers)).tap do |objects|
61
+ verify_equal_key_and_value_counts!(identifiers, objects)
62
+ cache_all(identifiers, objects, options)
66
63
  end
67
64
  end
68
65
 
@@ -78,11 +75,12 @@ class BulkCacheFetcher
78
75
  keys.zip(values) { |k, v| @cache.write(cache_key(k), v, options) }
79
76
  end
80
77
 
81
- # With an array looking like <tt>[nil, 1, nil, 2]</tt>, replaces the
82
- # nils with values taken from +found_objects+, in order.
83
- def coalesce(array_with_nils, found_objects)
78
+ # Given a list of +cache_keys+, either find associated objects from
79
+ # +cached_keys_with_objects, or grab them from +found_objects+, in
80
+ # order.
81
+ def coalesce(cache_keys, cached_keys_with_objects, found_objects)
84
82
  found_objects = Array(found_objects)
85
- array_with_nils.map { |obj| obj ? obj : found_objects.shift }
83
+ cache_keys.map { |key| cached_keys_with_objects.fetch(key) { found_objects.shift } }
86
84
  end
87
85
 
88
86
  # Returns the part of the identifier that we can use as the cache
@@ -13,14 +13,14 @@ class InMemoryCache
13
13
  def read_multi(*keys)
14
14
  results = {}
15
15
  keys.each do |key|
16
- results[key] = read(key) if read(key)
16
+ results[key] = read(key) if cache.has_key?(key)
17
17
  end
18
18
  results
19
19
  end
20
20
 
21
21
  end
22
22
 
23
- class BulkCacheFetcherTest < Minitest::Unit::TestCase
23
+ class BulkCacheFetcherTest < Minitest::Test
24
24
 
25
25
  def setup
26
26
  @cache = InMemoryCache.new
@@ -126,4 +126,13 @@ class BulkCacheFetcherTest < Minitest::Unit::TestCase
126
126
  end
127
127
  assert_equal(2, @cache.read(:one))
128
128
  end
129
+
130
+ def test_doesnt_break_if_nils_are_cached
131
+ @cache.write(:two, nil)
132
+ results = @cache_fetcher.fetch([:one, :two, :three]) do |keys|
133
+ [1, 3]
134
+ end
135
+ assert_equal(nil, results[1])
136
+ assert_equal(3, results[2])
137
+ end
129
138
  end
@@ -1,2 +1 @@
1
- require 'minitest/unit'
2
1
  require 'minitest/autorun'
metadata CHANGED
@@ -1,55 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bulk_cache_fetcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Weiss
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-04 00:00:00.000000000 Z
11
+ date: 2015-03-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.3'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  description: Fetches cache misses in bulk
@@ -59,8 +59,8 @@ executables: []
59
59
  extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
- - .gitignore
63
- - .travis.yml
62
+ - ".gitignore"
63
+ - ".travis.yml"
64
64
  - Gemfile
65
65
  - LICENSE.txt
66
66
  - README.md
@@ -79,17 +79,17 @@ require_paths:
79
79
  - lib
80
80
  required_ruby_version: !ruby/object:Gem::Requirement
81
81
  requirements:
82
- - - '>='
82
+ - - ">="
83
83
  - !ruby/object:Gem::Version
84
84
  version: '0'
85
85
  required_rubygems_version: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  requirements: []
91
91
  rubyforge_project:
92
- rubygems_version: 2.1.5
92
+ rubygems_version: 2.4.5
93
93
  signing_key:
94
94
  specification_version: 4
95
95
  summary: Bulk Cache Fetcher allows you to query the cache for a list of objects, and