identity_cache 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/test/fetch_test.rb CHANGED
@@ -5,81 +5,83 @@ class FetchTest < IdentityCache::TestCase
5
5
 
6
6
  def setup
7
7
  super
8
- Record.cache_index :title, :unique => true
9
- Record.cache_index :id, :title, :unique => true
8
+ Item.cache_index :title, :unique => true
9
+ Item.cache_index :id, :title, :unique => true
10
10
 
11
- @record = Record.new
11
+ @record = Item.new
12
12
  @record.id = 1
13
13
  @record.title = 'bob'
14
14
  @cached_value = {:class => @record.class}
15
15
  @record.encode_with(@cached_value)
16
- @blob_key = "#{NAMESPACE}blob:Record:#{cache_hash("created_at:datetime,id:integer,record_id:integer,title:string,updated_at:datetime")}:1"
17
- @index_key = "#{NAMESPACE}index:Record:title:#{cache_hash('bob')}"
16
+ @blob_key = "#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:1"
17
+ @index_key = "#{NAMESPACE}index:Item:title:#{cache_hash('bob')}"
18
18
  end
19
19
 
20
20
  def test_fetch_cache_hit
21
21
  IdentityCache.cache.expects(:read).with(@blob_key).returns(@cached_value)
22
22
 
23
- assert_equal @record, Record.fetch(1)
23
+ assert_equal @record, Item.fetch(1)
24
24
  end
25
25
 
26
26
  def test_fetch_hit_cache_namespace
27
- Record.send(:include, SwitchNamespace)
28
- Record.namespace = 'test_namespace'
27
+ old_ns = IdentityCache.cache_namespace
28
+ IdentityCache.cache_namespace = proc { |model| "#{model.table_name}:#{old_ns}" }
29
29
 
30
- new_blob_key = "test_namespace:#{@blob_key}"
30
+ new_blob_key = "items:#{@blob_key}"
31
31
  IdentityCache.cache.expects(:read).with(new_blob_key).returns(@cached_value)
32
32
 
33
- assert_equal @record, Record.fetch(1)
33
+ assert_equal @record, Item.fetch(1)
34
+ ensure
35
+ IdentityCache.cache_namespace = old_ns
34
36
  end
35
37
 
36
38
  def test_exists_with_identity_cache_when_cache_hit
37
39
  IdentityCache.cache.expects(:read).with(@blob_key).returns(@cached_value)
38
40
 
39
- assert Record.exists_with_identity_cache?(1)
41
+ assert Item.exists_with_identity_cache?(1)
40
42
  end
41
43
 
42
44
  def test_exists_with_identity_cache_when_cache_miss_and_in_db
43
45
  IdentityCache.cache.expects(:read).with(@blob_key).returns(nil)
44
- Record.expects(:find_by_id).with(1, :include => []).returns(@record)
46
+ Item.expects(:resolve_cache_miss).with(1).once.returns(@record)
45
47
 
46
- assert Record.exists_with_identity_cache?(1)
48
+ assert Item.exists_with_identity_cache?(1)
47
49
  end
48
50
 
49
51
  def test_exists_with_identity_cache_when_cache_miss_and_not_in_db
50
52
  IdentityCache.cache.expects(:read).with(@blob_key).returns(nil)
51
- Record.expects(:find_by_id).with(1, :include => []).returns(nil)
53
+ Item.expects(:resolve_cache_miss).with(1).once.returns(nil)
52
54
 
53
- assert !Record.exists_with_identity_cache?(1)
55
+ assert !Item.exists_with_identity_cache?(1)
54
56
  end
55
57
 
56
58
  def test_fetch_miss
57
- Record.expects(:find_by_id).with(1, :include => []).returns(@record)
59
+ Item.expects(:resolve_cache_miss).with(1).once.returns(@record)
58
60
 
59
61
  IdentityCache.cache.expects(:read).with(@blob_key).returns(nil)
60
62
  IdentityCache.cache.expects(:write).with(@blob_key, @cached_value)
61
63
 
62
- assert_equal @record, Record.fetch(1)
64
+ assert_equal @record, Item.fetch(1)
63
65
  end
64
66
 
65
67
  def test_fetch_by_id_not_found_should_return_nil
