Bylaw.Ecto.Query.Checks.OffsetWithoutLimit (bylaw_ecto_query v0.2.0)

Copy Markdown View Source

Validates that queries do not use offset without limit.

Offset without limit skips rows and then returns every remaining row. That can create an unbounded scan from an arbitrary position, which is usually an accidental pagination shape.

Examples

Bad:

from(Post, as: :post)
|> order_by([post: p], asc: p.inserted_at)
|> offset(10_000)

Why this is bad:

The query skips 10,000 rows and then returns every remaining row. That is usually an accidental unbounded pagination query.

Better:

from(Post, as: :post)
|> order_by([post: p], asc: p.inserted_at)
|> limit(50)
|> offset(10_000)

Why this is better:

limit gives the page a bounded size. Pair this with Bylaw.Ecto.Query.Checks.RequiredOrder when the page also needs stable row order.

Notes

This check only verifies that offset has a paired limit. It does not prove the order is deterministic or that offset pagination is the best strategy for a large table.

Options

  • :validate - explicit false disables this check. It can be used in the repo-wide check list or in call-site overrides passed to Bylaw.Ecto.Query.validate/4.

Run globally with defaults:

Bylaw.Ecto.Query.Checks.OffsetWithoutLimit

Run only for matching rule scopes:

{Bylaw.Ecto.Query.Checks.OffsetWithoutLimit,
 rules: [
   [where: [ecto_schemas: [Post]]],
   [where: [tables: ["posts"]]]
 ]}

This check has no check-specific rule options.

The check applies to the root query and nested source subqueries, join subqueries, CTE queries, combination branches, and expression subqueries.

Usage

Add this module to the explicit check list passed through Bylaw.Ecto.Query. See Bylaw.Ecto.Query for the full Ecto.Repo.prepare_query/3 setup.

Summary

Functions

validate(operation, query, opts)

Implements the Bylaw.Ecto.Query.Check validation callback.