Bylaw.Ecto.Query.Checks.NamedBindings (bylaw_ecto_query v0.1.0-alpha.1)

Copy Markdown View Source

Validates that an Ecto.Query uses named binding aliases in query expressions.

This check reads the prepared Ecto query struct. It requires the root binding and every join to declare an :as alias, then rejects field references that target bindings without a declared alias.

Ecto expands named binding lists such as [post: p] to the same prepared query shape as local binding variables such as post. Because that source syntax is no longer distinguishable from the prepared query struct, this check accepts both forms as long as the referenced binding has an alias.

Association join sources, joined preloads, and whole-binding selects are not rejected because Ecto either requires binding variables for those forms or erases the source syntax before this check runs.

Ecto's repo lookup helpers, such as Repo.get_by/3, generate rootless keyword where queries inside Ecto repo internals before Ecto.Repo.prepare_query/3 runs. The original caller did not have a place to provide a root :as alias in that form, so this check ignores that generated lookup shape. Predicate-oriented checks can still validate those generated where fields.

Examples

Bad:

from(Post, as: :post)
|> join(:inner, [post: p], c in assoc(p, :comments))
|> where([p], p.organization_id == ^organization_id)

Why this is bad:

The join binding has no :as alias, and the predicate relies on positional binding access. As the query grows, it becomes easier to reference the wrong binding.

Better:

query =
  from(Post, as: :post)
  |> join(:inner, [post: p], c in assoc(p, :comments), as: :comment)
  |> where([post: p], p.organization_id == ^organization_id)

Bylaw.Ecto.Query.Checks.NamedBindings.validate(:all, query, [])

Why this is better:

Field references are tied to explicit binding names instead of binding positions.

Notes

Ecto's prepared query struct erases some source syntax. This check accepts named binding lists and local binding variables when the referenced binding has an alias.

Options

  • :validate - explicit false disables the check. Defaults to true.

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.