66
68
  nonexistent_record_id = 10
67
69
  IdentityCache.cache.expects(:write).with(@blob_key + '0', IdentityCache::CACHED_NIL)
68
70
 
69
- assert_equal nil, Record.fetch_by_id(nonexistent_record_id)
71
+ assert_equal nil, Item.fetch_by_id(nonexistent_record_id)
70
72
  end
71
73
 
72
74
  def test_fetch_not_found_should_raise
73
75
  nonexistent_record_id = 10
74
76
  IdentityCache.cache.expects(:write).with(@blob_key + '0', IdentityCache::CACHED_NIL)
75
77
 
76
- assert_raises(ActiveRecord::RecordNotFound) { Record.fetch(nonexistent_record_id) }
78
+ assert_raises(ActiveRecord::RecordNotFound) { Item.fetch(nonexistent_record_id) }
77
79
  end
78
80
 
79
81
  def test_cached_nil_expiry_on_record_creation
80
82
  key = @record.primary_cache_index_key
81
83
 
82
- assert_equal nil, Record.fetch_by_id(@record.id)
84
+ assert_equal nil, Item.fetch_by_id(@record.id)
83
85
  assert_equal IdentityCache::CACHED_NIL, IdentityCache.cache.read(key)
84
86
 
85
87
  @record.save!
@@ -91,7 +93,7 @@ class FetchTest < IdentityCache::TestCase
91
93
  IdentityCache.cache.expects(:read).with(@index_key).returns(nil)
92
94
 
93
95
  # - not found, use sql, SELECT id FROM records WHERE title = '...' LIMIT 1"
94
- Record.connection.expects(:select_value).returns(1)
96
+ Item.connection.expects(:select_value).returns(1)
95
97
 
96
98
  # cache sql result
97
99
  IdentityCache.cache.expects(:write).with(@index_key, 1)
@@ -99,31 +101,37 @@ class FetchTest < IdentityCache::TestCase
99
101
  # got id, do memcache lookup on that, hit -> done
100
102
  IdentityCache.cache.expects(:read).with(@blob_key).returns(@cached_value)
101
103
 
102
- assert_equal @record, Record.fetch_by_title('bob')
104
+ assert_equal @record, Item.fetch_by_title('bob')
103
105
  end
104
106
 
105
107
  def test_fetch_by_title_cache_namespace
106
- Record.send(:include, SwitchNamespace)
108
+ Item.send(:include, SwitchNamespace)
107
109
  IdentityCache.cache.expects(:read).with("ns:#{@index_key}").returns(1)
108
110
  IdentityCache.cache.expects(:read).with("ns:#{@blob_key}").returns(@cached_value)
109
111
 
110
- assert_equal @record, Record.fetch_by_title('bob')
112
+ assert_equal @record, Item.fetch_by_title('bob')
111
113
  end
112
114
 
113
115
  def test_fetch_by_title_stores_idcnil
114
- Record.connection.expects(:select_value).once.returns(nil)
116
+ Item.connection.expects(:select_value).once.returns(nil)
115
117
  Rails.cache.expects(:write).with(@index_key, IdentityCache::CACHED_NIL)
116
118
  Rails.cache.expects(:read).with(@index_key).times(3).returns(nil, IdentityCache::CACHED_NIL, IdentityCache::CACHED_NIL)
117
- assert_equal nil, Record.fetch_by_title('bob') # select_value => nil
119
+ assert_equal nil, Item.fetch_by_title('bob') # select_value => nil
118
120
 
119
- assert_equal nil, Record.fetch_by_title('bob') # returns cached nil
120
- assert_equal nil, Record.fetch_by_title('bob') # returns cached nil
121
+ assert_equal nil, Item.fetch_by_title('bob') # returns cached nil
122
+ assert_equal nil, Item.fetch_by_title('bob') # returns cached nil
121
123
  end
122
124
 
123
125
  def test_fetch_by_bang_method
124
- Record.connection.expects(:select_value).returns(nil)
126
+ Item.connection.expects(:select_value).returns(nil)
125
127
  assert_raises ActiveRecord::RecordNotFound do
126
- Record.fetch_by_title!('bob')
128
+ Item.fetch_by_title!('bob')
127
129
  end
