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- explicitfalsedisables the check. Defaults totrue.
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
Implements the Bylaw.Ecto.Query.Check validation callback.
Functions
@spec validate( Bylaw.Ecto.Query.Check.operation(), Bylaw.Ecto.Query.Check.query(), opts() ) :: Bylaw.Ecto.Query.Check.result()
Implements the Bylaw.Ecto.Query.Check validation callback.