Hi elixir fam!
I’m running into some interesting errors with trying to implement a custom Postgrex Type Extension and I’m really hoping folks can help shed some light on it.
I’ve been trying really hard to add native support for ULID style UUIDs in my elixir application as it would be perfect for my team’s use case. I’ve made really great progress in about a week, but have been struggling to overcome a really pernicious issue for a few days now.
The particular postgresql extension I’m trying to make work is this one:
[ github: andrielfn / pg-ulid ]
Which adds native ULID support to postgresql. It’s fast, efficient, and it even adds a unique ulid
field type which is great! It’s an awesome extension and the author himself is big into Elixir!
The issue that I’m running into seems to stem from some kind of incompatibility or bug within Ecto or Postgrex for my particular use case. I’m trying to use the :ulid
field type added by the extention as the primary_key
identifier on all of my tables.
I’m not an expert in this area of Ecto/Postgrex, but I’ve managed to get almost full compatibility. I’m able to perform all of the basic CRUD functions so far. all while using ULIDs as the primary key, but certain kinds of actions just don’t work somehow.
For example Repo.reload/1
and a number internal tests handlers are broken and I can’t seem to figure out the root cause.
iex(1)> UlidTest.Accounts.create_user(%{name: "Hello world!"})
%UlidTest.Accounts.User{
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
id: "01JBCJYKBPXEMPD56NE290SETW",
name: "Hello world!",
inserted_at: ~N[2024-10-29 16:50:08],
updated_at: ~N[2024-10-29 16:50:08]
}
iex(2)> UlidTest.Accounts.get_user("01JBCJYKBPXEMPD56NE290SETW")
%UlidTest.Accounts.User{
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
id: "01JBCJYKBPXEMPD56NE290SETW",
name: "Hello world!",
inserted_at: ~N[2024-10-29 16:50:08],
updated_at: ~N[2024-10-29 16:50:08]
}
iex(3)> UlidTest.Accounts.get_user("01JBCJYKBPXEMPD56NE290SETW") |> UlidTest.Repo.reload()
** (FunctionClauseError) no function clause matching in UlidTest.PostgrexTypes."-inlined-Elixir.ULID.Extension/1-"/1
The following arguments were given to UlidTest.PostgrexTypes."-inlined-Elixir.ULID.Extension/1-"/1:
# 1
["01JBCJYKBPXEMPD56NE290SETW"]
(ulid_test 0.1.0) UlidTest.PostgrexTypes."-inlined-Elixir.ULID.Extension/1-"/1
(postgrex 0.19.2) lib/postgrex/query.ex:75: DBConnection.Query.Postgrex.Query.encode/3
(db_connection 2.7.0) lib/db_connection.ex:1449: DBConnection.encode/5
(db_connection 2.7.0) lib/db_connection.ex:1549: DBConnection.run_prepare_execute/5
(db_connection 2.7.0) lib/db_connection.ex:1653: DBConnection.run/6
(db_connection 2.7.0) lib/db_connection.ex:772: DBConnection.parsed_prepare_execute/5
(db_connection 2.7.0) lib/db_connection.ex:764: DBConnection.prepare_execute/4
(ecto_sql 3.12.1) lib/ecto/adapters/postgres/connection.ex:104: Ecto.Adapters.Postgres.Connection.prepare_execute/5
(ecto_sql 3.12.1) lib/ecto/adapters/sql.ex:1002: Ecto.Adapters.SQL.execute!/5
(ecto_sql 3.12.1) lib/ecto/adapters/sql.ex:994: Ecto.Adapters.SQL.execute/6
(ecto 3.12.4) lib/ecto/repo/queryable.ex:232: Ecto.Repo.Queryable.execute/4
(ecto 3.12.4) lib/ecto/repo/queryable.ex:19: Ecto.Repo.Queryable.all/3
(ecto 3.12.4) lib/ecto/repo/queryable.ex:154: Ecto.Repo.Queryable.one/3
iex:4: (file)
I'm really not sure what to make of this error, and I've spent several days throwing everything I have at it. It seems like Postgrex is trying to pass the ULID value toward the ULID.Extension contained within the Postgrex.Types definition, but failing to route it properly...
I’m also confused as to why it’s happening in that particular use-case because like was said before, all of the CRUD functions are working just fine, so why wouldn’t those functions exhibit the same issue?
I have put together a barebones sandbox app that showcases the problem that I’m encountering which can be found here:
Simply run the commands listed in the above example to make it happen.
(There is also some additional info in the README.md)
Some notable files changed from the phx.new app:
- lib/ulid_test/config/config.exs (settings to change primary_key → :ulid)
- lib/ulid_test/postgrex/types.ex (Custom Postgrex.Types.define/3)
- lib/ulid_test/postgrex/ulid.ex (ULID Postgrex.Extension)
- lib/ulid_test/ulid.ex (Custom Ecto.Type module)
Some additional information:
- elixir - 1.17.3-otp-27
- erlang - 27.1.2
- ecto - 3.12.4
- postgrex - 0.19.2
- apple M2 macbook (hardware)
If anyone more knowledgeable than myself can help me get unstuck on this I would be hugely grateful. Thank you guys in advance!