Error when no condition for a predicate matches
Closed this issue · 2 comments
Currently, when a predicate is defined and all rules ("cases") have a condition, the fallback value is nil
when none of the conditions matches.
In order to make the definition of predicates more explicit, and to force users to think about all the cases, this should be changed to raise if no condition matches.
This change is backward-incompatible. To migrate, users must look at each predicate and explicitly define a fallback rule returning nil
with no condition, if needed.
Example
defmodule Todo.List do
infer archived?: true, when: %{archived_at: {:not, nil}}
end
iex> %Todo.List{archived_at: nil}
...> |> Infer.get!(:archived?)
# current result
nil
# new result
** (Infer.MatchError) no rule condition matching for predicate :archived?
Hi @Zurga, thanks a lot for your feedback!
From my perspective, it does not necessarily clash as #5 proposes that
infer :archived?, when: %{archived_at: {:not, nil}}
implicitly means/defines
infer archived?: true, when: %{archived_at: {:not, nil}}
infer archived?: false
so, strictly speaking, when the condition for true
does not match, false
is returned. It's not "undefined".
However, from your feedback I conclude that it might be counter-intuitive, which also speaks against doing it like this.
In the meantime, I've also realized another problem with this proposal: Raising an error when no rule matches causes extra work. This is not a problem when rules are evaluated in Elixir. However, when rules are translated to SQL, it would mean an additional layer of checks to detect any cases where no rule matches.
Let's say, for example, we want to use the predicate above (:archived?
on a Todo.List
) to query for all archived Todo lists:
Dx.query_all(Todo.List, %{archived?: true})
Currently, Dx will translate this to something like SELECT * FROM todo_lists WHERE archived_at IS NOT NULL
.
Assuming we want to raise an error when no rule matches, and there is at least one list that's not archived, then Dx would have to raise an error. So this would somehow need to be reflected in the SQL. And that's pretty complex.
So I suggest closing this issue. What do you think?