@@ -411,6 +411,80 @@ public function test_eager_loading_belongs_to_avoids_n_plus_1(): void
411411
412412 $ this ->assertSame (2 , count (DB ::getQueryLog ()));
413413 }
414+
415+ // -----------------------------------------------------------------------
416+ // paginate() honours with()
417+ //
418+ // EagerBuilder previously only implemented get() and first() as
419+ // terminal methods that trigger Model::eagerLoad(). paginate() was
420+ // not declared on EagerBuilder, so it fell through __call() straight
421+ // to the underlying Query\Builder::paginate(), which calls its own
422+ // get() internally — never touching eager loading at all.
423+ //
424+ // The practical effect was: with() silently did nothing when
425+ // paginate() was used. Accessing the relation afterwards fell back
426+ // to lazy loading per row, reproducing the exact N+1 problem with()
427+ // exists to prevent — with no error or warning to signal it.
428+ //
429+ // EagerBuilder::paginate() now overrides the forwarded call, runs the
430+ // page query, then eager-loads relations on $page->data before
431+ // returning. These tests verify that fix.
432+ // -----------------------------------------------------------------------
433+
434+ public function test_paginate_after_with_eager_loads_relation (): void
435+ {
436+ $ this ->seedManyUsersWithPosts (userCount: 5 );
437+
438+ $ result = RelUser::with ('posts ' )->paginate (5 , 1 );
439+ $ first = $ result ->data ->first ();
440+
441+ $ this ->assertTrue (
442+ $ first ->relationLoaded ('posts ' ),
443+ 'paginate() must honour with() and eager-load relations on the current page. ' ,
444+ );
445+ $ this ->assertInstanceOf (Collection::class, $ first ->posts );
446+ }
447+
448+ public function test_paginate_after_select_with_eager_loads_relation (): void
449+ {
450+ // Same fix verified via the select()->with()->paginate() chain.
451+ $ this ->seedManyUsersWithPosts (userCount: 5 );
452+
453+ $ result = RelUser::select ('id ' , 'name ' )->with ('posts ' )->paginate (5 , 1 );
454+ $ first = $ result ->data ->first ();
455+
456+ $ this ->assertTrue (
457+ $ first ->relationLoaded ('posts ' ),
458+ 'paginate() must honour with() through the select()->with()->paginate() chain too. ' ,
459+ );
460+ }
461+
462+ public function test_paginate_after_with_avoids_n_plus_1_on_access (): void
463+ {
464+ // The real-world payoff: a paginated list view that does
465+ // Model::with('relation')->paginate(...) and then iterates the
466+ // page printing the relation must NOT trigger N+1 — the relation
467+ // should already be loaded from the single whereIn() query.
468+ $ userCount = $ this ->seedManyUsersWithPosts (userCount: 10 , postsPerUser: 1 );
469+
470+ DB ::flushQueryLog ();
471+ DB ::enableQueryLog ();
472+
473+ $ result = RelUser::with ('posts ' )->paginate ($ userCount , 1 );
474+ foreach ($ result ->data as $ user ) {
475+ $ user ->posts ->count (); // must be a no-op — already eager-loaded
476+ }
477+
478+ $ queryCount = count (DB ::getQueryLog ());
479+
480+ // 1 count() + 1 page select + 1 whereIn() for posts = 3, regardless
481+ // of how many users are on the page.
482+ $ this ->assertSame (
483+ 3 ,
484+ $ queryCount ,
485+ 'paginate() + with() must use a constant 3 queries, not one extra query per row. ' ,
486+ );
487+ }
414488}
415489
416490// -----------------------------------------------------------------------
0 commit comments