cache_back 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.5.1
data/lib/cache_back.rb CHANGED
@@ -5,7 +5,6 @@ require 'active_support'
5
5
  require 'cache_back/configuration_mixin'
6
6
  require 'cache_back/reload_association_mixin'
7
7
  require 'cache_back/cache'
8
- require 'cache_back/rack_middleware'
9
8
 
10
9
  module CacheBack
11
10
  CONFIGURATION = {:max_collection_size => 100}
@@ -54,6 +54,12 @@ module CacheBack
54
54
  Rails.cache.delete(*args)
55
55
  end
56
56
 
57
+ def delete_local(*keys)
58
+ keys.each do |key|
59
+ @local_cache.delete(key)
60
+ end
61
+ end
62
+
57
63
  def reset!
58
64
  @local_cache = {}
59
65
  end
@@ -4,57 +4,64 @@ module CacheBack
4
4
  @model_class = model_class
5
5
  end
6
6
 
7
- def attribute_value_pairs(options, scope)
8
- from_scope = attribute_value_pairs_for_conditions((scope || {})[:conditions])
9
- return nil unless from_scope
7
+ def attribute_value_pairs(options)
8
+ #pulls out the conditions from each hash
9
+ condition_fragments = [options[:conditions]]
10
10
 
11
- from_options = attribute_value_pairs_for_conditions(options[:conditions])
12
- return nil unless from_options
13
-
14
- pairs = from_scope.inject(from_options) do |memo, pair|
15
- attribute = pair[0]
16
- if memo_pair = memo.find{ |p| p[0] == attribute}
17
- memo_pair[0] = Array(memo_pair[0])
18
- memo_pair[0] << pair[1]
19
- else
20
- memo << pair
21
- end
11
+ #add the scope to the mix
12
+ if scope = @model_class.send(:scope, :find)
13
+ condition_fragments << scope[:conditions]
22
14
  end
23
15
 
24
- pairs.sort! { |pair1, pair2| pair1[0] <=> pair2[0] }
16
+ #add the type if we are on STI
17
+ condition_fragments << {:type => @model_class.name} if @model_class.finder_needs_type_condition?
25
18
 
26
- pairs.map do |attribute, value|
27
- if value.is_a?(Array)
28
- value.flatten!
29
- if value.size == 1
30
- [attribute.to_sym, value[0]]
31
- else
32
- [attribute.to_sym, value]
33
- end
34
- else
35
- [attribute.to_sym, value]
19
+ condition_fragments.compact!
20
+
21
+ #parses each conditions fragment but bails if one of the did not parse
22
+ attributes_fragments = condition_fragments.map do |condition_fragment|
23
+ attributes_fragment = attributes_for_conditions(condition_fragment)
24
+ return nil unless attributes_fragment
25
+ attributes_fragment
26
+ end
27
+
28
+ #merges the hashes but bails if there is an overlap
29
+ attributes = attributes_fragments.inject({}) do |memo, attributes_fragment|
30
+ attributes_fragment.each do |attribute, value|
31
+ return nil if memo.has_key?(attribute)
32
+ memo[attribute] = value
36
33
  end
34
+ memo
37
35
  end
36
+
37
+ attributes.keys.sort.map { |attribute| [attribute.to_sym, attributes[attribute]] }
38
38
  end
39
39
 
40
- def attribute_value_pairs_for_conditions(conditions)
41
- case conditions
42
- when Hash
43
- conditions.to_a.collect { |key, value| [key.to_s, value] }
44
- when String
45
- parse_indices_from_condition(conditions)
46
- when Array
47
- parse_indices_from_condition(*conditions)
48
- when NilClass
49
- []
40
+ def attributes_for_conditions(conditions)
41
+ pairs = case conditions
42
+ when Hash
43
+ return conditions.stringify_keys
44
+ when String
45
+ parse_indices_from_condition(conditions)
46
+ when Array
47
+ parse_indices_from_condition(*conditions)
48
+ when NilClass
49
+ []
50
+ end
51
+
52
+ return nil unless pairs
53
+
54
+ pairs.inject({}) do |memo, pair|
55
+ return nil if memo.has_key?(pair[0])
56
+ memo[pair[0]] = pair[1]
57
+ memo
50
58
  end
