identity_cache 0.2.5 → 0.3.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -4
  3. data/CHANGELOG.md +22 -0
  4. data/Gemfile +2 -0
  5. data/Gemfile.rails40 +1 -0
  6. data/Gemfile.rails41 +1 -0
  7. data/Gemfile.rails42 +1 -0
  8. data/README.md +7 -0
  9. data/identity_cache.gemspec +1 -1
  10. data/lib/identity_cache.rb +5 -2
  11. data/lib/identity_cache/belongs_to_caching.rb +13 -5
  12. data/lib/identity_cache/cache_key_generation.rb +12 -19
  13. data/lib/identity_cache/configuration_dsl.rb +83 -84
  14. data/lib/identity_cache/parent_model_expiration.rb +4 -3
  15. data/lib/identity_cache/query_api.rb +93 -91
  16. data/lib/identity_cache/version.rb +2 -2
  17. data/test/attribute_cache_test.rb +42 -63
  18. data/test/deeply_nested_associated_record_test.rb +1 -0
  19. data/test/denormalized_has_many_test.rb +18 -0
  20. data/test/denormalized_has_one_test.rb +15 -5
  21. data/test/fetch_multi_test.rb +25 -3
  22. data/test/fetch_test.rb +20 -7
  23. data/test/fixtures/serialized_record.mysql2 +0 -0
  24. data/test/fixtures/serialized_record.postgresql +0 -0
  25. data/test/helpers/active_record_objects.rb +10 -0
  26. data/test/helpers/database_connection.rb +6 -1
  27. data/test/helpers/serialization_format.rb +1 -1
  28. data/test/index_cache_test.rb +50 -25
  29. data/test/normalized_belongs_to_test.rb +21 -6
  30. data/test/normalized_has_many_test.rb +44 -0
  31. data/test/{fetch_multi_with_batched_associations_test.rb → prefetch_normalized_associations_test.rb} +41 -3
  32. data/test/save_test.rb +14 -14
  33. data/test/schema_change_test.rb +2 -0
  34. data/test/test_helper.rb +4 -4
  35. metadata +11 -10
  36. data/Gemfile.rails32 +0 -5
  37. data/test/fixtures/serialized_record +0 -0
@@ -1,6 +1,6 @@
1
1
  require "test_helper"
2
2
 
3
- class FetchMultiWithBatchedAssociationsTest < IdentityCache::TestCase
3
+ class PrefetchNormalizedAssociationsTest < IdentityCache::TestCase
4
4
  NAMESPACE = IdentityCache.cache_namespace
5
5
 
6
6
  def setup
@@ -14,7 +14,19 @@ class FetchMultiWithBatchedAssociationsTest < IdentityCache::TestCase
14
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
- def test_fetch_multi_with_includes_option_preloads_associations
17
+ def test_fetch_with_includes_option
18
+ Item.send(:cache_belongs_to, :item)
19
+ john = Item.create!(title: 'john')
20
+ @bob.update_column(:item_id, john)
21
+
22
+ spy = Spy.on(Item, :fetch_multi).and_call_through
23
+
24
+ assert_equal @bob, Item.fetch(@bob.id, includes: :item)
25
+
26
+ assert spy.calls.one?{ |call| call.args == [[john.id]] }
27
+ end
28
+
29
+ def test_fetch_multi_with_includes_option
18
30
  Item.send(:cache_belongs_to, :item)
19
31
  john = Item.create!(:title => 'john')
20
32
  jim = Item.create!(:title => 'jim')
@@ -23,7 +35,7 @@ class FetchMultiWithBatchedAssociationsTest < IdentityCache::TestCase
23
35
 
24
36
  spy = Spy.on(Item, :fetch_multi).and_call_through
25
37
 
26
- items = Item.fetch_multi(@bob.id, @joe.id, @fred.id, :includes => :item)
38
+ assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id, :includes => :item)
27
39
 
28
40
  assert spy.calls.one?{ |call| call.args == [[john.id, jim.id]] }
29
41
  end
@@ -184,6 +196,32 @@ class FetchMultiWithBatchedAssociationsTest < IdentityCache::TestCase
184
196
  Item.send(:find_batch, [@bob, @joe, @fred].map(&:id).map(&:to_s))
