Product Decisions This Supports
- Build vs. buy on derived data. A cheap, MIT-licensed alternative to two expensive paths: adding denormalized counter columns (plus event listeners and backfill migrations) or standing up a warehouse/reporting DB. It lets the app answer "how many open tickets does this customer have?" at read time by reusing logic you already wrote.
- Single source of truth for business rules. Today the same constraint typically exists twice — once in a scope that drives filtering, once re-implemented in PHP or raw SQL to render a column. Every copy is a future inconsistency bug ("this account shows as Active but is filtered out of the Active list"). Turning the scope itself into the select column makes filter and display definitionally identical.
- Feature bets this unlocks cheaply: sortable/filterable computed columns in admin and ops surfaces (last order date, lifetime value, open ticket count, days-since-last-login), paginated list views with per-row aggregates, CSV exports that match on-screen numbers, and API resource fields backed by the same definition the UI filters on.
- Roadmap sequencing. These are the "analytics-lite" requests that show up in every back-office backlog. This package moves them from "needs a data platform project" to "ships in a sprint," which buys time before committing to warehouse investment.
- Architecture direction. A deliberate choice to accept read-time cost in exchange for a simple write path. That's usually right for low-QPS internal tooling and wrong for high-traffic public endpoints — a decision worth recording rather than defaulting into.
- Tech debt reduction. Consolidates scope logic currently scattered across controllers, API resources, export jobs, and Blade templates into one reusable primitive.
When to Consider This Package
Adopt when:
- The codebase is Laravel + Eloquent and already has scopes encoding real business logic — there is reuse to capture.
- The surface is back-office, admin, or internal reporting: paginated reads, modest QPS, tolerant latency budgets.
- You need a handful of derived columns per view (1–5), not a hundred, and want them sortable.
- You value a small, forkable, MIT dependency over a framework-sized reporting layer.
- Your team can read a
EXPLAIN and will benchmark on production-shaped data before shipping.
Look elsewhere when:
- Queries are high-QPS or hit large tables — a correlated subquery per row is a real cost. Prefer denormalized counters with backfill, materialized views, or a read model.
- You need window functions, CTEs, or unions — reach for native SQL or a more expressive query builder.
- The scopes you'd convert use joins,
groupBy, or having; subselect semantics get fragile and should be prototyped before committing.
- No Eloquent scopes exist yet — build the scopes first, decide on this later.
- A BI/warehouse layer is already funded; don't fork metric definitions between app and warehouse.
- Database portability beyond what the package tests is a hard requirement.
Risk note to carry into the decision: 142 stars and 0 dependents means a thin maintainer base. Mitigations are cheap here — pin the version, vendor or fork on adoption, and keep a one-file escape hatch to raw SQL if it's abandoned. The low "opportunity" score reflects niche scope, not low utility; this is an internal-leverage tool, not a market play.
How to Pitch It (Stakeholders)
To executives: A free, MIT-licensed library that lets us ship the dashboard and reporting requests already on the roadmap by reusing query logic we've already written and tested. It's the cheap option — no warehouse, no schema denormalization, no new write-path complexity. Adoption cost is one dependency; the decision is reversible in an afternoon.
To engineering: One macro that turns an existing Eloquent scope into a correlated subquery column. It eliminates duplicated constraints between filters and rendered values, removes N+1 aggregation loops in list views and exports, and keeps a single definition of every metric. The generated SQL is inspectable, so it's auditable and benchmarkable.
Honest trade-offs, stated up front: we pay at read time rather than write time, it's bounded by what a subquery can express, and the maintainer base is small enough that we should pin and plan to vendor. For internal, paginated, low-QPS surfaces those are acceptable; for anything customer-facing at scale, we should route around it rather than bend it.