Skip to content

Add missing index on deliveries.created_at and make date filters sargable - #232

Merged
morcen merged 2 commits into
mainfrom
fix/issue-123-deliveries-created-at-index
Sep 22, 2026
Merged

morcen merged 2 commits into
mainfrom
fix/issue-123-deliveries-created-at-index

Conversation

@morcen

@morcen morcen commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner

What was broken

deliveries is the highest-volume, continuously-growing table in the app, but created_at — the column every listing query sorts by — has no index. On top of that, the from_date/to_date range filters used whereDate('created_at', ...), which wraps the column in a function and prevents Postgres from using a plain B-tree index even if one were added.

This pattern was duplicated across three query call sites:

  • Api\DeliveryController::index() (the /api/v1/deliveries listing)
  • DashboardController::deliveries() (the dashboard listing)
  • the same method's stat-card aggregate (groupBy('status') count query, cloned from the same filtered query)

As delivery volume grows, every one of these becomes a full table scan.

What changed

  • Added a migration indexing deliveries.created_at.
  • Replaced whereDate('created_at', ...) with direct timestamp range comparisons (>= start of day, < start of next day) in both controllers, so the filters stay sargable and can use the new index, while preserving identical inclusive day-range semantics.
  • Added tests/Feature/DeliveryDateRangeFilterBoundaryTest.php, covering:
    • the index exists on deliveries.created_at
    • the API date-range filter still includes the full first and last day of the range (boundary timestamps at 00:00:00 and 23:59:59)
    • the dashboard date-range filter does the same

Testing

  • vendor/bin/pint --dirty — clean
  • php artisan test — full suite passes (272 passed, 1 pre-existing skip)

Fixes #123

morcen and others added 2 commits September 21, 2026 19:22
… sargable

The deliveries table had no index on created_at, which every listing
query sorts by, and the from_date/to_date range filters used
whereDate('created_at', ...) in three separate call sites
(Api\DeliveryController::index, DashboardController::deliveries listing,
and its stat-card aggregate). Wrapping the column in whereDate() prevents
Postgres from using a plain B-tree index even if one existed, turning
every listing and dashboard load into a full table scan on the
highest-volume table in the app.

Add an index on created_at and replace whereDate() with direct
timestamp range comparisons (>= start of day, < start of next day) so
the filters remain index-friendly while preserving identical inclusive
day-range semantics.

Fixes #123
CI's Pint check runs --preset=psr12, which requires parentheses on
anonymous class instantiation and the opening brace on its own line.
Run vendor/bin/pint --preset=psr12 to match.
@morcen
morcen merged commit 5929bd3 into main Sep 22, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

deliveries.created_at has no index, and DeliveryController's whereDate() date filters can't use one anyway

2 participants