185
197
  end
186
198
 
199
+ def test_fetch_by_index_with_includes_option
200
+ Item.send(:cache_belongs_to, :item)
201
+ Item.cache_index :title
202
+ john = Item.create!(title: 'john')
203
+ @bob.update_column(:item_id, john)
204
+
205
+ spy = Spy.on(Item, :fetch_multi).and_call_through
206
+
207
+ assert_equal [@bob], Item.fetch_by_title('bob', includes: :item)
208
+
209
+ assert spy.calls.one?{ |call| call.args == [[john.id]] }
210
+ end
211
+
212
+ def test_fetch_by_unique_index_with_includes_option
213
+ Item.send(:cache_belongs_to, :item)
214
+ Item.cache_index :title, :unique => true
215
+ john = Item.create!(title: 'john')
216
+ @bob.update_column(:item_id, john)
217
+
218
+ spy = Spy.on(Item, :fetch_multi).and_call_through
219
+
220
+ assert_equal @bob, Item.fetch_by_title('bob', includes: :item)
221
+
222
+ assert spy.calls.one?{ |call| call.args == [[john.id]] }
223
+ end
224
+
187
225
  private
188
226
 
189
227
  def setup_has_many_children_and_grandchildren(*parents)
@@ -16,21 +16,21 @@ class SaveTest < IdentityCache::TestCase
16
16
  @record = Item.new
17
17
  @record.title = 'bob'
18
18
 
19
- expect_cache_delete("#{NAMESPACE}index:Item:id/title:#{cache_hash('2/bob')}")
20
- expect_cache_delete("#{NAMESPACE}index:Item:title:#{cache_hash('bob')}")
19
+ expect_cache_delete("#{NAMESPACE}attr:Item:id:id/title:#{cache_hash('2/bob')}")
20
+ expect_cache_delete("#{NAMESPACE}attr:Item:id:title:#{cache_hash('bob')}")
21
21
  expect_cache_delete("#{NAMESPACE}blob:Item:#{cache_hash("created_at:datetime,id:integer,item_id:integer,title:string,updated_at:datetime")}:2").once
22
22
  @record.save
23
23
  end
24
24
 
25
25
  def test_update
26
26
  # Regular flow, write index id, write index id/tile, delete data blob since Record has changed
27
- expect_cache_delete("#{NAMESPACE}index:Item:id/title:#{cache_hash('1/fred')}")
28
- expect_cache_delete("#{NAMESPACE}index:Item:title:#{cache_hash('fred')}")
27
+ expect_cache_delete("#{NAMESPACE}attr:Item:id:id/title:#{cache_hash('1/fred')}")
28
+ expect_cache_delete("#{NAMESPACE}attr:Item:id:title:#{cache_hash('fred')}")
29
29
  expect_cache_delete(@blob_key)
30
30
 
31
31
  # Delete index id, delete index id/title
32
- expect_cache_delete("#{NAMESPACE}index:Item:id/title:#{cache_hash('1/bob')}")
33
- expect_cache_delete("#{NAMESPACE}index:Item:title:#{cache_hash('bob')}")
32
+ expect_cache_delete("#{NAMESPACE}attr:Item:id:id/title:#{cache_hash('1/bob')}")
33
+ expect_cache_delete("#{NAMESPACE}attr:Item:id:title:#{cache_hash('bob')}")
34
34
 
35
35
  @record.title = 'fred'
36
36
  @record.save
@@ -38,8 +38,8 @@ class SaveTest < IdentityCache::TestCase
38
38
 
39
39
  def test_destroy
40
40
  # Regular flow: delete data blob, delete index id, delete index id/tile
41
- expect_cache_delete("#{NAMESPACE}index:Item:id/title:#{cache_hash('1/bob')}")
42
- expect_cache_delete("#{NAMESPACE}index:Item:title:#{cache_hash('bob')}")
41
+ expect_cache_delete("#{NAMESPACE}attr:Item:id:id/title:#{cache_hash('1/bob')}")
42
+ expect_cache_delete("#{NAMESPACE}attr:Item:id:title:#{cache_hash('bob')}")
43
43
  expect_cache_delete(@blob_key)
