Reputation: 169
I have a complex use case of cond
I'm curious if this is the best way to do it.
The code below basically attempts to match up a customer with an existing record.
I need the code to stop checking once a query permutation returns any rows.
customers = cond do
(c = CustomerRepo.findExactNameAndDob(store_id, firstname, lastname, dob)) |> length > 0 -> c
(c = CustomerRepo.findExactNameAndMobile(store_id, firstname, lastname, phone)) |> length > 0 -> c
(c = CustomerRepo.findExactNameAndEmail(store_id, firstname, lastname, email)) |> length > 0 -> c
(c = CustomerRepo.findExactNameAndLocation(store_id, firstname, lastname, address, postcode)) |> length > 0 -> c
true -> nil
end
There's many more queries, I've trimmed this a bit. Don't focus on the business logic, I just want to clean up this condition.
Upvotes: 1
Views: 127
Reputation: 222158
We can make use of the fact that the function is in the same module and the first three arguments are fixed to simplify this using Enum.reduce_while/3
:
[
{:findExactNameAndDob, [dob]},
{:findExactNameAndMobile, [phone]},
{:findExactNameAndEmail, [email]},
{:findExactNameAndLocation, [address, postcode]}
]
|> Enum.reduce_while(nil, fn {func, args}, nil ->
case apply(CustomerRepo, func, [store_id, firstname, lastname] ++ args) do
[] -> {:cont, nil}
customers -> {:halt, customers}
end
end)
This should make the code much simpler since you say you have many more such clauses in the actual code.
Edit: There's a simpler way assuming the success value is not nil or false (here it's always a list so it's fine) using Enum.find_value/2
:
[
{:findExactNameAndDob, [dob]},
{:findExactNameAndMobile, [phone]},
{:findExactNameAndEmail, [email]},
{:findExactNameAndLocation, [address, postcode]}
]
|> Enum.find_value(fn {func, args} ->
case apply(CustomerRepo, func, [store_id, firstname, lastname] ++ args) do
[] -> false
customers -> customers
end
end)
Upvotes: 1