From 9deb4d78ca746da730a78c7799dc49c035c6417e Mon Sep 17 00:00:00 2001 From: Kir Shatrov Date: Wed, 14 Feb 2024 17:50:03 -0800 Subject: [PATCH] Allow prefetch_associations on association that was prefetched before --- lib/identity_cache/cached/belongs_to.rb | 22 ++++++++++------- test/prefetch_associations_test.rb | 33 +++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/lib/identity_cache/cached/belongs_to.rb b/lib/identity_cache/cached/belongs_to.rb index 86a6b749..4428b6fa 100644 --- a/lib/identity_cache/cached/belongs_to.rb +++ b/lib/identity_cache/cached/belongs_to.rb @@ -77,16 +77,20 @@ def fetch_async(load_strategy, records) end end - load_strategy.load_multi( - reflection.klass.cached_primary_index, - ids_to_owner_record.keys - ) do |associated_records_by_id| - associated_records_by_id.each do |id, associated_record| - owner_record = ids_to_owner_record.fetch(id) - write(owner_record, associated_record) - end + if ids_to_owner_record.keys.any? + load_strategy.load_multi( + reflection.klass.cached_primary_index, + ids_to_owner_record.keys + ) do |associated_records_by_id| + associated_records_by_id.each do |id, associated_record| + owner_record = ids_to_owner_record.fetch(id) + write(owner_record, associated_record) + end - yield associated_records_by_id.values.compact + yield associated_records_by_id.values.compact + end + else + yield records.filter_map { |record| record.instance_variable_get(records_variable_name) } end end end diff --git a/test/prefetch_associations_test.rb b/test/prefetch_associations_test.rb index f82d6fac..7a980244 100644 --- a/test/prefetch_associations_test.rb +++ b/test/prefetch_associations_test.rb @@ -270,6 +270,39 @@ def test_fetch_multi_batch_fetches_first_level_associations_who_dont_include_ide end end + def test_fetch_multi_batch_fetches_non_embedded_second_level_belongs_to_associations_in_repeating_prefetch + Item.send(:cache_belongs_to, :item) + AssociatedRecord.send(:cache_belongs_to, :item) + + @bob_child = @bob.associated_records.create!(name: "bob child") + @fred_child = @fred.associated_records.create!(name: "fred child") + @bob.update_attribute(:item_id, @bob.id) + @fred.update_attribute(:item_id, @fred.id) + + # populate the cache entries and associated children ID variables + AssociatedRecord.fetch_multi(@bob_child.id, @fred_child.id) + Item.fetch_multi(@bob.id, @fred.id) + + assert_memcache_operations(2) do + @cached_bob_child, @cached_fred_child = AssociatedRecord.fetch_multi( + @bob_child.id, @fred_child.id, includes: [:item] + ) + end + + assert_memcache_operations(1) do + AssociatedRecord.prefetch_associations({ item: :item }, [@cached_bob_child, @cached_fred_child]) + end + + assert_queries(0) do + assert_memcache_operations(0) do + @cached_bob_parent = @cached_bob_child.fetch_item + @cached_fred_parent = @cached_fred_child.fetch_item + assert_equal(@bob, @cached_bob_parent.fetch_item) + assert_equal(@fred, @cached_fred_parent.fetch_item) + end + end + end + def test_fetch_multi_batch_fetches_non_embedded_second_level_has_many_associations Item.send(:cache_has_many, :associated_records, embed: :ids) AssociatedRecord.send(:cache_has_many, :deeply_associated_records, embed: :ids)