44
44
 
45
45
  @record.destroy
@@ -47,8 +47,8 @@ class SaveTest < IdentityCache::TestCase
47
47
 
48
48
  def test_destroy_with_changed_attributes
49
49
  # Make sure to delete the old cache index key, since the new title never ended up in an index
50
- expect_cache_delete("#{NAMESPACE}index:Item:id/title:#{cache_hash('1/bob')}")
51
- expect_cache_delete("#{NAMESPACE}index:Item:title:#{cache_hash('bob')}")
50
+ expect_cache_delete("#{NAMESPACE}attr:Item:id:id/title:#{cache_hash('1/bob')}")
51
+ expect_cache_delete("#{NAMESPACE}attr:Item:id:title:#{cache_hash('bob')}")
52
52
  expect_cache_delete(@blob_key)
53
53
 
54
54
  @record.title = 'fred'
@@ -57,16 +57,16 @@ class SaveTest < IdentityCache::TestCase
57
57
 
58
58
  def test_touch_will_expire_the_caches
59
59
  # Regular flow: delete data blob, delete index id, delete index id/tile
60
- expect_cache_delete("#{NAMESPACE}index:Item:id/title:#{cache_hash('1/bob')}")
61
- expect_cache_delete("#{NAMESPACE}index:Item:title:#{cache_hash('bob')}")
60
+ expect_cache_delete("#{NAMESPACE}attr:Item:id:id/title:#{cache_hash('1/bob')}")
61
+ expect_cache_delete("#{NAMESPACE}attr:Item:id:title:#{cache_hash('bob')}")
62
62
  expect_cache_delete(@blob_key)
63
63
 
64
64
  @record.touch
65
65
  end
66
66
 
67
67
  def test_expire_cache_works_in_a_transaction
68
- expect_cache_delete("#{NAMESPACE}index:Item:id/title:#{cache_hash('1/bob')}")
69
- expect_cache_delete("#{NAMESPACE}index:Item:title:#{cache_hash('bob')}")
68
+ expect_cache_delete("#{NAMESPACE}attr:Item:id:id/title:#{cache_hash('1/bob')}")
69
+ expect_cache_delete("#{NAMESPACE}attr:Item:id:title:#{cache_hash('bob')}")
70
70
  expect_cache_delete(@blob_key)
71
71
 
72
72
  ActiveRecord::Base.transaction do
@@ -83,6 +83,7 @@ class SchemaChangeTest < IdentityCache::TestCase
83
83
  end
84
84
 
85
85
  def test_embed_existing_cache_has_many
86
+ PolymorphicRecord.include(IdentityCache)
86
87
  Item.cache_has_many :polymorphic_records, :inverse_name => :owner, :embed => :ids
87
88
  read_new_schema
88
89
 
@@ -96,6 +97,7 @@ class SchemaChangeTest < IdentityCache::TestCase
96
97
  end
97
98
 
98
99
  def test_add_non_embedded_cache_has_many
100
+ PolymorphicRecord.include(IdentityCache)
99
101
  record = Item.fetch(@record.id)
100
102
 
101
103
  Item.cache_has_many :polymorphic_records, :inverse_name => :owner, :embed => :ids
@@ -59,7 +59,7 @@ class IdentityCache::TestCase < Minitest::Test
59
59
  end
60
60
 
61
61
  def assert_not_nil(*args)
62
- assert *args
62
+ assert(*args)
63
63
  end
64
64
 
65
65
  def assert_queries(num = 1)
@@ -67,7 +67,7 @@ class IdentityCache::TestCase < Minitest::Test
67
67
  subscriber = ActiveSupport::Notifications.subscribe('sql.active_record', counter)
68
68
  exception = false
69
69
  yield
70
- rescue => e
70
+ rescue
71
71
  exception = true
72
72
  raise
73
73
  ensure
@@ -80,7 +80,7 @@ class IdentityCache::TestCase < Minitest::Test
80
80
  subscriber = ActiveSupport::Notifications.subscribe(/cache_.*\.active_support/, counter)
81
81
  exception = false
82
82
  yield
