cache_back 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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