identity_cache 0.5.1 → 1.0.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.
Files changed (91) hide show
  1. checksums.yaml +5 -5
  2. data/.github/probots.yml +2 -0
  3. data/.github/workflows/ci.yml +26 -0
  4. data/.gitignore +1 -0
  5. data/.rubocop.yml +5 -0
  6. data/.travis.yml +24 -9
  7. data/CHANGELOG.md +21 -0
  8. data/Gemfile +5 -1
  9. data/README.md +28 -26
  10. data/Rakefile +14 -5
  11. data/dev.yml +9 -16
  12. data/gemfiles/Gemfile.latest-release +6 -0
  13. data/gemfiles/Gemfile.rails-edge +6 -0
  14. data/gemfiles/Gemfile.rails52 +6 -0
  15. data/identity_cache.gemspec +26 -10
  16. data/lib/identity_cache.rb +49 -46
  17. data/lib/identity_cache/belongs_to_caching.rb +12 -40
  18. data/lib/identity_cache/cache_fetcher.rb +6 -5
  19. data/lib/identity_cache/cache_hash.rb +2 -2
  20. data/lib/identity_cache/cache_invalidation.rb +4 -11
  21. data/lib/identity_cache/cache_key_generation.rb +17 -65
  22. data/lib/identity_cache/cache_key_loader.rb +128 -0
  23. data/lib/identity_cache/cached.rb +7 -0
  24. data/lib/identity_cache/cached/association.rb +87 -0
  25. data/lib/identity_cache/cached/attribute.rb +123 -0
  26. data/lib/identity_cache/cached/attribute_by_multi.rb +37 -0
  27. data/lib/identity_cache/cached/attribute_by_one.rb +88 -0
  28. data/lib/identity_cache/cached/belongs_to.rb +93 -0
  29. data/lib/identity_cache/cached/embedded_fetching.rb +41 -0
  30. data/lib/identity_cache/cached/prefetcher.rb +51 -0
  31. data/lib/identity_cache/cached/primary_index.rb +97 -0
  32. data/lib/identity_cache/cached/recursive/association.rb +68 -0
  33. data/lib/identity_cache/cached/recursive/has_many.rb +9 -0
  34. data/lib/identity_cache/cached/recursive/has_one.rb +9 -0
  35. data/lib/identity_cache/cached/reference/association.rb +16 -0
  36. data/lib/identity_cache/cached/reference/has_many.rb +105 -0
  37. data/lib/identity_cache/cached/reference/has_one.rb +100 -0
  38. data/lib/identity_cache/configuration_dsl.rb +53 -215
  39. data/lib/identity_cache/encoder.rb +95 -0
  40. data/lib/identity_cache/expiry_hook.rb +36 -0
  41. data/lib/identity_cache/fallback_fetcher.rb +2 -1
  42. data/lib/identity_cache/load_strategy/eager.rb +28 -0
  43. data/lib/identity_cache/load_strategy/lazy.rb +71 -0
  44. data/lib/identity_cache/load_strategy/load_request.rb +20 -0
  45. data/lib/identity_cache/load_strategy/multi_load_request.rb +27 -0
  46. data/lib/identity_cache/memoized_cache_proxy.rb +127 -58
  47. data/lib/identity_cache/parent_model_expiration.rb +45 -11
  48. data/lib/identity_cache/query_api.rb +128 -394
  49. data/lib/identity_cache/railtie.rb +8 -0
  50. data/lib/identity_cache/record_not_found.rb +6 -0
  51. data/lib/identity_cache/should_use_cache.rb +1 -0
  52. data/lib/identity_cache/version.rb +3 -2
  53. data/lib/identity_cache/with_primary_index.rb +136 -0
  54. data/lib/identity_cache/without_primary_index.rb +24 -3
  55. data/performance/cache_runner.rb +28 -34
  56. data/performance/cpu.rb +3 -2
  57. data/performance/externals.rb +4 -3
  58. data/performance/profile.rb +6 -5
  59. data/railgun.yml +16 -0
  60. metadata +44 -73
  61. data/Gemfile.rails42 +0 -6
  62. data/Gemfile.rails50 +0 -6
  63. data/test/attribute_cache_test.rb +0 -110
  64. data/test/cache_fetch_includes_test.rb +0 -46
  65. data/test/cache_hash_test.rb +0 -14
  66. data/test/cache_invalidation_test.rb +0 -139
  67. data/test/deeply_nested_associated_record_test.rb +0 -19
  68. data/test/denormalized_has_many_test.rb +0 -214
  69. data/test/denormalized_has_one_test.rb +0 -160
  70. data/test/fetch_multi_test.rb +0 -308
  71. data/test/fetch_test.rb +0 -258
  72. data/test/fixtures/serialized_record.mysql2 +0 -0
  73. data/test/fixtures/serialized_record.postgresql +0 -0
  74. data/test/helpers/active_record_objects.rb +0 -106
  75. data/test/helpers/database_connection.rb +0 -72
  76. data/test/helpers/serialization_format.rb +0 -51
  77. data/test/helpers/update_serialization_format.rb +0 -27
  78. data/test/identity_cache_test.rb +0 -29
  79. data/test/index_cache_test.rb +0 -161
  80. data/test/memoized_attributes_test.rb +0 -59
  81. data/test/memoized_cache_proxy_test.rb +0 -107
  82. data/test/normalized_belongs_to_test.rb +0 -107
  83. data/test/normalized_has_many_test.rb +0 -231
  84. data/test/normalized_has_one_test.rb +0 -9
  85. data/test/prefetch_associations_test.rb +0 -379
  86. data/test/readonly_test.rb +0 -109
  87. data/test/recursive_denormalized_has_many_test.rb +0 -131
  88. data/test/save_test.rb +0 -82
  89. data/test/schema_change_test.rb +0 -112
  90. data/test/serialization_format_change_test.rb +0 -16
  91. data/test/test_helper.rb +0 -140
