Elixir, Ecto pattern matching conditional with db query not behaving as expected

情到浓时终转凉″ 提交于 2019-12-13 06:17:29

问题


If the record does not exist, I would expect this conditional to create it, but it does not.... nil is returned.

case Repo.get_by(User, %{email: "hulk@hogan.com"}) do
    struct ->
      struct
    nil ->
      params = Map.merge(%{email: "hulk@hogan.com"}, %{password: "password"})
      Repo.insert!(User.changeset(User.__struct__, params))
end

# returns nil.... huwutt???

However, if I change the ordering of the condition, it works. What am I missing here?

case Repo.get_by(User, %{email: "hulk@hogan.com"}) do
    nil ->
      params = Map.merge(%{email: "hulk@hogan.com"}, %{password: "password"})
      Repo.insert!(User.changeset(User.__struct__, params))
    struct ->
      struct
end

# returns a set of 24" pythons, brother.... huzah!

回答1:


According to the documentation

case allows us to compare a value against many patterns until we find a matching one:

In another word, the first matching case will run and case will not proceed further.

In your first example, the first case will always be matched since you are not providing any guards, and as such, struct will bind to nil. Your second approach solves the problem because you're pattern matching a specific case first, and then defaulting to a general case by binding the evaluation of case to struct.

Also note that you can use guards in your first case to make sure that the value of struct is a map as outlined here.

case Repo.get_by(User, %{email: "hulk@hogan.com"}) do
    struct when is_map(struct) ->
      struct
    nil ->
      params = Map.merge(%{email: "hulk@hogan.com"}, %{password: "password"})
      Repo.insert!(User.changeset(User.__struct__, params))
end


来源:https://stackoverflow.com/questions/42776078/elixir-ecto-pattern-matching-conditional-with-db-query-not-behaving-as-expected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!