Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Eloquent Eager Limit X Laravel Cte Laravel Package

staudenmeir/eloquent-eager-limit-x-laravel-cte

A Laravel package that combines eager limit loading with common table expressions, letting you limit eager-loaded relationships per parent model using CTEs. Useful for fetching only the latest or top N related records for each parent in a single query.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. This is a compatibility shim, not a capability. It exists only because staudenmeir/eloquent-eager-limit (per-parent LIMIT compiled as ROW_NUMBER() OVER (PARTITION BY ...)) and staudenmeir/laravel-cte (WITH / WITH RECURSIVE in the query builder) both override Laravel's SQL-compilation path and relation internals, and used together they emit malformed SQL. Adopting this package is therefore a decision to own a conflict-resolution layer above two upstream dependencies we would otherwise take directly.

That makes the fit narrow and conditional: justified only where a single query shape simultaneously needs recursive/hierarchical querying and top-N-per-parent eager loading. If we need one behaviour, we take the corresponding upstream package and skip this entirely — that is the single most likely correct answer, and the TPM should force that question before anything else. Where it does fit, integration is idiomatic Eloquent: trait composition on models and relations, no service provider, no migration, no daemon. The architectural surface is genuinely small.

Integration feasibility. Mechanically this is a Composer require plus trait usage. The real work is proving a three-way version intersection: bridge × both parent packages × Laravel/PHP core. The last tag is February 2023, placing it in the Laravel 9/10 window. Laravel 11 and 12 changed grammar and relation internals, and a package whose entire value is overriding protected compilation behaviour is precisely what breaks on a major bump. Compatibility must be proven by spike, never assumed from the version constraint.

Technical risk — the dominant finding.

  • Abandonment: high. Six stars, zero dependents, single maintainer, no release in over two years. There is no production user base to discover breakage ahead of us; we would be the canary.
  • Internal-API exposure: high. Value depends on protected grammar and relation internals Laravel treats as non-public and changes freely between majors.
  • Database floor: material. Window functions and CTEs require MySQL 8.0+, PostgreSQL, SQLite 3.25+, or SQL Server. A MySQL 5.7 estate is disqualified outright — that is a hosting/upgrade roadmap consequence with cost and migration risk attached, not a library footnote.
  • Silent correctness: moderate but the one to fear. Per-parent limiting is only as correct as the PARTITION BY key. A wrong partition returns plausible-looking wrong data rather than an error — the worst failure class for a feed or reporting surface, because it survives QA and surfaces as a business-data dispute.
  • Blast radius: favourable, and this is what makes the risk manageable rather than disqualifying. Compile-time SQL generation only — no persistence, no queue, no external I/O, no runtime state. Failure surfaces as a broken or wrong query on a bounded set of endpoints, not as data corruption or a stalled worker.

Key questions to resolve before commitment.

  1. Which exact Laravel and PHP versions does the current release support, and does that intersect our target platform?
  2. Do we have a current, demonstrable need for CTEs and per-parent limits in the same query — or is this speculative?
  3. What is our production database and version, and does it clear the window-function floor? If not, what does upgrading cost and who funds it?
  4. Has a simpler native path (latestOfMany() / ofMany(), a whereIn subquery, a precomputed summary table) already been ruled out? This is the cheapest possible outcome and must be checked first.
  5. Who owns a vendored fork if upstream goes dark, and is that effort budgeted?
  6. How deep does the feed/reporting layer sit inside Eloquent versus a dedicated read model? The existence of a merge package is itself a signal that two advanced builder extensions collide on the same path — worth a design conversation now, while the surface is small.

Integration Approach

Stack fit. Adopt only on Laravel projects running MySQL 8+/PostgreSQL/SQLite 3.25+/SQL Server where at least one model graph genuinely requires both behaviours. Framework-native, PSR-4, MIT, no infrastructure footprint and no configuration surface to secure. The decision is therefore almost entirely about ownership and version pinning rather than architecture — which is good news, because it means the decision is reversible if we wrap it properly.

Migration path. Pick the route explicitly at the outset; do not drift into one.

  • Route A — consume the bridge directly. Appropriate for a scoped, time-boxed need where the collision is real today. Fastest to value, inherits full upstream risk.
  • Route B — vendor or fork under app/Support/ or a private package. Given zero dependents and a stale release, this is the realistic default rather than a pessimistic edge case. MIT makes it clean and the surface area is small enough that a fork is a legitimate build decision, not a rescue plan.
  • Avoid — transitive convenience. Pulling it in because it appeared in the dependency tree defers the compatibility problem to the worst possible moment: a Laravel upgrade with no owner.

