elixir-dx/dx

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?
Zurga commented

I feel like this issue clashes with #5.

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?