Skip to content

Do not assume JoinExpr.on is a QueryExpr#747

Draft
lukaszsamson wants to merge 1 commit into
elixir-ecto:masterfrom
lukaszsamson:relax-join-on-pattern-matches
Draft

Do not assume JoinExpr.on is a QueryExpr#747
lukaszsamson wants to merge 1 commit into
elixir-ecto:masterfrom
lukaszsamson:relax-join-on-pattern-matches

Conversation

@lukaszsamson

Copy link
Copy Markdown
Contributor

Companion to elixir-ecto/ecto#4765 (fix for elixir-ecto/ecto#4763).

That PR makes interpolated join queries (join: x in ^query) carry their on expression as a BooleanExpr instead of a QueryExpr, since wheres folded into the on may hold subqueries and BooleanExpr already owns them. Per the review discussion, the BooleanExpr is kept in the normalized query rather than converted back, so adapters must accept it.

This relaxes the %JoinExpr{on: %QueryExpr{expr: expr}} pattern matches in the postgres, myxql, and tds connections to the map shape %JoinExpr{on: %{expr: expr}}, accepting both structs. The relaxed patterns are compatible in both directions: this branch passes against ecto 3.14 from hex as well as against the ecto PR branch (ECTO_PATH), so it can ship independently of the ecto release.

Two failure modes without this change (verified by running this suite against the ecto PR branch):

  • join/2 raises FunctionClauseError for any interpolated join query — loud.
  • the using_join comprehensions (for %JoinExpr{on: %QueryExpr{expr: value}} <- joins, ...) silently drop the join conditions from the WHERE clause of update_all/delete_all — wrong SQL, no error. There was no test coverage for interpolated join queries in update_all/delete_all, so this PR adds it for all three adapters (the new tests pass on current ecto releases too, since the generated SQL is unchanged).

Tests asserting the new subquery-in-join-on SQL itself (e.g. ON p1."id" IN (SELECT ...)) are intentionally left out for now, as they require the unreleased ecto — they can be added once the ecto side ships.

🤖 Generated with Claude Code

Ecto is changing interpolated join queries (join: x in ^query) to carry
their "on" expression as a BooleanExpr instead of a QueryExpr, since
folded wheres may hold subqueries (elixir-ecto/ecto#4765). Relax the
join.on pattern matches to the map shape so both structs are accepted.

This matters beyond the crash in join/2: the using_join comprehensions
filtered joins by on: %QueryExpr{}, so a BooleanExpr "on" would have
been silently dropped from the WHERE clause of update_all/delete_all.
Add coverage for interpolated join queries in update_all/delete_all,
which previously had none.

The relaxed patterns remain compatible with current Ecto releases.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant