Elixir使用多个Map重载参数并重试Repo.get_by()

时间:2017-02-14 18:42:59

标签: elixir ecto

我想重载一个函数,该函数将map作为几个不同情况的参数。调用函数时,将根据映射中的键执行不同的函数。

例如,在此find_user!()函数中,我可以通过idemailmobile个数字字段找到用户,这些字段都在数据库中编入索引。

  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

虽然,在这种情况下,我同时拥有emailmobile号码,我想使用提供的电子邮件在数据库中查找记录,如果找不到,请查找手机号码。如果两者都找不到,则应返回标准nil或RecordNotFound异常。

  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

我开始使用这些字段并开始尝试使用条件来Enum.any?来测试是否对包含emailmobile的地图进行了检索,但在此之前我已经实现了当我在控制台中运行MyApplication.find_user!(%{ "email" => "admin@example.com","mobile" => "0009998888"})函数时,重载转到第一个重载的find_user!(%{"email" => email})函数而不是我的函数。我认为这是因为它首先与该领域匹配。

有没有办法用这样的参数映射重载Elixir中的函数?或者我是否接近这个问题?也许我应该使用递归样式函数来初始尝试查找记录,然后使用不同的属性重试。

1 个答案:

答案 0 :(得分:2)

这是另一种方法,不需要在前三个函数中添加任何内容:

  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