identity_cache 0.0.4 → 0.0.5

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/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