128
130
  end
131
+
132
+ def test_fetch_does_not_communicate_to_cache_with_nil_id
133
+ IdentityCache.cache.expects(:read).never
134
+ IdentityCache.cache.expects(:write).never
135
+ assert_raises(ActiveRecord::RecordNotFound) { Item.fetch(nil) }
136
+ end
129
137
  end
Binary file
@@ -18,39 +18,43 @@ end
18
18
  module ActiveRecordObjects
19
19
 
20
20
  def setup_models(base = ActiveRecord::Base)
21
- Object.send :const_set, 'DeeplyAssociatedRecord', Class.new(base).tap {|klass|
22
- klass.send :include, IdentityCache
23
- klass.belongs_to :associated_record
21
+ Object.send :const_set, 'DeeplyAssociatedRecord', Class.new(base) {
22
+ include IdentityCache
23
+ belongs_to :associated_record
24
+ default_scope { order('name DESC') }
24
25
  }
25
26
 
26
- Object.send :const_set, 'AssociatedRecord', Class.new(base).tap {|klass|
27
- klass.send :include, IdentityCache
28
- klass.belongs_to :record
29
- klass.has_many :deeply_associated_records, :order => "name DESC"
27
+ Object.send :const_set, 'AssociatedRecord', Class.new(base) {
28
+ include IdentityCache
29
+ belongs_to :item
30
+ has_many :deeply_associated_records
31
+ default_scope { order('id DESC') }
30
32
  }
31
33
 
32
- Object.send :const_set, 'NormalizedAssociatedRecord', Class.new(base).tap {|klass|
33
- klass.send :include, IdentityCache
34
- klass.belongs_to :record
34
+ Object.send :const_set, 'NormalizedAssociatedRecord', Class.new(base) {
35
+ include IdentityCache
36
+ belongs_to :item
37
+ default_scope { order('id DESC') }
35
38
  }
36
39
 
37
- Object.send :const_set, 'NotCachedRecord', Class.new(base).tap {|klass|
38
- klass.belongs_to :record, :touch => true
40
+ Object.send :const_set, 'NotCachedRecord', Class.new(base) {
41
+ belongs_to :item, :touch => true
42
+ default_scope { order('id DESC') }
39
43
  }
40
44
 
41
- Object.send :const_set, 'PolymorphicRecord', Class.new(base).tap {|klass|
42
- klass.belongs_to :owner, :polymorphic => true
45
+ Object.send :const_set, 'PolymorphicRecord', Class.new(base) {
46
+ belongs_to :owner, :polymorphic => true
43
47
  }
44
48
 
45
- Object.send :const_set, 'Record', Class.new(base).tap {|klass|
46
- klass.send :include, IdentityCache
47
- klass.belongs_to :record
48
- klass.has_many :associated_records, :order => "id DESC"
49
- klass.has_many :normalized_associated_records, :order => "id DESC"
50
- klass.has_many :not_cached_records, :order => "id DESC"
51
- klass.has_many :polymorphic_records, :as => 'owner'
52
- klass.has_one :polymorphic_record, :as => 'owner'
53
- klass.has_one :associated, :class_name => 'AssociatedRecord', :order => "id ASC"
49
+ Object.send :const_set, 'Item', Class.new(base) {
50
+ include IdentityCache
51
+ belongs_to :item
52
+ has_many :associated_records
53
+ has_many :normalized_associated_records
54
+ has_many :not_cached_records
55
+ has_many :polymorphic_records, :as => 'owner'
56
+ has_one :polymorphic_record, :as => 'owner'
57
+ has_one :associated, :class_name => 'AssociatedRecord'
54
58
  }
55
59
  end
56
60
 
@@ -62,6 +66,6 @@ module ActiveRecordObjects
62
66
  Object.send :remove_const, 'NormalizedAssociatedRecord'
63
67
  Object.send :remove_const, 'AssociatedRecord'
64
68
  Object.send :remove_const, 'NotCachedRecord'
65
- Object.send :remove_const, 'Record'
69
+ Object.send :remove_const, 'Item'
66
70
  end
67
71
  end
@@ -28,11 +28,11 @@ module DatabaseConnection
28
28
  TABLES = {
29
29
  :polymorphic_records => [[:string, :owner_type], [:integer, :owner_id], [:timestamps]],
30
30
  :deeply_associated_records => [[:string, :name], [:integer, :associated_record_id]],
31
- :associated_records => [[:string, :name], [:integer, :record_id]],
32
- :normalized_associated_records => [[:string, :name], [:integer, :record_id]],
33
- :not_cached_records => [[:string, :name], [:integer, :record_id]],
34
- :records => [[:integer, :record_id], [:string, :title], [:timestamps]],
35
- :records2 => [[:integer, :record_id], [:string, :title], [:timestamps]]
31
+ :associated_records => [[:string, :name], [:integer, :item_id]],
32
+ :normalized_associated_records => [[:string, :name], [:integer, :item_id]],
33
+ :not_cached_records => [[:string, :name], [:integer, :item_id]],
34
+ :items => [[:integer, :item_id], [:string, :title], [:timestamps]],
35
+ :items2 => [[:integer, :item_id], [:string, :title], [:timestamps]]
36
36
  }
37
37
 
38
38
  DATABASE_CONFIG = {
@@ -1,22 +1,22 @@
1
1
  module SerializationFormat
2
2
  def serialized_record
3
3
  AssociatedRecord.cache_has_many :deeply_associated_records, :embed => true
4
- AssociatedRecord.cache_belongs_to :record, :embed => false
5
- Record.cache_has_many :associated_records, :embed => true
6
- Record.cache_has_one :associated
4
+ AssociatedRecord.cache_belongs_to :item, :embed => false
5
+ Item.cache_has_many :associated_records, :embed => true
6
+ Item.cache_has_one :associated
7
7
 
8
- record = Record.new(:title => 'foo')
8
+ record = Item.new(:title => 'foo')
9
9
  record.associated_records << AssociatedRecord.new(:name => 'bar')
10
10
  record.associated_records << AssociatedRecord.new(:name => 'baz')
11
11
  record.associated = AssociatedRecord.new(:name => 'bork')
12
12
  record.not_cached_records << NotCachedRecord.new(:name => 'NoCache')
13
13
  record.associated.deeply_associated_records << DeeplyAssociatedRecord.new(:name => "corge")
14
14
  record.associated.deeply_associated_records << DeeplyAssociatedRecord.new(:name => "qux")
15
- record.created_at = DateTime.new
15
+ record.created_at = Time.parse('1970-01-01T00:00:00 UTC')
16
16
  record.save
17
- Record.update_all("updated_at='#{record.created_at}'", "id='#{record.id}'")
17
+ Item.where(id: record.id).update_all(updated_at: record.created_at)
18
18
  record.reload
19
- Record.fetch(record.id)
19
+ Item.fetch(record.id)
20
20
  IdentityCache.fetch(record.primary_cache_index_key)
21
21
  end
22
22
 
@@ -5,82 +5,81 @@ class ExpirationTest < IdentityCache::TestCase
5
5
 
6
6
  def setup
7
7
  super
8
- @record = Record.new
8
+ @record = Item.new
9
9
  @record.id = 1
10
10
  @record.title = 'bob'
11
- @cache_key = "#{NAMESPACE}index:Record:title:#{cache_hash(@record.title)}"
11
+ @cache_key = "#{NAMESPACE}index:Item:title:#{cache_hash(@record.title)}"
12
12
  end
13
13
 
14
14
  def test_unique_index_caches_nil
15
- Record.cache_index :title, :unique => true
16
- assert_equal nil, Record.fetch_by_title('bob')
15
+ Item.cache_index :title, :unique => true
16
+ assert_equal nil, Item.fetch_by_title('bob')
17
17
  assert_equal IdentityCache::CACHED_NIL, IdentityCache.cache.read(@cache_key)
18
18
  end
19
19
 
20
20
  def test_unique_index_expired_by_new_record
21
- Record.cache_index :title, :unique => true
21
+ Item.cache_index :title, :unique => true
22
22
  IdentityCache.cache.write(@cache_key, IdentityCache::CACHED_NIL)
23
23
  @record.save!
24
24
  assert_equal nil, IdentityCache.cache.read(@cache_key)
25
25
  end
26
26
 
27
27
  def test_unique_index_filled_on_fetch_by
28
- Record.cache_index :title, :unique => true
28
+ Item.cache_index :title, :unique => true
29
29
  @record.save!
30
- assert_equal @record, Record.fetch_by_title('bob')
30
+ assert_equal @record, Item.fetch_by_title('bob')
31
31
  assert_equal @record.id, IdentityCache.cache.read(@cache_key)
32
32
  end
33
33
 
34
34
  def test_unique_index_expired_by_updated_record
35
- Record.cache_index :title, :unique => true
35
+ Item.cache_index :title, :unique => true
36
36
  @record.save!
37
37
  IdentityCache.cache.write(@cache_key, @record.id)
38
38
 
39
39
  @record.title = 'robert'
40
- new_cache_key = "#{NAMESPACE}index:Record:title:#{cache_hash(@record.title)}"
40
+ new_cache_key = "#{NAMESPACE}index:Item:title:#{cache_hash(@record.title)}"
41
41
  IdentityCache.cache.write(new_cache_key, IdentityCache::CACHED_NIL)
42
42
  @record.save!
43
43
  assert_equal nil, IdentityCache.cache.read(@cache_key)
44
44
  assert_equal nil, IdentityCache.cache.read(new_cache_key)
45
45
  end
46
46
 
47
-
48
47
  def test_non_unique_index_caches_empty_result
49
- Record.cache_index :title
50
- assert_equal [], Record.fetch_by_title('bob')
48
+ Item.cache_index :title
49
+ assert_equal [], Item.fetch_by_title('bob')
51
50
  assert_equal [], IdentityCache.cache.read(@cache_key)
52
51
  end
53
52
 
54
53
  def test_non_unique_index_expired_by_new_record
55
- Record.cache_index :title
54
+ Item.cache_index :title
56
55
  IdentityCache.cache.write(@cache_key, [])
57
56
  @record.save!
58
57
  assert_equal nil, IdentityCache.cache.read(@cache_key)
59
58
  end
60
59
 
61
60
  def test_non_unique_index_filled_on_fetch_by
62
- Record.cache_index :title
61
+ Item.cache_index :title
63
62
  @record.save!
64
- assert_equal [@record], Record.fetch_by_title('bob')
63
+ assert_equal [@record], Item.fetch_by_title('bob')
65
64
  assert_equal [@record.id], IdentityCache.cache.read(@cache_key)
66
65
  end
67
66
 
68
67
  def test_non_unique_index_fetches_multiple_records
69
- Record.cache_index :title
68
+ Item.cache_index :title
70
69
  @record.save!
71
- record2 = Record.create(:id => 2, :title => 'bob')
70
+ record2 = Item.create(:id => 2, :title => 'bob')
72
71
 
73
- assert_equal [@record, record2], Record.fetch_by_title('bob')
72
+ assert_equal [@record, record2], Item.fetch_by_title('bob')
74
73
  assert_equal [1, 2], IdentityCache.cache.read(@cache_key)
75
74
  end
76
75
 
77
76
  def test_non_unique_index_expired_by_updating_record
78
- Record.cache_index :title
77
+ Item.cache_index :title
79
78
  @record.save!
80
79
  IdentityCache.cache.write(@cache_key, [@record.id])
81
80
 
82
81
  @record.title = 'robert'
83
- new_cache_key = "#{NAMESPACE}index:Record:title:#{cache_hash(@record.title)}"
82
+ new_cache_key = "#{NAMESPACE}index:Item:title:#{cache_hash(@record.title)}"
84
83
  IdentityCache.cache.write(new_cache_key, [])
85
84
  @record.save!
86
85
  assert_equal nil, IdentityCache.cache.read(@cache_key)
@@ -88,7 +87,7 @@ class ExpirationTest < IdentityCache::TestCase
88
87
  end
89
88
 
90
89
  def test_non_unique_index_expired_by_destroying_record
91
- Record.cache_index :title
90
+ Item.cache_index :title
92
91
  @record.save!
93
92
  IdentityCache.cache.write(@cache_key, [@record.id])
94
93
  @record.destroy
@@ -96,10 +95,10 @@ class ExpirationTest < IdentityCache::TestCase
96
95
  end
97
96
 
98
97
  def test_set_table_name_cache_fetch
99
- Record.cache_index :title
100
- Record.table_name = 'records2'
98
+ Item.cache_index :title
99
+ Item.table_name = 'items2'
101
100
  @record.save!
102
- assert_equal [@record], Record.fetch_by_title('bob')
101
+ assert_equal [@record], Item.fetch_by_title('bob')
103
102
  assert_equal [@record.id], IdentityCache.cache.read(@cache_key)
104
103
  end
105
104
  end
@@ -102,4 +102,9 @@ class MemoizedCacheProxyTest < IdentityCache::TestCase
102
102
  assert_equal 'bar', Rails.cache.read('foo')
103
103
  end
104
104
 
105
+ def test_set_backend_should_not_touch_rails
106
+ Rails.expects(:cache).never
107
+ IdentityCache.instance_variable_set(:@cache, nil)
108
+ IdentityCache.cache_backend = Rails::Cache.new
109
+ end
105
110
  end
@@ -3,9 +3,9 @@ require "test_helper"
3
3
  class NormalizedBelongsToTest < IdentityCache::TestCase
4
4
  def setup
5
5
  super
6
- AssociatedRecord.cache_belongs_to :record, :embed => false
6
+ AssociatedRecord.cache_belongs_to :item, :embed => false
7
7
 
8
- @parent_record = Record.new(:title => 'foo')
8
+ @parent_record = Item.new(:title => 'foo')
9
9
  @parent_record.associated_records << AssociatedRecord.new(:name => 'bar')
10
10
  @parent_record.save
11
11
  @parent_record.reload
@@ -13,34 +13,34 @@ class NormalizedBelongsToTest < IdentityCache::TestCase
13
13
  end
14
14
 
15
15
  def test_fetching_the_association_should_delegate_to_the_normal_association_fetcher_if_any_transactions_are_open
16
- Record.expects(:fetch_by_id).never
16
+ Item.expects(:fetch_by_id).never
17
17
  @record.transaction do
18
- assert_equal @parent_record, @record.fetch_record
18
+ assert_equal @parent_record, @record.fetch_item
19
19
  end
20
20
  end
21
21
 
22
22
  def test_fetching_the_association_should_delegate_to_the_normal_association_fetcher_if_the_normal_association_is_loaded
23
23
  # Warm the ActiveRecord association
24
- @record.record
24
+ @record.item
25
25
 
26
- Record.expects(:fetch_by_id).never
27
- assert_equal @parent_record, @record.fetch_record
26
+ Item.expects(:fetch_by_id).never
27
+ assert_equal @parent_record, @record.fetch_item
28
28
  end
29
29
 
30
30
  def test_fetching_the_association_should_fetch_the_record_from_identity_cache
31
- Record.expects(:fetch_by_id).with(@parent_record.id).returns(@parent_record)
32
- assert_equal @parent_record, @record.fetch_record
31
+ Item.expects(:fetch_by_id).with(@parent_record.id).returns(@parent_record)
32
+ assert_equal @parent_record, @record.fetch_item
33
33
  end
34
34
 
35
35
  def test_fetching_the_association_should_assign_the_result_to_the_association_so_that_successive_accesses_are_cached
36
- Record.expects(:fetch_by_id).with(@parent_record.id).returns(@parent_record)
37
- @record.fetch_record
38
- assert @record.association(:record).loaded?
39
- assert_equal @parent_record, @record.record
36
+ Item.expects(:fetch_by_id).with(@parent_record.id).returns(@parent_record)
37
+ @record.fetch_item
38
+ assert @record.association(:item).loaded?
39
+ assert_equal @parent_record, @record.item
40
40
  end
41
41
 
42
42
  def test_fetching_the_association_shouldnt_raise_if_the_record_cant_be_found
43
- Record.expects(:fetch_by_id).with(@parent_record.id).returns(nil)
44
- assert_equal nil, @record.fetch_record
43
+ Item.expects(:fetch_by_id).with(@parent_record.id).returns(nil)
44
+ assert_equal nil, @record.fetch_item
45
45
  end
46
46
  end