If only one behaviour is needed, depend on the upstream package directly. If the requirement is "latest one per parent," latestOfMany() / ofMany() or a summary table likely closes it with zero new dependencies — verify first.

Compatibility. Three constraints must all hold simultaneously and must be asserted, not inferred: the bridge supports our Laravel/PHP major; both upstream packages do too; and our database clears the window-function and CTE floor. Pin the exact version, add it to the Laravel-major upgrade checklist, and add a CI test asserting generated SQL for representative queries so a framework bump fails loudly at PR time instead of in production.

Sequencing.

  1. Spike in a branch. Reproduce the exact target query (CTE + limited eager load) and capture generated SQL via toSql() or the query log. Confirm the partition key and the ROW_NUMBER predicate match what we would hand-write. This is the highest-value verification step and gates everything downstream.
  2. Confirm the DB floor in every environment — staging and production, not just local dev. A green local Postgres proves nothing about a legacy MySQL estate.
  3. Wrap it. Put the capability behind one internal helper/repository so no call site imports the vendor trait. Removal or a fork becomes a one-file change.
  4. Attach it to named endpoints, not to models globally. Scope keeps the blast radius bounded and the rollback trivial.
  5. Ship with a fallback. The pre-agreed degradation path — over-fetch and slice in PHP, restructure the query, or fall back to a read model — is defined before launch, not invented during an incident.
  6. Re-evaluate at the next Laravel major. Default assumption: the bridge does not survive it, and the fork becomes the primary.

Operational Impact

Maintenance. This is the dominant lifecycle cost and it is ownership, not operations. A single-maintainer package with a 2023 release and no dependents means no upstream support contract in practice. Budget roughly one day to vendor or reimplement the trait if upstream stalls — the logic is small — and treat the fork as a planned contingency with a named owner rather than an unassigned "if it breaks we'll figure it out." Add the dependency to the Laravel-major upgrade checklist so it is a scheduled cost, not a surprise.

Support. No vendor, no SLA, no community to escalate through. Internal support means the team that wrapped it owns it: the helper layer is the support boundary, and it should be documented enough that someone who did not write it can debug the generated SQL. Because there is no schema or infrastructure change, runbooks stay simple — the troubleshooting tool is the query log.

Scaling. Favourable and predictable. Per-parent limiting through window functions moves work from PHP fetch-then-slice into the database, which is strictly better on memory and round trips for large relation collections — the p95 improvement is the point of adopting it. CTEs likewise replace PHP-side recursion that degrades past a handful of levels. The counterweight is that heavy PARTITION BY and recursive CTE queries concentrate cost on the database tier; index coverage on the partition key becomes a real performance concern and should be reviewed alongside the queries, not after the first latency incident.

Failure modes. Ranked by what a TPM actually has to plan for:

  • Silent wrong data (most serious). A mis-specified partition key returns plausible-but-wrong results with no exception. Mitigate with SQL assertions in CI and a spot-check against hand-written queries on representative data.
  • Breakage on framework upgrade. Grammar/relation internals change; queries fail loudly. This is the acceptable failure mode — CI catches it at PR time.
  • Abandonment. No fix arrives for a future major. Mitigated by the fork contingency and the one-file wrapper.
  • Database floor violation. On MySQL 5.7 the capability simply cannot be delivered at any price — a deploy-time blocker, which is why the floor is a platform commitment, not a footnote.
  • Wrong-query regression on a bounded endpoint set. Contained; roll back to the fallback path.

Notably absent: data corruption, stalled workers, queue backlogs, external-service outages. Compile-time-only behaviour is the reason this risk profile is tolerable.

Ramp-up. Low for engineers already fluent in Eloquent internals, moderate for everyone else — the concepts (PARTITION BY, ROW_NUMBER, recursive CTEs) are not everyday knowledge on a typical product team. Plan for the wrapper helper to carry the explainability burden: call sites should read as "top N per parent" in domain terms, never as window-function SQL. Two costs to name explicitly: the initial spike (days, not weeks) and the organisational conversation about the database floor, which has budget and hosting implications and should be decided deliberately rather than as a side effect of a Composer require.

Recommendation. Green-light as a scoped, pinned dependency behind one internal helper for the specific feed/hierarchy work — not as a platform standard. Buy the capability, pin the artifact, and make removal a one-file change.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums