Reputation: 3047
I want to overload a function that takes a map as a parameter for a few different cases. When calling the function, a different function will execute based on the keys in the map.
For example, in this find_user!()
function, I can find the user by id
, email
, or mobile
number fields which are all indexed in the database.
def find_user!(%{"id" => user_id}) do
Repo.get(User, user_id)
end
def find_user!(%{"email" => email}) do
IO.puts "get user by email"
Repo.get_by(User, email: email)
end
def find_user!(%{"mobile" => mobile}) do
IO.puts "get user by mobile"
Repo.get_by(User, mobile: mobile)
end
Although, in this case I have both an email
and a mobile
number and I want to lookup the record in the database using the provided email and if it cannot be found, look it up by mobile number. If it cannot be found by both, it should return the standard nil
or RecordNotFound exception.
def find_user!(%{"email" => email, "mobile" => mobile } = params) do
Enum.any?(params, fn(x,y) -> IO.puts "#{x} , #{y} " end )
#Try finding by Email, then try finding by mobile
# code goes here
end
I started with the fields and began experimenting with the Enum.any?
with a conditional to test if any retrieval for the map containing email
and mobile
but before I could get too far I realized that when I ran the MyApplication.find_user!(%{ "email" => "[email protected]","mobile" => "0009998888"})
function in the console, that the overloading went to the first overloaded find_user!(%{"email" => email})
function instead of my function. I assume this is because it matched the field first.
Is there a way to overload a function in Elixir with a map of parameters like this? Or am I approaching this problem wrong? Maybe I should be using a recursive style function to do the initial try of looking up the record and then retry using a different attribute.
Upvotes: 0
Views: 470
Reputation: 158
Here is another way to do this, without adding anything to your first three functions:
def find_user!(%{"id" => user_id}) do
Repo.get(User, user_id)
end
def find_user!(%{"email" => email} = params) do
IO.puts "get user by email, then mobile"
case Repo.get_by(User, email: email) do
nil -> Repo.get_by(User, mobile: params["mobile"])
val -> val
end
end
def find_user!(%{"mobile" => mobile}) do
IO.puts "get user by mobile"
Repo.get_by(User, mobile: mobile)
end
Upvotes: 2