83
- rescue => e
83
+ rescue
84
84
  exception = true
85
85
  raise
86
86
  ensure
@@ -101,7 +101,7 @@ end
101
101
 
102
102
  class SQLCounter
103
103
  cattr_accessor :ignored_sql
104
- self.ignored_sql = [/^PRAGMA (?!(table_info))/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^SHOW max_identifier_length/, /^BEGIN/, /^COMMIT/]
104
+ self.ignored_sql = [/^PRAGMA (?!(table_info))/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^SHOW max_identifier_length/, /^BEGIN/, /^COMMIT/, /^SHOW /]
105
105
 
106
106
  # FIXME: this needs to be refactored so specific database can add their own
107
107
  # ignored SQL. This ignored SQL is for Oracle.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: identity_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Camilo Lopez
@@ -14,7 +14,7 @@ authors:
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
- date: 2015-05-29 00:00:00.000000000 Z
17
+ date: 2016-01-20 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: ar_transaction_changes
@@ -36,14 +36,14 @@ dependencies:
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: '3.2'
39
+ version: 4.0.4
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: '3.2'
46
+ version: 4.0.4
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: memcached
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -197,7 +197,6 @@ files:
197
197
  - CHANGELOG.md
198
198
  - CONTRIBUTING.md
199
199
  - Gemfile
200
- - Gemfile.rails32
201
200
  - Gemfile.rails40
202
201
  - Gemfile.rails41
203
202
  - Gemfile.rails42
@@ -230,9 +229,9 @@ files:
230
229
  - test/denormalized_has_many_test.rb
231
230
  - test/denormalized_has_one_test.rb
232
231
  - test/fetch_multi_test.rb
233
- - test/fetch_multi_with_batched_associations_test.rb
234
232
  - test/fetch_test.rb
235
- - test/fixtures/serialized_record
233
+ - test/fixtures/serialized_record.mysql2
234
+ - test/fixtures/serialized_record.postgresql
236
235
  - test/helpers/active_record_objects.rb
237
236
  - test/helpers/database_connection.rb
238
237
  - test/helpers/serialization_format.rb
@@ -243,6 +242,7 @@ files:
243
242
  - test/normalized_belongs_to_test.rb
244
243
  - test/normalized_has_many_test.rb
245
244
  - test/normalized_has_one_test.rb
245
+ - test/prefetch_normalized_associations_test.rb
246
246
  - test/readonly_test.rb
247
247
  - test/recursive_denormalized_has_many_test.rb
248
248
  - test/save_test.rb
@@ -268,7 +268,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
268
268
  version: '0'
269
269
  requirements: []
270
270
  rubyforge_project:
271
- rubygems_version: 2.2.3
271
+ rubygems_version: 2.2.0
272
272
  signing_key:
273
273
  specification_version: 4
274
274
  summary: IdentityCache lets you specify how you want to cache your model objects,
@@ -284,9 +284,9 @@ test_files:
284
284
  - test/denormalized_has_many_test.rb
285
285
  - test/denormalized_has_one_test.rb
286
286
  - test/fetch_multi_test.rb
287
- - test/fetch_multi_with_batched_associations_test.rb
288
287
  - test/fetch_test.rb
289
- - test/fixtures/serialized_record
288
+ - test/fixtures/serialized_record.mysql2
289
+ - test/fixtures/serialized_record.postgresql
290
290
  - test/helpers/active_record_objects.rb
291
291
  - test/helpers/database_connection.rb
292
292
  - test/helpers/serialization_format.rb
@@ -297,6 +297,7 @@ test_files:
297
297
  - test/normalized_belongs_to_test.rb
298
298
  - test/normalized_has_many_test.rb
299
299
  - test/normalized_has_one_test.rb
300
+ - test/prefetch_normalized_associations_test.rb
300
301
  - test/readonly_test.rb
301
302
  - test/recursive_denormalized_has_many_test.rb
302
303
  - test/save_test.rb
@@ -1,5 +0,0 @@
1
- source 'https://rubygems.org'
2
- gemspec
3
-
4
- gem 'activerecord', '~> 3.2.16'
5
- gem 'activesupport', '~> 3.2.16'