hnhl
hnhl

Reputation: 137

Ecto Repo.exists?() do something only when false

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

Answers (3)

Venkatesh Shanmugham
Venkatesh Shanmugham

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

Daniel
Daniel

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:

  1. Refactor to 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

Aleksei Matiushkin
Aleksei Matiushkin

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

Related Questions