Have a look at this:
def get_patient!(id, user_id) do
case CurrentUser.is_manager(user_id) do
true -> Repo.get!(Patient, id) # manager can access all without ACL
false -> Patient # normal user, check if current_user is listed in patient's ACL
|> where([p], fragment("? = '{}'", p.acl)) # A -> ACL array is empty, so this row is open for all users..
|> or_where([p], fragment("? @> ?::bigint[]", p.acl, ^[user_id])) # B -> user_id is listed in the ACL array
|> where(id: ^id) # C -> match patient record itself
|> Repo.one
end
end
This works as expected (discovered this after wasting some time on it…)
However, if I place statement C
first (before A
and B
), I don’t get the expected results.
I this normal when using or_where
? Thank you.
It’s normal. Here are there heuristics:
where
- if no filters came before, emit just the condition. if some filters came before, combine them with this new condition using AND
boolean operator
:or_where
- if no filters came before, emit just the condition. if some filters came before, wrap them in brackets and combine them with this new condition using OR
operator
It’s the same way you should think about it using regular boolean logic. Order matters
1 Like
Is there a way to specify (in pipe) that A
and B
should be a set and C
another (I mean to wrap them somehow with some code so C
can be placed first)?
Is there a way to specify explicitly that [C
AND [A
OR B
]]?
where(A) |> or_where(B) |> where(C)
just need to remember or_where
is OR everything that came behind it.
1 Like
If you want to control precedance manually you can use the dynamic macro to build up conditions: Ecto.Query — Ecto v3.7.0
With multiple where
or or_where
ordering determines precedance.
2 Likes