Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions lib/expr.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2922,6 +2922,29 @@ defmodule AshSql.Expr do
end)
end)

# Joins for `rest` are derived from the refs in the filter and are left
# joins, so a predicate with no refs (e.g. `exists(a.bs, true)`) drops the
# remaining path entirely, and a null-satisfiable predicate is satisfied
# by null-extended rows. Requiring a non-nil primary key at every hop
# (not just the last: `no_attributes?` hops join with `on: true`)
# excludes both while being a no-op for real rows.
filter =
rest
|> Enum.scan([], fn rel_name, prefix -> prefix ++ [rel_name] end)
|> Enum.reduce(filter, fn prefix, filter ->
with target when not is_nil(target) <-
Ash.Resource.Info.related(first_relationship.destination, prefix),
[pk | _] <- Ash.Resource.Info.primary_key(target) do
Ash.Query.BooleanExpression.optimized_new(
:and,
filter,
Ash.Expr.expr(not is_nil(^Ash.Expr.ref(prefix, pk)))
)
else
_ -> filter
end
end)

query =
if first_relationship.type == :many_to_many do
put_in(query.__ash_bindings__[:lateral_join_bindings], [:join_source])
Expand Down
Loading