@@ -1,258 +0,0 @@
1
- require "test_helper"
2
-
3
- class FetchTest < IdentityCache::TestCase
4
- NAMESPACE = IdentityCache::CacheKeyGeneration::DEFAULT_NAMESPACE
5
-
6
- def setup
7
- super
8
- Item.cache_index :title, :unique => true
9
- Item.cache_index :id, :title, :unique => true
10
-
11
- @record = Item.new
12
- @record.id = 1
13
- @record.title = 'bob'
14
- @cached_value = { class: @record.class.name, attributes: @record.attributes_before_type_cast }
15
- @blob_key = "#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:1"
16
- @index_key = "#{NAMESPACE}attr:Item:id:title:#{cache_hash('bob')}"
17
- end
18
-
19
- def test_fetch_with_garbage_input
20
- assert_nil Item.fetch_by_id('garbage')
21
- end
22
-
23
- def test_fetch_cache_hit
24
- IdentityCache.cache.expects(:fetch).with(@blob_key).returns(@cached_value)
25
-
26
- assert_equal @record, Item.fetch(1)
27
- end
28
-
29
- def test_fetch_hit_cache_namespace
30
- old_ns = IdentityCache.cache_namespace
31
- IdentityCache.cache_namespace = proc { |model| "#{model.table_name}:#{old_ns}" }
32
-
33
- new_blob_key = "items:#{@blob_key}"
34
- IdentityCache.cache.expects(:fetch).with(new_blob_key).returns(@cached_value)
35
-
36
- assert_equal @record, Item.fetch(1)
37
- ensure
38
- IdentityCache.cache_namespace = old_ns
39
- end
40
-
41
- def test_exists_with_identity_cache_when_cache_hit
42
- IdentityCache.cache.expects(:fetch).with(@blob_key).returns(@cached_value)
43
-
44
- assert Item.exists_with_identity_cache?(1)
45
- end
46
-
47
- def test_exists_with_identity_cache_when_cache_miss_and_in_db
48
- fetch = Spy.on(IdentityCache.cache, :fetch).and_call_through
49
- Item.expects(:resolve_cache_miss).with(1).once.returns(@record)
50
-
51
- assert Item.exists_with_identity_cache?(1)
52
- assert fetch.has_been_called_with?(@blob_key)
53
- end
54
-
55
- def test_exists_with_identity_cache_when_cache_miss_and_not_in_db
56
- fetch = Spy.on(IdentityCache.cache, :fetch).and_call_through
57
- Item.expects(:resolve_cache_miss).with(1).once.returns(nil)
58
-
59
- assert !Item.exists_with_identity_cache?(1)
60
- assert fetch.has_been_called_with?(@blob_key)
61
- end
62
-
63
- def test_fetch_miss
64
- Item.expects(:resolve_cache_miss).with(1).once.returns(@record)
65
-
66
- results = []
67
- fetch = Spy.on(IdentityCache.cache, :fetch).and_return {|_, &block| block.call.tap {|result| results << result}}
68
-
69
- assert_equal @record, Item.fetch(1)
70
- assert fetch.has_been_called_with?(@blob_key)
71
- assert_equal [@cached_value], results
72
- end
73
-
74
- def test_fetch_miss_with_non_id_primary_key
75
- hashed_key = Zlib::crc32("foo") % (2 ** 30 - 1)
76
- fixture = KeyedRecord.create!(:value => "foo") { |r| r.hashed_key = hashed_key }
77
- assert_equal fixture, KeyedRecord.fetch(hashed_key)
78
- end
79
-
80
- def test_fetch_conflict
81
- resolve_cache_miss = Spy.on(Item, :resolve_cache_miss).and_return do
82
- @record.send(:expire_cache)
83
- @record
84
- end
85
- add = Spy.on(fetcher, :add).and_call_through
86
-
87
- assert_equal @record, Item.fetch(1)
88
- assert resolve_cache_miss.has_been_called_with?(1)
89
- assert add.has_been_called_with?(@blob_key, @cached_value)
90
- assert_equal IdentityCache::DELETED, backend.read(@record.primary_cache_index_key)
91
- end
92
-
93
- def test_fetch_conflict_after_delete
94
- @record.send(:expire_cache)
95
- assert_equal IdentityCache::DELETED, backend.read(@record.primary_cache_index_key)
96
-
97
- resolve_cache_miss = Spy.on(Item, :resolve_cache_miss).and_return do
98
- @record.send(:expire_cache)
99
- @record
100
- end
101
- add = Spy.on(IdentityCache.cache.cache_fetcher, :add).and_call_through
102
-
103
- assert_equal @record, Item.fetch(1)
104
- assert resolve_cache_miss.has_been_called_with?(1)
105
- refute add.has_been_called?
106
- assert_equal IdentityCache::DELETED, backend.read(@record.primary_cache_index_key)
107
- end
108
-
109
- def test_fetch_by_id_not_found_should_return_nil
110
- nonexistent_record_id = 10
111
- fetcher.expects(:add).with(@blob_key + '0', IdentityCache::CACHED_NIL)
112
-
113
- assert_nil Item.fetch_by_id(nonexistent_record_id)
114
- end
115
-
116
- def test_fetch_not_found_should_raise
117
- nonexistent_record_id = 10
118
- fetcher.expects(:add).with(@blob_key + '0', IdentityCache::CACHED_NIL)
119
-
120
- assert_raises(ActiveRecord::RecordNotFound) { Item.fetch(nonexistent_record_id) }
121
- end
122
-
123
- def test_cached_nil_expiry_on_record_creation
124
- key = @record.primary_cache_index_key
125
-
126
- assert_nil Item.fetch_by_id(@record.id)
127
- assert_equal IdentityCache::CACHED_NIL, backend.read(key)
128
-
129
- @record.save!
130
- assert_equal IdentityCache::DELETED, backend.read(key)
131
- end
132
-
133
- def test_fetch_by_title_hit
134
- values = []
135
- fetch = Spy.on(IdentityCache.cache, :fetch).and_return do |key, &block|
136
- case key
137
- # Read record with title bob
138
- when @index_key then block.call.tap {|val| values << val}
139
- # got id, do memcache lookup on that, hit -> done
140
- when @blob_key then @cached_value
141
- end
142
- end
143
-
144
- # Id not found, use sql, SELECT id FROM records WHERE title = '...' LIMIT 1"
145
- Item.connection.expects(:exec_query).returns(ActiveRecord::Result.new(['id'], [[1]]))
146
-
147
- assert_equal @record, Item.fetch_by_title('bob')
148
- assert_equal [1], values
149
- assert fetch.has_been_called_with?(@index_key)
150
- assert fetch.has_been_called_with?(@blob_key)
151
- end
152
-
153
- def test_fetch_by_title_cache_namespace
154
- Item.send(:include, SwitchNamespace)
155
- IdentityCache.cache.expects(:fetch).with("ns:#{@index_key}").returns(1)
156
- IdentityCache.cache.expects(:fetch).with("ns:#{@blob_key}").returns(@cached_value)
157
-
158
- assert_equal @record, Item.fetch_by_title('bob')
159
- end
160
-
161
- def test_fetch_by_title_stores_idcnil
162
- Item.connection.expects(:exec_query).once.returns(ActiveRecord::Result.new([], []))
163
- add = Spy.on(fetcher, :add).and_call_through
164
- fetch = Spy.on(fetcher, :fetch).and_call_through
165
- assert_nil Item.fetch_by_title('bob') # exec_query => nil
166
-
167
- assert_nil Item.fetch_by_title('bob') # returns cached nil
168
- assert_nil Item.fetch_by_title('bob') # returns cached nil
169
-
170
- assert add.has_been_called_with?(@index_key, IdentityCache::CACHED_NIL)
171
- assert_equal 3, fetch.calls.length
172
- end
173
-
174
- def test_fetch_by_bang_method
175
- Item.connection.expects(:exec_query).returns(ActiveRecord::Result.new([], []))
176
- assert_raises ActiveRecord::RecordNotFound do
177
- Item.fetch_by_title!('bob')
178
- end
179
- end
180
-
181
- def test_fetch_does_not_communicate_to_cache_with_nil_id
182
- fetcher.expects(:fetch).never
183
- fetcher.expects(:add).never
184
- assert_raises(ActiveRecord::RecordNotFound) { Item.fetch(nil) }
185
- end
186
-
187
- def test_fetch_cache_hit_does_not_checkout_database_connection
188
- @record.save!
189
- record = Item.fetch(@record.id)
190
-
191
- ActiveRecord::Base.clear_active_connections!
192
-
193
- assert_equal record, Item.fetch(@record.id)
194
-
195
- assert_equal false, ActiveRecord::Base.connection_handler.active_connections?
196
- end
197
-
198
- def test_fetch_raises_when_called_on_a_scope
199
- assert_raises(IdentityCache::UnsupportedScopeError) do
200
- Item.where(updated_at: nil).fetch(1)
201
- end
202
- end
203
-
204
- def test_fetch_by_raises_when_called_on_a_scope
205
- assert_raises(IdentityCache::UnsupportedScopeError) do
206
- Item.where(updated_at: nil).fetch_by_id(1)
207
- end
208
- end
209
-
210
- def test_fetch_on_derived_model_raises
211
- assert_raises(IdentityCache::DerivedModelError) do
212
- StiRecordTypeA.fetch(1)
213
- end
214
- end
215
-
216
- def test_returned_records_are_readonly_on_cache_hit
217
- IdentityCache.with_fetch_read_only_records do
218
- IdentityCache.cache.expects(:fetch).with(@blob_key).returns(@cached_value)
219
- assert Item.fetch(1).readonly?
220
- end
221
- end
222
-
223
- def test_returned_records_are_readonly_on_cache_miss
224
- IdentityCache.with_fetch_read_only_records do
225
- fetch = Spy.on(IdentityCache.cache, :fetch).and_call_through
226
- Item.expects(:resolve_cache_miss).with(1).once.returns(@record)
227
-
228
- assert Item.exists_with_identity_cache?(1)
229
- assert fetch.has_been_called_with?(@blob_key)
230
- assert Item.fetch(1).readonly?
231
- end
232
- end
233
-
234
- def test_returned_records_are_not_readonly_with_open_transactions
235
- IdentityCache.with_fetch_read_only_records do
236
-
237
- @record.transaction do
238
- fetch = Spy.on(IdentityCache.cache, :fetch).and_call_through
239
- Item.expects(:resolve_cache_miss).with(1).once.returns(@record)
240
-
241
- refute IdentityCache.should_use_cache?
242
- refute fetch.has_been_called_with?(@blob_key)
243
- refute Item.fetch(1).readonly?, "Fetched item was read-only"
244
- end
245
- end
246
- end
247
-
248
- def test_respects_should_use_cache_on_record
249
- @record.save
250
- Item.stubs(:should_use_cache?).returns(false)
251
-
252
- assert_memcache_operations(0) do
253
- assert_queries(1) do
254
- Item.fetch_by_id(@record.id)
255
- end
256
- end
257
- end
258
- end
@@ -1,106 +0,0 @@
1
- module SwitchNamespace
2
-
3
- module ClassMethods
4
- def rails_cache_key_namespace
5
- "#{self.namespace}:#{super}"
6
- end
7
- end
8
-
9
- def self.included(base)
10
- base.extend ClassMethods
11
- base.class_eval do
12
- class_attribute :namespace
13
- self.namespace = 'ns'
14
- end
15
- end
16
- end
17
-
18
- module ActiveRecordObjects
19
-
20
- def setup_models(base = ActiveRecord::Base)
21
- Object.send :const_set, 'DeeplyAssociatedRecord', Class.new(base) {
22
- include IdentityCache
23
- belongs_to :item
24
- belongs_to :associated_record
25
- default_scope { order('name DESC') }
26
- }
27
-
28
- Object.send :const_set, 'AssociatedRecord', Class.new(base) {
29
- include IdentityCache
30
- belongs_to :item, inverse_of: :associated_records
31
- belongs_to :item_two, inverse_of: :associated_records
32
- has_many :deeply_associated_records
33
- default_scope { order('id DESC') }
34
- }
35
-
36
- Object.send :const_set, 'NormalizedAssociatedRecord', Class.new(base) {
37
- include IdentityCache
38
- belongs_to :item
39
- default_scope { order('id DESC') }
40
- }
41
-
42
- Object.send :const_set, 'NotCachedRecord', Class.new(base) {
43
- belongs_to :item, :touch => true
44
- default_scope { order('id DESC') }
45
- }
46
-
47
- Object.send :const_set, 'PolymorphicRecord', Class.new(base) {
48
- belongs_to :owner, :polymorphic => true
49
- }
50
-
51
- Object.send :const_set, 'Deeply', Module.new
52
- Deeply.send :const_set, 'Nested', Module.new
53
- Deeply::Nested.send :const_set, 'AssociatedRecord', Class.new(base) {
54
- include IdentityCache
55
- }
56
-
57
- Object.send :const_set, 'Item', Class.new(base) {
58
- include IdentityCache
59
- belongs_to :item
60
- has_many :associated_records, inverse_of: :item
61
- has_many :deeply_associated_records, inverse_of: :item
62
- has_many :normalized_associated_records
63
- has_many :not_cached_records
64
- has_many :polymorphic_records, :as => 'owner'
65
- has_one :polymorphic_record, :as => 'owner'
66
- has_one :associated, :class_name => 'AssociatedRecord'
67
- }
68
-
69
- Object.send :const_set, 'ItemTwo', Class.new(base) {
70
- include IdentityCache
71
- has_many :associated_records, inverse_of: :item_two, foreign_key: :item_two_id
72
- self.table_name = 'items2'
73
- }
74
-
75
- Object.send :const_set, 'KeyedRecord', Class.new(base) {
76
- include IdentityCache
77
- self.primary_key = "hashed_key"
78
- }
79
-
80
- Object.send :const_set, 'StiRecord', Class.new(base) {
81
- include IdentityCache
82
- has_many :polymorphic_records, :as => 'owner'
83
- }
84
-
85
- Object.send :const_set, 'StiRecordTypeA', Class.new(StiRecord) {
86
- }
87
- end
88
-
89
- def teardown_models
90
- ActiveSupport::DescendantsTracker.clear
91
- ActiveSupport::Dependencies.clear
92
- Object.send :remove_const, 'DeeplyAssociatedRecord'
93
- Object.send :remove_const, 'PolymorphicRecord'
94
- Object.send :remove_const, 'NormalizedAssociatedRecord'
95
- Object.send :remove_const, 'AssociatedRecord'
96
- Object.send :remove_const, 'NotCachedRecord'
97
- Object.send :remove_const, 'Item'
98
- Object.send :remove_const, 'ItemTwo'
99
- Object.send :remove_const, 'KeyedRecord'
100
- Object.send :remove_const, 'StiRecord'
101
- Object.send :remove_const, 'StiRecordTypeA'
102
- Deeply::Nested.send :remove_const, 'AssociatedRecord'
103
- Deeply.send :remove_const, 'Nested'
104
- Object.send :remove_const, 'Deeply'
105
- end
106
- end
@@ -1,72 +0,0 @@
1
- module DatabaseConnection
2
- def self.db_name
3
- ENV.fetch('DB', 'mysql2')
4
- end
5
-
6
- def self.setup
7
- db_config = ENV['DATABASE_URL'] || DEFAULT_CONFIG[db_name]
8
- begin
9
- ActiveRecord::Base.establish_connection(db_config)
10
- ActiveRecord::Base.connection
11
- rescue
12
- raise unless db_config.is_a?(Hash)
13
- ActiveRecord::Base.establish_connection(db_config.merge('database' => nil))
14
- ActiveRecord::Base.connection.create_database(db_config['database'])
15
- ActiveRecord::Base.establish_connection(db_config)
16
- end
17
- end
18
-
19
- def self.drop_tables
20
- TABLES.keys.each do |table|
21
- ActiveRecord::Base.connection.drop_table(table) if table_exists?(table)
22
- end
23
- end
24
-
25
- def self.table_exists?(table)
26
- if ActiveRecord::Base.connection.respond_to?(:data_source_exists?)
27
- ActiveRecord::Base.connection.data_source_exists?(table)
28
- else
29
- ActiveRecord::Base.connection.table_exists?(table)
30
- end
31
- end
32
-
33
- def self.create_tables
34
- TABLES.each do |table, fields|
35
- fields = fields.dup
36
- options = fields.last.is_a?(Hash) ? fields.pop : {}
37
- ActiveRecord::Base.connection.create_table(table, options) do |t|
38
- fields.each do |column_type, *args|
39
- t.send(column_type, *args)
40
- end
41
- end
42
- end
43
- end
44
-
45
- TABLES = {
46
- :polymorphic_records => [[:string, :owner_type], [:integer, :owner_id], [:timestamps, null: true]],
47
- :deeply_associated_records => [[:string, :name], [:integer, :associated_record_id], [:integer, :item_id], [:timestamps, null: true]],
48
- :associated_records => [[:string, :name], [:integer, :item_id], [:integer, :item_two_id]],
49
- :normalized_associated_records => [[:string, :name], [:integer, :item_id], [:timestamps, null: true]],
50
- :not_cached_records => [[:string, :name], [:integer, :item_id], [:timestamps, null: true]],
51
- :items => [[:integer, :item_id], [:string, :title], [:timestamps, null: true]],
52
- :items2 => [[:integer, :item_id], [:string, :title], [:timestamps, null: true]],
53
- :keyed_records => [[:string, :value], :primary_key => "hashed_key"],
54
- :sti_records => [[:string, :type], [:string, :name]],
55
- }
56
-
57
- DEFAULT_CONFIG = {
58
- 'mysql2' => {
59
- 'adapter' => 'mysql2',
60
- 'database' => 'identity_cache_test',
61
- 'host' => ENV['MYSQL_HOST'] || '127.0.0.1',
62
- 'username' => 'root'
63
- },
64
- 'postgresql' => {
65
- 'adapter' => 'postgresql',
66
- 'database' => 'identity_cache_test',
67
- 'host' => ENV['POSTGRES_HOST'] || '127.0.0.1',
68
- 'username' => 'postgres',
69
- 'prepared_statements' => false,
70
- }
71
- }
72
- end
@@ -1,51 +0,0 @@
1
- module SerializationFormat
2
- def serialized_record
3
- AssociatedRecord.cache_has_many :deeply_associated_records, :embed => true
4
- AssociatedRecord.cache_belongs_to :item, :embed => false
5
- Item.cache_has_many :associated_records, :embed => true
6
- Item.cache_has_one :associated
7
- time = Time.parse('1970-01-01T00:00:00 UTC')
8
-
9
- record = Item.new(:title => 'foo')
10
- record.associated_records << AssociatedRecord.new(:name => 'bar')
11
- record.associated_records << AssociatedRecord.new(:name => 'baz')
12
- record.associated = AssociatedRecord.new(:name => 'bork')
13
- record.not_cached_records << NotCachedRecord.new(:name => 'NoCache', created_at: time)
14
- record.associated.deeply_associated_records << DeeplyAssociatedRecord.new(:name => "corge", created_at: time)
15
- record.associated.deeply_associated_records << DeeplyAssociatedRecord.new(:name => "qux", created_at: time)
16
- record.created_at = time
17
- record.save
18
- [Item, NotCachedRecord, DeeplyAssociatedRecord].each do |model|
19
- model.update_all(updated_at: time)
20
- end
21
- record.reload
22
- Item.fetch(record.id)
23
-
24
- IdentityCache.fetch(record.primary_cache_index_key) do
25
- STDERR.puts(
26
- "\e[31m" \
27
- "The record could not be retrieved from the cache." \
28
- "Did you configure MEMCACHED_HOST?" \
29
- "\e[0m",
30
- )
31
- exit(1)
32
- end
33
- end
34
-
35
- def serialized_record_file
36
- File.expand_path("../../fixtures/serialized_record.#{DatabaseConnection.db_name}", __FILE__)
37
- end
38
-
39
- def serialize(record, anIO = nil)
40
- hash = {
41
- :version => IdentityCache::CACHE_VERSION,
42
- :record => record
43
- }
44
-
45
- if anIO
46
- Marshal.dump(hash, anIO)
47
- else
48
- Marshal.dump(hash)
49
- end
50
- end
51
- end