cnck1387

cnck1387

Why does Repo.get and Repo.get_by return the resource or nil instead of an ok or error tuple?

Hi,

Repo.insert, Repo.update and Repo.delete all return {:ok, resource} or {:error, changeset}.

But Repo.get and Repo.get_by return resource or nil.

I also noticed a decent amount of custom code (such as the Programming Phoenix Rumbl example app) prefers to use the tuple style, such as the RumblWeb.Auth.login_by_email_and_pass function returning {:ok, conn} or {:error, _reason, conn}.

That made me very curious. Why doesn’t Repo.get return {:ok, resource} or {:error, :resource_not_found}?

If it’s an API oversight and too late to change, what do you think about adding this custom function to your lib/myapp/repo.ex and always using this instead of get_by?

  def fetch_by(queryable, clauses, opts \\ []) do
    case get_by(queryable, clauses, opts) do
      nil ->
        {:error, :resource_not_found}

      resource ->
        {:ok, resource}
    end
  end

The fetch function (not included here) would do the same thing, except wrap get.

Edit: For clarity, it would be useful to have this because when pattern matching on else when using with it’s a lot more obvious to see what went wrong when you match on something like {:error, :resource_not_found} vs matching on nil.

Most Liked

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Yup. I add this to all my apps repo modules usually:

  def fetch(query) do
    case all(query) do
      [] -> {:error, query}
      [obj] -> {:ok, obj}
      _ -> raise "Expected one or no items, got many items #{inspect(query)}"
    end
  end

Super handy when you use with as well.

13
Post #4
benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Ah well I actually have three functions:

  def fetch_by(query, args) do
    query
    |> where(^args)
    |> fetch
  end

  def fetch(query, id) do
    query
    |> where(id: ^id)
    |> fetch
  end

  def fetch(query) do
    case all(query) do
      [] -> {:error, query}
      [obj] -> {:ok, obj}
      _ -> raise "Expected one or no items, got many items #{inspect(query)}"
    end
  end
benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Yeah there’s a reason my fetch uses all internally because you can also run into issues if your query selects just one column which can be nil.

value = User |> select([u], u.banned_at) |> Repo.get(id)

If value is nil, was the user never banned? or do they not exist? The fetch function I wrote will return {:ok, nil} for a user that exists but the column is nil, and {:error, query} if they don’t exist at all.

I proposed it to the ecto team a while ago, you can find the discussion here: Repo.get returns ambiguous responses · Issue #1225 · elixir-ecto/ecto · GitHub

Where Next?

Popular in Questions Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> somethi...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lists...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
New
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New

Other popular topics Top

hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43806 214
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement