Skip to content

Commit b7a5ddc

Browse files
Copilotdjezzzl
andcommitted
Add ActiveRecord context binding specs (n1_bind_to and automatic binding)
Co-authored-by: djezzzl <9407725+djezzzl@users.noreply.github.com>
1 parent 8ef8be8 commit b7a5ddc

1 file changed

Lines changed: 63 additions & 0 deletions

File tree

spec/activerecord_spec.rb

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ def perform(elements)
5959
elements.each { |element| fulfill(element, [element, something]) }
6060
end
6161
end
62+
63+
n1_optimized :extra_data do
64+
def perform(elements)
65+
Entity.perform!
66+
67+
elements.each { |element| fulfill(element, [element, :extra]) }
68+
end
69+
end
6270
end)
6371

6472
stub_const("Company", Class.new(ActiveRecord::Base) do
@@ -311,6 +319,61 @@ def perform(elements)
311319
end
312320
end
313321

322+
context "with context binding" do
323+
let(:objects) { [Entity.create!, Entity.create!] }
324+
325+
describe "n1_bind_to" do
326+
it "returns correct data for each bound object" do
327+
objects.each { |obj| obj.n1_bind_to(objects) }
328+
329+
expect(objects.first.data).to eq([objects.first])
330+
expect(objects.last.data).to eq([objects.last])
331+
end
332+
333+
it "loads all bound objects in a single batch" do
334+
objects.each { |obj| obj.n1_bind_to(objects) }
335+
336+
expect { objects.map(&:data) }.to change(Entity, :count).by(1)
337+
end
338+
339+
it "caches the result after the first load" do
340+
objects.each { |obj| obj.n1_bind_to(objects) }
341+
342+
expect { objects.map(&:data) }.to change(Entity, :count).by(1)
343+
expect { objects.map(&:data) }.not_to change(Entity, :count)
344+
end
345+
346+
it "lazily loads when the first object is accessed" do
347+
objects.each { |obj| obj.n1_bind_to(objects) }
348+
349+
expect { objects.first.data }.to change(Entity, :count).by(1)
350+
expect { objects.last.data }.not_to change(Entity, :count)
351+
end
352+
end
353+
354+
describe "automatic context binding" do
355+
it "automatically binds objects after loading via preloader" do
356+
N1Loader::Preloader.new(objects).preload(:data)
357+
358+
# Accessing data triggers perform for all objects and auto-calls n1_bind_to
359+
objects.first.data
360+
361+
# extra_data should now batch in a single perform call for all bound objects
362+
expect { objects.map(&:extra_data) }.to change(Entity, :count).by(1)
363+
end
364+
365+
it "does not trigger another load for siblings once auto-bound" do
366+
N1Loader::Preloader.new(objects).preload(:data)
367+
368+
# First element access triggers auto-bind for the entire collection
369+
objects.first.data
370+
371+
objects.first.extra_data
372+
expect { objects.last.extra_data }.not_to change(Entity, :count)
373+
end
374+
end
375+
end
376+
314377
context "with deep includes" do
315378
let(:objects) { Company.includes(data: :company) }
316379

0 commit comments

Comments
 (0)