DogEatDog
DogEatDog

Reputation: 3047

Elixir Overloading Parameter with multiple Map and retry Repo.get_by()

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

Answers (1)

kmptkp
kmptkp

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

Related Questions