51
59
  end
52
60
 
53
61
  AND = /\s+AND\s+/i
54
62
  TABLE_AND_COLUMN = /(?:(?:`|")?(\w+)(?:`|")?\.)?(?:`|")?(\w+)(?:`|")?/ # Matches: `users`.id, `users`.`id`, users.id, id
55
63
  VALUE = /'?(\d+|\?|(?:(?:[^']|'')*))'?/ # Matches: 123, ?, '123', '12''3'
56
- KEY_EQ_VALUE = /^\(?#{TABLE_AND_COLUMN}\s+=\s+#{VALUE}\)?$/ # Matches: KEY = VALUE, (KEY = VALUE)
57
- ORDER = /^#{TABLE_AND_COLUMN}\s*(ASC|DESC)?$/i # Matches: COLUMN ASC, COLUMN DESC, COLUMN
64
+ KEY_EQ_VALUE = /^[\(\s]*#{TABLE_AND_COLUMN}\s+=\s+#{VALUE}[\)\s]*$/ # Matches: KEY = VALUE, (KEY = VALUE), ()(KEY = VALUE))
58
65
 
59
66
  def parse_indices_from_condition(conditions = '', *values)
60
67
  values = values.dup
@@ -69,4 +76,4 @@ module CacheBack
69
76
  end
70
77
  end
71
78
  end
72
- end
79
+ end
@@ -1,4 +1,5 @@
1
1
  require 'active_support'
2
+ require 'zlib'
2
3
 
3
4
  module CacheBack
4
5
  autoload :ReadMixin, 'cache_back/read_mixin'
@@ -6,37 +7,12 @@ module CacheBack
6
7
  autoload :DirtyMixin, 'cache_back/dirty_mixin'
7
8
 
8
9
  module ConfigurationMixin
9
- def cache_back_version(version)
10
- @cache_back_version = version.to_s
11
- end
12
-
13
- def inherited_cache_back_version
14
- if self == ActiveRecord::Base
15
- @cache_back_version
16
- else
17
- @cache_back_version ||= superclass.inherited_cache_back_version
18
- end
19
- end
20
-
21
- def inherited_cache_back_options
22
- if self == ActiveRecord::Base
23
- @cache_back_option
24
- else
25
- @cache_back_option ||= superclass.inherited_cache_back_options
26
- end
10
+ def cache_back_key_prefix
11
+ @cache_back_key_prefix ||= "cache_back/#{table_name}/version=#{Zlib.crc32(column_names.sort.join)}/"
27
12
  end
28
13
 
29
14
  def cache_back_key_for(attribute_value_pairs)
30
- key = "cache_back/#{table_name}/version=#{inherited_cache_back_version}"
31
- attribute_value_pairs.each do |attribute, value|
32
- key << "/#{attribute}="
33
- if value.is_a?(Array)
34
- key << value.join(',')
35
- else
36
- key << value.to_s
37
- end
38
- end
39
- key
15
+ cache_back_key_prefix + attribute_value_pairs.map {|attribute, value| attribute.to_s + '=' + value.to_s}.join('/')
40
16
  end
41
17
 
42
18
  def cache_back_key_for_id(id)
@@ -58,12 +34,7 @@ module CacheBack
58
34
  end
59
35
 
60
36
  def has_cache_back_on(*args)
61
- options = args.extract_options!
62
37
  attributes = args.sort! { |x, y| x.to_s <=> y.to_s }
63
-
64
- @cache_back_version ||= options.delete(:version) || '1'
65
- @cache_back_option ||= options
66
-
67
38
  if attributes != [:id] && !cache_back_indices.include?([:id])
68
39
  has_cache_back_on(:id)
69
40
  end
@@ -12,5 +12,7 @@ module CacheBack
12
12
  end
13
13
  end
14
14
  end
15
+
16
+ alias_method :cache_back_dirty_method, :cache_back_dirty_methods
15
17
  end
16
18
  end
@@ -19,7 +19,7 @@ module CacheBack
19
19
  end
20
20
 
21
21
  def find_every_with_cache_back(options)
22
- attribute_value_pairs = cache_back_conditions_parser.attribute_value_pairs(options, scope(:find)) if cache_safe?(options)
22
+ attribute_value_pairs = cache_back_conditions_parser.attribute_value_pairs(options) if cache_safe?(options)
23
23
 
24
24
  limit = (options[:limit] || (scope(:find) || {})[:limit])
25
25
 
@@ -48,7 +48,7 @@ module CacheBack
48
48
  end
49
49
 
50
50
  def find_some_with_cache_back(ids, options)
51
- attribute_value_pairs = cache_back_conditions_parser.attribute_value_pairs(options, scope(:find)) if cache_safe?(options)
51
+ attribute_value_pairs = cache_back_conditions_parser.attribute_value_pairs(options) if cache_safe?(options)
52
52
  attribute_value_pairs << [:id, ids] if attribute_value_pairs
53
53
 
54
54
  limit = (options[:limit] || (scope(:find) || {})[:limit])
@@ -88,6 +88,5 @@ module CacheBack
88
88
  def cache_back_conditions_parser
89
89
  @cache_back_conditions_parser ||= CacheBack::ConditionsParser.new(self)
90
90
  end
91
-
92
91
  end
93
92
  end
@@ -2,9 +2,8 @@ module CacheBack
2
2
  module ReloadAssociationMixin
3
3
  def reload_with_cache_back_clearing(*args)
4
4
  # TODO we could calculate the right key to clear by parsing the association conditions.
5
- # this would clear less keys, and we would not have to load the target
6
- load_target
7
- target.clear_cache_back_indices if target.respond_to?(:clear_cache_back_indices)
5
+ # this would clear less keys
6
+ CacheBack.cache.reset!
8
7
  reload_without_cache_back_clearing(*args)
9
8
  end
10
9
 
@@ -20,29 +20,43 @@ module CacheBack
20
20
 
21
21
  def store_in_cache_back
22
22
  if !readonly? && cache_back_key
23
- CacheBack.cache.write(cache_back_key, self, self.class.inherited_cache_back_options)
23
+ CacheBack.cache.write(cache_back_key, self)
24
24
  end
25
25
  end
26
26
 
27
- def clear_cache_back_indices
27
+ def cache_back_keys
28
28
  new_attributes = attributes.symbolize_keys
29
29
 
30
30
  old_attributes = Hash[changes.map {|attribute, values| [attribute, values[0]]}].symbolize_keys
31
31
  old_attributes.reverse_merge!(new_attributes)
32
32
 
33
+ keys = []
33
34
  self.class.cache_back_indices.each do |index|
34
35
  old_key = self.class.cache_back_key_for(index.map { |attribute| [attribute, old_attributes[attribute]]})
35
36
  new_key = self.class.cache_back_key_for(index.map { |attribute| [attribute, new_attributes[attribute]]})
36
37
 
37
38
  [old_key, new_key].uniq.each do |key|
38
- CacheBack.cache.delete(key)
39
- CacheBack.cache.delete("#{key}/first")
39
+ keys << key
40
+ keys << "#{key}/first"
40
41
  end
41
42
  end
43
+ keys
44
+ end
45
+
46
+ def clear_cache_back_indices
47
+ cache_back_keys.each do |key|
48
+ CacheBack.cache.delete(key)
49
+ end
50
+ end
51
+
52
+ def clear_local_cache_back_indices
53
+ cache_back_keys.each do |key|
54
+ CacheBack.cache.delete_local(key)
55
+ end
42
56
  end
43
57
 
44
58
  def reload_with_cache_back_clearing(*args)
45
- clear_cache_back_indices
59
+ clear_local_cache_back_indices
46
60
  reload_without_cache_back_clearing(*args)
47
61
  end
48
62
  end
@@ -20,12 +20,12 @@ class CacheExpiryTest < ActiveSupport::TestCase
20
20
  end
21
21
 
22
22
  should "clear all indices for instance when deleted" do
23
- CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/id=#{@post.id}")
24
- CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/id=#{@post.id}/first")
25
- CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/title=#{@post.title}")
26
- CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/title=#{@post.title}/first")
27
- CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/blog_id=#{@post.blog_id}")
28
- CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/blog_id=#{@post.blog_id}/first")
23
+ CacheBack.cache.expects(:delete).with(Post.cache_back_key_prefix + "id=#{@post.id}")
24
+ CacheBack.cache.expects(:delete).with(Post.cache_back_key_prefix + "id=#{@post.id}/first")
25
+ CacheBack.cache.expects(:delete).with(Post.cache_back_key_prefix + "title=#{@post.title}")
26
+ CacheBack.cache.expects(:delete).with(Post.cache_back_key_prefix + "title=#{@post.title}/first")
27
+ CacheBack.cache.expects(:delete).with(Post.cache_back_key_prefix + "blog_id=#{@post.blog_id}")
28
+ CacheBack.cache.expects(:delete).with(Post.cache_back_key_prefix + "blog_id=#{@post.blog_id}/first")
29
29
  CacheBack.cache.expects(:delete).never
30
30
 
31
31
  @post.destroy
@@ -38,14 +38,14 @@ class CacheExpiryTest < ActiveSupport::TestCase
38
38
  end
39
39
 
40
40
  should "clear all indices for instance when updated" do
41
- CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/id=#{@post.id}")
42
- CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/id=#{@post.id}/first")
43
- CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/title=#{@post.title}")
44
- CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/title=#{@post.title}/first")
45
- CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/title=new title")
46
- CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/title=new title/first")
47
- CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/blog_id=#{@post.blog_id}")
48
- CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/blog_id=#{@post.blog_id}/first")
41
+ CacheBack.cache.expects(:delete).with(Post.cache_back_key_prefix + "id=#{@post.id}")
42
+ CacheBack.cache.expects(:delete).with(Post.cache_back_key_prefix + "id=#{@post.id}/first")
43
+ CacheBack.cache.expects(:delete).with(Post.cache_back_key_prefix + "title=#{@post.title}")
44
+ CacheBack.cache.expects(:delete).with(Post.cache_back_key_prefix + "title=#{@post.title}/first")
45
+ CacheBack.cache.expects(:delete).with(Post.cache_back_key_prefix + "title=new title")
46
+ CacheBack.cache.expects(:delete).with(Post.cache_back_key_prefix + "title=new title/first")
47
+ CacheBack.cache.expects(:delete).with(Post.cache_back_key_prefix + "blog_id=#{@post.blog_id}")
48
+ CacheBack.cache.expects(:delete).with(Post.cache_back_key_prefix + "blog_id=#{@post.blog_id}/first")
49
49
  CacheBack.cache.expects(:delete).never
50
50
 
51
51
  @post.title = "new title"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cache_back
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mick Staugaard
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-29 00:00:00 -08:00
12
+ date: 2009-11-30 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -53,7 +53,6 @@ files:
53
53
  - lib/cache_back/conditions_parser.rb
54
54
  - lib/cache_back/configuration_mixin.rb
55
55
  - lib/cache_back/dirty_mixin.rb
56
- - lib/cache_back/rack_middleware.rb
57
56
  - lib/cache_back/read_mixin.rb
58
57
  - lib/cache_back/reload_association_mixin.rb
59
58
  - lib/cache_back/write_mixin.rb
@@ -1,13 +0,0 @@
1
- module CacheBack
2
- class RackMiddleware
3
- def initialize(app)
4
- @app = app
5
- end
6
-
7
- def call(env)
8
- result = @app.call(env)
9
- CacheBack.cache.reset!
10
- result
11
- end
12
- end
13
- end