This will not fully solve the @leaf problem, as it in many-to-many relation when you want to filter out specific relation it will not be so easy. Simplest solution would be if Ecto would support existential queries directly which would greatly simplify this query. Instead we need to write something like:
filtered_user_ids =
from role in Roles,
inner_join: ur in "user_roles", on: role.id == ur.role_id,
group_by: ur.user_id,
having: ^requested_prof_id not in fragment("array_agg(?)", role.prof_id),
select: %{user_id: ur.user_id}
from user in User,
inner_join: ur in subquery(^filtered_user_ids), on: user.id == ur.user_id
I haven’t tested that query though, so it can have some issues.
If you want to use existential queries anyway then you can do:
from user in User,
where: fragment("""
NOT EXIST (
SELECT 1
FROM user_roles
INNER JOIN roles
ON roles.id = user_roles.role_id
WHERE roles.prof_id = ?
AND user_roles.user_id = ?
""",
^requested_prof_id,
user.id
)