diff --git a/lib/batch_loader/executor_proxy.rb b/lib/batch_loader/executor_proxy.rb index 2c2bbdb..ff0f4c9 100644 --- a/lib/batch_loader/executor_proxy.rb +++ b/lib/batch_loader/executor_proxy.rb @@ -9,7 +9,7 @@ class ExecutorProxy def initialize(default_value, key, &block) @default_value = default_value @block = block - @block_hash_key = "#{key}#{block.source_location}" + @block_hash_key = [block.source_location, key] @global_executor = BatchLoader::Executor.ensure_current end diff --git a/spec/batch_loader_spec.rb b/spec/batch_loader_spec.rb index 58d55ba..7e7f502 100644 --- a/spec/batch_loader_spec.rb +++ b/spec/batch_loader_spec.rb @@ -97,14 +97,42 @@ end end - laoded_author = batch_loader.call(Author, 1) + loader_author = batch_loader.call(Author, 1) loader_reader = batch_loader.call(Reader, 2) expect(Author).to receive(:where).with(id: [1]).once.and_call_original - expect(laoded_author).to eq(author) + expect(loader_author).to eq(author) expect(Reader).to receive(:where).with(id: [2]).once.and_call_original expect(loader_reader).to eq(reader) end + + it 'batches multiple items with hash-identical keys' do + user = Author.new(id: 1) + same_user = Reader.new(id: 1) + other_user = Reader.new(id: 2) + + post_1 = Post.save(user_id: 1, title: "First post") + post_2 = Post.save(user_id: 1, title: "Second post") + post_3 = Post.save(user_id: 2, title: "First post") + + batch_loader = ->(user, title) do + BatchLoader.for(title).batch(key: user) do |titles, loader, args| + args[:key].posts.select { |p| titles.include?(p.title) }.each { |post| loader.call(post.title, post) } + end + end + + loader_1 = batch_loader.call(user, "First post") + loader_2 = batch_loader.call(same_user, "Second post") + loader_3 = batch_loader.call(other_user, "First post") + + expect(user).to receive(:posts).once.and_call_original + expect(same_user).not_to receive(:posts) + expect(other_user).to receive(:posts).once.and_call_original + + expect(loader_1).to eq(post_1) + expect(loader_2).to eq(post_2) + expect(loader_3).to eq(post_3) + end end context 'loader' do diff --git a/spec/fixtures/models.rb b/spec/fixtures/models.rb index 3c5f209..768e3fc 100644 --- a/spec/fixtures/models.rb +++ b/spec/fixtures/models.rb @@ -1,10 +1,10 @@ class Post - attr_accessor :user_id + attr_accessor :user_id, :title class << self - def save(user_id:) + def save(user_id:, title: nil) ensure_init_store - @posts << new(user_id: user_id) + new(user_id: user_id, title: title).tap { |post| @posts << post } end def all @@ -23,8 +23,9 @@ def ensure_init_store end end - def initialize(user_id:) + def initialize(user_id:, title: nil) self.user_id = user_id + self.title = title || "Untitled" end def user_lazy(cache: true) @@ -68,6 +69,18 @@ def batch "Batch from User" end + def hash + [User, id].hash + end + + def posts + Post.all.select { |p| p.user_id == id } + end + + def eql?(other) + other.is_a?(User) && id == other.id + end + private def some_private_method