staudenmeir/eloquent-eager-limit-x-laravel-adjacency-list
Compatibility package combining staudenmeir/laravel-adjacency-list with eloquent-eager-limit, letting Laravel apps cap eager-loaded relations on recursive adjacency list queries. Adds the missing trait support so hierarchical models can limit eager loads per parent without N+1 queries.
LIMIT applied per parent on a recursively eager-loaded relationship — the exact intersection where eloquent-eager-limit (per-parent limit via window functions) and laravel-adjacency-list (recursive relationships over parent_id) collide at the trait level. This bridge exists so those two compose instead of conflicting, which means the feature is scoped as product work rather than as a SQL research project.ROW_NUMBER() OVER (PARTITION BY parent_id) plus custom hydration, (b) load-everything-and-slice, or (c) one Composer dependency. Option (b) is the silent default; option (a) is a week of query plumbing with no product surface; option (c) is free and MIT-licensed. That reframes the roadmap conversation from "do we have database bandwidth this quarter" to "does this feature earn its keep" — the question you actually want the room arguing about.Consider it when:
parent_id or equivalent column on the same table. If you are on nested set, closure table, or materialized path, the recursive half buys you nothing and the underlying primitive is wrong for the job.Look elsewhere when:
LIMIT plus global pagination is genuinely awkward; a materialized path or a different data model is the honest answer.composer.json — not the README. Close this before you spec the feature, not mid-sprint.For executives. This is a small, free, MIT-licensed PHP library that lets us ship tree-shaped product experiences — threaded conversations, nested categories, org structures, preview navigation — inside the Laravel application and database we already run. The commercial point is simple: the obvious way to build these features reads far more data than the screen shows, and that cost only appears after launch, as slow pages and database spend. This library makes the efficient query the default. The price is one Composer dependency and a short validation spike: no new infrastructure, no vendor contract, no data migration. Recommendation: approve a time-boxed evaluation on one real feature, not a blanket engineering standard.
For engineering. It composes two packages from the same maintainer — eager-load limiting and adjacency-list trees — so you can attach a LIMIT to a recursively eager-loaded relationship without falling into N+1 or hand-writing window functions. Integration is composer require plus traits on the tree model; no schema change, no backfill. Three things to verify before we commit: the Laravel/PHP matrix in composer.json for the bridge and both upstream packages; that our engine supports window functions; and that the traits coexist with our global scopes and soft deletes. Pin the exact version as a four-tuple in the PR (bridge, eager-limit, adjacency-list, Laravel), wrap it in an internal abstraction so swapping in a hand-rolled ROW_NUMBER() scope is a one-file change, and spike on one model in one bounded context — not on models other teams depend on.
For product and roadmap. This unblocks a class of preview experiences we have been deferring: threads that show a few replies behind a "see all," category pages with per-section featurettes, hierarchy-aware pickers and breadcrumbs, capped reporting lines. It does not unblock deep traversal, recommendations, or hierarchy analytics — those keep their own evaluation and stay off the near-term roadmap. The move is to pick the single highest-value tree feature, build it behind a flag against realistic data volume, and measure query count and p95 latency before widening use. Document a depth ceiling and test depth 2+ explicitly; do not assume limit() composes below direct children.
Risks to flag. Maturity: single maintainer, no release since May 2023, a 1.x API that may still move, and release notes that appear inherited from the upstream adjacency-list package rather than written for the bridge — expect engineers to read upstream source for behaviour questions. Correctness: cycles, soft-deleted nodes, and scope bypass on traversed records are unverified, and scope bypass is the most likely silent defect. Coupling: relationship traits on domain models are invasive to remove, so exit cost is a query-layer rewrite, not a version bump. Mitigations: an exact version pin recorded as a four-tuple, an internal abstraction at the call site, a flag-guarded pilot on one non-critical feature, and a documented fallback — a hand-written adjacency table plus an Eloquent scope, roughly the same effort as the integration minus the maintenance dependency.
How can I help you explore Laravel packages today?