defmodule MyApp.Account do
use Ecto.Schema
@primary_key {:id, MyApp.AccountID, autogenerate: true}
schema "accounts" do
field :name, :string
# ... more fields here
end
end
defmodule MyApp.AccountID do
@behaviour Ecto.Type
@hashids Hashids.new(min_len: 8, salt: "**salt**")
@moduledoc """
Converts integers to Hashids.
See http://hashids.org/ for more information.
"""
def type(), do: :id
def cast(term) when is_integer(term), do: {:ok, Hashids.encode(@hashids, term)}
def cast(term) when is_binary(term), do: dump(term)
def cast(_), do: :error
def dump(term) when is_binary(term) do
Hashids.decode!(@hashids, term)
|> case do
[int] -> {:ok, int}
_ -> :error
end
end
def dump(term) when is_integer(term), do: {:ok, term}
def dump(_), do: :error
def load(term) when is_integer(term), do: cast(term)
def load(_), do: :error
end
When inserting into a Repo I get integer (:id) keys back from Ecto.
This returns {:ok, %MyApp.Account{id: 323, name: "hello"} but I’m expecting that the id field should be passed through the load function on my custom type on it’s way back from the database.
Is this a bug in Ecto or am I doing something wrong?
I’m using the name :id because I want my database to generate the primary key for me, I have not figured out another way to “trick” the database (postgres) do it for me.
Hmm, if I swap autogenerate: true for read_after_writes: true on the field options it seems to work as expected
Can someone verify if this is the correct thing to do?
defmodule MyApp.Account do
use Ecto.Schema
@primary_key {:id, MyApp.AccountID, read_after_writes: true}
schema "accounts" do
field :name, :string
# ... more fields here
end
end