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.
- 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
@@ -6,83 +6,83 @@ class CacheFetchIncludesTest < IdentityCache::TestCase
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def test_cached_embedded_has_manys_are_included_in_includes
|
9
|
-
|
10
|
-
assert_equal [:associated_records],
|
9
|
+
Item.send(:cache_has_many, :associated_records, :embed => true)
|
10
|
+
assert_equal [:associated_records], Item.cache_fetch_includes
|
11
11
|
end
|
12
12
|
|
13
13
|
def test_cached_nonembedded_has_manys_are_included_in_includes
|
14
|
-
|
15
|
-
assert_equal [],
|
14
|
+
Item.send(:cache_has_many, :associated_records, :embed => false)
|
15
|
+
assert_equal [], Item.cache_fetch_includes
|
16
16
|
end
|
17
17
|
|
18
18
|
def test_cached_has_ones_are_included_in_includes
|
19
|
-
|
20
|
-
assert_equal [:associated],
|
19
|
+
Item.send(:cache_has_one, :associated)
|
20
|
+
assert_equal [:associated], Item.cache_fetch_includes
|
21
21
|
end
|
22
22
|
|
23
23
|
def test_cached_nonembedded_belongs_tos_are_not_included_in_includes
|
24
|
-
|
25
|
-
assert_equal [],
|
24
|
+
Item.send(:cache_belongs_to, :item)
|
25
|
+
assert_equal [], Item.cache_fetch_includes
|
26
26
|
end
|
27
27
|
|
28
28
|
def test_cached_child_associations_are_included_in_includes
|
29
|
-
|
29
|
+
Item.send(:cache_has_many, :associated_records, :embed => true)
|
30
30
|
AssociatedRecord.send(:cache_has_many, :deeply_associated_records, :embed => true)
|
31
|
-
assert_equal [{:associated_records => [:deeply_associated_records]}],
|
31
|
+
assert_equal [{:associated_records => [:deeply_associated_records]}], Item.cache_fetch_includes
|
32
32
|
end
|
33
33
|
|
34
34
|
def test_multiple_cached_associations_and_child_associations_are_included_in_includes
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
Item.send(:cache_has_many, :associated_records, :embed => true)
|
36
|
+
Item.send(:cache_has_many, :polymorphic_records, {:inverse_name => :owner, :embed => true})
|
37
|
+
Item.send(:cache_has_one, :associated, :embed => true)
|
38
38
|
AssociatedRecord.send(:cache_has_many, :deeply_associated_records, :embed => true)
|
39
39
|
assert_equal [
|
40
40
|
{:associated_records => [:deeply_associated_records]},
|
41
41
|
:polymorphic_records,
|
42
42
|
{:associated => [:deeply_associated_records]}
|
43
|
-
],
|
43
|
+
], Item.cache_fetch_includes
|
44
44
|
end
|
45
45
|
|
46
46
|
def test_empty_additions_for_top_level_associations_makes_no_difference
|
47
|
-
|
48
|
-
assert_equal [:associated_records],
|
47
|
+
Item.send(:cache_has_many, :associated_records, :embed => true)
|
48
|
+
assert_equal [:associated_records], Item.cache_fetch_includes({})
|
49
49
|
end
|
50
50
|
|
51
51
|
def test_top_level_additions_are_included_in_includes
|
52
|
-
assert_equal [{:associated_records => []}],
|
52
|
+
assert_equal [{:associated_records => []}], Item.cache_fetch_includes({:associated_records => []})
|
53
53
|
end
|
54
54
|
|
55
55
|
def test_top_level_additions_alongside_top_level_cached_associations_are_included_in_includes
|
56
|
-
|
56
|
+
Item.send(:cache_has_many, :associated_records, :embed => true)
|
57
57
|
assert_equal [
|
58
58
|
:associated_records,
|
59
59
|
{:polymorphic_records => []}
|
60
|
-
],
|
60
|
+
], Item.cache_fetch_includes({:polymorphic_records => []})
|
61
61
|
end
|
62
62
|
|
63
63
|
def test_child_level_additions_for_top_level_cached_associations_are_included_in_includes
|
64
|
-
|
64
|
+
Item.send(:cache_has_many, :associated_records, :embed => true)
|
65
65
|
assert_equal [
|
66
66
|
{:associated_records => [{:deeply_associated_records => []}]}
|
67
|
-
],
|
67
|
+
], Item.cache_fetch_includes({:associated_records => :deeply_associated_records})
|
68
68
|
end
|
69
69
|
|
70
70
|
def test_array_child_level_additions_for_top_level_cached_associations_are_included_in_includes
|
71
|
-
|
71
|
+
Item.send(:cache_has_many, :associated_records, :embed => true)
|
72
72
|
assert_equal [
|
73
73
|
{:associated_records => [{:deeply_associated_records => []}]}
|
74
|
-
],
|
74
|
+
], Item.cache_fetch_includes({:associated_records => [:deeply_associated_records]})
|
75
75
|
end
|
76
76
|
|
77
77
|
def test_array_child_level_additions_for_child_level_cached_associations_are_included_in_includes
|
78
|
-
|
78
|
+
Item.send(:cache_has_many, :associated_records, :embed => true)
|
79
79
|
AssociatedRecord.send(:cache_has_many, :deeply_associated_records, :embed => true)
|
80
80
|
assert_equal [
|
81
81
|
{:associated_records => [
|
82
82
|
:deeply_associated_records,
|
83
83
|
{:record => []}
|
84
84
|
]}
|
85
|
-
],
|
85
|
+
], Item.cache_fetch_includes({:associated_records => [:record]})
|
86
86
|
end
|
87
87
|
|
88
88
|
end
|
@@ -3,9 +3,9 @@ require "test_helper"
|
|
3
3
|
class DenormalizedHasManyTest < IdentityCache::TestCase
|
4
4
|
def setup
|
5
5
|
super
|
6
|
-
|
6
|
+
Item.cache_has_many :associated_records, :embed => true
|
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.save
|
@@ -14,27 +14,27 @@ class DenormalizedHasManyTest < IdentityCache::TestCase
|
|
14
14
|
|
15
15
|
def test_uncached_record_from_the_db_will_use_normal_association
|
16
16
|
expected = @record.associated_records
|
17
|
-
record_from_db =
|
17
|
+
record_from_db = Item.find(@record.id)
|
18
18
|
|
19
|
-
|
19
|
+
Item.any_instance.expects(:associated_records).returns(expected)
|
20
20
|
|
21
21
|
assert_equal @record, record_from_db
|
22
22
|
assert_equal expected, record_from_db.fetch_associated_records
|
23
23
|
end
|
24
24
|
|
25
25
|
def test_on_cache_hit_record_should_come_back_with_cached_association
|
26
|
-
|
26
|
+
Item.fetch(@record.id) # warm cache
|
27
27
|
|
28
|
-
record_from_cache_hit =
|
28
|
+
record_from_cache_hit = Item.fetch(@record.id)
|
29
29
|
assert_equal @record, record_from_cache_hit
|
30
30
|
|
31
31
|
expected = @record.associated_records
|
32
|
-
|
32
|
+
Item.any_instance.expects(:associated_records).never
|
33
33
|
assert_equal expected, record_from_cache_hit.fetch_associated_records
|
34
34
|
end
|
35
35
|
|
36
36
|
def test_on_cache_miss_record_should_embed_associated_objects_and_return
|
37
|
-
record_from_cache_miss =
|
37
|
+
record_from_cache_miss = Item.fetch(@record.id)
|
38
38
|
expected = @record.associated_records
|
39
39
|
|
40
40
|
assert_equal @record, record_from_cache_miss
|
@@ -42,10 +42,11 @@ class DenormalizedHasManyTest < IdentityCache::TestCase
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def test_changes_in_associated_records_should_expire_the_parents_cache
|
45
|
-
|
45
|
+
Item.fetch(@record.id)
|
46
46
|
key = @record.primary_cache_index_key
|
47
47
|
assert_not_nil IdentityCache.cache.read(key)
|
48
48
|
|
49
|
+
IdentityCache.cache.expects(:delete).with(@record.associated_records.first.primary_cache_index_key)
|
49
50
|
IdentityCache.cache.expects(:delete).with(key)
|
50
51
|
@record.associated_records.first.save
|
51
52
|
end
|
@@ -53,12 +54,13 @@ class DenormalizedHasManyTest < IdentityCache::TestCase
|
|
53
54
|
def test_changes_in_associated_records_foreign_keys_should_expire_new_parent_and_old_parents_cache
|
54
55
|
@associatated_record = @record.associated_records.first
|
55
56
|
old_key = @record.primary_cache_index_key
|
56
|
-
@new_record =
|
57
|
+
@new_record = Item.create
|
57
58
|
new_key = @new_record.primary_cache_index_key
|
58
59
|
|
60
|
+
IdentityCache.cache.expects(:delete).with(@associatated_record.primary_cache_index_key)
|
59
61
|
IdentityCache.cache.expects(:delete).with(old_key)
|
60
62
|
IdentityCache.cache.expects(:delete).with(new_key)
|
61
|
-
@associatated_record.
|
63
|
+
@associatated_record.item_id = @new_record.id
|
62
64
|
@associatated_record.save!
|
63
65
|
end
|
64
66
|
|
@@ -70,13 +72,13 @@ class DenormalizedHasManyTest < IdentityCache::TestCase
|
|
70
72
|
|
71
73
|
def test_cache_without_guessable_inverse_name_raises
|
72
74
|
assert_raises IdentityCache::InverseAssociationError do
|
73
|
-
|
75
|
+
Item.cache_has_many :polymorphic_records, :embed => true
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
77
79
|
def test_cache_without_guessable_inverse_name_does_not_raise_when_inverse_name_specified
|
78
80
|
assert_nothing_raised do
|
79
|
-
|
81
|
+
Item.cache_has_many :polymorphic_records, :inverse_name => :owner, :embed => true
|
80
82
|
end
|
81
83
|
end
|
82
84
|
|
@@ -3,9 +3,9 @@ require "test_helper"
|
|
3
3
|
class DenormalizedHasOneTest < IdentityCache::TestCase
|
4
4
|
def setup
|
5
5
|
super
|
6
|
-
|
7
|
-
|
8
|
-
@record =
|
6
|
+
Item.cache_has_one :associated
|
7
|
+
Item.cache_index :title, :unique => true
|
8
|
+
@record = Item.new(:title => 'foo')
|
9
9
|
@record.associated = AssociatedRecord.new(:name => 'bar')
|
10
10
|
@record.save
|
11
11
|
|
@@ -16,7 +16,7 @@ class DenormalizedHasOneTest < IdentityCache::TestCase
|
|
16
16
|
IdentityCache.cache.expects(:read).with(@record.secondary_cache_index_key_for_current_values([:title]))
|
17
17
|
IdentityCache.cache.expects(:read).with(@record.primary_cache_index_key)
|
18
18
|
|
19
|
-
record_from_cache_miss =
|
19
|
+
record_from_cache_miss = Item.fetch_by_title('foo')
|
20
20
|
|
21
21
|
assert_equal @record, record_from_cache_miss
|
22
22
|
assert_not_nil @record.fetch_associated
|
@@ -28,11 +28,13 @@ class DenormalizedHasOneTest < IdentityCache::TestCase
|
|
28
28
|
@record.associated = nil
|
29
29
|
@record.save!
|
30
30
|
@record.reload
|
31
|
-
|
31
|
+
@record.populate_association_caches
|
32
|
+
Item.expects(:resolve_cache_miss).with(@record.id).once.returns(@record)
|
33
|
+
|
32
34
|
IdentityCache.cache.expects(:read).with(@record.secondary_cache_index_key_for_current_values([:title]))
|
33
35
|
IdentityCache.cache.expects(:read).with(@record.primary_cache_index_key)
|
34
36
|
|
35
|
-
record_from_cache_miss =
|
37
|
+
record_from_cache_miss = Item.fetch_by_title('foo')
|
36
38
|
record_from_cache_miss.expects(:associated).never
|
37
39
|
|
38
40
|
assert_equal @record, record_from_cache_miss
|
@@ -42,17 +44,18 @@ class DenormalizedHasOneTest < IdentityCache::TestCase
|
|
42
44
|
end
|
43
45
|
|
44
46
|
def test_on_record_from_the_db_will_use_normal_association
|
45
|
-
record_from_db =
|
47
|
+
record_from_db = Item.find_by_title('foo')
|
46
48
|
|
47
49
|
assert_equal @record, record_from_db
|
48
50
|
assert_not_nil record_from_db.fetch_associated
|
49
51
|
end
|
50
52
|
|
51
53
|
def test_on_cache_hit_record_should_come_back_with_cached_association
|
52
|
-
|
53
|
-
|
54
|
+
@record.populate_association_caches
|
55
|
+
Item.expects(:resolve_cache_miss).with(1).once.returns(@record)
|
56
|
+
Item.fetch_by_title('foo')
|
54
57
|
|
55
|
-
record_from_cache_hit =
|
58
|
+
record_from_cache_hit = Item.fetch_by_title('foo')
|
56
59
|
expected = @record.associated
|
57
60
|
|
58
61
|
assert_equal @record, record_from_cache_hit
|
@@ -64,10 +67,11 @@ class DenormalizedHasOneTest < IdentityCache::TestCase
|
|
64
67
|
@record.save!
|
65
68
|
@record.reload
|
66
69
|
|
67
|
-
|
68
|
-
|
70
|
+
@record.populate_association_caches
|
71
|
+
Item.expects(:resolve_cache_miss).with(1).once.returns(@record)
|
72
|
+
Item.fetch_by_title('foo')
|
69
73
|
|
70
|
-
record_from_cache_hit =
|
74
|
+
record_from_cache_hit = Item.fetch_by_title('foo')
|
71
75
|
record_from_cache_hit.expects(:associated).never
|
72
76
|
|
73
77
|
assert_equal @record, record_from_cache_hit
|
@@ -77,11 +81,13 @@ class DenormalizedHasOneTest < IdentityCache::TestCase
|
|
77
81
|
end
|
78
82
|
|
79
83
|
def test_changes_in_associated_record_should_expire_the_parents_cache
|
80
|
-
|
84
|
+
Item.fetch_by_title('foo')
|
81
85
|
key = @record.primary_cache_index_key
|
82
86
|
assert_not_nil IdentityCache.cache.read(key)
|
83
87
|
|
84
88
|
IdentityCache.cache.expects(:delete).at_least(1).with(key)
|
89
|
+
IdentityCache.cache.expects(:delete).with(@record.associated.primary_cache_index_key)
|
90
|
+
|
85
91
|
@record.associated.save
|
86
92
|
end
|
87
93
|
|
@@ -93,13 +99,13 @@ class DenormalizedHasOneTest < IdentityCache::TestCase
|
|
93
99
|
|
94
100
|
def test_cache_without_guessable_inverse_name_raises
|
95
101
|
assert_raises IdentityCache::InverseAssociationError do
|
96
|
-
|
102
|
+
Item.cache_has_one :polymorphic_record, :embed => true
|
97
103
|
end
|
98
104
|
end
|
99
105
|
|
100
106
|
def test_cache_without_guessable_inverse_name_does_not_raise_when_inverse_name_specified
|
101
107
|
assert_nothing_raised do
|
102
|
-
|
108
|
+
Item.cache_has_one :polymorphic_record, :inverse_name => :owner, :embed => true
|
103
109
|
end
|
104
110
|
end
|
105
111
|
end
|
data/test/fetch_multi_test.rb
CHANGED
@@ -1,32 +1,32 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class FetchMultiTest < IdentityCache::TestCase
|
4
|
-
NAMESPACE = IdentityCache
|
4
|
+
NAMESPACE = IdentityCache.cache_namespace
|
5
5
|
|
6
6
|
def setup
|
7
7
|
super
|
8
|
-
@bob =
|
9
|
-
@joe =
|
10
|
-
@fred =
|
11
|
-
@bob_blob_key = "#{NAMESPACE}blob:
|
12
|
-
@joe_blob_key = "#{NAMESPACE}blob:
|
13
|
-
@fred_blob_key = "#{NAMESPACE}blob:
|
14
|
-
@tenth_blob_key = "#{NAMESPACE}blob:
|
8
|
+
@bob = Item.create!(:title => 'bob')
|
9
|
+
@joe = Item.create!(:title => 'joe')
|
10
|
+
@fred = Item.create!(:title => 'fred')
|
11
|
+
@bob_blob_key = "#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:1"
|
12
|
+
@joe_blob_key = "#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:2"
|
13
|
+
@fred_blob_key = "#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:3"
|
14
|
+
@tenth_blob_key = "#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:10"
|
15
15
|
end
|
16
16
|
|
17
17
|
def test_fetch_multi_with_no_records
|
18
|
-
assert_equal [],
|
18
|
+
assert_equal [], Item.fetch_multi
|
19
19
|
end
|
20
20
|
|
21
21
|
def test_fetch_multi_namespace
|
22
|
-
|
22
|
+
Item.send(:include, SwitchNamespace)
|
23
23
|
bob_blob_key, joe_blob_key, fred_blob_key = [@bob_blob_key, @joe_blob_key, @fred_blob_key].map { |k| "ns:#{k}" }
|
24
24
|
cache_response = {}
|
25
25
|
cache_response[bob_blob_key] = cache_response_for(@bob)
|
26
26
|
cache_response[joe_blob_key] = cache_response_for(@joe)
|
27
27
|
cache_response[fred_blob_key] = cache_response_for(@fred)
|
28
28
|
IdentityCache.cache.expects(:read_multi).with(bob_blob_key, joe_blob_key, fred_blob_key).returns(cache_response)
|
29
|
-
assert_equal [@bob, @joe, @fred],
|
29
|
+
assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id)
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_fetch_multi_with_all_hits
|
@@ -35,7 +35,7 @@ class FetchMultiTest < IdentityCache::TestCase
|
|
35
35
|
cache_response[@joe_blob_key] = cache_response_for(@joe)
|
36
36
|
cache_response[@fred_blob_key] = cache_response_for(@fred)
|
37
37
|
IdentityCache.cache.expects(:read_multi).with(@bob_blob_key, @joe_blob_key, @fred_blob_key).returns(cache_response)
|
38
|
-
assert_equal [@bob, @joe, @fred],
|
38
|
+
assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id)
|
39
39
|
end
|
40
40
|
|
41
41
|
def test_fetch_multi_with_all_misses
|
@@ -44,7 +44,7 @@ class FetchMultiTest < IdentityCache::TestCase
|
|
44
44
|
cache_response[@joe_blob_key] = nil
|
45
45
|
cache_response[@fred_blob_key] = nil
|
46
46
|
IdentityCache.cache.expects(:read_multi).with(@bob_blob_key, @joe_blob_key, @fred_blob_key).returns(cache_response)
|
47
|
-
assert_equal [@bob, @joe, @fred],
|
47
|
+
assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id)
|
48
48
|
end
|
49
49
|
|
50
50
|
def test_fetch_multi_with_mixed_hits_and_misses
|
@@ -53,7 +53,7 @@ class FetchMultiTest < IdentityCache::TestCase
|
|
53
53
|
cache_response[@joe_blob_key] = nil
|
54
54
|
cache_response[@fred_blob_key] = cache_response_for(@fred)
|
55
55
|
IdentityCache.cache.expects(:read_multi).with(@bob_blob_key, @joe_blob_key, @fred_blob_key).returns(cache_response)
|
56
|
-
assert_equal [@bob, @joe, @fred],
|
56
|
+
assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id)
|
57
57
|
end
|
58
58
|
|
59
59
|
def test_fetch_multi_with_mixed_hits_and_misses_and_responses_in_the_wrong_order
|
@@ -62,21 +62,21 @@ class FetchMultiTest < IdentityCache::TestCase
|
|
62
62
|
cache_response[@joe_blob_key] = nil
|
63
63
|
cache_response[@fred_blob_key] = cache_response_for(@fred)
|
64
64
|
IdentityCache.cache.expects(:read_multi).with(@bob_blob_key, @fred_blob_key, @joe_blob_key).returns(cache_response)
|
65
|
-
assert_equal [@bob, @fred, @joe],
|
65
|
+
assert_equal [@bob, @fred, @joe], Item.fetch_multi(@bob.id, @fred.id, @joe.id)
|
66
66
|
end
|
67
67
|
|
68
68
|
def test_fetch_multi_with_mixed_hits_and_misses_and_non_existant_keys_1
|
69
69
|
populate_only_fred
|
70
70
|
|
71
71
|
IdentityCache.cache.expects(:read_multi).with(@tenth_blob_key, @bob_blob_key, @joe_blob_key, @fred_blob_key).returns(@cache_response)
|
72
|
-
assert_equal [@bob, @joe, @fred],
|
72
|
+
assert_equal [@bob, @joe, @fred], Item.fetch_multi(10, @bob.id, @joe.id, @fred.id)
|
73
73
|
end
|
74
74
|
|
75
75
|
def test_fetch_multi_with_mixed_hits_and_misses_and_non_existant_keys_2
|
76
76
|
populate_only_fred
|
77
77
|
|
78
78
|
IdentityCache.cache.expects(:read_multi).with(@fred_blob_key, @bob_blob_key, @tenth_blob_key, @joe_blob_key).returns(@cache_response)
|
79
|
-
assert_equal [@fred, @bob, @joe],
|
79
|
+
assert_equal [@fred, @bob, @joe], Item.fetch_multi(@fred.id, @bob.id, 10, @joe.id)
|
80
80
|
end
|
81
81
|
|
82
82
|
|
@@ -101,31 +101,31 @@ class FetchMultiTest < IdentityCache::TestCase
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def test_fetch_multi_duplicate_ids
|
104
|
-
assert_equal [@joe, @bob, @joe],
|
104
|
+
assert_equal [@joe, @bob, @joe], Item.fetch_multi(@joe.id, @bob.id, @joe.id)
|
105
105
|
end
|
106
106
|
|
107
107
|
def test_fetch_multi_with_open_transactions_hits_the_database
|
108
|
-
|
108
|
+
Item.connection.expects(:open_transactions).at_least_once.returns(1)
|
109
109
|
IdentityCache.cache.expects(:read_multi).never
|
110
|
-
assert_equal [@bob, @joe, @fred],
|
110
|
+
assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id)
|
111
111
|
end
|
112
112
|
|
113
113
|
def test_fetch_multi_with_open_transactions_returns_results_in_the_order_of_the_passed_ids
|
114
|
-
|
115
|
-
assert_equal [@joe, @bob, @fred],
|
114
|
+
Item.connection.expects(:open_transactions).at_least_once.returns(1)
|
115
|
+
assert_equal [@joe, @bob, @fred], Item.fetch_multi(@joe.id, @bob.id, @fred.id)
|
116
116
|
end
|
117
117
|
|
118
118
|
def test_fetch_multi_with_duplicate_ids_in_transaction_returns_results_in_the_order_of_the_passed_ids
|
119
|
-
|
120
|
-
assert_equal [@joe, @bob, @joe],
|
119
|
+
Item.connection.expects(:open_transactions).at_least_once.returns(1)
|
120
|
+
assert_equal [@joe, @bob, @joe], Item.fetch_multi(@joe.id, @bob.id, @joe.id)
|
121
121
|
end
|
122
122
|
|
123
123
|
def test_find_batch_coerces_ids_to_primary_key_type
|
124
124
|
mock_relation = mock("ActiveRecord::Relation")
|
125
|
-
|
126
|
-
mock_relation.expects(:includes).returns(stub(:
|
125
|
+
Item.expects(:where).returns(mock_relation)
|
126
|
+
mock_relation.expects(:includes).returns(stub(:to_a => [@bob, @joe, @fred]))
|
127
127
|
|
128
|
-
|
128
|
+
Item.find_batch([@bob, @joe, @fred].map(&:id).map(&:to_s))
|
129
129
|
end
|
130
130
|
|
131
131
|
def test_fetch_multi_doesnt_freeze_keys
|
@@ -135,7 +135,7 @@ class FetchMultiTest < IdentityCache::TestCase
|
|
135
135
|
|
136
136
|
IdentityCache.expects(:fetch_multi).with{ |*args| args.none?(&:frozen?) }.returns(cache_response)
|
137
137
|
|
138
|
-
|
138
|
+
Item.fetch_multi(@bob.id, @joe.id)
|
139
139
|
end
|
140
140
|
|
141
141
|
private
|
@@ -1,23 +1,23 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
|
-
class
|
4
|
-
NAMESPACE = IdentityCache
|
3
|
+
class FetchMultiWithBatchedAssociationsTest < IdentityCache::TestCase
|
4
|
+
NAMESPACE = IdentityCache.cache_namespace
|
5
5
|
|
6
6
|
def setup
|
7
7
|
super
|
8
|
-
@bob =
|
9
|
-
@joe =
|
10
|
-
@fred =
|
11
|
-
@bob_blob_key = "#{NAMESPACE}blob:
|
12
|
-
@joe_blob_key = "#{NAMESPACE}blob:
|
13
|
-
@fred_blob_key = "#{NAMESPACE}blob:
|
14
|
-
@tenth_blob_key = "#{NAMESPACE}blob:
|
8
|
+
@bob = Item.create!(:title => 'bob')
|
9
|
+
@joe = Item.create!(:title => 'joe')
|
10
|
+
@fred = Item.create!(:title => 'fred')
|
11
|
+
@bob_blob_key = "#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:1"
|
12
|
+
@joe_blob_key = "#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:2"
|
13
|
+
@fred_blob_key = "#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:3"
|
14
|
+
@tenth_blob_key = "#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:10"
|
15
15
|
end
|
16
16
|
|
17
17
|
def test_fetch_multi_includes_cached_associations_in_the_database_find
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
Item.send(:cache_has_many, :associated_records, :embed => true)
|
19
|
+
Item.send(:cache_has_one, :associated)
|
20
|
+
Item.send(:cache_belongs_to, :item)
|
21
21
|
|
22
22
|
cache_response = {}
|
23
23
|
cache_response[@bob_blob_key] = nil
|
@@ -27,15 +27,15 @@ class FetchMultiTest < IdentityCache::TestCase
|
|
27
27
|
IdentityCache.cache.expects(:read_multi).with(@bob_blob_key, @joe_blob_key, @fred_blob_key).returns(cache_response)
|
28
28
|
|
29
29
|
mock_relation = mock("ActiveRecord::Relation")
|
30
|
-
|
31
|
-
mock_relation.expects(:includes).with([:associated_records, :associated]).returns(stub(:
|
32
|
-
assert_equal [@bob, @joe, @fred],
|
30
|
+
Item.expects(:where).returns(mock_relation)
|
31
|
+
mock_relation.expects(:includes).with([:associated_records, :associated]).returns(stub(:to_a => [@bob, @joe, @fred]))
|
32
|
+
assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id)
|
33
33
|
end
|
34
34
|
|
35
35
|
def test_fetch_multi_includes_cached_associations_and_other_asked_for_associations_in_the_database_find
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
Item.send(:cache_has_many, :associated_records, :embed => true)
|
37
|
+
Item.send(:cache_has_one, :associated)
|
38
|
+
Item.send(:cache_belongs_to, :item)
|
39
39
|
|
40
40
|
cache_response = {}
|
41
41
|
cache_response[@bob_blob_key] = nil
|
@@ -45,13 +45,13 @@ class FetchMultiTest < IdentityCache::TestCase
|
|
45
45
|
IdentityCache.cache.expects(:read_multi).with(@bob_blob_key, @joe_blob_key, @fred_blob_key).returns(cache_response)
|
46
46
|
|
47
47
|
mock_relation = mock("ActiveRecord::Relation")
|
48
|
-
|
49
|
-
mock_relation.expects(:includes).with([:associated_records, :associated, {:
|
50
|
-
assert_equal [@bob, @joe, @fred],
|
48
|
+
Item.expects(:where).returns(mock_relation)
|
49
|
+
mock_relation.expects(:includes).with([:associated_records, :associated, {:item => []}]).returns(stub(:to_a => [@bob, @joe, @fred]))
|
50
|
+
assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id, {:includes => :item})
|
51
51
|
end
|
52
52
|
|
53
53
|
def test_fetch_multi_batch_fetches_non_embedded_first_level_has_many_associations
|
54
|
-
|
54
|
+
Item.send(:cache_has_many, :associated_records, :embed => false)
|
55
55
|
|
56
56
|
child_records = []
|
57
57
|
[@bob, @joe].each do |parent|
|
@@ -61,55 +61,55 @@ class FetchMultiTest < IdentityCache::TestCase
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
-
|
64
|
+
Item.fetch_multi(@bob.id, @joe.id) # populate the cache entries and associated children ID variables
|
65
65
|
|
66
66
|
assert_memcache_operations(2) do
|
67
|
-
@cached_bob, @cached_joe =
|
67
|
+
@cached_bob, @cached_joe = Item.fetch_multi(@bob.id, @joe.id, :includes => :associated_records)
|
68
68
|
assert_equal child_records[0..2].sort, @cached_bob.fetch_associated_records.sort
|
69
69
|
assert_equal child_records[3..5].sort, @cached_joe.fetch_associated_records.sort
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
73
|
def test_fetch_multi_batch_fetches_first_level_belongs_to_associations
|
74
|
-
AssociatedRecord.send(:cache_belongs_to, :
|
74
|
+
AssociatedRecord.send(:cache_belongs_to, :item, :embed => false)
|
75
75
|
|
76
76
|
@bob_child = @bob.associated_records.create!(:name => "bob child")
|
77
77
|
@fred_child = @fred.associated_records.create!(:name => "fred child")
|
78
78
|
|
79
79
|
# populate the cache entries and associated children ID variables
|
80
80
|
AssociatedRecord.fetch_multi(@bob_child.id, @fred_child.id)
|
81
|
-
|
81
|
+
Item.fetch_multi(@bob.id, @fred.id)
|
82
82
|
|
83
83
|
assert_memcache_operations(2) do
|
84
|
-
@cached_bob_child, @cached_fred_child = AssociatedRecord.fetch_multi(@bob_child.id, @fred_child.id, :includes => :
|
85
|
-
assert_equal @bob, @cached_bob_child.
|
86
|
-
assert_equal @fred, @cached_fred_child.
|
84
|
+
@cached_bob_child, @cached_fred_child = AssociatedRecord.fetch_multi(@bob_child.id, @fred_child.id, :includes => :item)
|
85
|
+
assert_equal @bob, @cached_bob_child.fetch_item
|
86
|
+
assert_equal @fred, @cached_fred_child.fetch_item
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
90
|
def test_fetch_multi_batch_fetches_first_level_associations_who_dont_include_identity_cache
|
91
|
-
|
92
|
-
|
91
|
+
Item.send(:has_many, :not_cached_records)
|
92
|
+
Item.send(:cache_has_many, :not_cached_records, :embed => true)
|
93
93
|
|
94
94
|
@bob_child = @bob.not_cached_records.create!(:name => "bob child")
|
95
95
|
@fred_child = @fred.not_cached_records.create!(:name => "fred child")
|
96
96
|
|
97
97
|
# populate the cache entries and associated children ID variables
|
98
|
-
|
98
|
+
Item.fetch_multi(@bob.id, @fred.id)
|
99
99
|
|
100
100
|
assert_memcache_operations(1) do
|
101
|
-
@cached_bob_child, @cached_fred_child =
|
101
|
+
@cached_bob_child, @cached_fred_child = Item.fetch_multi(@bob.id, @fred.id, :includes => :not_cached_records)
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
105
|
def test_fetch_multi_batch_fetches_non_embedded_second_level_has_many_associations
|
106
|
-
|
106
|
+
Item.send(:cache_has_many, :associated_records, :embed => false)
|
107
107
|
AssociatedRecord.send(:cache_has_many, :deeply_associated_records, :embed => false)
|
108
108
|
|
109
109
|
child_records, grandchildren = setup_has_many_children_and_grandchildren(@bob, @joe)
|
110
110
|
|
111
111
|
assert_memcache_operations(3) do
|
112
|
-
@cached_bob, @cached_joe =
|
112
|
+
@cached_bob, @cached_joe = Item.fetch_multi(@bob.id, @joe.id, :includes => {:associated_records => :deeply_associated_records})
|
113
113
|
bob_children = @cached_bob.fetch_associated_records.sort
|
114
114
|
joe_children = @cached_joe.fetch_associated_records.sort
|
115
115
|
|
@@ -123,48 +123,48 @@ class FetchMultiTest < IdentityCache::TestCase
|
|
123
123
|
end
|
124
124
|
|
125
125
|
def test_fetch_multi_batch_fetches_non_embedded_second_level_belongs_to_associations
|
126
|
-
|
127
|
-
AssociatedRecord.send(:cache_belongs_to, :
|
126
|
+
Item.send(:cache_belongs_to, :item, :embed => false)
|
127
|
+
AssociatedRecord.send(:cache_belongs_to, :item, :embed => false)
|
128
128
|
|
129
129
|
@bob_child = @bob.associated_records.create!(:name => "bob child")
|
130
130
|
@fred_child = @fred.associated_records.create!(:name => "fred child")
|
131
|
-
@bob.update_attribute(:
|
132
|
-
@fred.update_attribute(:
|
131
|
+
@bob.update_attribute(:item_id, @bob.id)
|
132
|
+
@fred.update_attribute(:item_id, @fred.id)
|
133
133
|
|
134
134
|
# populate the cache entries and associated children ID variables
|
135
135
|
AssociatedRecord.fetch_multi(@bob_child.id, @fred_child.id)
|
136
|
-
|
136
|
+
Item.fetch_multi(@bob.id, @fred.id)
|
137
137
|
|
138
138
|
assert_memcache_operations(3) do
|
139
|
-
@cached_bob_child, @cached_fred_child = AssociatedRecord.fetch_multi(@bob_child.id, @fred_child.id, :includes => {:
|
139
|
+
@cached_bob_child, @cached_fred_child = AssociatedRecord.fetch_multi(@bob_child.id, @fred_child.id, :includes => {:item => :item})
|
140
140
|
|
141
|
-
@cached_bob_parent = @cached_bob_child.
|
142
|
-
@cached_fred_parent = @cached_fred_child.
|
143
|
-
assert_equal @bob, @cached_bob_parent.
|
144
|
-
assert_equal @fred, @cached_fred_parent.
|
141
|
+
@cached_bob_parent = @cached_bob_child.fetch_item
|
142
|
+
@cached_fred_parent = @cached_fred_child.fetch_item
|
143
|
+
assert_equal @bob, @cached_bob_parent.fetch_item
|
144
|
+
assert_equal @fred, @cached_fred_parent.fetch_item
|
145
145
|
end
|
146
146
|
end
|
147
147
|
|
148
148
|
def test_fetch_multi_doesnt_batch_fetches_belongs_to_associations_if_the_foreign_key_isnt_present
|
149
|
-
AssociatedRecord.send(:cache_belongs_to, :
|
149
|
+
AssociatedRecord.send(:cache_belongs_to, :item, :embed => false)
|
150
150
|
@child = AssociatedRecord.create!(:name => "bob child")
|
151
151
|
# populate the cache entry
|
152
152
|
AssociatedRecord.fetch_multi(@child.id)
|
153
153
|
|
154
154
|
assert_memcache_operations(1) do
|
155
|
-
@cached_child = AssociatedRecord.fetch_multi(@child.id, :includes => :
|
155
|
+
@cached_child = AssociatedRecord.fetch_multi(@child.id, :includes => :item)
|
156
156
|
end
|
157
157
|
end
|
158
158
|
|
159
159
|
|
160
160
|
def test_fetch_multi_batch_fetches_non_embedded_second_level_associations_through_embedded_first_level_has_many_associations
|
161
|
-
|
161
|
+
Item.send(:cache_has_many, :associated_records, :embed => true)
|
162
162
|
AssociatedRecord.send(:cache_has_many, :deeply_associated_records, :embed => false)
|
163
163
|
|
164
164
|
child_records, grandchildren = setup_has_many_children_and_grandchildren(@bob, @joe)
|
165
165
|
|
166
166
|
assert_memcache_operations(2) do
|
167
|
-
@cached_bob, @cached_joe =
|
167
|
+
@cached_bob, @cached_joe = Item.fetch_multi(@bob.id, @joe.id, :includes => {:associated_records => :deeply_associated_records})
|
168
168
|
bob_children = @cached_bob.fetch_associated_records.sort
|
169
169
|
joe_children = @cached_joe.fetch_associated_records.sort
|
170
170
|
|
@@ -178,7 +178,7 @@ class FetchMultiTest < IdentityCache::TestCase
|
|
178
178
|
end
|
179
179
|
|
180
180
|
def test_fetch_multi_batch_fetches_non_embedded_second_level_associations_through_embedded_first_level_has_one_associations
|
181
|
-
|
181
|
+
Item.send(:cache_has_one, :associated, :embed => true)
|
182
182
|
AssociatedRecord.send(:cache_has_many, :deeply_associated_records, :embed => false)
|
183
183
|
|
184
184
|
@bob_child = @bob.create_associated!(:name => "bob child")
|
@@ -186,10 +186,10 @@ class FetchMultiTest < IdentityCache::TestCase
|
|
186
186
|
|
187
187
|
grandchildren = setup_grandchildren(@bob_child, @joe_child)
|
188
188
|
AssociatedRecord.fetch_multi(@bob_child.id, @joe_child.id)
|
189
|
-
|
189
|
+
Item.fetch_multi(@bob.id, @joe.id)
|
190
190
|
|
191
191
|
assert_memcache_operations(2) do
|
192
|
-
@cached_bob, @cached_joe =
|
192
|
+
@cached_bob, @cached_joe = Item.fetch_multi(@bob.id, @joe.id, :includes => {:associated => :deeply_associated_records})
|
193
193
|
bob_child = @cached_bob.fetch_associated
|
194
194
|
joe_child = @cached_joe.fetch_associated
|
195
195
|
|
@@ -200,10 +200,10 @@ class FetchMultiTest < IdentityCache::TestCase
|
|
200
200
|
|
201
201
|
def test_find_batch_coerces_ids_to_primary_key_type
|
202
202
|
mock_relation = mock("ActiveRecord::Relation")
|
203
|
-
|
204
|
-
mock_relation.expects(:includes).returns(stub(:
|
203
|
+
Item.expects(:where).returns(mock_relation)
|
204
|
+
mock_relation.expects(:includes).returns(stub(:to_a => [@bob, @joe, @fred]))
|
205
205
|
|
206
|
-
|
206
|
+
Item.find_batch([@bob, @joe, @fred].map(&:id).map(&:to_s))
|
207
207
|
end
|
208
208
|
|
209
209
|
private
|
@@ -220,7 +220,7 @@ class FetchMultiTest < IdentityCache::TestCase
|
|
220
220
|
end
|
221
221
|
end
|
222
222
|
|
223
|
-
|
223
|
+
Item.fetch_multi(*parents.map(&:id)) # populate the cache entries and associated children ID variables
|
224
224
|
|
225
225
|
return child_records, grandchildren
|
226
226
|
end
|