Reputation: 137
I am pretty new to Elixir/Ecto and unlike other languages, I find it kind of confusing on how control flows work
I want to just only do something when Repo.exists?()
returns false. According to the docs, this returns a boolean. I tried
**/Orginal OP code**
alias App.MyModule
params.id
|> MyModule.check_if_person_exist()
|> Repo.exists?()
|> if false do
IO.puts("\n\nFALSEEE\n\n")
MySchema
|> MySchema.changeset(%{data: data})
|> Repo.insert_or_update()
...
...
App.MyModule file
def check_if_person_exist(id) do
from(s in Schema
where id = ^id,
select %{
person: s.person
}
)
end
case do
false ->
//do stuff
But I get an error saying no case clause matching true
I just want to do something only if false and not check for true. Is that not possible to do with Ecto/Elixir?
//**MyQuery.Module**
def myqueryfunc(id) do
query = from(s in Schema
where id = ^id,
select %{
person: s.person
}
)
end
//**Some other file**
alias MyQuery.Module
query = Module.myqueryfunc(id)
case Repo.one(query) do
false ->
MySchema
|> MySchema.changeset(%{data: data})
|> Repo.insert_or_update()
Do I have to take into consideration true
?
I only care if it is false.
If I do have to handle true, what can I do to do nothing when it is true?
Will this work
query
|>Repo.exists?()
|> false
|> if(do: //insert or update)
Upvotes: 1
Views: 2022
Reputation: 81
First of all, you shouldn't use a pipe operator like this
code
|> Repo.exists?()
|> if do
the above one is an Ambiguous pipe statement, you could see elixir pipe operator
You could use case
statement like below to do your control flow
params.id
|> MyModule.check_if_person_exist()
|> Repo.exists?()
|> case do
true -> nil
false ->
IO.puts("\n\nFALSEEE\n\n")
MySchema
|> MySchema.changeset(%{data: data})
|> Repo.insert_or_update()
end
Upvotes: -2
Reputation: 2554
Functional languages have the concept of pure functions. A pure function must always return a value, there is no such thing as procedures in elixir.
Case statements must be exhaustive, in your case your Repo.exists?/1
returns true
and in your case statement you don't handle it.
You can solve this problem in several ways:
if
:if !Repo.exists?(query) do
MySchema
|> MySchema.changeset(%{data: data})
|> Repo.insert_or_update()
end
This solution however is not the best one, since function will either return nil or your updated entry, instead I would do the following:
case Repo.one(query) do
nil ->
MySchema
|> MySchema.changeset(%{data: data})
|> Repo.insert_or_update()
result -> result
end
In this way you guarantee that you will return a entry in both cases. This practice is applied a lot even in ecto internals.
Upvotes: 2
Reputation: 121010
If there is no matching clause, the code will raise CaseClauseError
iex|💧|1 ▸ case true do
...|💧|1 ▸ false -> :ok
...|💧|1 ▸ end
** (CaseClauseError) no case clause matching: true
Yes, you need to cover all the possible outcomes with case/2
. OTOH, we have if/2
, which is more tolerant and silently returns nil
if there is no else:
clause.
iex|💧|2 ▸ false |> if(do: :ok)
nil
So you might either do if/2
or handle all the clauses in the case/2
expression as
query
|> Repo.exists?()
|> case do
false -> ...
true -> :ok # or `nil` or whatever
end
Upvotes: 2