identity_cache 0.4.1 → 1.1.0
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 -5
- data/.github/probots.yml +2 -0
- data/.github/workflows/ci.yml +92 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +5 -0
- data/CAVEATS.md +25 -0
- data/CHANGELOG.md +73 -19
- data/Gemfile +5 -1
- data/LICENSE +1 -1
- data/README.md +49 -27
- data/Rakefile +14 -5
- data/dev.yml +12 -16
- data/gemfiles/Gemfile.latest-release +8 -0
- data/gemfiles/Gemfile.min-supported +7 -0
- data/gemfiles/Gemfile.rails-edge +7 -0
- data/identity_cache.gemspec +29 -10
- data/lib/identity_cache.rb +78 -51
- data/lib/identity_cache/belongs_to_caching.rb +12 -40
- data/lib/identity_cache/cache_fetcher.rb +6 -5
- data/lib/identity_cache/cache_hash.rb +2 -2
- data/lib/identity_cache/cache_invalidation.rb +4 -11
- data/lib/identity_cache/cache_key_generation.rb +17 -65
- data/lib/identity_cache/cache_key_loader.rb +128 -0
- data/lib/identity_cache/cached.rb +7 -0
- data/lib/identity_cache/cached/association.rb +87 -0
- data/lib/identity_cache/cached/attribute.rb +123 -0
- data/lib/identity_cache/cached/attribute_by_multi.rb +37 -0
- data/lib/identity_cache/cached/attribute_by_one.rb +88 -0
- data/lib/identity_cache/cached/belongs_to.rb +100 -0
- data/lib/identity_cache/cached/embedded_fetching.rb +41 -0
- data/lib/identity_cache/cached/prefetcher.rb +61 -0
- data/lib/identity_cache/cached/primary_index.rb +96 -0
- data/lib/identity_cache/cached/recursive/association.rb +109 -0
- data/lib/identity_cache/cached/recursive/has_many.rb +9 -0
- data/lib/identity_cache/cached/recursive/has_one.rb +9 -0
- data/lib/identity_cache/cached/reference/association.rb +16 -0
- data/lib/identity_cache/cached/reference/has_many.rb +105 -0
- data/lib/identity_cache/cached/reference/has_one.rb +100 -0
- data/lib/identity_cache/configuration_dsl.rb +53 -215
- data/lib/identity_cache/encoder.rb +95 -0
- data/lib/identity_cache/expiry_hook.rb +36 -0
- data/lib/identity_cache/fallback_fetcher.rb +2 -1
- data/lib/identity_cache/load_strategy/eager.rb +28 -0
- data/lib/identity_cache/load_strategy/lazy.rb +71 -0
- data/lib/identity_cache/load_strategy/load_request.rb +20 -0
- data/lib/identity_cache/load_strategy/multi_load_request.rb +27 -0
- data/lib/identity_cache/mem_cache_store_cas.rb +53 -0
- data/lib/identity_cache/memoized_cache_proxy.rb +137 -58
- data/lib/identity_cache/parent_model_expiration.rb +46 -11
- data/lib/identity_cache/query_api.rb +102 -408
- data/lib/identity_cache/railtie.rb +8 -0
- data/lib/identity_cache/record_not_found.rb +6 -0
- data/lib/identity_cache/should_use_cache.rb +1 -0
- data/lib/identity_cache/version.rb +3 -2
- data/lib/identity_cache/with_primary_index.rb +136 -0
- data/lib/identity_cache/without_primary_index.rb +24 -3
- data/performance/cache_runner.rb +25 -73
- data/performance/cpu.rb +4 -3
- data/performance/externals.rb +4 -3
- data/performance/profile.rb +6 -5
- data/railgun.yml +16 -0
- metadata +60 -73
- data/.travis.yml +0 -30
- data/Gemfile.rails42 +0 -6
- data/Gemfile.rails50 +0 -6
- data/test/attribute_cache_test.rb +0 -110
- data/test/cache_fetch_includes_test.rb +0 -46
- data/test/cache_hash_test.rb +0 -14
- data/test/cache_invalidation_test.rb +0 -139
- data/test/deeply_nested_associated_record_test.rb +0 -19
- data/test/denormalized_has_many_test.rb +0 -211
- data/test/denormalized_has_one_test.rb +0 -160
- data/test/fetch_multi_test.rb +0 -308
- data/test/fetch_test.rb +0 -258
- data/test/fixtures/serialized_record.mysql2 +0 -0
- data/test/fixtures/serialized_record.postgresql +0 -0
- data/test/helpers/active_record_objects.rb +0 -106
- data/test/helpers/database_connection.rb +0 -72
- data/test/helpers/serialization_format.rb +0 -42
- data/test/helpers/update_serialization_format.rb +0 -24
- data/test/identity_cache_test.rb +0 -29
- data/test/index_cache_test.rb +0 -161
- data/test/memoized_attributes_test.rb +0 -49
- data/test/memoized_cache_proxy_test.rb +0 -107
- data/test/normalized_belongs_to_test.rb +0 -107
- data/test/normalized_has_many_test.rb +0 -231
- data/test/normalized_has_one_test.rb +0 -9
- data/test/prefetch_associations_test.rb +0 -364
- data/test/readonly_test.rb +0 -109
- data/test/recursive_denormalized_has_many_test.rb +0 -131
- data/test/save_test.rb +0 -82
- data/test/schema_change_test.rb +0 -112
- data/test/serialization_format_change_test.rb +0 -16
- data/test/test_helper.rb +0 -140
@@ -1,107 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class MemoizedCacheProxyTest < IdentityCache::TestCase
|
4
|
-
def test_changing_default_cache
|
5
|
-
IdentityCache.cache_backend = ActiveSupport::Cache::MemoryStore.new
|
6
|
-
IdentityCache.cache.write('foo', 'bar')
|
7
|
-
assert_equal 'bar', IdentityCache.cache.fetch('foo')
|
8
|
-
end
|
9
|
-
|
10
|
-
def test_fetch_multi_with_fallback_fetcher
|
11
|
-
IdentityCache.cache_backend = backend = ActiveSupport::Cache::MemoryStore.new
|
12
|
-
IdentityCache.cache.write('foo', 'bar')
|
13
|
-
backend.expects(:write).with('bar', 'baz')
|
14
|
-
yielded = nil
|
15
|
-
assert_equal({'foo' => 'bar', 'bar' => 'baz'}, IdentityCache.cache.fetch_multi('foo', 'bar') {|_| yielded = ['baz'] })
|
16
|
-
assert_equal ['baz'], yielded
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_fetch_should_short_circuit_on_memoized_values
|
20
|
-
fetcher.expects(:fetch).never
|
21
|
-
|
22
|
-
IdentityCache.cache.with_memoization do
|
23
|
-
IdentityCache.cache.write('foo', 'bar')
|
24
|
-
assert_equal 'bar', IdentityCache.cache.fetch('foo')
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def test_fetch_should_short_circuit_on_falsy_memoized_values
|
29
|
-
fetcher.expects(:fetch).never
|
30
|
-
|
31
|
-
IdentityCache.cache.with_memoization do
|
32
|
-
IdentityCache.cache.write('foo', nil)
|
33
|
-
assert_nil IdentityCache.cache.fetch('foo')
|
34
|
-
IdentityCache.cache.write('bar', false)
|
35
|
-
assert_equal false, IdentityCache.cache.fetch('bar')
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_fetch_should_try_memcached_on_not_memoized_values
|
40
|
-
fetcher.expects(:fetch).with('foo').returns('bar')
|
41
|
-
|
42
|
-
IdentityCache.cache.with_memoization do
|
43
|
-
assert_equal 'bar', IdentityCache.cache.fetch('foo')
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def test_write_should_memoize_values
|
48
|
-
fetcher.expects(:fetch).never
|
49
|
-
fetcher.expects(:write).with('foo', 'bar')
|
50
|
-
|
51
|
-
IdentityCache.cache.with_memoization do
|
52
|
-
IdentityCache.cache.write('foo', 'bar')
|
53
|
-
assert_equal 'bar', IdentityCache.cache.fetch('foo')
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def test_fetch_should_memoize_values
|
58
|
-
backend.write('foo', 'bar')
|
59
|
-
|
60
|
-
IdentityCache.cache.with_memoization do
|
61
|
-
assert_equal 'bar', IdentityCache.cache.fetch('foo')
|
62
|
-
backend.delete('foo')
|
63
|
-
assert_equal 'bar', IdentityCache.cache.fetch('foo')
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def test_fetch_multi_should_memoize_values
|
68
|
-
expected_hash = {'foo' => 'bar', 'fooz' => IdentityCache::CACHED_NIL}
|
69
|
-
|
70
|
-
backend.write('foo', 'bar')
|
71
|
-
|
72
|
-
IdentityCache.cache.with_memoization do
|
73
|
-
assert_equal(expected_hash, IdentityCache.cache.fetch_multi('foo', 'fooz') {|_| [IdentityCache::CACHED_NIL] })
|
74
|
-
assert_equal(expected_hash, IdentityCache.cache.memoized_key_values)
|
75
|
-
backend.delete('foo')
|
76
|
-
backend.write('fooz', 'baz')
|
77
|
-
assert_equal(expected_hash, IdentityCache.cache.fetch_multi('foo', 'fooz'))
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def test_fetch_multi_with_partially_memoized_should_read_missing_keys_from_memcache
|
82
|
-
IdentityCache.cache.write('foo', 'bar')
|
83
|
-
@backend.write('fooz', 'baz')
|
84
|
-
|
85
|
-
IdentityCache.cache.with_memoization do
|
86
|
-
assert_equal({'foo' => 'bar', 'fooz' => 'baz'}, IdentityCache.cache.fetch_multi('foo', 'fooz'))
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def test_fetch_multi_with_blank_values_should_not_hit_the_cache_engine
|
91
|
-
@backend.expects(:fetch_multi).never
|
92
|
-
|
93
|
-
IdentityCache.cache.with_memoization do
|
94
|
-
IdentityCache.cache.write('foo', [])
|
95
|
-
IdentityCache.cache.write('bar', false)
|
96
|
-
IdentityCache.cache.write('baz', {})
|
97
|
-
assert_equal({'foo' => [], 'bar' => false, 'baz' => {}}, IdentityCache.cache.fetch_multi('foo', 'bar', 'baz'))
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def test_with_memoization_should_not_clear_rails_cache_when_the_block_ends
|
102
|
-
IdentityCache.cache.with_memoization do
|
103
|
-
IdentityCache.cache.write('foo', 'bar')
|
104
|
-
end
|
105
|
-
assert_equal 'bar', @backend.fetch('foo')
|
106
|
-
end
|
107
|
-
end
|
@@ -1,107 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class NormalizedBelongsToTest < IdentityCache::TestCase
|
4
|
-
def setup
|
5
|
-
super
|
6
|
-
AssociatedRecord.cache_belongs_to :item, :embed => false
|
7
|
-
|
8
|
-
@parent_record = Item.new(:title => 'foo')
|
9
|
-
@parent_record.associated_records << AssociatedRecord.new(:name => 'bar')
|
10
|
-
@parent_record.save
|
11
|
-
@parent_record.reload
|
12
|
-
@record = @parent_record.associated_records.first
|
13
|
-
# Reset association cache, so we remove the inverse of in memory reference
|
14
|
-
@record.association(:item).reset
|
15
|
-
end
|
16
|
-
|
17
|
-
def test_fetching_the_association_should_delegate_to_the_normal_association_fetcher_if_any_transactions_are_open
|
18
|
-
Item.expects(:fetch_by_id).never
|
19
|
-
@record.transaction do
|
20
|
-
assert_equal @parent_record, @record.fetch_item
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_fetching_the_association_should_delegate_to_the_normal_association_fetcher_if_the_normal_association_is_loaded
|
25
|
-
# Warm the ActiveRecord association
|
26
|
-
@record.item
|
27
|
-
|
28
|
-
Item.expects(:fetch_by_id).never
|
29
|
-
assert_equal @parent_record, @record.fetch_item
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_fetching_the_association_should_fetch_the_record_from_identity_cache
|
33
|
-
Item.expects(:fetch_by_id).with(@parent_record.id).returns(@parent_record)
|
34
|
-
assert_equal @parent_record, @record.fetch_item
|
35
|
-
end
|
36
|
-
|
37
|
-
def test_fetching_the_association_should_assign_the_result_to_an_instance_variable_so_that_successive_accesses_are_cached
|
38
|
-
Item.expects(:fetch_by_id).with(@parent_record.id).returns(@parent_record)
|
39
|
-
assert_equal @parent_record, @record.fetch_item
|
40
|
-
assert_equal false, @record.association(:item).loaded?
|
41
|
-
assert_equal @parent_record, @record.fetch_item
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_fetching_the_association_should_cache_nil_and_not_raise_if_the_record_cant_be_found
|
45
|
-
Item.expects(:fetch_by_id).with(@parent_record.id).returns(nil)
|
46
|
-
assert_nil @record.fetch_item # miss
|
47
|
-
assert_nil @record.fetch_item # hit
|
48
|
-
end
|
49
|
-
|
50
|
-
def test_cache_belongs_to_on_derived_model_raises
|
51
|
-
assert_raises(IdentityCache::DerivedModelError) do
|
52
|
-
StiRecordTypeA.cache_belongs_to :item, :embed => false
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def test_fetching_polymorphic_belongs_to_association
|
57
|
-
PolymorphicRecord.include IdentityCache
|
58
|
-
PolymorphicRecord.cache_belongs_to :owner
|
59
|
-
PolymorphicRecord.create!(owner: @parent_record)
|
60
|
-
|
61
|
-
assert_equal @parent_record, PolymorphicRecord.first.fetch_owner
|
62
|
-
end
|
63
|
-
|
64
|
-
def test_returned_record_should_be_readonly_on_cache_hit
|
65
|
-
IdentityCache.with_fetch_read_only_records do
|
66
|
-
@record.fetch_item # warm cache
|
67
|
-
assert @record.fetch_item.readonly?
|
68
|
-
refute @record.item.readonly?
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def test_returned_record_should_be_readonly_on_cache_miss
|
73
|
-
IdentityCache.with_fetch_read_only_records do
|
74
|
-
assert @record.fetch_item.readonly?
|
75
|
-
refute @record.item.readonly?
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def test_db_returned_record_should_never_be_readonly
|
80
|
-
IdentityCache.with_fetch_read_only_records do
|
81
|
-
uncached_record = @record.item
|
82
|
-
refute uncached_record.readonly?
|
83
|
-
@record.fetch_item
|
84
|
-
refute uncached_record.readonly?
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def test_returned_record_with_open_transactions_should_not_be_readonly
|
89
|
-
IdentityCache.with_fetch_read_only_records do
|
90
|
-
Item.transaction do
|
91
|
-
refute IdentityCache.should_use_cache?
|
92
|
-
refute @record.fetch_item.readonly?
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def test_respects_should_use_cache_on_parent
|
98
|
-
@record.reload
|
99
|
-
@parent_record.class.stubs(:should_use_cache?).returns(false)
|
100
|
-
|
101
|
-
assert_queries(1) do
|
102
|
-
assert_memcache_operations(0) do
|
103
|
-
@record.fetch_item
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
@@ -1,231 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class NormalizedHasManyTest < IdentityCache::TestCase
|
4
|
-
def setup
|
5
|
-
super
|
6
|
-
Item.cache_has_many :associated_records, :embed => :ids
|
7
|
-
|
8
|
-
@record = Item.new(:title => 'foo')
|
9
|
-
@record.not_cached_records << NotCachedRecord.new(:name => 'NoCache')
|
10
|
-
@record.associated_records << AssociatedRecord.new(:name => 'bar')
|
11
|
-
@record.associated_records << AssociatedRecord.new(:name => 'baz')
|
12
|
-
@record.save
|
13
|
-
@record.reload
|
14
|
-
@baz, @bar = @record.associated_records[0], @record.associated_records[1]
|
15
|
-
@not_cached = @record.not_cached_records.first
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_a_records_list_of_associated_ids_on_the_parent_record_retains_association_sort_order
|
19
|
-
assert_equal [2, 1], @record.associated_record_ids
|
20
|
-
|
21
|
-
AssociatedRecord.create(name: 'foo', item_id: @record.id)
|
22
|
-
@record.reload
|
23
|
-
assert_equal [3, 2, 1], @record.associated_record_ids
|
24
|
-
end
|
25
|
-
|
26
|
-
def test_defining_a_denormalized_has_many_cache_caches_the_list_of_associated_ids_on_the_parent_record_during_cache_miss
|
27
|
-
fetched_record = Item.fetch(@record.id)
|
28
|
-
assert_equal [2, 1], fetched_record.cached_associated_record_ids
|
29
|
-
assert_equal false, fetched_record.associated_records.loaded?
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_batch_fetching_of_association_for_multiple_parent_records
|
33
|
-
record2 = Item.new(:title => 'two')
|
34
|
-
record2.associated_records << AssociatedRecord.new(:name => 'a')
|
35
|
-
record2.associated_records << AssociatedRecord.new(:name => 'b')
|
36
|
-
record2.save!
|
37
|
-
|
38
|
-
fetched_records = assert_queries(2) do
|
39
|
-
Item.fetch_multi(@record.id, record2.id)
|
40
|
-
end
|
41
|
-
assert_equal [[2, 1], [4, 3]], fetched_records.map(&:cached_associated_record_ids)
|
42
|
-
assert_equal false, fetched_records.any?{ |record| record.associated_records.loaded? }
|
43
|
-
end
|
44
|
-
|
45
|
-
def test_batch_fetching_of_deeply_associated_records
|
46
|
-
Item.has_many :denormalized_associated_records, class_name: 'AssociatedRecord'
|
47
|
-
Item.cache_has_many :denormalized_associated_records, embed: true
|
48
|
-
AssociatedRecord.cache_has_many :deeply_associated_records, embed: :ids
|
49
|
-
@record.associated_records[0].deeply_associated_records << DeeplyAssociatedRecord.new(:name => 'deep1')
|
50
|
-
@record.associated_records[1].deeply_associated_records << DeeplyAssociatedRecord.new(:name => 'deep2')
|
51
|
-
@record.associated_records.each(&:save!)
|
52
|
-
|
53
|
-
fetched_records = assert_queries(4) do
|
54
|
-
Item.fetch(@record.id)
|
55
|
-
end
|
56
|
-
assert_no_queries do
|
57
|
-
assert_equal [[1], [2]], fetched_records.fetch_denormalized_associated_records.map(&:cached_deeply_associated_record_ids)
|
58
|
-
assert_equal false, fetched_records.fetch_denormalized_associated_records.any?{ |record| record.deeply_associated_records.loaded? }
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def test_batch_fetching_stops_with_nil_parent
|
63
|
-
Item.cache_has_one :associated, embed: true
|
64
|
-
AssociatedRecord.cache_has_many :deeply_associated_records, embed: :ids
|
65
|
-
AssociatedRecord.delete_all
|
66
|
-
|
67
|
-
fetched_records = assert_queries(3) do
|
68
|
-
Item.fetch(@record.id)
|
69
|
-
end
|
70
|
-
assert_no_queries do
|
71
|
-
assert_equal @record, fetched_records
|
72
|
-
assert_nil fetched_records.fetch_associated
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def test_fetching_associated_ids_will_populate_the_value_if_the_record_isnt_from_the_cache
|
77
|
-
assert_equal [2, 1], @record.fetch_associated_record_ids
|
78
|
-
end
|
79
|
-
|
80
|
-
def test_fetching_associated_ids_will_use_the_cached_value_if_the_record_is_from_the_cache
|
81
|
-
@record = Item.fetch(@record.id)
|
82
|
-
assert_queries(0) do
|
83
|
-
assert_equal [2, 1], @record.fetch_associated_record_ids
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def test_the_cached_the_list_of_associated_ids_on_the_parent_record_should_not_be_populated_by_default
|
88
|
-
assert_nil @record.cached_associated_record_ids
|
89
|
-
end
|
90
|
-
|
91
|
-
def test_fetching_the_association_should_fetch_each_record_by_id
|
92
|
-
assert_equal [@baz, @bar], @record.fetch_associated_records
|
93
|
-
end
|
94
|
-
|
95
|
-
def test_fetching_the_association_from_a_record_on_a_cache_hit_should_not_issue_any_queries
|
96
|
-
# Populate the cache
|
97
|
-
@record = Item.fetch(@record.id)
|
98
|
-
@record.fetch_associated_records
|
99
|
-
assert_queries(0) do
|
100
|
-
@record = Item.fetch(@record.id)
|
101
|
-
assert_equal [@baz, @bar], @record.fetch_associated_records
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def test_fetching_the_association_from_a_identity_cached_record_should_not_re_fetch_the_association_ids
|
106
|
-
@record = Item.fetch(@record.id)
|
107
|
-
@record.expects(:associated_record_ids).never
|
108
|
-
assert_equal [@baz, @bar], @record.fetch_associated_records
|
109
|
-
end
|
110
|
-
|
111
|
-
def test_fetching_the_association_should_delegate_to_the_normal_association_fetcher_if_any_transaction_are_open
|
112
|
-
@record = Item.fetch(@record.id)
|
113
|
-
|
114
|
-
assert_memcache_operations(0) do
|
115
|
-
@record.transaction do
|
116
|
-
assert_equal [@baz, @bar], @record.fetch_associated_records
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def test_fetching_the_association_should_delegate_to_the_normal_association_fetcher_if_the_normal_association_is_loaded
|
122
|
-
# Warm the ActiveRecord association
|
123
|
-
@record.associated_records.to_a
|
124
|
-
|
125
|
-
assert_memcache_operations(0) do
|
126
|
-
assert_equal [@baz, @bar], @record.fetch_associated_records
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
def test_saving_a_child_record_shouldnt_expire_the_parents_blob_if_the_foreign_key_hasnt_changed
|
131
|
-
IdentityCache.cache.expects(:delete).with(@record.primary_cache_index_key).never
|
132
|
-
IdentityCache.cache.expects(:delete).with(@baz.primary_cache_index_key)
|
133
|
-
@baz.name = 'foo'
|
134
|
-
@baz.save!
|
135
|
-
assert_equal [@baz.id, @bar.id], Item.fetch(@record.id).cached_associated_record_ids
|
136
|
-
assert_equal [@baz, @bar], Item.fetch(@record.id).fetch_associated_records
|
137
|
-
end
|
138
|
-
|
139
|
-
def test_creating_a_child_record_should_expire_the_parents_cache_blob
|
140
|
-
IdentityCache.cache.expects(:delete).with(@record.primary_cache_index_key).once
|
141
|
-
IdentityCache.cache.expects(:delete).with(@bar.primary_cache_index_key[0...-1] + '3')
|
142
|
-
@qux = @record.associated_records.create!(:name => 'qux')
|
143
|
-
assert_equal [@qux, @baz, @bar], Item.fetch(@record.id).fetch_associated_records
|
144
|
-
end
|
145
|
-
|
146
|
-
def test_saving_a_child_record_should_expire_the_new_and_old_parents_cache_blob
|
147
|
-
@new_record = Item.create
|
148
|
-
@baz.item = @new_record
|
149
|
-
|
150
|
-
IdentityCache.cache.expects(:delete).with(@record.primary_cache_index_key).once
|
151
|
-
IdentityCache.cache.expects(:delete).with(@new_record.primary_cache_index_key).once
|
152
|
-
IdentityCache.cache.expects(:delete).with(@baz.primary_cache_index_key).once
|
153
|
-
|
154
|
-
@baz.save!
|
155
|
-
|
156
|
-
assert_equal [@bar.id], Item.fetch(@record.id).cached_associated_record_ids
|
157
|
-
assert_equal [@bar], Item.fetch(@record.id).fetch_associated_records
|
158
|
-
end
|
159
|
-
|
160
|
-
def test_saving_a_child_record_in_a_transaction_should_expire_the_new_and_old_parents_cache_blob
|
161
|
-
@new_record = Item.create
|
162
|
-
@baz.item_id = @new_record.id
|
163
|
-
|
164
|
-
@baz.transaction do
|
165
|
-
IdentityCache.cache.expects(:delete).with(@record.primary_cache_index_key).once
|
166
|
-
IdentityCache.cache.expects(:delete).with(@new_record.primary_cache_index_key).once
|
167
|
-
IdentityCache.cache.expects(:delete).with(@baz.primary_cache_index_key).once
|
168
|
-
|
169
|
-
@baz.save!
|
170
|
-
@baz.reload
|
171
|
-
end
|
172
|
-
|
173
|
-
assert_equal [@bar.id], Item.fetch(@record.id).cached_associated_record_ids
|
174
|
-
assert_equal [@bar], Item.fetch(@record.id).fetch_associated_records
|
175
|
-
end
|
176
|
-
|
177
|
-
def test_destroying_a_child_record_should_expire_the_parents_cache_blob
|
178
|
-
IdentityCache.cache.expects(:delete).with(@record.primary_cache_index_key).once
|
179
|
-
IdentityCache.cache.expects(:delete).with(@baz.primary_cache_index_key).once
|
180
|
-
@baz.destroy
|
181
|
-
assert_equal [@bar], @record.reload.fetch_associated_records
|
182
|
-
end
|
183
|
-
|
184
|
-
def test_saving_a_child_record_should_expire_only_itself
|
185
|
-
IdentityCache.cache.expects(:delete).with(@baz.primary_cache_index_key).once
|
186
|
-
@baz.save!
|
187
|
-
end
|
188
|
-
|
189
|
-
def test_touching_child_with_touch_true_on_parent_expires_parent
|
190
|
-
IdentityCache.cache.expects(:delete).with(@record.primary_cache_index_key).once
|
191
|
-
@not_cached.touch
|
192
|
-
end
|
193
|
-
|
194
|
-
def test_saving_child_with_touch_true_on_parent_expires_parent
|
195
|
-
IdentityCache.cache.expects(:delete).with(@record.primary_cache_index_key).once
|
196
|
-
@not_cached.name = 'Changed'
|
197
|
-
@not_cached.save!
|
198
|
-
end
|
199
|
-
|
200
|
-
def test_fetch_association_does_not_allow_chaining
|
201
|
-
check = proc { assert_equal false, Item.fetch(@record.id).fetch_associated_records.respond_to?(:where) }
|
202
|
-
2.times { check.call } # for miss and hit
|
203
|
-
Item.transaction { check.call }
|
204
|
-
end
|
205
|
-
|
206
|
-
def test_returned_records_should_be_readonly_on_cache_hit
|
207
|
-
IdentityCache.with_fetch_read_only_records do
|
208
|
-
Item.fetch(@record.id) # warm cache
|
209
|
-
record_from_cache_hit = Item.fetch(@record.id)
|
210
|
-
record_from_cache_hit.fetch_associated_records.all?(&:readonly?)
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
def test_returned_records_should_be_readonly_on_cache_miss
|
215
|
-
IdentityCache.with_fetch_read_only_records do
|
216
|
-
record_from_cache_miss = Item.fetch(@record.id)
|
217
|
-
assert record_from_cache_miss.fetch_associated_records.all?(&:readonly?)
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
def test_respects_should_use_cache_on_association
|
222
|
-
@record.reload
|
223
|
-
AssociatedRecord.stubs(:should_use_cache?).returns(false)
|
224
|
-
|
225
|
-
assert_queries(1) do
|
226
|
-
assert_memcache_operations(0) do
|
227
|
-
@record.fetch_associated_records
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
|
-
end
|