Hello
I’m using Ecto along with PostgreSQL. I’ve been trying to add a field containing a 2-tuple to an Ecto schema, but can’t seem to make it work.
There is no built-in :tuple
type in Ecto, so I tried to create an Ecto.Type
, but that does not seem to be enough:
defmodule MyType do
use Ecto.Type
@impl Ecto.Type
def type, do: :my_type
@impl Ecto.Type
def cast({one, two}) when is_binary(one) and is_binary(two), do: {:ok, {one, two}}
def cast(_), do: :error
@impl Ecto.Type
def cast({one, two}) when is_binary(one) and is_binary(two), do: {:ok, {one, two}}
def cast(_), do: :error
@impl Ecto.Type
def load({one, two}) do
{:ok, {one, two}}
end
end
I create the field in an Ecto migration using this command:
execute "CREATE TYPE my_type AS (one text, two text)"
Then, when trying to insert a struct from a schema with a field of this type, I get the following message:
(DBConnection.EncodeError) cannot encode anonymous tuple {"one", "two"}. Please define a custom Postgrex extension that matches on its underlying type:
use Postgrex.BinaryExtension, type: "typeinthedb"
I tried to follow the instructions and create an extension, but could never make it work.
What blows my mind is that the library :ex_money_sql
(cc @kip) does not seem to have to create a Postgrex extension (or at least, I could never find it). See type source. Postgrex is pretty clear on the subject: “Anonymous composite types are decoded (read) as tuples but they cannot be encoded (written) to the database” (doc). So how does it work? Why does it work? I’m a bit lost here
If you see any flaw in my reasoning, please tell me what I’m doing wrong
Thanks for your time,