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.
- checksums.yaml +5 -13
- data/.gitignore +1 -1
- data/.ruby-version +1 -0
- data/.travis.yml +6 -2
- data/Gemfile +3 -0
- data/Gemfile.rails4 +8 -0
- data/README.md +2 -1
- data/identity_cache.gemspec +2 -6
- data/lib/identity_cache.rb +9 -1
- data/lib/identity_cache/belongs_to_caching.rb +1 -1
- data/lib/identity_cache/cache_key_generation.rb +13 -4
- data/lib/identity_cache/configuration_dsl.rb +6 -6
- data/lib/identity_cache/query_api.rb +21 -10
- data/lib/identity_cache/version.rb +1 -1
- data/performance/cache_runner.rb +14 -15
- data/test/attribute_cache_test.rb +29 -8
- data/test/cache_fetch_includes_test.rb +25 -25
- data/test/denormalized_has_many_test.rb +15 -13
- data/test/denormalized_has_one_test.rb +22 -16
- data/test/fetch_multi_test.rb +28 -28
- data/test/fetch_multi_with_batched_associations_test.rb +56 -56
- data/test/fetch_test.rb +38 -30
- data/test/fixtures/serialized_record +0 -0
- data/test/helpers/active_record_objects.rb +28 -24
- data/test/helpers/database_connection.rb +5 -5
- data/test/helpers/serialization_format.rb +7 -7
- data/test/index_cache_test.rb +23 -24
- data/test/memoized_cache_proxy_test.rb +5 -0
- data/test/normalized_belongs_to_test.rb +15 -15
- data/test/normalized_has_many_test.rb +28 -23
- data/test/recursive_denormalized_has_many_test.rb +14 -14
- data/test/save_test.rb +18 -18
- data/test/schema_change_test.rb +26 -13
- metadata +26 -60
data/test/fetch_test.rb
CHANGED
@@ -5,81 +5,83 @@ class FetchTest < IdentityCache::TestCase
|
|
5
5
|
|
6
6
|
def setup
|
7
7
|
super
|
8
|
-
|
9
|
-
|
8
|
+
Item.cache_index :title, :unique => true
|
9
|
+
Item.cache_index :id, :title, :unique => true
|
10
10
|
|
11
|
-
@record =
|
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:
|
17
|
-
@index_key = "#{NAMESPACE}index:
|
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,
|
23
|
+
assert_equal @record, Item.fetch(1)
|
24
24
|
end
|
25
25
|
|
26
26
|
def test_fetch_hit_cache_namespace
|
27
|
-
|
28
|
-
|
27
|
+
old_ns = IdentityCache.cache_namespace
|
28
|
+
IdentityCache.cache_namespace = proc { |model| "#{model.table_name}:#{old_ns}" }
|
29
29
|
|
30
|
-
new_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,
|
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
|
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
|
-
|
46
|
+
Item.expects(:resolve_cache_miss).with(1).once.returns(@record)
|
45
47
|
|
46
|
-
assert
|
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
|
-
|
53
|
+
Item.expects(:resolve_cache_miss).with(1).once.returns(nil)
|
52
54
|
|
53
|
-
assert !
|
55
|
+
assert !Item.exists_with_identity_cache?(1)
|
54
56
|
end
|
55
57
|
|
56
58
|
def test_fetch_miss
|
57
|
-
|
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,
|
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,
|
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) {
|
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,
|
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
|
-
|
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,
|
104
|
+
assert_equal @record, Item.fetch_by_title('bob')
|
103
105
|
end
|
104
106
|
|
105
107
|
def test_fetch_by_title_cache_namespace
|
106
|
-
|
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,
|
112
|
+
assert_equal @record, Item.fetch_by_title('bob')
|
111
113
|
end
|
112
114
|
|
113
115
|
def test_fetch_by_title_stores_idcnil
|
114
|
-
|
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,
|
119
|
+
assert_equal nil, Item.fetch_by_title('bob') # select_value => nil
|
118
120
|
|
119
|
-
assert_equal nil,
|
120
|
-
assert_equal 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
|
-
|
126
|
+
Item.connection.expects(:select_value).returns(nil)
|
125
127
|
assert_raises ActiveRecord::RecordNotFound do
|
126
|
-
|
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)
|
22
|
-
|
23
|
-
|
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)
|
27
|
-
|
28
|
-
|
29
|
-
|
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)
|
33
|
-
|
34
|
-
|
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)
|
38
|
-
|
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)
|
42
|
-
|
45
|
+
Object.send :const_set, 'PolymorphicRecord', Class.new(base) {
|
46
|
+
belongs_to :owner, :polymorphic => true
|
43
47
|
}
|
44
48
|
|
45
|
-
Object.send :const_set, '
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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, '
|
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, :
|
32
|
-
:normalized_associated_records => [[:string, :name], [:integer, :
|
33
|
-
:not_cached_records => [[:string, :name], [:integer, :
|
34
|
-
:
|
35
|
-
:
|
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 :
|
5
|
-
|
6
|
-
|
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 =
|
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 =
|
15
|
+
record.created_at = Time.parse('1970-01-01T00:00:00 UTC')
|
16
16
|
record.save
|
17
|
-
|
17
|
+
Item.where(id: record.id).update_all(updated_at: record.created_at)
|
18
18
|
record.reload
|
19
|
-
|
19
|
+
Item.fetch(record.id)
|
20
20
|
IdentityCache.fetch(record.primary_cache_index_key)
|
21
21
|
end
|
22
22
|
|
data/test/index_cache_test.rb
CHANGED
@@ -5,82 +5,81 @@ class ExpirationTest < IdentityCache::TestCase
|
|
5
5
|
|
6
6
|
def setup
|
7
7
|
super
|
8
|
-
@record =
|
8
|
+
@record = Item.new
|
9
9
|
@record.id = 1
|
10
10
|
@record.title = 'bob'
|
11
|
-
@cache_key = "#{NAMESPACE}index:
|
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
|
-
|
16
|
-
assert_equal nil,
|
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
|
-
|
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
|
-
|
28
|
+
Item.cache_index :title, :unique => true
|
29
29
|
@record.save!
|
30
|
-
assert_equal @record,
|
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
|
-
|
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:
|
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
|
-
|
50
|
-
assert_equal [],
|
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
|
-
|
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
|
-
|
61
|
+
Item.cache_index :title
|
63
62
|
@record.save!
|
64
|
-
assert_equal [@record],
|
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
|
-
|
68
|
+
Item.cache_index :title
|
70
69
|
@record.save!
|
71
|
-
record2 =
|
70
|
+
record2 = Item.create(:id => 2, :title => 'bob')
|
72
71
|
|
73
|
-
assert_equal [@record, record2],
|
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
|
-
|
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:
|
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
|
-
|
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
|
-
|
100
|
-
|
98
|
+
Item.cache_index :title
|
99
|
+
Item.table_name = 'items2'
|
101
100
|
@record.save!
|
102
|
-
assert_equal [@record],
|
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 :
|
6
|
+
AssociatedRecord.cache_belongs_to :item, :embed => false
|
7
7
|
|
8
|
-
@parent_record =
|
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
|
-
|
16
|
+
Item.expects(:fetch_by_id).never
|
17
17
|
@record.transaction do
|
18
|
-
assert_equal @parent_record, @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.
|
24
|
+
@record.item
|
25
25
|
|
26
|
-
|
27
|
-
assert_equal @parent_record, @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
|
-
|
32
|
-
assert_equal @parent_record, @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
|
-
|
37
|
-
@record.
|
38
|
-
assert @record.association(:
|
39
|
-
assert_equal @parent_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
|
-
|
44
|
-
assert_equal nil, @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
|